All customization and QGIS browser work in one commit.
@ -178,6 +178,8 @@
|
||||
<file>themes/default/mIconTableLayer.png</file>
|
||||
<file>themes/default/mIconUnknownLayerType.png</file>
|
||||
<file>themes/default/mIconWaitingForLayerType.png</file>
|
||||
<file>themes/default/mIconWms.png</file>
|
||||
<file>themes/default/mIconWmsLayer.png</file>
|
||||
<file>themes/default/mMapserverExport.png</file>
|
||||
<file>themes/default/plugin.png</file>
|
||||
<file>themes/default/propertyicons/action.png</file>
|
||||
|
BIN
images/splash/deblin.png
Normal file
After Width: | Height: | Size: 277 KiB |
Before Width: | Height: | Size: 426 KiB After Width: | Height: | Size: 277 KiB |
BIN
images/splash/splash.png.orig
Normal file
After Width: | Height: | Size: 426 KiB |
BIN
images/themes/default/customization/calendarwidget.png
Normal file
After Width: | Height: | Size: 968 B |
BIN
images/themes/default/customization/checkbox.png
Normal file
After Width: | Height: | Size: 817 B |
BIN
images/themes/default/customization/columnview.png
Normal file
After Width: | Height: | Size: 518 B |
BIN
images/themes/default/customization/combobox.png
Normal file
After Width: | Height: | Size: 853 B |
BIN
images/themes/default/customization/commandlinkbutton.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
images/themes/default/customization/dateedit.png
Normal file
After Width: | Height: | Size: 672 B |
BIN
images/themes/default/customization/datetimeedit.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
images/themes/default/customization/dial.png
Normal file
After Width: | Height: | Size: 978 B |
BIN
images/themes/default/customization/dialogbuttonbox.png
Normal file
After Width: | Height: | Size: 1003 B |
BIN
images/themes/default/customization/dockwidget.png
Normal file
After Width: | Height: | Size: 638 B |
BIN
images/themes/default/customization/doublespinbox.png
Normal file
After Width: | Height: | Size: 749 B |
BIN
images/themes/default/customization/fontcombobox.png
Normal file
After Width: | Height: | Size: 966 B |
BIN
images/themes/default/customization/frame.png
Normal file
After Width: | Height: | Size: 721 B |
BIN
images/themes/default/customization/graphicsview.png
Normal file
After Width: | Height: | Size: 1.2 KiB |
BIN
images/themes/default/customization/groupbox.png
Normal file
After Width: | Height: | Size: 439 B |
BIN
images/themes/default/customization/groupboxcollapsible.png
Normal file
After Width: | Height: | Size: 702 B |
BIN
images/themes/default/customization/hscrollbar.png
Normal file
After Width: | Height: | Size: 408 B |
BIN
images/themes/default/customization/hslider.png
Normal file
After Width: | Height: | Size: 729 B |
BIN
images/themes/default/customization/hsplit.png
Normal file
After Width: | Height: | Size: 164 B |
BIN
images/themes/default/customization/label.png
Normal file
After Width: | Height: | Size: 953 B |
BIN
images/themes/default/customization/lcdnumber.png
Normal file
After Width: | Height: | Size: 555 B |
BIN
images/themes/default/customization/line.png
Normal file
After Width: | Height: | Size: 287 B |
BIN
images/themes/default/customization/lineedit.png
Normal file
After Width: | Height: | Size: 405 B |
BIN
images/themes/default/customization/listbox.png
Normal file
After Width: | Height: | Size: 797 B |
BIN
images/themes/default/customization/listview.png
Normal file
After Width: | Height: | Size: 756 B |
BIN
images/themes/default/customization/mdiarea.png
Normal file
After Width: | Height: | Size: 643 B |
BIN
images/themes/default/customization/plaintextedit.png
Normal file
After Width: | Height: | Size: 807 B |
BIN
images/themes/default/customization/progress.png
Normal file
After Width: | Height: | Size: 559 B |
BIN
images/themes/default/customization/pushbutton.png
Normal file
After Width: | Height: | Size: 408 B |
BIN
images/themes/default/customization/radiobutton.png
Normal file
After Width: | Height: | Size: 586 B |
BIN
images/themes/default/customization/scrollarea.png
Normal file
After Width: | Height: | Size: 548 B |
BIN
images/themes/default/customization/spacer.png
Normal file
After Width: | Height: | Size: 686 B |
BIN
images/themes/default/customization/spinbox.png
Normal file
After Width: | Height: | Size: 680 B |
BIN
images/themes/default/customization/tabbar.png
Normal file
After Width: | Height: | Size: 623 B |
BIN
images/themes/default/customization/table.png
Normal file
After Width: | Height: | Size: 483 B |
BIN
images/themes/default/customization/tabwidget.png
Normal file
After Width: | Height: | Size: 572 B |
BIN
images/themes/default/customization/textedit.png
Normal file
After Width: | Height: | Size: 823 B |
BIN
images/themes/default/customization/timeedit.png
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
images/themes/default/customization/toolbox.png
Normal file
After Width: | Height: | Size: 783 B |
BIN
images/themes/default/customization/toolbutton.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
images/themes/default/customization/vline.png
Normal file
After Width: | Height: | Size: 314 B |
BIN
images/themes/default/customization/vscrollbar.png
Normal file
After Width: | Height: | Size: 415 B |
BIN
images/themes/default/customization/vslider.png
Normal file
After Width: | Height: | Size: 726 B |
BIN
images/themes/default/customization/vspacer.png
Normal file
After Width: | Height: | Size: 677 B |
BIN
images/themes/default/customization/widget.png
Normal file
After Width: | Height: | Size: 716 B |
BIN
images/themes/default/customization/widgetstack.png
Normal file
After Width: | Height: | Size: 828 B |
BIN
images/themes/default/customization/wizard.png
Normal file
After Width: | Height: | Size: 898 B |
BIN
images/themes/default/mIconWms.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
images/themes/default/mIconWmsLayer.png
Normal file
After Width: | Height: | Size: 2.1 KiB |
129
python/widgets_tree.py
Executable file
@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
"""
|
||||
Reads .ui files from ../src/ui/ directory and write to stdout an XML describing
|
||||
widgets tree.
|
||||
|
||||
Python bindings must be compiled and in PYTHONPATH
|
||||
|
||||
QGIS libraries must be in LD_LIBRARY_PATH
|
||||
|
||||
Output should go to ../resources/customization.xml
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
import os, glob, imp
|
||||
from PyQt4.QtGui import *
|
||||
from PyQt4.uic import loadUi, compileUi
|
||||
from xml.etree.ElementTree import Element, SubElement, Comment, tostring
|
||||
from xml.dom import minidom
|
||||
|
||||
# qwt_plot is missing somehow but it may depend on installed packages
|
||||
from PyQt4 import Qwt5 as qwt_plot
|
||||
sys.modules['qwt_plot'] = qwt_plot
|
||||
|
||||
# loadUi is looking for custom widget in module which is lowercase version of
|
||||
# the class, which do not exist (AFAIK) -> preload them, problems anyway:
|
||||
# missing in gui: QgsColorRampComboBox, QgsRendererRulesTreeWidget,
|
||||
# QgsRendererRulesTreeWidget, QgsAttributeTableView
|
||||
# and QgsProjectionSelector cannot open db file
|
||||
from qgis import gui
|
||||
for m in ['qgscolorbutton', 'qgscolorrampcombobox', 'qgsprojectionselector', 'qgslabelpreview', 'qgsrulebasedrendererv2widget', 'qgsattributetableview' ]:
|
||||
sys.modules[m] = gui
|
||||
|
||||
class UiInspector:
|
||||
def __init__(self ):
|
||||
self.ui_dir = os.path.abspath ( os.path.join( os.path.dirname(__file__) , '../src/ui/*.ui' ) )
|
||||
self.printMsg ( "Loading UI files " + self.ui_dir )
|
||||
# list of widget classes we want to follow
|
||||
self.follow = [
|
||||
QWidget, QDialog,
|
||||
QCheckBox, QComboBox, QDial, QPushButton, QLabel, QLCDNumber, QLineEdit, QRadioButton, QScrollBar, QSlider, QSpinBox, QTextEdit,
|
||||
QDateEdit, QTimeEdit, QDateTimeEdit, QListView, QProgressBar, QTableView, QTabWidget, QTextBrowser, QDialogButtonBox,
|
||||
QScrollArea, QGroupBox, QStackedWidget,
|
||||
]
|
||||
|
||||
def printMsg ( self, msg ):
|
||||
sys.stderr.write( msg + "\n" )
|
||||
|
||||
def widgetXml(self, element, widget, level = 0, label = None ):
|
||||
#print tostring ( element )
|
||||
#self.printMsg ( "class: " + str( type ( widget ) ) )
|
||||
#self.printMsg ( "objectName: " + widget.objectName() )
|
||||
#self.printMsg ( "windowTitle: " + widget.windowTitle() )
|
||||
|
||||
if not widget.objectName(): return
|
||||
|
||||
lab = label
|
||||
if hasattr( widget, 'text' ):
|
||||
lab = widget.text()
|
||||
if widget.windowTitle():
|
||||
label = widget.windowTitle()
|
||||
if not lab:
|
||||
lab = ''
|
||||
|
||||
lab = unicode(lab).encode("ascii","replace")
|
||||
|
||||
sub_element = SubElement( element, 'widget')
|
||||
sub_element.set('class', widget.__class__.__name__ )
|
||||
sub_element.set('objectName', widget.objectName() )
|
||||
sub_element.set('label', lab )
|
||||
|
||||
#print str ( widget.children () )
|
||||
# tab widget label is stored in QTabWidget->QTabBarPrivate->tabList->QTab ..
|
||||
if type(widget) in [ QTabWidget ]:
|
||||
children = list ( { 'widget': widget.widget(i), 'label': widget.tabText(i) } for i in range ( 0, widget.count() ) )
|
||||
else:
|
||||
children = list ( { 'widget': c, 'label': None } for c in widget.children () )
|
||||
for child in children:
|
||||
w = child['widget']
|
||||
if w.isWidgetType() and ( type(w) in self.follow ):
|
||||
self.widgetXml ( sub_element, w, level+1, child['label'] )
|
||||
|
||||
|
||||
def treeXml(self, element ):
|
||||
xml = ''
|
||||
# debug
|
||||
for p in glob.glob( self.ui_dir ):
|
||||
#for p in ['/home/radim/devel/qgis_trunk/src/ui/qgsabout.ui']:
|
||||
#for p in ['/home/radim/devel/qgis_trunk/src/ui/qgsrasterlayerpropertiesbase.ui']:
|
||||
self.printMsg ( "Loading " + p )
|
||||
# qgsrasterlayerpropertiesbase.ui is giving: No module named qwt_plot
|
||||
try:
|
||||
widget = loadUi ( p )
|
||||
#print dir ( ui )
|
||||
self.widgetXml ( element, widget )
|
||||
except Exception, e:
|
||||
#except IOError, e:
|
||||
self.printMsg ( str(e) )
|
||||
|
||||
return xml
|
||||
|
||||
def xml( self ) :
|
||||
#xml = "<?xml version='1.0' encoding='UTF-8'?>\n"
|
||||
#xml += "<!DOCTYPE qgiswidgets SYSTEM 'http://mrcc.com/qgiswidgets.dtd'>\n"
|
||||
element = Element('qgiswidgets')
|
||||
self.treeXml( element )
|
||||
|
||||
string = tostring ( element, 'utf-8' )
|
||||
reparsed = minidom.parseString(string)
|
||||
xml = reparsed.toprettyxml(indent=" ")
|
||||
return xml
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = QApplication(sys.argv) # required by loadUi
|
||||
inspector = UiInspector()
|
||||
xml = inspector.xml()
|
||||
sys.stdout.write( xml )
|
||||
sys.stdout.flush()
|
||||
|
||||
del app
|
||||
sys.exit(0)
|
@ -1,5 +1,5 @@
|
||||
|
||||
INSTALL(FILES srs.db qgis.db qgis_help.db symbology-ng-style.xml spatialite.db
|
||||
INSTALL(FILES srs.db qgis.db qgis_help.db symbology-ng-style.xml spatialite.db customization.xml customization.ini
|
||||
DESTINATION ${QGIS_DATA_DIR}/resources)
|
||||
|
||||
SUBDIRS(context_help)
|
||||
|
1832
resources/customization.ini
Normal file
2024
resources/customization.xml
Normal file
@ -1,4 +1,4 @@
|
||||
SUBDIRS(astyle core analysis ui gui app providers plugins helpviewer)
|
||||
SUBDIRS(astyle core analysis ui gui app providers plugins helpviewer browser)
|
||||
|
||||
IF (WITH_BINDINGS)
|
||||
SUBDIRS(python)
|
||||
|
@ -16,6 +16,7 @@ SET(QGIS_APP_SRCS
|
||||
qgsclipboard.cpp
|
||||
qgscontinuouscolordialog.cpp
|
||||
qgsconfigureshortcutsdialog.cpp
|
||||
qgscustomization.cpp
|
||||
qgscustomprojectiondialog.cpp
|
||||
qgsdbfilterproxymodel.cpp
|
||||
qgsdbtablemodel.cpp
|
||||
@ -23,7 +24,6 @@ SET(QGIS_APP_SRCS
|
||||
qgsdelattrdialog.cpp
|
||||
qgsdisplayangle.cpp
|
||||
qgsfieldcalculator.cpp
|
||||
qgsnewvectorlayerdialog.cpp
|
||||
qgsgraduatedsymboldialog.cpp
|
||||
qgsidentifyresults.cpp
|
||||
qgsfeatureaction.cpp
|
||||
@ -67,8 +67,6 @@ SET(QGIS_APP_SRCS
|
||||
qgsmeasuredialog.cpp
|
||||
qgsmeasuretool.cpp
|
||||
qgsmergeattributesdialog.cpp
|
||||
qgsnewhttpconnection.cpp
|
||||
qgsnumericsortlistviewitem.cpp
|
||||
qgsoptions.cpp
|
||||
qgspastetransformations.cpp
|
||||
qgspointrotationitem.cpp
|
||||
@ -80,7 +78,6 @@ SET(QGIS_APP_SRCS
|
||||
qgsrastercalcdialog.cpp
|
||||
qgsrasterlayerproperties.cpp
|
||||
qgstextannotationdialog.cpp
|
||||
qgswmssourceselect.cpp
|
||||
qgsshortcutsmanager.cpp
|
||||
qgssinglesymboldialog.cpp
|
||||
qgssnappingdialog.cpp
|
||||
@ -94,7 +91,6 @@ SET(QGIS_APP_SRCS
|
||||
qgshighlight.cpp
|
||||
qgshandlebadlayers.cpp
|
||||
|
||||
qgsmanageconnectionsdialog.cpp
|
||||
|
||||
composer/qgsattributeselectiondialog.cpp
|
||||
composer/qgscomposer.cpp
|
||||
@ -131,12 +127,6 @@ SET(QGIS_APP_SRCS
|
||||
ogr/qgsvectorlayersaveasdialog.cpp
|
||||
|
||||
attributetable/qgsattributetabledialog.cpp
|
||||
attributetable/qgsattributetablemodel.cpp
|
||||
attributetable/qgsattributetablememorymodel.cpp
|
||||
attributetable/qgsattributetableview.cpp
|
||||
attributetable/qgsattributetablefiltermodel.cpp
|
||||
attributetable/qgsattributetableidcolumnpair.cpp
|
||||
attributetable/qgsattributetabledelegate.cpp
|
||||
|
||||
gps/qgsgpsinformationwidget.cpp
|
||||
gps/qgsgpsmarker.cpp
|
||||
@ -157,6 +147,7 @@ SET (QGIS_APP_MOC_HDRS
|
||||
qgsbookmarks.h
|
||||
qgsconfigureshortcutsdialog.h
|
||||
qgscontinuouscolordialog.h
|
||||
qgscustomization.h
|
||||
qgscustomprojectiondialog.h
|
||||
qgsdbtablemodel.h
|
||||
qgsdelattrdialog.h
|
||||
@ -170,7 +161,6 @@ SET (QGIS_APP_MOC_HDRS
|
||||
qgslabelengineconfigdialog.h
|
||||
qgslabelinggui.h
|
||||
qgslabelpropertydialog.h
|
||||
qgsmanageconnectionsdialog.h
|
||||
qgsmaptooladdfeature.h
|
||||
qgsmaptooladdisland.h
|
||||
qgsmaptooladdring.h
|
||||
@ -199,8 +189,6 @@ SET (QGIS_APP_MOC_HDRS
|
||||
qgsmeasuredialog.h
|
||||
qgsmeasuretool.h
|
||||
qgsmergeattributesdialog.h
|
||||
qgsnewhttpconnection.h
|
||||
qgsnewvectorlayerdialog.h
|
||||
qgsoptions.h
|
||||
qgspastetransformations.h
|
||||
qgspluginmanager.h
|
||||
@ -218,7 +206,6 @@ SET (QGIS_APP_MOC_HDRS
|
||||
qgsundowidget.h
|
||||
qgsuniquevaluedialog.h
|
||||
qgsvectorlayerproperties.h
|
||||
qgswmssourceselect.h
|
||||
qgshandlebadlayers.h
|
||||
|
||||
composer/qgsattributeselectiondialog.h
|
||||
@ -245,11 +232,7 @@ SET (QGIS_APP_MOC_HDRS
|
||||
ogr/qgsogrsublayersdialog.h
|
||||
ogr/qgsvectorlayersaveasdialog.h
|
||||
|
||||
attributetable/qgsattributetableview.h
|
||||
attributetable/qgsattributetablemodel.h
|
||||
attributetable/qgsattributetablememorymodel.h
|
||||
attributetable/qgsattributetabledialog.h
|
||||
attributetable/qgsattributetabledelegate.h
|
||||
|
||||
gps/qgsgpsinformationwidget.h
|
||||
)
|
||||
@ -364,7 +347,7 @@ INCLUDE_DIRECTORIES(
|
||||
../core
|
||||
../core/gps ../core/gps/qextserialport
|
||||
../core/composer ../core/raster ../core/renderer ../core/symbology ../core/symbology-ng
|
||||
../gui ../gui/symbology-ng
|
||||
../gui ../gui/symbology-ng ../gui/attributetable
|
||||
../plugins
|
||||
../python
|
||||
gps
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "qgsmapcanvas.h"
|
||||
#include "qgsfieldcalculator.h"
|
||||
#include "qgsfeatureaction.h"
|
||||
#include "qgsattributeaction.h"
|
||||
|
||||
class QgsAttributeTableDock : public QDockWidget
|
||||
{
|
||||
@ -64,6 +65,10 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
|
||||
QSettings settings;
|
||||
restoreGeometry( settings.value( "/Windows/BetterAttributeTable/geometry" ).toByteArray() );
|
||||
|
||||
// extent has to be set before the model is created
|
||||
QgsAttributeTableModel::setCurrentExtent( QgisApp::instance()->mapCanvas()->extent() );
|
||||
connect( QgisApp::instance()->mapCanvas(), SIGNAL( extentsChanged() ), this, SLOT( updateExtent() ) );
|
||||
|
||||
mView->setLayer( mLayer );
|
||||
mFilterModel = ( QgsAttributeTableFilterModel * ) mView->model();
|
||||
mModel = ( QgsAttributeTableModel * )(( QgsAttributeTableFilterModel * )mView->model() )->sourceModel();
|
||||
@ -126,10 +131,7 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
|
||||
connect( mView->verticalHeader(), SIGNAL( sectionPressed( int ) ), this, SLOT( updateRowPressed( int ) ) );
|
||||
connect( mModel, SIGNAL( modelChanged() ), this, SLOT( updateSelection() ) );
|
||||
|
||||
if ( settings.value( "/qgis/attributeTableBehaviour", 0 ).toInt() == 2 )
|
||||
{
|
||||
connect( QgisApp::instance()->mapCanvas(), SIGNAL( extentsChanged() ), mModel, SLOT( layerModified() ) );
|
||||
}
|
||||
connect( mView, SIGNAL(willShowContextMenu( QMenu*, QModelIndex ) ), this, SLOT(viewWillShowContextMenu(QMenu*, QModelIndex ) ) );
|
||||
|
||||
mLastClickedHeaderIndex = 0;
|
||||
mSelectionModel = new QItemSelectionModel( mFilterModel );
|
||||
@ -241,19 +243,7 @@ void QgsAttributeTableDialog::on_mCopySelectedRowsButton_clicked()
|
||||
|
||||
void QgsAttributeTableDialog::on_mZoomMapToSelectedRowsButton_clicked()
|
||||
{
|
||||
QSettings settings;
|
||||
bool canvasFeatures = settings.value( "/qgis/attributeTableBehaviour", 0 ).toInt() == 2;
|
||||
if ( canvasFeatures )
|
||||
{
|
||||
disconnect( QgisApp::instance()->mapCanvas(), SIGNAL( extentsChanged() ), mModel, SLOT( layerModified() ) );
|
||||
}
|
||||
|
||||
QgisApp::instance()->mapCanvas()->zoomToSelected( mLayer );
|
||||
|
||||
if ( canvasFeatures )
|
||||
{
|
||||
connect( QgisApp::instance()->mapCanvas(), SIGNAL( extentsChanged() ), mModel, SLOT( layerModified() ) );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAttributeTableDialog::on_mInvertSelectionButton_clicked()
|
||||
@ -821,3 +811,49 @@ void QgsAttributeTableDialog::addFeature()
|
||||
mModel->reload( mModel->index( 0, 0 ), mModel->index( mModel->rowCount(), mModel->columnCount() ) );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsAttributeTableDialog::updateExtent()
|
||||
{
|
||||
// let the model know about the new extent (we may be showing only features from current extent)
|
||||
QgsAttributeTableModel::setCurrentExtent( QgisApp::instance()->mapCanvas()->extent() );
|
||||
}
|
||||
|
||||
void QgsAttributeTableDialog::viewWillShowContextMenu( QMenu* menu, QModelIndex atIndex )
|
||||
{
|
||||
if ( mLayer->actions()->size() != 0 )
|
||||
{
|
||||
|
||||
QAction *a = menu->addAction( tr( "Run action" ) );
|
||||
a->setEnabled( false );
|
||||
|
||||
for ( int i = 0; i < mLayer->actions()->size(); i++ )
|
||||
{
|
||||
const QgsAction &action = mLayer->actions()->at( i );
|
||||
|
||||
if ( !action.runable() )
|
||||
continue;
|
||||
|
||||
QgsAttributeTableAction *a = new QgsAttributeTableAction( action.name(), mView, mModel, i, atIndex );
|
||||
menu->addAction( action.name(), a, SLOT( execute() ) );
|
||||
}
|
||||
}
|
||||
|
||||
QgsAttributeTableAction *a = new QgsAttributeTableAction( tr( "Open form" ), mView, mModel, -1, atIndex );
|
||||
menu->addAction( tr( "Open form" ), a, SLOT( featureForm() ) );
|
||||
}
|
||||
|
||||
void QgsAttributeTableAction::execute()
|
||||
{
|
||||
mModel->executeAction( mAction, mFieldIdx );
|
||||
}
|
||||
|
||||
void QgsAttributeTableAction::featureForm()
|
||||
{
|
||||
QgsFeature f = mModel->feature( mFieldIdx );
|
||||
|
||||
QgsFeatureAction action( tr( "Attributes changed" ), f, mModel->layer(), -1, this );
|
||||
if ( mModel->layer()->isEditable() )
|
||||
action.editFeature();
|
||||
else
|
||||
action.viewFeatureForm();
|
||||
}
|
||||
|
@ -58,6 +58,10 @@ class QgsAttributeTableDialog : public QDialog, private Ui::QgsAttributeTableDia
|
||||
*/
|
||||
void editingToggled();
|
||||
|
||||
void updateExtent();
|
||||
|
||||
void viewWillShowContextMenu( QMenu* menu, QModelIndex atIndex );
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* submits the data
|
||||
@ -213,4 +217,25 @@ class QgsAttributeTableDialog : public QDialog, private Ui::QgsAttributeTableDia
|
||||
QDockWidget *mDock;
|
||||
};
|
||||
|
||||
|
||||
class QgsAttributeTableAction : public QAction
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsAttributeTableAction( const QString &name, QgsAttributeTableView *view, QgsAttributeTableModel *model, int action, const QModelIndex &fieldIdx ) :
|
||||
QAction( name, view ), mModel( model ), mAction( action ), mFieldIdx( fieldIdx )
|
||||
{}
|
||||
|
||||
public slots:
|
||||
void execute();
|
||||
void featureForm();
|
||||
|
||||
private:
|
||||
QgsAttributeTableModel *mModel;
|
||||
int mAction;
|
||||
QModelIndex mFieldIdx;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -34,6 +34,7 @@
|
||||
#include <QTranslator>
|
||||
#include <QImageReader>
|
||||
|
||||
#include "qgscustomization.h"
|
||||
#include "qgspluginregistry.h"
|
||||
|
||||
#include <cstdio>
|
||||
@ -67,6 +68,7 @@ typedef SInt32 SRefCon;
|
||||
#include "qgsmapcanvas.h"
|
||||
#include "qgsapplication.h"
|
||||
#include <qgsconfig.h>
|
||||
#include <qgscustomization.h>
|
||||
#include <qgssvnversion.h>
|
||||
#include "qgsexception.h"
|
||||
#include "qgsproject.h"
|
||||
@ -99,6 +101,7 @@ void usage( std::string const & appName )
|
||||
<< "\t[--extent xmin,ymin,xmax,ymax]\tset initial map extent\n"
|
||||
<< "\t[--nologo]\thide splash screen\n"
|
||||
<< "\t[--noplugins]\tdon't restore plugins on startup\n"
|
||||
<< "\t[--nocustomization]\tdon't apply GUI customization\n"
|
||||
<< "\t[--optionspath path]\tuse the given QSettings path\n"
|
||||
<< "\t[--configpath path]\tuse the given path for all user configuration\n"
|
||||
<< "\t[--help]\t\tthis text\n\n"
|
||||
@ -212,6 +215,7 @@ int main( int argc, char *argv[] )
|
||||
|
||||
bool myHideSplash = false;
|
||||
bool myRestorePlugins = true;
|
||||
bool myCustomization = true;
|
||||
|
||||
// This behaviour will set initial extent of map canvas, but only if
|
||||
// there are no command line arguments. This gives a usable map
|
||||
@ -246,6 +250,7 @@ int main( int argc, char *argv[] )
|
||||
{"help", no_argument, 0, '?'},
|
||||
{"nologo", no_argument, 0, 'n'},
|
||||
{"noplugins", no_argument, 0, 'P'},
|
||||
{"nocustomization", no_argument, 0, 'C'},
|
||||
/* These options don't set a flag.
|
||||
* We distinguish them by their indices. */
|
||||
{"snapshot", required_argument, 0, 's'},
|
||||
@ -309,6 +314,10 @@ int main( int argc, char *argv[] )
|
||||
myRestorePlugins = false;
|
||||
break;
|
||||
|
||||
case 'C':
|
||||
myCustomization = false;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
myInitialExtent = optarg;
|
||||
break;
|
||||
@ -365,6 +374,10 @@ int main( int argc, char *argv[] )
|
||||
{
|
||||
myRestorePlugins = false;
|
||||
}
|
||||
else if ( arg == "--nocustomization" || arg == "-C" )
|
||||
{
|
||||
myCustomization = false;
|
||||
}
|
||||
else if ( i + 1 < argc && ( arg == "--snapshot" || arg == "-s" ) )
|
||||
{
|
||||
mySnapshotFileName = QDir::convertSeparators( QFileInfo( QFile::decodeName( argv[++i] ) ).absoluteFilePath() );
|
||||
@ -434,6 +447,9 @@ int main( int argc, char *argv[] )
|
||||
QSettings::setPath( QSettings::IniFormat, QSettings::UserScope, configpath );
|
||||
}
|
||||
|
||||
// GUI customization is enabled by default unless --nocustomization argument is used
|
||||
QgsCustomization::instance()->setEnabled(myCustomization);
|
||||
|
||||
QgsApplication myApp( argc, argv, myUseGuiFlag, configpath );
|
||||
|
||||
// (if Windows/Mac, use icon from resource)
|
||||
@ -447,6 +463,10 @@ int main( int argc, char *argv[] )
|
||||
QCoreApplication::setOrganizationDomain( "qgis.org" );
|
||||
QCoreApplication::setApplicationName( "QGIS" );
|
||||
QCoreApplication::setAttribute( Qt::AA_DontShowIconsInMenus, false );
|
||||
|
||||
// Load and set possible default customization, must be done afterQgsApplication init and QSettings ( QCoreApplication ) init
|
||||
QgsCustomization::instance()->loadDefault();
|
||||
|
||||
#ifdef Q_OS_MACX
|
||||
// If the GDAL plugins are bundled with the application and GDAL_DRIVER_PATH
|
||||
// is not already defined, use the GDAL plugins in the application bundle.
|
||||
@ -596,6 +616,12 @@ int main( int argc, char *argv[] )
|
||||
QgisApp *qgis = new QgisApp( mypSplash, myRestorePlugins ); // "QgisApp" used to find canonical instance
|
||||
qgis->setObjectName( "QgisApp" );
|
||||
|
||||
myApp.connect (
|
||||
&myApp, SIGNAL( preNotify( QObject *, QEvent *, bool *)),
|
||||
//qgis, SLOT( preNotify( QObject *, QEvent *))
|
||||
QgsCustomization::instance(), SLOT( preNotify( QObject *, QEvent *, bool *))
|
||||
);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// If no --project was specified, parse the args to look for a //
|
||||
// .qgs file and set myProjectFileName to it. This allows loading //
|
||||
|
@ -111,6 +111,7 @@
|
||||
#include "qgscoordinatetransform.h"
|
||||
#include "qgscredentialdialog.h"
|
||||
#include "qgscursors.h"
|
||||
#include "qgscustomization.h"
|
||||
#include "qgscustomprojectiondialog.h"
|
||||
#include "qgsdatasourceuri.h"
|
||||
#include "qgsencodingfiledialog.h"
|
||||
@ -145,6 +146,7 @@
|
||||
#include "qgsproject.h"
|
||||
#include "qgsprojectproperties.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
#include "qgspythonrunner.h"
|
||||
#include "qgsquerybuilder.h"
|
||||
#include "qgsrastercalcdialog.h"
|
||||
#include "qgsrasterlayer.h"
|
||||
@ -162,7 +164,7 @@
|
||||
#include "qgsvectorfilewriter.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsvectorlayerproperties.h"
|
||||
#include "qgswmssourceselect.h"
|
||||
//#include "qgswmssourceselect.h"
|
||||
#include "ogr/qgsogrsublayersdialog.h"
|
||||
#include "ogr/qgsopenvectorlayerdialog.h"
|
||||
#include "ogr/qgsvectorlayersaveasdialog.h"
|
||||
@ -298,7 +300,7 @@ static void setTitleBarText_( QWidget & qgisApp )
|
||||
{
|
||||
caption += " - " + QgsProject::instance()->title();
|
||||
}
|
||||
|
||||
caption = QgisApp::tr( "Quantum GIS pro Deblin" ); //for dbl
|
||||
qgisApp.setWindowTitle( caption );
|
||||
} // setTitleBarText_( QWidget * qgisApp )
|
||||
|
||||
@ -466,6 +468,7 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, QWidget * parent,
|
||||
// set graphical message output
|
||||
QgsMessageOutput::setMessageOutputCreator( messageOutputViewer_ );
|
||||
|
||||
|
||||
// set graphical credential requester
|
||||
new QgsCredentialDialog( this );
|
||||
|
||||
@ -481,7 +484,6 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, QWidget * parent,
|
||||
qApp->processEvents();
|
||||
loadPythonSupport();
|
||||
|
||||
|
||||
// Create the plugin registry and load plugins
|
||||
// load any plugins that were running in the last session
|
||||
mSplash->showMessage( tr( "Restoring loaded plugins" ), Qt::AlignHCenter | Qt::AlignBottom );
|
||||
@ -535,6 +537,9 @@ QgisApp::QgisApp( QSplashScreen *splash, bool restorePlugins, QWidget * parent,
|
||||
qApp->processEvents();
|
||||
restoreWindowState();
|
||||
|
||||
// do main window customization - after window state has been restored, before the window is shown
|
||||
QgsCustomization::instance()->updateMainWindow();
|
||||
|
||||
mSplash->showMessage( tr( "QGIS Ready!" ), Qt::AlignHCenter | Qt::AlignBottom );
|
||||
|
||||
mMapTipsVisible = false;
|
||||
@ -822,6 +827,7 @@ void QgisApp::createActions()
|
||||
connect( mActionCustomProjection, SIGNAL( triggered() ), this, SLOT( customProjection() ) );
|
||||
connect( mActionConfigureShortcuts, SIGNAL( triggered() ), this, SLOT( configureShortcuts() ) );
|
||||
connect( mActionStyleManagerV2, SIGNAL( triggered() ), this, SLOT( showStyleManagerV2() ) );
|
||||
connect( mActionCustomization, SIGNAL( triggered() ), this, SLOT( customize() ) );
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
// Window Menu Items
|
||||
@ -990,8 +996,9 @@ void QgisApp::createMenus()
|
||||
|
||||
// Panel and Toolbar Submenus
|
||||
mPanelMenu = new QMenu( tr( "Panels" ) );
|
||||
mPanelMenu->setObjectName("mPanelMenu");
|
||||
mToolbarMenu = new QMenu( tr( "Toolbars" ) );
|
||||
|
||||
mToolbarMenu->setObjectName("mToolbarMenu");
|
||||
|
||||
// Get platform for menu layout customization (Gnome, Kde, Mac, Win)
|
||||
QDialogButtonBox::ButtonLayout layout =
|
||||
@ -1018,6 +1025,7 @@ void QgisApp::createMenus()
|
||||
mEditMenu->addAction( mActionOptions );
|
||||
mEditMenu->addAction( mActionSnappingOptions );
|
||||
mEditMenu->addAction( mActionConfigureShortcuts );
|
||||
mEditMenu->addAction( mActionCustomization );
|
||||
mEditMenu->addAction( mActionStyleManagerV2 );
|
||||
mEditMenu->addAction( mActionCustomProjection );
|
||||
}
|
||||
@ -1086,7 +1094,6 @@ void QgisApp::createToolBars()
|
||||
// select tool button
|
||||
|
||||
QToolButton *bt = new QToolButton( mAttributesToolBar );
|
||||
bt->setObjectName( "SelectTool" );
|
||||
bt->setPopupMode( QToolButton::MenuButtonPopup );
|
||||
QList<QAction*> selectActions;
|
||||
selectActions << mActionSelect << mActionSelectRectangle << mActionSelectPolygon
|
||||
@ -1103,14 +1110,13 @@ void QgisApp::createToolBars()
|
||||
case 4: defSelectAction = mActionSelectRadius; break;
|
||||
}
|
||||
bt->setDefaultAction( defSelectAction );
|
||||
|
||||
mAttributesToolBar->insertWidget( mActionDeselectAll, bt );
|
||||
QAction* selectAction = mAttributesToolBar->insertWidget( mActionDeselectAll, bt );
|
||||
selectAction->setObjectName( "ActionSelect" );
|
||||
connect( bt, SIGNAL( triggered( QAction * ) ), this, SLOT( toolButtonActionTriggered( QAction * ) ) );
|
||||
|
||||
// measure tool button
|
||||
|
||||
bt = new QToolButton( mAttributesToolBar );
|
||||
bt->setObjectName( "MeasureTool" );
|
||||
bt->setPopupMode( QToolButton::MenuButtonPopup );
|
||||
bt->addAction( mActionMeasure );
|
||||
bt->addAction( mActionMeasureArea );
|
||||
@ -1124,13 +1130,13 @@ void QgisApp::createToolBars()
|
||||
case 2: defMeasureAction = mActionMeasureAngle; break;
|
||||
}
|
||||
bt->setDefaultAction( defMeasureAction );
|
||||
mAttributesToolBar->insertWidget( mActionMapTips, bt );
|
||||
QAction* measureAction = mAttributesToolBar->insertWidget( mActionMapTips, bt );
|
||||
measureAction->setObjectName( "ActionMeasure" );
|
||||
connect( bt, SIGNAL( triggered( QAction * ) ), this, SLOT( toolButtonActionTriggered( QAction * ) ) );
|
||||
|
||||
// annotation tool button
|
||||
|
||||
bt = new QToolButton();
|
||||
bt->setObjectName( "AnnotationTool" );
|
||||
bt->setPopupMode( QToolButton::MenuButtonPopup );
|
||||
bt->addAction( mActionTextAnnotation );
|
||||
bt->addAction( mActionFormAnnotation );
|
||||
@ -1144,7 +1150,8 @@ void QgisApp::createToolBars()
|
||||
case 2: defAnnotationAction = mActionAnnotation; break;
|
||||
}
|
||||
bt->setDefaultAction( defAnnotationAction );
|
||||
mAttributesToolBar->addWidget( bt );
|
||||
QAction* annotationAction = mAttributesToolBar->addWidget( bt );
|
||||
annotationAction->setObjectName( "ActionAnnotation" );
|
||||
connect( bt, SIGNAL( triggered( QAction * ) ), this, SLOT( toolButtonActionTriggered( QAction * ) ) );
|
||||
|
||||
// Help Toolbar
|
||||
@ -1160,6 +1167,7 @@ void QgisApp::createStatusBar()
|
||||
// And also rendering suppression checkbox
|
||||
//
|
||||
mProgressBar = new QProgressBar( statusBar() );
|
||||
mProgressBar->setObjectName( "mProgressBar" );
|
||||
mProgressBar->setMaximumWidth( 100 );
|
||||
mProgressBar->hide();
|
||||
mProgressBar->setWhatsThis( tr( "Progress bar that displays the status "
|
||||
@ -1173,6 +1181,7 @@ void QgisApp::createStatusBar()
|
||||
statusBar()->setFont( myFont );
|
||||
//toggle to switch between mouse pos and extents display in status bar widget
|
||||
mToggleExtentsViewButton = new QToolButton( statusBar() );
|
||||
mToggleExtentsViewButton->setObjectName( "mToggleExtentsViewButton" );
|
||||
mToggleExtentsViewButton->setMaximumWidth( 20 );
|
||||
mToggleExtentsViewButton->setMaximumHeight( 20 );
|
||||
mToggleExtentsViewButton->setIcon( getThemeIcon( "tracking.png" ) );
|
||||
@ -1183,6 +1192,7 @@ void QgisApp::createStatusBar()
|
||||
|
||||
// add a label to show current scale
|
||||
mCoordsLabel = new QLabel( QString(), statusBar() );
|
||||
mCoordsLabel->setObjectName( "mCoordsLabel" );
|
||||
mCoordsLabel->setFont( myFont );
|
||||
mCoordsLabel->setMinimumWidth( 10 );
|
||||
mCoordsLabel->setMaximumHeight( 20 );
|
||||
@ -1195,6 +1205,7 @@ void QgisApp::createStatusBar()
|
||||
|
||||
//coords status bar widget
|
||||
mCoordsEdit = new QLineEdit( QString(), statusBar() );
|
||||
mCoordsEdit->setObjectName( "mCoordsEdit" );
|
||||
mCoordsEdit->setFont( myFont );
|
||||
mCoordsEdit->setMinimumWidth( 10 );
|
||||
mCoordsEdit->setMaximumWidth( 300 );
|
||||
@ -1214,6 +1225,7 @@ void QgisApp::createStatusBar()
|
||||
|
||||
// add a label to show current scale
|
||||
mScaleLabel = new QLabel( QString(), statusBar() );
|
||||
mScaleLabel->setObjectName( "mScaleLable" );
|
||||
mScaleLabel->setFont( myFont );
|
||||
mScaleLabel->setMinimumWidth( 10 );
|
||||
mScaleLabel->setMaximumHeight( 20 );
|
||||
@ -1225,6 +1237,7 @@ void QgisApp::createStatusBar()
|
||||
statusBar()->addPermanentWidget( mScaleLabel, 0 );
|
||||
|
||||
mScaleEdit = new QLineEdit( QString(), statusBar() );
|
||||
mScaleEdit->setObjectName( "mScaleEdit" );
|
||||
mScaleEdit->setFont( myFont );
|
||||
mScaleEdit->setMinimumWidth( 10 );
|
||||
mScaleEdit->setMaximumWidth( 100 );
|
||||
@ -1242,6 +1255,7 @@ void QgisApp::createStatusBar()
|
||||
|
||||
//stop rendering status bar widget
|
||||
mStopRenderButton = new QToolButton( statusBar() );
|
||||
mStopRenderButton->setObjectName( "mStopRenderButton" );
|
||||
mStopRenderButton->setMaximumWidth( 20 );
|
||||
mStopRenderButton->setMaximumHeight( 20 );
|
||||
mStopRenderButton->setIcon( getThemeIcon( "mIconStopRendering.png" ) );
|
||||
@ -1249,6 +1263,7 @@ void QgisApp::createStatusBar()
|
||||
statusBar()->addPermanentWidget( mStopRenderButton, 0 );
|
||||
// render suppression status bar widget
|
||||
mRenderSuppressionCBox = new QCheckBox( tr( "Render" ), statusBar() );
|
||||
mRenderSuppressionCBox->setObjectName( "mRenderSuppressionCBox" );
|
||||
mRenderSuppressionCBox->setChecked( true );
|
||||
mRenderSuppressionCBox->setFont( myFont );
|
||||
mRenderSuppressionCBox->setWhatsThis( tr( "When checked, the map layers "
|
||||
@ -1259,6 +1274,7 @@ void QgisApp::createStatusBar()
|
||||
statusBar()->addPermanentWidget( mRenderSuppressionCBox, 0 );
|
||||
// On the fly projection active CRS label
|
||||
mOnTheFlyProjectionStatusLabel = new QLabel( QString(), statusBar() );
|
||||
mOnTheFlyProjectionStatusLabel->setObjectName( "mOnTheFlyProjectionStatusLabel" );
|
||||
mOnTheFlyProjectionStatusLabel->setFont( myFont );
|
||||
mOnTheFlyProjectionStatusLabel->setMinimumWidth( 10 );
|
||||
mOnTheFlyProjectionStatusLabel->setMaximumHeight( 20 );
|
||||
@ -1271,6 +1287,7 @@ void QgisApp::createStatusBar()
|
||||
// Changed this to a tool button since a QPushButton is
|
||||
// sculpted on OS X and the icon is never displayed [gsherman]
|
||||
mOnTheFlyProjectionStatusButton = new QToolButton( statusBar() );
|
||||
mOnTheFlyProjectionStatusButton->setObjectName( "mOntheFlyProjectionStatusButton" );
|
||||
mOnTheFlyProjectionStatusButton->setMaximumWidth( 20 );
|
||||
// Maintain uniform widget height in status bar by setting button height same as labels
|
||||
// For Qt/Mac 3.3, the default toolbutton height is 30 and labels were expanding to match
|
||||
@ -1362,6 +1379,7 @@ void QgisApp::setTheme( QString theThemeName )
|
||||
mActionCheckQgisVersion->setIcon( getThemeIcon( "/mActionCheckQgisVersion.png" ) );
|
||||
mActionOptions->setIcon( getThemeIcon( "/mActionOptions.png" ) );
|
||||
mActionConfigureShortcuts->setIcon( getThemeIcon( "/mActionOptions.png" ) );
|
||||
mActionCustomization->setIcon( getThemeIcon( "/mActionOptions.png" ) );
|
||||
mActionHelpContents->setIcon( getThemeIcon( "/mActionHelpContents.png" ) );
|
||||
mActionLocalHistogramStretch->setIcon( getThemeIcon( "/mActionLocalHistogramStretch.png" ) );
|
||||
mActionFullHistogramStretch->setIcon( getThemeIcon( "/mActionFullHistogramStretch.png" ) );
|
||||
@ -2456,7 +2474,17 @@ void QgisApp::addWmsLayer()
|
||||
// Fudge for now
|
||||
QgsDebugMsg( "about to addRasterLayer" );
|
||||
|
||||
QgsWMSSourceSelect *wmss = new QgsWMSSourceSelect( this );
|
||||
// TODO: QDialog for now, switch to QWidget in future
|
||||
QDialog *wmss = dynamic_cast<QDialog*> ( QgsProviderRegistry::instance()->getSelectWidget( QString("wms"), this ) );
|
||||
if ( !wmss )
|
||||
{
|
||||
QMessageBox::warning( this, tr( "WMS" ), tr( "Cannot get WMS select dialog from provider." ) );
|
||||
return;
|
||||
}
|
||||
connect ( wmss , SIGNAL ( addRasterLayer( QString const &, QString const &, QString const &,QStringList const &,QStringList const &,QString const &,
|
||||
QString const &) ),
|
||||
this , SLOT ( addRasterLayer( QString const &, QString const &, QString const &,QStringList const &,QStringList const &,QString const &,
|
||||
QString const &) ) );
|
||||
wmss->exec();
|
||||
delete wmss;
|
||||
}
|
||||
@ -2585,96 +2613,17 @@ void QgisApp::newVectorLayer()
|
||||
return;
|
||||
}
|
||||
|
||||
QgsNewVectorLayerDialog geomDialog( this );
|
||||
if ( geomDialog.exec() == QDialog::Rejected )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QGis::WkbType geometrytype = geomDialog.selectedType();
|
||||
QString fileformat = geomDialog.selectedFileFormat();
|
||||
int crsId = geomDialog.selectedCrsId();
|
||||
QgsDebugMsg( QString( "New file format will be: %1" ).arg( fileformat ) );
|
||||
|
||||
std::list<std::pair<QString, QString> > attributes;
|
||||
geomDialog.attributes( attributes );
|
||||
|
||||
QString enc;
|
||||
QString fileName;
|
||||
QString fileName = QgsNewVectorLayerDialog::runAndCreateLayer( this, &enc );
|
||||
|
||||
QSettings settings;
|
||||
QString lastUsedDir = settings.value( "/UI/lastVectorFileFilterDir", "." ).toString();
|
||||
|
||||
QgsDebugMsg( "Saving vector file dialog without filters: " );
|
||||
|
||||
QgsEncodingFileDialog* openFileDialog =
|
||||
new QgsEncodingFileDialog( this, tr( "Save As" ), lastUsedDir, "", QString( "" ) );
|
||||
|
||||
openFileDialog->setFileMode( QFileDialog::AnyFile );
|
||||
openFileDialog->setAcceptMode( QFileDialog::AcceptSave );
|
||||
openFileDialog->setConfirmOverwrite( true );
|
||||
|
||||
if ( settings.contains( "/UI/lastVectorFileFilter" ) )
|
||||
if ( !fileName.isEmpty() )
|
||||
{
|
||||
QString lastUsedFilter = settings.value( "/UI/lastVectorFileFilter", QVariant( QString::null ) ).toString();
|
||||
openFileDialog->selectFilter( lastUsedFilter );
|
||||
//then add the layer to the view
|
||||
QStringList fileNames;
|
||||
fileNames.append( fileName );
|
||||
//todo: the last parameter will change accordingly to layer type
|
||||
addVectorLayers( fileNames, enc, "file" );
|
||||
}
|
||||
|
||||
if ( openFileDialog->exec() == QDialog::Rejected )
|
||||
{
|
||||
delete openFileDialog;
|
||||
return;
|
||||
}
|
||||
|
||||
fileName = openFileDialog->selectedFiles().first();
|
||||
|
||||
if ( fileformat == "ESRI Shapefile" && !fileName.endsWith( ".shp", Qt::CaseInsensitive ) )
|
||||
fileName += ".shp";
|
||||
|
||||
enc = openFileDialog->encoding();
|
||||
|
||||
settings.setValue( "/UI/lastVectorFileFilter", openFileDialog->selectedFilter() );
|
||||
settings.setValue( "/UI/lastVectorFileFilterDir", openFileDialog->directory().absolutePath() );
|
||||
|
||||
delete openFileDialog;
|
||||
|
||||
//try to create the new layer with OGRProvider instead of QgsVectorFileWriter
|
||||
QgsProviderRegistry * pReg = QgsProviderRegistry::instance();
|
||||
QString ogrlib = pReg->library( "ogr" );
|
||||
// load the data provider
|
||||
QLibrary* myLib = new QLibrary( ogrlib );
|
||||
bool loaded = myLib->load();
|
||||
if ( loaded )
|
||||
{
|
||||
QgsDebugMsg( "ogr provider loaded" );
|
||||
|
||||
typedef bool ( *createEmptyDataSourceProc )( const QString&, const QString&, const QString&, QGis::WkbType,
|
||||
const std::list<std::pair<QString, QString> >&, const QgsCoordinateReferenceSystem * );
|
||||
createEmptyDataSourceProc createEmptyDataSource = ( createEmptyDataSourceProc ) cast_to_fptr( myLib->resolve( "createEmptyDataSource" ) );
|
||||
if ( createEmptyDataSource )
|
||||
{
|
||||
if ( geometrytype != QGis::WKBUnknown )
|
||||
{
|
||||
QgsCoordinateReferenceSystem srs( crsId, QgsCoordinateReferenceSystem::InternalCrsId );
|
||||
createEmptyDataSource( fileName, fileformat, enc, geometrytype, attributes, &srs );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( "geometry type not recognised" );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( "Resolving newEmptyDataSource(...) failed" );
|
||||
}
|
||||
}
|
||||
|
||||
//then add the layer to the view
|
||||
QStringList fileNames;
|
||||
fileNames.append( fileName );
|
||||
//todo: the last parameter will change accordingly to layer type
|
||||
addVectorLayers( fileNames, enc, "file" );
|
||||
}
|
||||
|
||||
#ifdef HAVE_SPATIALITE
|
||||
@ -4675,10 +4624,23 @@ void QgisApp::showPluginManager()
|
||||
}
|
||||
}
|
||||
|
||||
static void _runPythonString( const QString &expr )
|
||||
// implementation of the python runner
|
||||
class QgsPythonRunnerImpl : public QgsPythonRunner
|
||||
{
|
||||
QgisApp::instance()->runPythonString( expr );
|
||||
}
|
||||
public:
|
||||
QgsPythonRunnerImpl(QgsPythonUtils* pythonUtils) : mPythonUtils(pythonUtils) {}
|
||||
virtual bool runCommand( QString command, QString messageOnError = QString() )
|
||||
{
|
||||
if ( mPythonUtils && mPythonUtils->isEnabled() )
|
||||
{
|
||||
return mPythonUtils->runString( command, messageOnError );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
QgsPythonUtils* mPythonUtils;
|
||||
};
|
||||
|
||||
void QgisApp::loadPythonSupport()
|
||||
{
|
||||
@ -4724,7 +4686,9 @@ void QgisApp::loadPythonSupport()
|
||||
if ( mPythonUtils && mPythonUtils->isEnabled() )
|
||||
{
|
||||
QgsPluginRegistry::instance()->setPythonUtils( mPythonUtils );
|
||||
QgsAttributeAction::setPythonExecute( _runPythonString );
|
||||
|
||||
// init python runner
|
||||
QgsPythonRunner::setInstance( new QgsPythonRunnerImpl(mPythonUtils) );
|
||||
|
||||
std::cout << "Python support ENABLED :-) " << std::endl; // OK
|
||||
}
|
||||
@ -4868,6 +4832,11 @@ void QgisApp::configureShortcuts()
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
void QgisApp::customize()
|
||||
{
|
||||
QgsCustomization::instance()->openDialog();
|
||||
}
|
||||
|
||||
|
||||
void QgisApp::options()
|
||||
{
|
||||
@ -6646,13 +6615,6 @@ void QgisApp::updateUndoActions()
|
||||
mActionRedo->setEnabled( canRedo );
|
||||
}
|
||||
|
||||
void QgisApp::runPythonString( const QString &expr )
|
||||
{
|
||||
if ( mPythonUtils && mPythonUtils->isEnabled() )
|
||||
{
|
||||
mPythonUtils->runString( expr );
|
||||
}
|
||||
}
|
||||
|
||||
// add project directory to python path
|
||||
void QgisApp::projectChanged( const QDomDocument &doc )
|
||||
@ -6678,7 +6640,7 @@ void QgisApp::projectChanged( const QDomDocument &doc )
|
||||
|
||||
expr += QString( "sys.path.append('%1')" ).arg( prevProjectDir );
|
||||
|
||||
runPythonString( expr );
|
||||
QgsPythonRunner::run( expr );
|
||||
}
|
||||
|
||||
void QgisApp::writeProject( QDomDocument &doc )
|
||||
|
@ -113,18 +113,6 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
|
||||
*/
|
||||
bool addRasterLayers( QStringList const & theLayerQStringList, bool guiWarning = true );
|
||||
|
||||
/** Open a raster layer using the Raster Data Provider.
|
||||
* Note this is included to support WMS layers only at this stage,
|
||||
* GDAL layer support via a Provider is not yet implemented.
|
||||
*/
|
||||
QgsRasterLayer* addRasterLayer( QString const & rasterLayerPath,
|
||||
QString const & baseName,
|
||||
QString const & providerKey,
|
||||
QStringList const & layers,
|
||||
QStringList const & styles,
|
||||
QString const & format,
|
||||
QString const & crs );
|
||||
|
||||
/** open a raster layer for the given file
|
||||
@returns false if unable to open a raster layer for rasterFile
|
||||
@note
|
||||
@ -345,9 +333,6 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
|
||||
QToolBar *helpToolBar() { return mHelpToolBar; }
|
||||
QToolBar *rasterToolBar() { return mRasterToolBar; }
|
||||
|
||||
//! run python
|
||||
void runPythonString( const QString &expr );
|
||||
|
||||
//! show layer properties
|
||||
void showLayerProperties( QgsMapLayer *ml );
|
||||
|
||||
@ -436,6 +421,17 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
|
||||
//! Watch for QFileOpenEvent.
|
||||
virtual bool event( QEvent * event );
|
||||
|
||||
/** Open a raster layer using the Raster Data Provider.
|
||||
* Note this is included to support WMS layers only at this stage,
|
||||
* GDAL layer support via a Provider is not yet implemented.
|
||||
*/
|
||||
QgsRasterLayer* addRasterLayer( QString const & rasterLayerPath,
|
||||
QString const & baseName,
|
||||
QString const & providerKey,
|
||||
QStringList const & layers,
|
||||
QStringList const & styles,
|
||||
QString const & format,
|
||||
QString const & crs );
|
||||
protected:
|
||||
|
||||
//! Handle state changes (WindowTitleChange)
|
||||
@ -590,6 +586,8 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
|
||||
void customProjection();
|
||||
//! configure shortcuts
|
||||
void configureShortcuts();
|
||||
//! show customization dialog
|
||||
void customize();
|
||||
//! options dialog slot
|
||||
void options();
|
||||
//! Whats-this help slot
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "qgshighlight.h"
|
||||
#include "qgssearchstring.h"
|
||||
#include "qgssearchtreenode.h"
|
||||
#include "qgspythonrunner.h"
|
||||
|
||||
#include "qgisapp.h"
|
||||
|
||||
@ -282,15 +283,15 @@ QgsAttributeDialog::QgsAttributeDialog( QgsVectorLayer *vl, QgsFeature *thepFeat
|
||||
int pos = module.lastIndexOf( "." );
|
||||
if ( pos >= 0 )
|
||||
{
|
||||
QgisApp::instance()->runPythonString( QString( "import %1" ).arg( module.left( pos ) ) );
|
||||
QgsPythonRunner::run( QString( "import %1" ).arg( module.left( pos ) ) );
|
||||
}
|
||||
|
||||
mFormNr = smFormCounter++;
|
||||
QgisApp::instance()->runPythonString( QString( "_qgis_featureform_%1 = wrapinstance( %2, QtGui.QDialog )" ).arg( mFormNr ).arg(( unsigned long ) mDialog ) );
|
||||
QgsPythonRunner::run( QString( "_qgis_featureform_%1 = wrapinstance( %2, QtGui.QDialog )" ).arg( mFormNr ).arg(( unsigned long ) mDialog ) );
|
||||
|
||||
QString expr = QString( "%1(_qgis_featureform_%2,'%3',%4)" ).arg( vl->editFormInit() ).arg( mFormNr ).arg( vl->id() ).arg( mFeature->id() );
|
||||
QgsDebugMsg( QString( "running featureForm init: %1" ).arg( expr ) );
|
||||
QgisApp::instance()->runPythonString( expr );
|
||||
QgsPythonRunner::run( expr );
|
||||
}
|
||||
|
||||
restoreGeometry();
|
||||
@ -401,7 +402,7 @@ void QgsAttributeDialog::dialogDestroyed()
|
||||
if ( -1 < mFormNr )
|
||||
{
|
||||
QString expr = QString( "if locals().has_key('_qgis_featureform_%1'): del _qgis_featureform_%1\n" ).arg( mFormNr );
|
||||
QgisApp::instance()->runPythonString( expr );
|
||||
QgsPythonRunner::run( expr );
|
||||
}
|
||||
|
||||
mDialog = NULL;
|
||||
|
897
src/app/qgscustomization.cpp
Normal file
@ -0,0 +1,897 @@
|
||||
/***************************************************************************
|
||||
qgscustomization.cpp - Customization
|
||||
-------------------
|
||||
begin : 2011-04-01
|
||||
copyright : (C) 2011 Radim Blazek
|
||||
email : radim dot blazek at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
/* $Id$ */
|
||||
#include "qgscustomization.h"
|
||||
#include "qgisapp.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgslogger.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QDir>
|
||||
#include <QDockWidget>
|
||||
#include <QDomDocument>
|
||||
#include <QDomElement>
|
||||
#include <QDomNode>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QMessageBox>
|
||||
#include <QSettings>
|
||||
#include <QPushButton>
|
||||
#include <QKeySequence>
|
||||
#include <QToolButton>
|
||||
#include <QStatusBar>
|
||||
|
||||
//standard includes
|
||||
#include <cassert>
|
||||
#include <fstream>
|
||||
#include <typeinfo>
|
||||
|
||||
#ifdef Q_OS_MACX
|
||||
QgsCustomizationDialog::QgsCustomizationDialog()
|
||||
: QMainWindow( NULL, Qt::WindowSystemMenuHint ), // Modeless dialog with close button only
|
||||
mSettings ( "QuantumGIS", "QGISCUSTOMIZATION" )
|
||||
#else
|
||||
QgsCustomizationDialog::QgsCustomizationDialog()
|
||||
: QMainWindow( NULL ), mSettings ( "QuantumGIS", "QGISCUSTOMIZATION" )
|
||||
#endif
|
||||
{
|
||||
setupUi( this );
|
||||
init();
|
||||
QStringList myHeaders;
|
||||
myHeaders << tr("Object name") << tr("Label") << tr("Description");
|
||||
treeWidget->setHeaderLabels ( myHeaders );
|
||||
|
||||
mLastDirSettingsName = QString("/UI/lastCustomizationDir" );
|
||||
//treeWidget->hideColumn(0)
|
||||
connect( buttonBox->button( QDialogButtonBox::Ok ), SIGNAL( clicked() ), this, SLOT( ok() ) );
|
||||
connect( buttonBox->button( QDialogButtonBox::Apply ), SIGNAL( clicked() ), this, SLOT( apply() ) );
|
||||
connect( buttonBox->button( QDialogButtonBox::Cancel ), SIGNAL( clicked() ), this, SLOT( cancel() ) );
|
||||
connect( buttonBox->button( QDialogButtonBox::Reset ), SIGNAL( clicked() ), this, SLOT( reset() ) );
|
||||
|
||||
}
|
||||
|
||||
QgsCustomizationDialog::~QgsCustomizationDialog()
|
||||
{
|
||||
}
|
||||
|
||||
QTreeWidgetItem * QgsCustomizationDialog::item ( QString thePath, QTreeWidgetItem *theItem )
|
||||
{
|
||||
QString path = thePath;
|
||||
if ( path.startsWith("/") ) path = path.mid(1); // remove '/'
|
||||
QStringList names = path.split('/');
|
||||
path = QStringList(names.mid(1)).join ("/" );
|
||||
|
||||
if ( ! theItem )
|
||||
{
|
||||
for (int i = 0; i < treeWidget->topLevelItemCount(); ++i)
|
||||
{
|
||||
QTreeWidgetItem *myItem = treeWidget->topLevelItem(i);
|
||||
QString objectName = myItem->text(0);
|
||||
if ( objectName == names[0] )
|
||||
{
|
||||
return item ( path, myItem );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < theItem->childCount(); ++i) {
|
||||
QTreeWidgetItem *myItem = theItem->child(i);
|
||||
QString objectName = myItem->text(0);
|
||||
if ( objectName == names[0] )
|
||||
{
|
||||
if ( names.size () == 1 )
|
||||
{
|
||||
return myItem;
|
||||
}
|
||||
else
|
||||
{
|
||||
return item ( path, myItem );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
QgsDebugMsg( "not found") ;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool QgsCustomizationDialog::itemChecked ( QString thePath )
|
||||
{
|
||||
QgsDebugMsg( QString("thePath = %1").arg(thePath));
|
||||
QTreeWidgetItem *myItem = item ( thePath );
|
||||
if ( !myItem ) return true;
|
||||
return myItem->checkState(0) == Qt::Checked ? true : false;
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::setItemChecked ( QString thePath, bool on )
|
||||
{
|
||||
QgsDebugMsg( QString("thePath = %1 on = %2").arg(thePath).arg(on));
|
||||
QTreeWidgetItem *myItem = item ( thePath );
|
||||
if ( !myItem ) return;
|
||||
myItem->setCheckState(0, on ? Qt::Checked : Qt::Unchecked);
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::settingsToItem( QString thePath, QTreeWidgetItem *theItem, QSettings *theSettings )
|
||||
{
|
||||
QString objectName = theItem->text(0);
|
||||
if (objectName.isEmpty())
|
||||
return; // object is not identifiable
|
||||
|
||||
QString myPath = thePath + "/" + objectName;
|
||||
|
||||
bool on = theSettings->value(myPath, true).toBool();
|
||||
theItem->setCheckState(0, on ? Qt::Checked : Qt::Unchecked );
|
||||
|
||||
for (int i = 0; i < theItem->childCount(); ++i) {
|
||||
QTreeWidgetItem *myItem = theItem->child(i);
|
||||
settingsToItem( myPath, myItem, theSettings );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::itemToSettings( QString thePath, QTreeWidgetItem *theItem, QSettings *theSettings )
|
||||
{
|
||||
|
||||
QString objectName = theItem->text(0);
|
||||
if (objectName.isEmpty())
|
||||
return; // object is not identifiable
|
||||
|
||||
QString myPath = thePath + "/" + objectName;
|
||||
bool on = theItem->checkState(0) == Qt::Checked ? true : false;
|
||||
theSettings->setValue( myPath, on );
|
||||
|
||||
for (int i = 0; i < theItem->childCount(); ++i) {
|
||||
QTreeWidgetItem *myItem = theItem->child(i);
|
||||
itemToSettings( myPath, myItem, theSettings );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::treeToSettings ( QSettings *theSettings )
|
||||
{
|
||||
for (int i = 0; i < treeWidget->topLevelItemCount(); ++i) {
|
||||
itemToSettings( QString("/Customization"), treeWidget->topLevelItem(i), theSettings );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::settingsToTree ( QSettings *theSettings )
|
||||
{
|
||||
for (int i = 0; i < treeWidget->topLevelItemCount(); ++i)
|
||||
{
|
||||
settingsToItem( QString("/Customization"), treeWidget->topLevelItem(i), theSettings );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::reset()
|
||||
{
|
||||
mSettings.sync();
|
||||
settingsToTree ( &mSettings );
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::ok()
|
||||
{
|
||||
apply();
|
||||
hide();
|
||||
}
|
||||
void QgsCustomizationDialog::apply()
|
||||
{
|
||||
QgsDebugMsg( QString("columnCount = %1").arg( treeWidget->columnCount() ) );
|
||||
treeToSettings ( &mSettings );
|
||||
mSettings.setValue( QgsCustomization::instance()->statusPath(), QgsCustomization::User);
|
||||
mSettings.sync();
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::cancel()
|
||||
{
|
||||
hide();
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::on_actionSave_triggered( bool checked )
|
||||
{
|
||||
QSettings mySettings;
|
||||
QString lastDir = mySettings.value( mLastDirSettingsName, "." ).toString();
|
||||
|
||||
QString fileName = QFileDialog::getSaveFileName(this,
|
||||
tr( "Choose a customization INI file" ),
|
||||
lastDir, tr( "Customization files (*.ini)" ) );
|
||||
|
||||
if ( fileName.isEmpty() ) return;
|
||||
QFileInfo fileInfo( fileName );
|
||||
mySettings.setValue ( mLastDirSettingsName, fileInfo.absoluteDir().absolutePath () );
|
||||
|
||||
QSettings fileSettings( fileName, QSettings::IniFormat);
|
||||
treeToSettings ( &fileSettings );
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::on_actionLoad_triggered( bool checked )
|
||||
{
|
||||
QSettings mySettings;
|
||||
QString lastDir = mySettings.value( mLastDirSettingsName, "." ).toString();
|
||||
|
||||
QString fileName = QFileDialog::getOpenFileName(this,
|
||||
tr( "Choose a customization INI file" ),
|
||||
lastDir, tr( "Customization files (*.ini)" ) );
|
||||
|
||||
if ( fileName.isEmpty() ) return;
|
||||
QFileInfo fileInfo( fileName );
|
||||
mySettings.setValue ( mLastDirSettingsName, fileInfo.absoluteDir().absolutePath () );
|
||||
|
||||
QSettings fileSettings( fileName, QSettings::IniFormat);
|
||||
settingsToTree ( &fileSettings );
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::on_actionExpandAll_triggered( bool checked )
|
||||
{
|
||||
treeWidget->expandAll();
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::on_actionCollapseAll_triggered( bool checked )
|
||||
{
|
||||
treeWidget->collapseAll();
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::on_actionSelectAll_triggered( bool checked )
|
||||
{
|
||||
QList<QTreeWidgetItem*> items = treeWidget->findItems("*",Qt::MatchWildcard|Qt::MatchRecursive, 0);
|
||||
|
||||
QList<QTreeWidgetItem*>::iterator i;
|
||||
for ( i = items.begin(); i != items.end(); ++i)
|
||||
{
|
||||
(*i)->setCheckState(0, Qt::Checked);
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::init()
|
||||
{
|
||||
QgsDebugMsg( "Entered" );
|
||||
QTreeWidgetItem * wi = createTreeItemWidgets();
|
||||
if ( wi ) {
|
||||
treeWidget->insertTopLevelItem(0, wi );
|
||||
treeWidget->expandItem( wi );
|
||||
}
|
||||
|
||||
treeWidget->insertTopLevelItems( 0, QgsCustomization::instance()->mMainWindowItems );
|
||||
|
||||
for (int i = 0; i < treeWidget->topLevelItemCount(); i++)
|
||||
treeWidget->expandItem( treeWidget->topLevelItem(i) );
|
||||
|
||||
// load check states from the settings
|
||||
reset();
|
||||
|
||||
treeWidget->sortItems(0, Qt::AscendingOrder);
|
||||
treeWidget->resizeColumnToContents(0);
|
||||
}
|
||||
|
||||
QTreeWidgetItem * QgsCustomizationDialog::createTreeItemWidgets()
|
||||
{
|
||||
QgsDebugMsg( "Entered" );
|
||||
|
||||
QDomDocument myDoc( "QgsWidgets" );
|
||||
QFile myFile( QgsApplication::pkgDataPath() + "/resources/customization.xml" );
|
||||
if( !myFile.open( QIODevice::ReadOnly ) )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if( !myDoc.setContent( &myFile ) )
|
||||
{
|
||||
myFile.close();
|
||||
return NULL;
|
||||
}
|
||||
myFile.close();
|
||||
|
||||
QDomElement myRoot = myDoc.documentElement();
|
||||
if( myRoot.tagName() != "qgiswidgets" )
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
QTreeWidgetItem *myItem = readWidgetsXmlNode ( myRoot );
|
||||
myItem->setData ( 0, Qt::DisplayRole, tr("Widgets" ) );
|
||||
|
||||
return myItem;
|
||||
}
|
||||
|
||||
QTreeWidgetItem * QgsCustomizationDialog::readWidgetsXmlNode ( QDomNode theNode )
|
||||
{
|
||||
QgsDebugMsg( "Entered" );
|
||||
QDomElement myElement = theNode.toElement();
|
||||
|
||||
QString name = myElement.attribute( "objectName", "");
|
||||
QStringList data( name );
|
||||
|
||||
data << myElement.attribute( "label", name);
|
||||
data << myElement.attribute( "description", "");
|
||||
|
||||
QTreeWidgetItem *myItem = new QTreeWidgetItem ( data );
|
||||
|
||||
// It is nice to have icons for each Qt widget class, is it too heavy?
|
||||
// There are 47 png files, total 196K in qt/tools/designer/src/components/formeditor/images/
|
||||
QString iconName = myElement.attribute( "class", "" ).toLower().mid(1) + ".png";
|
||||
QString iconPath = QgsApplication::iconPath( "/customization/" + iconName );
|
||||
QgsDebugMsg( "iconPath = " + iconPath );
|
||||
if ( QFile::exists( iconPath ) )
|
||||
{
|
||||
myItem->setIcon (0, QIcon(iconPath) );
|
||||
}
|
||||
myItem->setFlags ( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable );
|
||||
myItem->setCheckState(0, Qt::Checked);
|
||||
|
||||
QDomNode n = theNode.firstChild();
|
||||
while( !n.isNull() )
|
||||
{
|
||||
QDomElement e = n.toElement();
|
||||
if( !e.isNull() )
|
||||
{
|
||||
QTreeWidgetItem *wi = readWidgetsXmlNode ( n );
|
||||
myItem->insertChild ( 0, wi );
|
||||
}
|
||||
n = n.nextSibling();
|
||||
}
|
||||
return myItem;
|
||||
}
|
||||
|
||||
bool QgsCustomizationDialog::switchWidget ( QWidget * widget, QMouseEvent *event )
|
||||
{
|
||||
QgsDebugMsg ( "Entered" );
|
||||
if ( !actionCatch->isChecked() ) { return false; }
|
||||
QString path = widgetPath(widget);
|
||||
QgsDebugMsg ( "path = " + path );
|
||||
|
||||
if ( path.startsWith ( "/QgsCustomizationDialogBase" ) )
|
||||
{
|
||||
// do not allow modification of this dialog
|
||||
return false;
|
||||
}
|
||||
else if ( path.startsWith( "/QgisApp" ) )
|
||||
{
|
||||
// changes to main window
|
||||
// (work with toolbars, tool buttons)
|
||||
if (widget->inherits("QToolBar"))
|
||||
{
|
||||
path = "/Toolbars/" + widget->objectName();
|
||||
}
|
||||
else if (widget->inherits("QToolButton"))
|
||||
{
|
||||
QToolButton* toolbutton = qobject_cast<QToolButton*>(widget);
|
||||
QAction* action = toolbutton->defaultAction();
|
||||
QString toolbarName = widget->parent()->objectName();
|
||||
QString actionName = action->objectName();
|
||||
path = "/Toolbars/" + toolbarName + "/" + actionName;
|
||||
}
|
||||
else
|
||||
{
|
||||
// unsupported widget in main window
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// ordinary widget in a dialog
|
||||
path = "/Widgets" + path;
|
||||
}
|
||||
|
||||
QgsDebugMsg ( "path final = " + path );
|
||||
bool on = !itemChecked ( path );
|
||||
|
||||
QgsDebugMsg ( QString ( "on = %1" ).arg(on) );
|
||||
|
||||
setItemChecked ( path, on );
|
||||
QTreeWidgetItem *myItem = item ( path );
|
||||
if ( myItem ) {
|
||||
treeWidget->scrollToItem ( myItem, QAbstractItemView::PositionAtCenter );
|
||||
treeWidget->clearSelection();
|
||||
myItem->setSelected ( true );
|
||||
|
||||
QString style;
|
||||
if ( !on ) {
|
||||
style = "background-color: #FFCCCC;";
|
||||
}
|
||||
widget->setStyleSheet( style );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString QgsCustomizationDialog::widgetPath ( QWidget * theWidget, QString thePath )
|
||||
{
|
||||
// go up until QDialog is reached
|
||||
QString name = theWidget->objectName();
|
||||
|
||||
QString path = thePath;
|
||||
|
||||
if ( !QgsCustomization::mInternalWidgets.contains ( name ) )
|
||||
{
|
||||
if ( !path.isEmpty() ) {
|
||||
path = name + "/" + path;
|
||||
}
|
||||
else
|
||||
{
|
||||
path = name;
|
||||
}
|
||||
}
|
||||
|
||||
QWidget * parent = theWidget->parentWidget();
|
||||
|
||||
if ( !parent || theWidget->inherits("QDialog") )
|
||||
{
|
||||
return "/" + path;
|
||||
}
|
||||
|
||||
return widgetPath ( parent, path );
|
||||
}
|
||||
|
||||
void QgsCustomizationDialog::setCatch ( bool on )
|
||||
{
|
||||
actionCatch->setChecked ( on );
|
||||
}
|
||||
bool QgsCustomizationDialog::catchOn ( )
|
||||
{
|
||||
return actionCatch->isChecked ( );
|
||||
}
|
||||
|
||||
void QgsCustomization::addTreeItemActions(QTreeWidgetItem* parentItem, const QList<QAction*>& actions)
|
||||
{
|
||||
foreach (QAction* action, actions)
|
||||
{
|
||||
if (action->menu())
|
||||
{
|
||||
// it is a submenu
|
||||
addTreeItemMenu(parentItem, action->menu());
|
||||
}
|
||||
else
|
||||
{
|
||||
// it is an ordinary action
|
||||
QStringList strs;
|
||||
strs << action->objectName() << action->text();
|
||||
QTreeWidgetItem* myItem = new QTreeWidgetItem(parentItem, strs);
|
||||
myItem->setIcon( 0, action->icon() );
|
||||
myItem->setFlags ( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable );
|
||||
myItem->setCheckState(0, Qt::Checked);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCustomization::addTreeItemMenu(QTreeWidgetItem* parentItem, QMenu* menu)
|
||||
{
|
||||
QStringList menustrs;
|
||||
menustrs << menu->objectName() << menu->title();
|
||||
QTreeWidgetItem* menuItem = new QTreeWidgetItem( parentItem, menustrs);
|
||||
menuItem->setFlags ( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable );
|
||||
menuItem->setCheckState(0, Qt::Checked);
|
||||
|
||||
addTreeItemActions(menuItem, menu->actions());
|
||||
}
|
||||
|
||||
void QgsCustomization::createTreeItemMenus ( )
|
||||
{
|
||||
QStringList data;
|
||||
data << "Menus";
|
||||
|
||||
QTreeWidgetItem *topItem = new QTreeWidgetItem ( data );
|
||||
|
||||
QMenuBar* menubar = QgisApp::instance()->menuBar();
|
||||
foreach (QObject* obj, menubar->children())
|
||||
{
|
||||
if (obj->inherits("QMenu"))
|
||||
{
|
||||
QMenu* menu = qobject_cast<QMenu*>(obj);
|
||||
addTreeItemMenu(topItem, menu);
|
||||
}
|
||||
}
|
||||
|
||||
mMainWindowItems << topItem;
|
||||
}
|
||||
|
||||
void QgsCustomization::createTreeItemToolbars ( )
|
||||
{
|
||||
QStringList data;
|
||||
data << "Toolbars";
|
||||
|
||||
QTreeWidgetItem *topItem = new QTreeWidgetItem ( data );
|
||||
|
||||
QMainWindow* mw = QgisApp::instance();
|
||||
foreach (QObject* obj, mw->children())
|
||||
{
|
||||
if (obj->inherits("QToolBar"))
|
||||
{
|
||||
QToolBar* tb = qobject_cast<QToolBar*>(obj);
|
||||
QStringList tbstrs;
|
||||
tbstrs << tb->objectName() << tb->windowTitle();
|
||||
QTreeWidgetItem* tbItem = new QTreeWidgetItem( topItem, tbstrs );
|
||||
tbItem->setFlags ( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable );
|
||||
tbItem->setCheckState(0, Qt::Checked);
|
||||
|
||||
addTreeItemActions(tbItem, tb->actions());
|
||||
}
|
||||
}
|
||||
|
||||
mMainWindowItems << topItem;
|
||||
}
|
||||
|
||||
void QgsCustomization::createTreeItemDocks ( )
|
||||
{
|
||||
QStringList data;
|
||||
data << "Docks";
|
||||
|
||||
QTreeWidgetItem *topItem = new QTreeWidgetItem ( data );
|
||||
|
||||
QMainWindow* mw = QgisApp::instance();
|
||||
foreach (QObject* obj, mw->children())
|
||||
{
|
||||
if (obj->inherits("QDockWidget"))
|
||||
{
|
||||
QDockWidget* dw = qobject_cast<QDockWidget*> (obj);
|
||||
QStringList dwstrs;
|
||||
dwstrs << dw->objectName() << dw->windowTitle();
|
||||
QTreeWidgetItem* dwItem = new QTreeWidgetItem( topItem, dwstrs );
|
||||
dwItem->setFlags ( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable );
|
||||
dwItem->setCheckState(0, Qt::Checked);
|
||||
}
|
||||
}
|
||||
|
||||
mMainWindowItems << topItem;
|
||||
}
|
||||
|
||||
void QgsCustomization::createTreeItemStatus ( )
|
||||
{
|
||||
QStringList data;
|
||||
data << "StatusBar";
|
||||
|
||||
QTreeWidgetItem *topItem = new QTreeWidgetItem ( data );
|
||||
topItem->setFlags ( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable );
|
||||
topItem->setCheckState(0, Qt::Checked);
|
||||
|
||||
QStatusBar* sb = QgisApp::instance()->statusBar();
|
||||
foreach (QObject* obj, sb->children())
|
||||
{
|
||||
if (obj->inherits("QWidget") && !obj->objectName().isEmpty())
|
||||
{
|
||||
QStringList strs;
|
||||
strs << obj->objectName();
|
||||
QTreeWidgetItem* item = new QTreeWidgetItem( topItem, strs );
|
||||
item->setFlags ( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable );
|
||||
item->setCheckState(0, Qt::Checked);
|
||||
}
|
||||
}
|
||||
|
||||
mMainWindowItems << topItem;
|
||||
}
|
||||
|
||||
QStringList QgsCustomization::mInternalWidgets = QStringList() << "qt_tabwidget_stackedwidget" << "qt_tabwidget_tabbar";
|
||||
|
||||
QgsCustomization *QgsCustomization::pinstance = 0;
|
||||
QgsCustomization *QgsCustomization::instance()
|
||||
{
|
||||
if ( pinstance == 0 )
|
||||
{
|
||||
pinstance = new QgsCustomization();
|
||||
}
|
||||
return pinstance;
|
||||
}
|
||||
|
||||
QgsCustomization::QgsCustomization( ) :
|
||||
pDialog(0),
|
||||
mEnabled(true),
|
||||
mStatusPath("/Customization/status"),
|
||||
mSettings ( "QuantumGIS", "QGISCUSTOMIZATION" )
|
||||
{
|
||||
QgsDebugMsg( "Entered" );
|
||||
}
|
||||
|
||||
QgsCustomization::~QgsCustomization()
|
||||
{
|
||||
}
|
||||
|
||||
void QgsCustomization::updateMainWindow()
|
||||
{
|
||||
// collect tree items even if the customization is disabled
|
||||
createTreeItemMenus();
|
||||
createTreeItemToolbars();
|
||||
createTreeItemDocks();
|
||||
createTreeItemStatus();
|
||||
|
||||
if (!mEnabled)
|
||||
return;
|
||||
|
||||
QMainWindow* mw = QgisApp::instance();
|
||||
QMenuBar* menubar = mw->menuBar();
|
||||
|
||||
mSettings.beginGroup("Customization/Menus");
|
||||
|
||||
// hide menus and menu actions
|
||||
|
||||
foreach (QObject* obj, menubar->children())
|
||||
{
|
||||
if (obj->inherits("QMenu"))
|
||||
{
|
||||
QMenu* menu = qobject_cast<QMenu*>(obj);
|
||||
bool visible = mSettings.value(menu->objectName(), true).toBool();
|
||||
if (!visible)
|
||||
{
|
||||
menubar->removeAction(menu->menuAction());
|
||||
}
|
||||
else
|
||||
{
|
||||
updateMenu(menu, mSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mSettings.endGroup();
|
||||
|
||||
// remove toolbars, toolbar actions
|
||||
|
||||
mSettings.beginGroup("Customization/Toolbars");
|
||||
foreach (QObject* obj, mw->children())
|
||||
{
|
||||
if (obj->inherits("QToolBar"))
|
||||
{
|
||||
QToolBar* tb = qobject_cast<QToolBar*>(obj);
|
||||
bool visible = mSettings.value(tb->objectName(), true).toBool();
|
||||
if (!visible)
|
||||
{
|
||||
mw->removeToolBar(tb);
|
||||
}
|
||||
else
|
||||
{
|
||||
mSettings.beginGroup(tb->objectName());
|
||||
// hide individual toolbar actions
|
||||
foreach (QAction* action, tb->actions())
|
||||
{
|
||||
visible = mSettings.value(action->objectName(), true).toBool();
|
||||
if (!visible)
|
||||
tb->removeAction(action);
|
||||
}
|
||||
mSettings.endGroup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mSettings.endGroup();
|
||||
|
||||
// remove dock widgets
|
||||
|
||||
mSettings.beginGroup("Customization/Docks");
|
||||
foreach (QObject* obj, mw->children())
|
||||
{
|
||||
if (obj->inherits("QDockWidget"))
|
||||
{
|
||||
bool visible = mSettings.value(obj->objectName(), true).toBool();
|
||||
if (!visible)
|
||||
{
|
||||
mw->removeDockWidget(qobject_cast<QDockWidget*>(obj));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mSettings.endGroup();
|
||||
|
||||
// remove status bar widgets
|
||||
|
||||
if (mSettings.value("Customization/StatusBar", true).toBool())
|
||||
{
|
||||
mSettings.beginGroup("Customization/StatusBar");
|
||||
|
||||
QStatusBar* sb = mw->statusBar();
|
||||
foreach (QObject* obj, sb->children())
|
||||
{
|
||||
if (obj->inherits("QWidget"))
|
||||
{
|
||||
QWidget* widget = qobject_cast<QWidget*>(obj);
|
||||
bool visible = mSettings.value(widget->objectName(), true).toBool();
|
||||
if (!visible)
|
||||
{
|
||||
sb->removeWidget(widget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mSettings.endGroup();
|
||||
}
|
||||
else
|
||||
{
|
||||
mw->statusBar()->hide();
|
||||
//mw->setStatusBar( 0 ); // do not delete the status bar: some parts of the app use it
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCustomization::updateMenu(QMenu* menu, QSettings& settings)
|
||||
{
|
||||
settings.beginGroup(menu->objectName());
|
||||
// hide individual menu actions and call recursively on visible submenus
|
||||
foreach (QAction* action, menu->actions())
|
||||
{
|
||||
QString objName = (action->menu() ? action->menu()->objectName() : action->objectName());
|
||||
bool visible = settings.value(objName, true).toBool();
|
||||
if (!visible)
|
||||
menu->removeAction(action);
|
||||
else if (action->menu())
|
||||
{
|
||||
// it is a submenu - let's look if there isn't something to remove
|
||||
updateMenu(action->menu(), settings);
|
||||
}
|
||||
}
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void QgsCustomization::openDialog()
|
||||
{
|
||||
QgsDebugMsg( "Entered" );
|
||||
if ( !pDialog ) {
|
||||
pDialog = new QgsCustomizationDialog();
|
||||
}
|
||||
|
||||
// I am trying too enable switching widget status by clicking in main app, so I need non modal
|
||||
pDialog->show();
|
||||
}
|
||||
|
||||
void QgsCustomization::customizeWidget( QWidget * widget, QEvent * event )
|
||||
{
|
||||
// Test if the widget is child of QDialog
|
||||
if ( !widget->inherits("QDialog") ) return;
|
||||
|
||||
QgsDebugMsg( QString ( "objectName = %1 event type = %2" ).arg( widget->objectName()).arg( event->type() ) );
|
||||
|
||||
QgsDebugMsg( QString ( "%1 x %2").arg(typeid( *widget ).name()).arg(typeid( QDialog ).name() ));
|
||||
QString path = "/Customization/Widgets/";
|
||||
|
||||
QgsCustomization::customizeWidget( path, widget );
|
||||
}
|
||||
|
||||
void QgsCustomization::customizeWidget( QString thePath, QWidget * theWidget )
|
||||
{
|
||||
QSettings mySettings ("QuantumGIS", "QGISCUSTOMIZATION" );
|
||||
QString name = theWidget->objectName();
|
||||
QString myPath = thePath;
|
||||
|
||||
// Qt may insert some internal classes in the tree, e.g. QTabWidgetPrivate inserts
|
||||
// qt_tabwidget_stackedwidget, such widgets do not appear in the tree generated
|
||||
// from ui files and do not have sense from user poin of view -> skip
|
||||
|
||||
if ( !QgsCustomization::mInternalWidgets.contains ( name ) )
|
||||
{
|
||||
myPath = thePath + "/" + name;
|
||||
}
|
||||
|
||||
QObjectList children = theWidget->children();
|
||||
QObjectList::iterator i;
|
||||
for ( i = children.begin(); i != children.end(); ++i)
|
||||
{
|
||||
if ( !(*i)->inherits("QWidget") ) continue;
|
||||
QWidget * w = qobject_cast<QWidget*>(*i);
|
||||
|
||||
QString p = myPath + "/" + w->objectName();
|
||||
|
||||
bool on = mySettings.value( p, true ).toBool();
|
||||
QgsDebugMsg( QString("p = %1 on = %2").arg(p).arg(on) );
|
||||
if ( on )
|
||||
{
|
||||
QgsCustomization::customizeWidget( myPath, w );
|
||||
}
|
||||
else
|
||||
{
|
||||
QLayout *l = theWidget->layout();
|
||||
if ( l )
|
||||
{
|
||||
QgsDebugMsg( "remove" );
|
||||
QgsCustomization::removeFromLayout( l, w );
|
||||
w->hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg( "hide" );
|
||||
w->hide();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCustomization::removeFromLayout( QLayout *theLayout, QWidget * theWidget )
|
||||
{
|
||||
if ( theLayout->indexOf( theWidget ) >= 0 )
|
||||
{
|
||||
theLayout->removeWidget ( theWidget );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
QObjectList children = theLayout->children();
|
||||
QObjectList::iterator i;
|
||||
for ( i = children.begin(); i != children.end(); ++i)
|
||||
{
|
||||
if ( !(*i)->inherits("QLayout") ) continue;
|
||||
QLayout *l = qobject_cast<QLayout*>(*i);
|
||||
|
||||
QgsCustomization::removeFromLayout( l, theWidget );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCustomization::preNotify( QObject * receiver, QEvent * event, bool * done )
|
||||
{
|
||||
QWidget * widget = 0;
|
||||
if ( receiver->isWidgetType() )
|
||||
{
|
||||
widget = static_cast<QWidget*>( receiver );
|
||||
}
|
||||
|
||||
if ( mEnabled && widget && event->type() == QEvent::Show )
|
||||
{
|
||||
QgsCustomization::customizeWidget ( widget, event );
|
||||
if ( widget->inherits("QDialog") && pDialog && pDialog->isVisible() ) {
|
||||
}
|
||||
}
|
||||
else if ( mEnabled && widget && (event->type() == QEvent::Hide || event->type() == QEvent::Close) )
|
||||
{
|
||||
if ( widget->inherits("QDialog") && pDialog && pDialog->isVisible() ){
|
||||
}
|
||||
}
|
||||
else if ( widget && event->type() == QEvent::MouseButtonPress )
|
||||
{
|
||||
QgsDebugMsg( "click" );
|
||||
if ( pDialog && pDialog->isVisible() ) {
|
||||
QMouseEvent *e = static_cast<QMouseEvent*>(event);
|
||||
*done = pDialog->switchWidget ( widget, e );
|
||||
}
|
||||
}
|
||||
// Shortcut arrives only if it is defined and used in main app
|
||||
// This would be also possible without necessity to add shortcut to main app
|
||||
// but it is better to have it there to avoid future conflicts
|
||||
else if ( event->type() == QEvent::KeyPress )
|
||||
{
|
||||
if ( pDialog && pDialog->isVisible() ) {
|
||||
QKeyEvent *e = static_cast<QKeyEvent*>(event);
|
||||
QgsDebugMsg( QString("key = %1 modifiers = %2").arg(e->key()).arg(e->modifiers() ) ) ;
|
||||
if ( e->key() == Qt::Key_M && e->modifiers() == Qt::ControlModifier )
|
||||
{
|
||||
pDialog->setCatch ( !pDialog->catchOn() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsCustomization::loadDefault()
|
||||
{
|
||||
QSettings mySettings;
|
||||
|
||||
// Check customization state
|
||||
int status = mySettings.value( mStatusPath, QgsCustomization::NotSet).toInt();
|
||||
QgsDebugMsg( "Status path = " + mStatusPath );
|
||||
QgsDebugMsg( QString("status = %1").arg(status) );
|
||||
if ( status == QgsCustomization::User || status == QgsCustomization::Default ) return;
|
||||
|
||||
// Look for default
|
||||
QString path = QgsApplication::pkgDataPath() + "/resources/customization.ini";
|
||||
if ( ! QFile::exists( path ) )
|
||||
{
|
||||
QgsDebugMsg( "Default customization not found in " + path );
|
||||
return;
|
||||
}
|
||||
QgsDebugMsg( "Loading default customization from " + path );
|
||||
|
||||
QSettings fileSettings( path, QSettings::IniFormat);
|
||||
QStringList keys = fileSettings.allKeys();
|
||||
QgsDebugMsg( QString("size = %1").arg( keys.size () ) );
|
||||
QStringList::const_iterator i;
|
||||
for ( i = keys.begin(); i != keys.end(); ++i)
|
||||
{
|
||||
QString p(*i);
|
||||
|
||||
bool val = fileSettings.value(p).toBool();
|
||||
|
||||
mSettings.setValue(p, val);
|
||||
}
|
||||
mySettings.setValue(mStatusPath, QgsCustomization::Default);
|
||||
}
|
165
src/app/qgscustomization.h
Normal file
@ -0,0 +1,165 @@
|
||||
/***************************************************************************
|
||||
qgscustomization.h - Customization
|
||||
-------------------
|
||||
begin : 2011-04-01
|
||||
copyright : (C) 2011 Radim Blazek
|
||||
email : radim dot blazek at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
/* $Id$ */
|
||||
#ifndef QGSCUSTOMIZATION_H
|
||||
#define QGSCUSTOMIZATION_H
|
||||
|
||||
#include "ui_qgscustomizationdialogbase.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDomNode>
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QSettings>
|
||||
#include <QTreeWidgetItem>
|
||||
|
||||
class QString;
|
||||
class QWidget;
|
||||
class QTreeWidgetItem;
|
||||
|
||||
class QgsCustomizationDialog : public QMainWindow, private Ui::QgsCustomizationDialogBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QgsCustomizationDialog();
|
||||
~QgsCustomizationDialog();
|
||||
|
||||
// get item by path
|
||||
QTreeWidgetItem *item ( QString thePath, QTreeWidgetItem *theItem=0 );
|
||||
|
||||
//
|
||||
|
||||
// return current item state for given path
|
||||
bool itemChecked ( QString thePath );
|
||||
// set item state for given path
|
||||
void setItemChecked ( QString thePath, bool on );
|
||||
|
||||
// recursively save tree item to settings
|
||||
void itemToSettings( QString thePath, QTreeWidgetItem *theItem, QSettings *theSettings );
|
||||
// recursively save settings to tree items
|
||||
void settingsToItem( QString thePath, QTreeWidgetItem *theItem, QSettings *theSettings );
|
||||
|
||||
// save current tree to settings
|
||||
void treeToSettings ( QSettings *theSettings );
|
||||
|
||||
// restore current tree from settings
|
||||
void settingsToTree ( QSettings *theSettings );
|
||||
|
||||
// switch widget item in tree
|
||||
bool switchWidget ( QWidget * widget, QMouseEvent *event );
|
||||
|
||||
// Get path of the widget
|
||||
QString widgetPath ( QWidget * theWidget, QString thePath = QString() );
|
||||
|
||||
void setCatch ( bool on );
|
||||
bool catchOn ( );
|
||||
|
||||
private slots:
|
||||
//void on_btnQgisUser_clicked();
|
||||
|
||||
// Save to settings
|
||||
void ok();
|
||||
void apply();
|
||||
|
||||
void cancel();
|
||||
|
||||
// Reset values from settings
|
||||
void reset();
|
||||
|
||||
// Save to settings to file
|
||||
void on_actionSave_triggered( bool checked );
|
||||
|
||||
// Load settings from file
|
||||
void on_actionLoad_triggered( bool checked );
|
||||
|
||||
void on_actionExpandAll_triggered( bool checked );
|
||||
void on_actionCollapseAll_triggered( bool checked );
|
||||
void on_actionSelectAll_triggered( bool checked );
|
||||
|
||||
private:
|
||||
void init();
|
||||
QTreeWidgetItem * createTreeItemWidgets ( );
|
||||
QTreeWidgetItem * readWidgetsXmlNode ( QDomNode theNode );
|
||||
|
||||
QString mLastDirSettingsName;
|
||||
QSettings mSettings;
|
||||
};
|
||||
|
||||
class QgsCustomization : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Status
|
||||
{
|
||||
NotSet = 0,
|
||||
User = 1, // Set by user
|
||||
Default = 2 // Default customization loaded and set
|
||||
};
|
||||
|
||||
//! Returns the instance pointer, creating the object on the first call
|
||||
static QgsCustomization* instance();
|
||||
|
||||
void openDialog();
|
||||
static void customizeWidget( QWidget * widget, QEvent * event );
|
||||
static void customizeWidget( QString path, QWidget * widget );
|
||||
static void removeFromLayout( QLayout *theLayout, QWidget * widget );
|
||||
|
||||
void updateMainWindow();
|
||||
|
||||
// make sure to enable/disable before creating QgisApp in order to get it customized (or not)
|
||||
void setEnabled(bool enabled) { mEnabled = enabled; }
|
||||
bool isEnabled() const { return mEnabled; }
|
||||
|
||||
// Load and set default customization
|
||||
void loadDefault();
|
||||
|
||||
// Internal Qt widget which has to bes kipped in paths
|
||||
static QStringList mInternalWidgets;
|
||||
|
||||
QString statusPath() { return mStatusPath; }
|
||||
|
||||
public slots:
|
||||
void preNotify( QObject * receiver, QEvent * event, bool * done );
|
||||
|
||||
protected:
|
||||
QgsCustomization( );
|
||||
~QgsCustomization();
|
||||
QgsCustomizationDialog *pDialog;
|
||||
|
||||
bool mEnabled;
|
||||
QString mStatusPath;
|
||||
|
||||
void updateMenu(QMenu* menu, QSettings& settings);
|
||||
void createTreeItemMenus ( );
|
||||
void createTreeItemToolbars ( );
|
||||
void createTreeItemDocks ( );
|
||||
void createTreeItemStatus ( );
|
||||
void addTreeItemMenu(QTreeWidgetItem* parentItem, QMenu* menu);
|
||||
void addTreeItemActions(QTreeWidgetItem* parentItem, const QList<QAction*>& actions);
|
||||
QList<QTreeWidgetItem*> mMainWindowItems;
|
||||
friend class QgsCustomizationDialog; // in order to access mMainWindowItems
|
||||
|
||||
private slots:
|
||||
|
||||
private:
|
||||
static QgsCustomization* pinstance;
|
||||
QSettings mSettings;
|
||||
|
||||
};
|
||||
#endif // QGSCUSTOMIZATION_H
|
||||
|
@ -215,7 +215,7 @@ void QgsVectorLayerProperties::setRow( int row, int idx, const QgsField &field )
|
||||
|
||||
QPushButton *pb = new QPushButton( editTypeButtonText( layer->editType( idx ) ) );
|
||||
tblAttributes->setCellWidget( row, attrEditTypeCol, pb );
|
||||
connect( pb, SIGNAL( clicked() ), this, SLOT( attributeTypeDialog() ) );
|
||||
connect( pb, SIGNAL( pressed() ), this, SLOT( attributeTypeDialog( ) ) );
|
||||
mButtonMap.insert( idx, pb );
|
||||
|
||||
//set the alias for the attribute
|
||||
@ -231,7 +231,7 @@ QgsVectorLayerProperties::~QgsVectorLayerProperties()
|
||||
settings.setValue( "/Windows/VectorLayerProperties/row", tabWidget->currentIndex() );
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::attributeTypeDialog()
|
||||
void QgsVectorLayerProperties::attributeTypeDialog( )
|
||||
{
|
||||
QPushButton *pb = qobject_cast<QPushButton *>( sender() );
|
||||
if ( !pb )
|
||||
@ -271,7 +271,6 @@ void QgsVectorLayerProperties::attributeTypeDialog()
|
||||
break;
|
||||
case QgsVectorLayer::CheckBox:
|
||||
mCheckedStates.insert( index, attributeTypeDialog.checkedState() );
|
||||
break;
|
||||
case QgsVectorLayer::LineEdit:
|
||||
case QgsVectorLayer::TextEdit:
|
||||
case QgsVectorLayer::UniqueValues:
|
||||
@ -384,22 +383,20 @@ void QgsVectorLayerProperties::editingToggled()
|
||||
|
||||
void QgsVectorLayerProperties::updateButtons()
|
||||
{
|
||||
int cap = layer->dataProvider()->capabilities();
|
||||
|
||||
mToggleEditingButton->setEnabled(( cap & QgsVectorDataProvider::EditingCapabilities ) && !layer->isReadOnly() );
|
||||
mToggleEditingButton->setChecked( layer->isEditable() );
|
||||
|
||||
if ( layer->isEditable() )
|
||||
{
|
||||
int cap = layer->dataProvider()->capabilities();
|
||||
mAddAttributeButton->setEnabled( cap & QgsVectorDataProvider::AddAttributes );
|
||||
mDeleteAttributeButton->setEnabled( cap & QgsVectorDataProvider::DeleteAttributes );
|
||||
mCalculateFieldButton->setEnabled( cap & QgsVectorDataProvider::ChangeAttributeValues );
|
||||
mToggleEditingButton->setChecked( true );
|
||||
}
|
||||
else
|
||||
{
|
||||
mAddAttributeButton->setDisabled( true );
|
||||
mDeleteAttributeButton->setDisabled( true );
|
||||
mCalculateFieldButton->setDisabled( true );
|
||||
mAddAttributeButton->setEnabled( false );
|
||||
mDeleteAttributeButton->setEnabled( false );
|
||||
mToggleEditingButton->setChecked( false );
|
||||
mCalculateFieldButton->setEnabled( false );
|
||||
}
|
||||
}
|
||||
|
||||
@ -608,44 +605,30 @@ void QgsVectorLayerProperties::apply()
|
||||
QgsVectorLayer::EditType editType = editTypeFromButtonText( pb->text() );
|
||||
layer->setEditType( idx, editType );
|
||||
|
||||
switch ( editType )
|
||||
if ( editType == QgsVectorLayer::ValueMap )
|
||||
{
|
||||
case QgsVectorLayer::ValueMap:
|
||||
if ( mValueMaps.contains( idx ) )
|
||||
{
|
||||
QMap<QString, QVariant> &map = layer->valueMap( idx );
|
||||
map.clear();
|
||||
map = mValueMaps[idx];
|
||||
}
|
||||
break;
|
||||
|
||||
case QgsVectorLayer::EditRange:
|
||||
case QgsVectorLayer::SliderRange:
|
||||
case QgsVectorLayer::DialRange:
|
||||
if ( mRanges.contains( idx ) )
|
||||
{
|
||||
layer->range( idx ) = mRanges[idx];
|
||||
}
|
||||
break;
|
||||
|
||||
case QgsVectorLayer::CheckBox:
|
||||
if ( mCheckedStates.contains( idx ) )
|
||||
{
|
||||
layer->setCheckedState( idx, mCheckedStates[idx].first, mCheckedStates[idx].second );
|
||||
}
|
||||
break;
|
||||
|
||||
case QgsVectorLayer::LineEdit:
|
||||
case QgsVectorLayer::UniqueValues:
|
||||
case QgsVectorLayer::UniqueValuesEditable:
|
||||
case QgsVectorLayer::Classification:
|
||||
case QgsVectorLayer::FileName:
|
||||
case QgsVectorLayer::Enumeration:
|
||||
case QgsVectorLayer::Immutable:
|
||||
case QgsVectorLayer::Hidden:
|
||||
case QgsVectorLayer::TextEdit:
|
||||
case QgsVectorLayer::Calendar:
|
||||
break;
|
||||
if ( mValueMaps.contains( idx ) )
|
||||
{
|
||||
QMap<QString, QVariant> &map = layer->valueMap( idx );
|
||||
map.clear();
|
||||
map = mValueMaps[idx];
|
||||
}
|
||||
}
|
||||
else if ( editType == QgsVectorLayer::EditRange ||
|
||||
editType == QgsVectorLayer::SliderRange ||
|
||||
editType == QgsVectorLayer::DialRange )
|
||||
{
|
||||
if ( mRanges.contains( idx ) )
|
||||
{
|
||||
layer->range( idx ) = mRanges[idx];
|
||||
}
|
||||
}
|
||||
else if ( editType == QgsVectorLayer::CheckBox )
|
||||
{
|
||||
if ( mCheckedStates.contains( idx ) )
|
||||
{
|
||||
layer->setCheckedState( idx, mCheckedStates[idx].first, mCheckedStates[idx].second );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -834,234 +817,7 @@ void QgsVectorLayerProperties::on_pbnIndex_clicked()
|
||||
|
||||
QString QgsVectorLayerProperties::metadata()
|
||||
{
|
||||
QString myMetadata = "<html><body>";
|
||||
myMetadata += "<table width=\"100%\">";
|
||||
|
||||
//-------------
|
||||
|
||||
myMetadata += "<tr class=\"glossy\"><td>";
|
||||
myMetadata += tr( "General:" );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
// data comment
|
||||
if ( !( layer->dataComment().isEmpty() ) )
|
||||
{
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "Layer comment: %1" ).arg( layer->dataComment() );
|
||||
myMetadata += "</td></tr>";
|
||||
}
|
||||
|
||||
//storage type
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "Storage type of this layer: %1" ).arg( layer->storageType() );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
// data source
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "Source for this layer: %1" ).arg( layer->publicSource() );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
//geom type
|
||||
|
||||
QGis::GeometryType type = layer->geometryType();
|
||||
|
||||
if ( type < 0 || type > QGis::NoGeometry )
|
||||
{
|
||||
QgsDebugMsg( "Invalid vector type" );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString typeString( QGis::qgisVectorGeometryType[layer->geometryType()] );
|
||||
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "Geometry type of the features in this layer: %1" ).arg( typeString );
|
||||
myMetadata += "</td></tr>";
|
||||
}
|
||||
|
||||
|
||||
//feature count
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "The number of features in this layer: %1" ).arg( layer->featureCount() );
|
||||
myMetadata += "</td></tr>";
|
||||
//capabilities
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "Editing capabilities of this layer: %1" ).arg( layer->capabilitiesString() );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
//-------------
|
||||
|
||||
QgsRectangle myExtent = layer->extent();
|
||||
myMetadata += "<tr class=\"glossy\"><td>";
|
||||
myMetadata += tr( "Extents:" );
|
||||
myMetadata += "</td></tr>";
|
||||
//extents in layer cs TODO...maybe make a little nested table to improve layout...
|
||||
myMetadata += "<tr><td>";
|
||||
|
||||
// Try to be a bit clever over what number format we use for the
|
||||
// extents. Some people don't like it using scientific notation when the
|
||||
// numbers get large, but for small numbers this is the more practical
|
||||
// option (so we can't force the format to 'f' for all values).
|
||||
// The scheme:
|
||||
// - for all numbers with more than 5 digits, force non-scientific notation
|
||||
// and 2 digits after the decimal point.
|
||||
// - for all smaller numbers let the OS decide which format to use (it will
|
||||
// generally use non-scientific unless the number gets much less than 1).
|
||||
|
||||
QString xMin, yMin, xMax, yMax;
|
||||
double changeoverValue = 99999; // The 'largest' 5 digit number
|
||||
if ( qAbs( myExtent.xMinimum() ) > changeoverValue )
|
||||
{
|
||||
xMin = QString( "%1" ).arg( myExtent.xMinimum(), 0, 'f', 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
xMin = QString( "%1" ).arg( myExtent.xMinimum() );
|
||||
}
|
||||
if ( qAbs( myExtent.yMinimum() ) > changeoverValue )
|
||||
{
|
||||
yMin = QString( "%1" ).arg( myExtent.yMinimum(), 0, 'f', 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
yMin = QString( "%1" ).arg( myExtent.yMinimum() );
|
||||
}
|
||||
if ( qAbs( myExtent.xMaximum() ) > changeoverValue )
|
||||
{
|
||||
xMax = QString( "%1" ).arg( myExtent.xMaximum(), 0, 'f', 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
xMax = QString( "%1" ).arg( myExtent.xMaximum() );
|
||||
}
|
||||
if ( qAbs( myExtent.yMaximum() ) > changeoverValue )
|
||||
{
|
||||
yMax = QString( "%1" ).arg( myExtent.yMaximum(), 0, 'f', 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
yMax = QString( "%1" ).arg( myExtent.yMaximum() );
|
||||
}
|
||||
|
||||
myMetadata += tr( "In layer spatial reference system units : " )
|
||||
+ tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" )
|
||||
.arg( xMin ).arg( yMin ).arg( xMax ).arg( yMax );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
//extents in project cs
|
||||
|
||||
try
|
||||
{
|
||||
#if 0
|
||||
// TODO: currently disabled, will revisit later [MD]
|
||||
QgsRectangle myProjectedExtent = coordinateTransform->transformBoundingBox( layer->extent() );
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "In project spatial reference system units : " )
|
||||
+ tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" )
|
||||
.arg( myProjectedExtent.xMinimum() )
|
||||
.arg( myProjectedExtent.yMinimum() )
|
||||
.arg( myProjectedExtent.xMaximum() )
|
||||
.arg( myProjectedExtent.yMaximum() );
|
||||
myMetadata += "</td></tr>";
|
||||
#endif
|
||||
|
||||
//
|
||||
// Display layer spatial ref system
|
||||
//
|
||||
myMetadata += "<tr class=\"glossy\"><td>";
|
||||
myMetadata += tr( "Layer Spatial Reference System:" );
|
||||
myMetadata += "</td></tr>";
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += layer->crs().toProj4().replace( QRegExp( "\"" ), " \"" );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
//
|
||||
// Display project (output) spatial ref system
|
||||
//
|
||||
#if 0
|
||||
// TODO: disabled for now, will revisit later [MD]
|
||||
myMetadata += "<tr><td bgcolor=\"gray\">";
|
||||
myMetadata += tr( "Project (Output) Spatial Reference System:" );
|
||||
myMetadata += "</td></tr>";
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += coordinateTransform->destCRS().toProj4().replace( QRegExp( "\"" ), " \"" );
|
||||
myMetadata += "</td></tr>";
|
||||
#endif
|
||||
}
|
||||
catch ( QgsCsException &cse )
|
||||
{
|
||||
Q_UNUSED( cse );
|
||||
QgsDebugMsg( cse.what() );
|
||||
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "In project spatial reference system units : " )
|
||||
+ tr( "(Invalid transformation of layer extents)" );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
//
|
||||
// Add the info about each field in the attribute table
|
||||
//
|
||||
myMetadata += "<tr class=\"glossy\"><td>";
|
||||
myMetadata += tr( "Attribute field info:" );
|
||||
myMetadata += "</td></tr>";
|
||||
myMetadata += "<tr><td>";
|
||||
|
||||
// Start a nested table in this trow
|
||||
myMetadata += "<table width=\"100%\">";
|
||||
myMetadata += "<tr><th>";
|
||||
myMetadata += tr( "Field" );
|
||||
myMetadata += "</th>";
|
||||
myMetadata += "<th>";
|
||||
myMetadata += tr( "Type" );
|
||||
myMetadata += "</th>";
|
||||
myMetadata += "<th>";
|
||||
myMetadata += tr( "Length" );
|
||||
myMetadata += "</th>";
|
||||
myMetadata += "<th>";
|
||||
myMetadata += tr( "Precision" );
|
||||
myMetadata += "</th>";
|
||||
myMetadata += "<th>";
|
||||
myMetadata += tr( "Comment" );
|
||||
myMetadata += "</th>";
|
||||
|
||||
//get info for each field by looping through them
|
||||
const QgsFieldMap& myFields = layer->pendingFields();
|
||||
for ( QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it )
|
||||
{
|
||||
const QgsField& myField = *it;
|
||||
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += myField.name();
|
||||
myMetadata += "</td>";
|
||||
myMetadata += "<td>";
|
||||
myMetadata += myField.typeName();
|
||||
myMetadata += "</td>";
|
||||
myMetadata += "<td>";
|
||||
myMetadata += QString( "%1" ).arg( myField.length() );
|
||||
myMetadata += "</td>";
|
||||
myMetadata += "<td>";
|
||||
myMetadata += QString( "%1" ).arg( myField.precision() );
|
||||
myMetadata += "</td>";
|
||||
myMetadata += "<td>";
|
||||
myMetadata += QString( "%1" ).arg( myField.comment() );
|
||||
myMetadata += "</td></tr>";
|
||||
}
|
||||
|
||||
//close field list
|
||||
myMetadata += "</table>"; //end of nested table
|
||||
#endif
|
||||
|
||||
myMetadata += "</td></tr>"; //end of stats container table row
|
||||
//
|
||||
// Close the table
|
||||
//
|
||||
|
||||
myMetadata += "</table>";
|
||||
|
||||
myMetadata += "</body></html>";
|
||||
return myMetadata;
|
||||
return layer->metadata();
|
||||
}
|
||||
|
||||
|
||||
|
112
src/browser/CMakeLists.txt
Normal file
@ -0,0 +1,112 @@
|
||||
|
||||
########################################################
|
||||
# Files
|
||||
|
||||
SET (BROWSER_SRCS
|
||||
main.cpp
|
||||
qgsbrowser.cpp
|
||||
qgsbrowsermodel.cpp
|
||||
)
|
||||
|
||||
SET (BROWSER_UIS qgsbrowserbase.ui)
|
||||
|
||||
SET (BROWSER_MOC_HDRS
|
||||
qgsbrowser.h
|
||||
qgsbrowsermodel.h
|
||||
)
|
||||
|
||||
#SET (BROWSER_RCCS qgsgps_plugin.qrc)
|
||||
|
||||
IF (WIN32)
|
||||
IF (MSVC)
|
||||
SET (BROWSER_SRCS ${BROWSER_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/../app/qgis_win32.rc)
|
||||
ELSE(MSVC)
|
||||
|
||||
# Icon for windows MINGW
|
||||
# Note: can't include .rc directly to source files
|
||||
# as it's ignored when used MinGW
|
||||
|
||||
IF (NOT WINDRES)
|
||||
FIND_PROGRAM(WINDRES windres)
|
||||
IF (NOT WINDRES)
|
||||
MESSAGE(FATAL_ERROR "windres not found - aborting")
|
||||
ENDIF (NOT WINDRES)
|
||||
ENDIF (NOT WINDRES)
|
||||
#############################################################
|
||||
# application icon
|
||||
# resource compilation for MinGW
|
||||
ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/icon.o
|
||||
COMMAND ${WINDRES} -I${CMAKE_CURRENT_SOURCE_DIR} -i${CMAKE_CURRENT_SOURCE_DIR}/../app/qgis_win32.rc
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/icon.o )
|
||||
SET(QGIS_APP_SRCS ${QGIS_APP_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/icon.o)
|
||||
ENDIF (MSVC)
|
||||
ENDIF (WIN32)
|
||||
|
||||
SET(IMAGE_RCCS ../../images/images.qrc)
|
||||
|
||||
########################################################
|
||||
# Build
|
||||
|
||||
QT4_WRAP_UI (BROWSER_UIS_H ${BROWSER_UIS})
|
||||
|
||||
QT4_WRAP_CPP (BROWSER_MOC_SRCS ${BROWSER_MOC_HDRS})
|
||||
|
||||
QT4_ADD_RESOURCES(IMAGE_RCC_SRCS ${IMAGE_RCCS})
|
||||
#QT4_ADD_RESOURCES(BROWSER_RCC_SRCS ${BROWSER_RCCS})
|
||||
|
||||
ADD_EXECUTABLE (qbrowser MACOSX_BUNDLE ${BROWSER_SRCS} ${BROWSER_MOC_SRCS} ${BROWSER_UIS_H} ${IMAGE_RCC_SRCS})
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../core
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../core/raster
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../gui
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../gui/attributetable
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../ui
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${GDAL_INCLUDE_DIR} # remove once raster layer is cleaned up
|
||||
)
|
||||
|
||||
IF (WITH_INTERNAL_SPATIALITE)
|
||||
INCLUDE_DIRECTORIES(../core/spatialite/headers/spatialite)
|
||||
ELSE (WITH_INTERNAL_SPATIALITE)
|
||||
INCLUDE_DIRECTORIES(${SQLITE3_INCLUDE_DIR})
|
||||
ENDIF (WITH_INTERNAL_SPATIALITE)
|
||||
|
||||
TARGET_LINK_LIBRARIES(qbrowser qgis_core qgis_gui)
|
||||
|
||||
IF (NOT WITH_INTERNAL_SPATIALITE)
|
||||
TARGET_LINK_LIBRARIES(qbrowser ${SQLITE3_LIBRARY})
|
||||
ENDIF (NOT WITH_INTERNAL_SPATIALITE)
|
||||
|
||||
IF (${QTVERSION} STRLESS "4.3.0")
|
||||
TARGET_LINK_LIBRARIES(qbrowser
|
||||
${QT_LIBRARIES}
|
||||
)
|
||||
ELSE (${QTVERSION} STRLESS "4.3.0")
|
||||
TARGET_LINK_LIBRARIES(qbrowser
|
||||
${QT_QTCORE_LIBRARY}
|
||||
${QT_QTGUI_LIBRARY}
|
||||
${QT_QTNETWORK_LIBRARY}
|
||||
${QT_QTSVG_LIBRARY}
|
||||
${QT_QTXML_LIBRARY}
|
||||
${QT_QTWEBKIT_LIBRARY}
|
||||
)
|
||||
ENDIF (${QTVERSION} STRLESS "4.3.0")
|
||||
|
||||
SET_TARGET_PROPERTIES(qbrowser PROPERTIES
|
||||
INSTALL_RPATH ${CMAKE_INSTALL_PREFIX}/${QGIS_LIB_DIR}
|
||||
INSTALL_RPATH_USE_LINK_PATH true
|
||||
)
|
||||
|
||||
|
||||
########################################################
|
||||
# Install
|
||||
|
||||
IF (APPLE)
|
||||
INSTALL (TARGETS qbrowser BUNDLE DESTINATION ${QGIS_BIN_DIR})
|
||||
# needed because global install_name prefix is for main qgis app
|
||||
INSTALL (CODE "EXECUTE_PROCESS(COMMAND install_name_tool -change ${CMAKE_INSTALL_NAME_DIR}/libqgis_core.${COMPLETE_VERSION}.dylib @executable_path/../../../../lib/libqgis_core.${COMPLETE_VERSION}.dylib \"$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${QGIS_BIN_DIR}/qbrowser.app/Contents/MacOS/qbrowser\")")
|
||||
INSTALL (CODE "EXECUTE_PROCESS (COMMAND ln -sfh ../../../${QGIS_FW_SUBDIR} \"$ENV{DESTDIR}${CMAKE_INSTALL_PREFIX}/${QGIS_BIN_DIR}/qbrowser.app/Contents/Frameworks\")")
|
||||
ELSE (APPLE)
|
||||
INSTALL (TARGETS qbrowser RUNTIME DESTINATION ${QGIS_BIN_DIR})
|
||||
ENDIF (APPLE)
|
112
src/browser/main.cpp
Normal file
@ -0,0 +1,112 @@
|
||||
/***************************************************************************
|
||||
main.cpp
|
||||
Browser main method
|
||||
-------------------
|
||||
begin : 2011-04-01
|
||||
copyright : (C) 2011 Radim Blazek
|
||||
email : radim dot blazek at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
#include <iostream>
|
||||
#include <QLocale>
|
||||
#include <QSettings>
|
||||
#include <QTranslator>
|
||||
#include <QMainWindow>
|
||||
#include <QLabel>
|
||||
#include <QDialog>
|
||||
#include <QApplication>
|
||||
#include "qgsbrowser.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsconfig.h"
|
||||
#include <qmainwindow.h>
|
||||
|
||||
int main( int argc, char ** argv )
|
||||
{
|
||||
QSettings settings;
|
||||
|
||||
|
||||
QgsApplication a( argc, argv, true );
|
||||
a.setThemeName( settings.value( "/Themes", "default" ).toString() );
|
||||
|
||||
// load providers
|
||||
#if defined(Q_WS_WIN)
|
||||
QString prefixPath = QApplication::applicationDirPath();
|
||||
#else
|
||||
QString prefixPath = QApplication::applicationDirPath()+"/..";
|
||||
#endif
|
||||
a.setPrefixPath( prefixPath, true );
|
||||
a.initQgis();
|
||||
|
||||
// Set up the QSettings environment must be done after qapp is created
|
||||
QCoreApplication::setOrganizationName( "QuantumGIS" );
|
||||
QCoreApplication::setOrganizationDomain( "qgis.org" );
|
||||
QCoreApplication::setApplicationName( "QGIS" );
|
||||
|
||||
/*
|
||||
QString myTranslationCode = "";
|
||||
|
||||
// This is mostly copy from Help viewer - not sure if important
|
||||
#if defined(Q_WS_MACX)
|
||||
// If we're on Mac, we have the resource library way above us...
|
||||
a.setPkgDataPath( QgsApplication::prefixPath() + "/../../../../" + QString( QGIS_DATA_SUBDIR ) );
|
||||
#elif defined(Q_WS_WIN)
|
||||
a.setPkgDataPath( QgsApplication::prefixPath() + "/" QGIS_DATA_SUBDIR );
|
||||
#else
|
||||
a.setPkgDataPath( QgsApplication::prefixPath() + "/../" QGIS_DATA_SUBDIR );
|
||||
#endif
|
||||
|
||||
QString i18nPath = QgsApplication::i18nPath();
|
||||
if ( myTranslationCode.isEmpty() )
|
||||
{
|
||||
myTranslationCode = QLocale::system().name();
|
||||
|
||||
QSettings settings;
|
||||
if ( settings.value( "locale/overrideFlag", false ).toBool() )
|
||||
{
|
||||
myTranslationCode = settings.value( "locale/userLocale", "en_US" ).toString();
|
||||
}
|
||||
}
|
||||
QgsDebugMsg( QString( "Setting translation to %1/qgis_%2" ).arg( i18nPath ).arg( myTranslationCode ) );
|
||||
*/
|
||||
/* Translation file for Qt.
|
||||
* The strings from the QMenuBar context section are used by Qt/Mac to shift
|
||||
* the About, Preferences and Quit items to the Mac Application menu.
|
||||
* These items must be translated identically in both qt_ and qgis_ files.
|
||||
*/
|
||||
/*
|
||||
QTranslator qttor( 0 );
|
||||
if ( qttor.load( QString( "qt_" ) + myTranslationCode, i18nPath ) )
|
||||
{
|
||||
a.installTranslator( &qttor );
|
||||
}
|
||||
*/
|
||||
/* Translation file for QGIS.
|
||||
*/
|
||||
/*
|
||||
QTranslator qgistor( 0 );
|
||||
if ( qgistor.load( QString( "qgis_" ) + myTranslationCode, i18nPath ) )
|
||||
{
|
||||
a.installTranslator( &qgistor );
|
||||
}
|
||||
*/
|
||||
|
||||
QgsBrowser w;
|
||||
|
||||
a.connect( &a, SIGNAL( aboutToQuit() ), &w, SLOT( saveWindowState() ) );
|
||||
w.restoreWindowState();
|
||||
|
||||
w.show();
|
||||
|
||||
a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
|
||||
|
||||
return a.exec();
|
||||
}
|
481
src/browser/qgsbrowser.cpp
Normal file
@ -0,0 +1,481 @@
|
||||
/***************************************************************************
|
||||
qgs.cpp -
|
||||
-------------------
|
||||
begin : 2011-04-01
|
||||
copyright : (C) 2011 Radim Blazek
|
||||
email : radim dot blazek at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
/* $Id$ */
|
||||
#include <typeinfo>
|
||||
|
||||
#include <QSettings>
|
||||
#include <QMessageBox>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsdataitem.h"
|
||||
#include "qgsbrowser.h"
|
||||
#include "qgsbrowsermodel.h"
|
||||
#include "qgsencodingfiledialog.h"
|
||||
#include "qgsgenericprojectionselector.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsmaplayerregistry.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
#include "qgsrasterlayer.h"
|
||||
#include "qgsnewvectorlayerdialog.h"
|
||||
|
||||
|
||||
QgsBrowser::QgsBrowser( QWidget *parent, Qt::WFlags flags )
|
||||
: QMainWindow( parent, flags ),
|
||||
mDirtyMetadata( true ), mDirtyPreview( true ), mDirtyAttributes( true ),
|
||||
mLayer( 0 ), mParamWidget(0)
|
||||
{
|
||||
setupUi( this );
|
||||
|
||||
// Disable tabs by default
|
||||
tabWidget->setTabEnabled ( tabWidget->indexOf( paramTab ), false );
|
||||
tabWidget->setTabEnabled ( tabWidget->indexOf( metaTab ), false );
|
||||
tabWidget->setTabEnabled ( tabWidget->indexOf( previewTab ), false );
|
||||
tabWidget->setTabEnabled ( tabWidget->indexOf( attributesTab ), false );
|
||||
|
||||
mModel = new QgsBrowserModel(treeView);
|
||||
treeView->setModel(mModel);
|
||||
|
||||
// Last expanded is stored, dont cover whole height with file system
|
||||
//treeView->expand( mModel->index(0,0) );
|
||||
|
||||
connect(treeView, SIGNAL(clicked(const QModelIndex&)), this, SLOT(itemClicked(const QModelIndex&)));
|
||||
|
||||
treeView->setExpandsOnDoubleClick (false);
|
||||
connect(treeView, SIGNAL(doubleClicked(const QModelIndex&)), this, SLOT(itemDoubleClicked(const QModelIndex&)));
|
||||
connect(treeView, SIGNAL(expanded(const QModelIndex&)), this, SLOT(itemExpanded(const QModelIndex&)));
|
||||
|
||||
connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged()));
|
||||
|
||||
connect( mActionNewVectorLayer, SIGNAL( triggered() ), this, SLOT( newVectorLayer() ) );
|
||||
|
||||
connect(stopRenderingButton, SIGNAL(clicked()), this, SLOT(stopRendering()) );
|
||||
|
||||
mapCanvas->setCanvasColor(Qt::white);
|
||||
|
||||
QSettings settings;
|
||||
QString lastPath = settings.value ( "/Browser/lastExpanded" ).toString();
|
||||
QgsDebugMsg ( "lastPath = " + lastPath );
|
||||
if ( !lastPath.isEmpty() )
|
||||
{
|
||||
expand( lastPath );
|
||||
}
|
||||
}
|
||||
|
||||
QgsBrowser::~QgsBrowser()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void QgsBrowser::expand( QString path, const QModelIndex& index )
|
||||
{
|
||||
QStringList paths = path.split('/');
|
||||
for ( int i = 0; i < mModel->rowCount(index); i++ )
|
||||
{
|
||||
QModelIndex idx = mModel->index(i, 0, index);
|
||||
QgsDataItem* ptr = (QgsDataItem*) idx.internalPointer();
|
||||
|
||||
if ( path.indexOf ( ptr->mPath ) == 0 )
|
||||
{
|
||||
treeView->expand( idx );
|
||||
treeView->scrollTo (idx, QAbstractItemView::PositionAtTop );
|
||||
expand( path, idx );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBrowser::itemClicked(const QModelIndex& index)
|
||||
{
|
||||
mIndex = index;
|
||||
|
||||
QgsDataItem* ptr = (QgsDataItem*) index.internalPointer();
|
||||
|
||||
// Disable preview, attributes tab
|
||||
|
||||
bool paramEnable = false;
|
||||
bool metaEnable = false;
|
||||
bool previewEnable = false;
|
||||
bool attributesEnable = false;
|
||||
|
||||
// mark all tabs as dirty
|
||||
mDirtyMetadata = true;
|
||||
mDirtyPreview = true;
|
||||
mDirtyAttributes = true;
|
||||
|
||||
// clear the previous stuff
|
||||
attributeTable->setLayer( NULL );
|
||||
QList<QgsMapCanvasLayer> nolayers;
|
||||
mapCanvas->setLayerSet( nolayers );
|
||||
metaTextBrowser->clear();
|
||||
if ( mParamWidget ) {
|
||||
paramLayout->removeWidget ( mParamWidget );
|
||||
mParamWidget->hide();
|
||||
delete mParamWidget;
|
||||
mParamWidget = 0;
|
||||
}
|
||||
|
||||
// QgsMapLayerRegistry deletes the previous layer(s) for us
|
||||
// TODO: in future we could cache the layers in the registry
|
||||
QgsMapLayerRegistry::instance()->removeAllMapLayers();
|
||||
mLayer = 0;
|
||||
|
||||
// this should probably go to the model and only emit signal when a layer is clicked
|
||||
|
||||
|
||||
mActionSetProjection->setEnabled ( ptr->capabilities() & QgsDataItem::SetCrs );
|
||||
|
||||
mParamWidget = ptr->paramWidget();
|
||||
if ( mParamWidget ) {
|
||||
paramLayout->addWidget ( mParamWidget );
|
||||
mParamWidget->show();
|
||||
paramEnable = true;
|
||||
}
|
||||
|
||||
QgsMapLayer::LayerType type;
|
||||
QString providerKey;
|
||||
QString uri;
|
||||
if ( ptr->layerInfo(type, providerKey, uri) )
|
||||
{
|
||||
QgsDebugMsg ( providerKey + " : " + uri );
|
||||
if ( type == QgsMapLayer::VectorLayer )
|
||||
{
|
||||
mLayer = new QgsVectorLayer( uri, QString(), providerKey);
|
||||
}
|
||||
if ( type == QgsMapLayer::RasterLayer )
|
||||
{
|
||||
// This should go to WMS provider
|
||||
QStringList URIParts = uri.split( "|" );
|
||||
QString rasterLayerPath = URIParts.at( 0 );
|
||||
QStringList layers;
|
||||
QStringList styles;
|
||||
QString format;
|
||||
QString crs;
|
||||
for ( int i = 1 ; i < URIParts.size(); i++ )
|
||||
{
|
||||
QString part = URIParts.at( i );
|
||||
int pos = part.indexOf( "=" );
|
||||
QString field = part.left( pos );
|
||||
QString value = part.mid( pos + 1 );
|
||||
|
||||
if ( field == "layers" ) layers = value.split(",");
|
||||
if ( field == "styles" ) styles = value.split(",");
|
||||
if ( field == "format" ) format = value;
|
||||
if ( field == "crs" ) crs = value;
|
||||
}
|
||||
QgsDebugMsg ( "rasterLayerPath = " + rasterLayerPath );
|
||||
QgsDebugMsg ( "layers = " + layers.join(" " ) );
|
||||
|
||||
mLayer = new QgsRasterLayer( 0, rasterLayerPath, "", providerKey, layers, styles, format, crs );
|
||||
}
|
||||
}
|
||||
|
||||
if ( mLayer && mLayer->isValid() )
|
||||
{
|
||||
QgsDebugMsg ( "Layer created");
|
||||
|
||||
QgsMapLayerRegistry::instance()->addMapLayer(mLayer);
|
||||
|
||||
metaEnable = true;
|
||||
previewEnable = true;
|
||||
if ( mLayer->type() == QgsMapLayer::VectorLayer ) {
|
||||
attributesEnable = true;
|
||||
}
|
||||
// force update of the current tab
|
||||
updateCurrentTab();
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug("No layer" );
|
||||
}
|
||||
|
||||
int selected = -1;
|
||||
if ( mLastTab.contains( typeid(*ptr).name() ) )
|
||||
{
|
||||
selected = mLastTab[ typeid(*ptr).name()];
|
||||
}
|
||||
|
||||
// Enabling tabs call tabChanged !
|
||||
tabWidget->setTabEnabled ( tabWidget->indexOf( paramTab ), paramEnable);
|
||||
tabWidget->setTabEnabled ( tabWidget->indexOf( metaTab ), metaEnable );
|
||||
tabWidget->setTabEnabled ( tabWidget->indexOf( previewTab ), previewEnable );
|
||||
tabWidget->setTabEnabled ( tabWidget->indexOf( attributesTab ), attributesEnable );
|
||||
|
||||
// select tab according last selection for this data item
|
||||
if ( selected >= 0 )
|
||||
{
|
||||
qDebug("set tab %s %d", typeid(*ptr).name(), selected );
|
||||
tabWidget->setCurrentIndex ( selected );
|
||||
}
|
||||
|
||||
qDebug("clicked: %d %d %s", index.row(), index.column(), ptr->mName.toAscii().data());
|
||||
}
|
||||
|
||||
void QgsBrowser::itemDoubleClicked(const QModelIndex& index)
|
||||
{
|
||||
QgsDataItem* ptr = (QgsDataItem*) index.internalPointer();
|
||||
|
||||
ptr->doubleClick();
|
||||
qDebug("doubleclicked: %d %d %s", index.row(), index.column(), ptr->mName.toAscii().data());
|
||||
}
|
||||
|
||||
void QgsBrowser::itemExpanded(const QModelIndex& index)
|
||||
{
|
||||
QSettings settings;
|
||||
QgsDataItem* ptr = (QgsDataItem*) index.internalPointer();
|
||||
/*
|
||||
if (ptr->mType == QgsDataItem::Directory || ptr->mType == QgsDataItem::Collection )
|
||||
{
|
||||
QgsDirectoryItem* i = (QgsDirectoryItem*) ptr;
|
||||
settings.setValue ( "/Browser/lastExpandedDir", i->mPath );
|
||||
}
|
||||
*/
|
||||
// TODO: save separately each type (FS, WMS)
|
||||
settings.setValue ( "/Browser/lastExpanded", ptr->mPath );
|
||||
QgsDebugMsg( "last expanded: " + ptr->mPath );
|
||||
}
|
||||
|
||||
void QgsBrowser::newVectorLayer()
|
||||
{
|
||||
// Set file dialog to last selected dir
|
||||
QSettings settings;
|
||||
QString lastPath = settings.value ( "/Browser/lastExpanded" ).toString();
|
||||
if ( !lastPath.isEmpty() )
|
||||
{
|
||||
settings.setValue( "/UI/lastVectorFileFilterDir", lastPath );
|
||||
}
|
||||
|
||||
QString fileName = QgsNewVectorLayerDialog::runAndCreateLayer( this );
|
||||
|
||||
if ( !fileName.isEmpty() )
|
||||
{
|
||||
QgsDebugMsg( "New vector layer: " + fileName );
|
||||
expand( fileName );
|
||||
QFileInfo fileInfo ( fileName );
|
||||
QString dirPath = fileInfo.absoluteDir().path();
|
||||
mModel->refresh ( dirPath );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBrowser::on_mActionWmsConnections_triggered()
|
||||
{
|
||||
QDialog *wmss = dynamic_cast<QDialog*> ( QgsProviderRegistry::instance()->getSelectWidget( QString("wms"), this ) );
|
||||
if ( !wmss )
|
||||
{
|
||||
QMessageBox::warning( this, tr( "WMS" ), tr( "Cannot get WMS select dialog from provider." ) );
|
||||
return;
|
||||
}
|
||||
wmss->exec();
|
||||
delete wmss;
|
||||
// TODO: refresh only WMS
|
||||
refresh();
|
||||
}
|
||||
|
||||
void QgsBrowser::on_mActionSetProjection_triggered()
|
||||
{
|
||||
if ( !mLayer ) { return; }
|
||||
QgsGenericProjectionSelector * mySelector = new QgsGenericProjectionSelector( this );
|
||||
mySelector->setMessage();
|
||||
mySelector->setSelectedCrsId( mLayer->crs().srsid() );
|
||||
if ( mySelector->exec() )
|
||||
{
|
||||
QgsCoordinateReferenceSystem srs( mySelector->selectedCrsId(), QgsCoordinateReferenceSystem::InternalCrsId );
|
||||
// TODO: open data source in write mode set crs and save
|
||||
//mLayer->setCrs( srs );
|
||||
// Is this safe?
|
||||
// selectedIndexes() is protected
|
||||
|
||||
QgsDataItem* ptr = (QgsDataItem*) mIndex.internalPointer();
|
||||
if ( ! ptr->setCrs ( srs ) )
|
||||
{
|
||||
QMessageBox::critical( this, tr( "CRS" ), tr( "Cannot set layer CRS" ));
|
||||
}
|
||||
QgsDebugMsg( srs.authid() + " - " + srs.description() );
|
||||
}
|
||||
else
|
||||
{
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
delete mySelector;
|
||||
}
|
||||
|
||||
void QgsBrowser::saveWindowState()
|
||||
{
|
||||
QSettings settings;
|
||||
settings.setValue( "/Windows/Browser/state", saveState() );
|
||||
settings.setValue( "/Windows/Browser/geometry", saveGeometry() );
|
||||
settings.setValue( "/Windows/Browser/sizes/0", splitter->sizes()[0] );
|
||||
settings.setValue( "/Windows/Browser/sizes/1", splitter->sizes()[1] );
|
||||
}
|
||||
|
||||
void QgsBrowser::restoreWindowState()
|
||||
{
|
||||
QSettings settings;
|
||||
if ( !restoreState( settings.value( "/Windows/Browser/state" ).toByteArray() ) )
|
||||
{
|
||||
QgsDebugMsg( "restore of UI state failed" );
|
||||
}
|
||||
if ( !restoreGeometry( settings.value( "/Windows/Browser/geometry" ).toByteArray() ) )
|
||||
{
|
||||
QgsDebugMsg( "restore of UI geometry failed" );
|
||||
}
|
||||
int size0 = settings.value( "/Windows/Browser/sizes/0" ).toInt();
|
||||
if ( size0 > 0 )
|
||||
{
|
||||
|
||||
QList<int> sizes;
|
||||
sizes << size0;
|
||||
sizes << settings.value( "/Windows/Browser/sizes/1" ).toInt();
|
||||
QgsDebugMsg( QString("set splitter sizes to %1 %2").arg(sizes[0]).arg(sizes[1]) );
|
||||
splitter->setSizes(sizes);
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBrowser::keyPressEvent( QKeyEvent * e )
|
||||
{
|
||||
QgsDebugMsg( "Entered");
|
||||
if ( e->key() == Qt::Key_Escape )
|
||||
{
|
||||
stopRendering();
|
||||
}
|
||||
else
|
||||
{
|
||||
e->ignore();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBrowser::stopRendering()
|
||||
{
|
||||
// you might have seen this already in QgisApp
|
||||
QgsDebugMsg( "Entered");
|
||||
if ( mapCanvas )
|
||||
{
|
||||
QgsMapRenderer* mypMapRenderer = mapCanvas->mapRenderer();
|
||||
if ( mypMapRenderer )
|
||||
{
|
||||
QgsRenderContext* mypRenderContext = mypMapRenderer->rendererContext();
|
||||
if ( mypRenderContext )
|
||||
{
|
||||
mypRenderContext->setRenderingStopped( true );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QgsBrowser::Tab QgsBrowser::activeTab()
|
||||
{
|
||||
QWidget* curr = tabWidget->currentWidget();
|
||||
if (curr == metaTab)
|
||||
return Metadata;
|
||||
if (curr == previewTab)
|
||||
return Preview;
|
||||
return Attributes;
|
||||
}
|
||||
|
||||
void QgsBrowser::updateCurrentTab()
|
||||
{
|
||||
// update contents of the current tab
|
||||
|
||||
Tab current = activeTab();
|
||||
|
||||
if (current == Metadata && mDirtyMetadata)
|
||||
{
|
||||
if (mLayer)
|
||||
{
|
||||
// Set meta
|
||||
QString myStyle = QgsApplication::reportStyleSheet();
|
||||
|
||||
metaTextBrowser->document()->setDefaultStyleSheet( myStyle );
|
||||
metaTextBrowser->setHtml( mLayer->metadata() );
|
||||
}
|
||||
else
|
||||
{
|
||||
metaTextBrowser->setHtml(QString());
|
||||
}
|
||||
mDirtyMetadata = false;
|
||||
}
|
||||
|
||||
if (current == Preview && mDirtyPreview)
|
||||
{
|
||||
if (mLayer)
|
||||
{
|
||||
// Create preview: add to map canvas
|
||||
QList<QgsMapCanvasLayer> layers;
|
||||
layers << QgsMapCanvasLayer(mLayer);
|
||||
mapCanvas->setLayerSet(layers);
|
||||
QgsRectangle fullExtent = mLayer->extent();
|
||||
fullExtent.scale(1.05); // add some border
|
||||
mapCanvas->setExtent(fullExtent);
|
||||
mapCanvas->refresh();
|
||||
}
|
||||
mDirtyPreview = false;
|
||||
}
|
||||
|
||||
if (current == Attributes && mDirtyAttributes)
|
||||
{
|
||||
if ( mLayer && mLayer->type() == QgsMapLayer::VectorLayer )
|
||||
{
|
||||
QgsVectorLayer* vlayer = qobject_cast<QgsVectorLayer*>( mLayer );
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
attributeTable->setLayer( vlayer );
|
||||
QApplication::restoreOverrideCursor();
|
||||
}
|
||||
else
|
||||
{
|
||||
attributeTable->setLayer( NULL );
|
||||
}
|
||||
mDirtyAttributes = false;
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBrowser::tabChanged()
|
||||
{
|
||||
updateCurrentTab();
|
||||
// Store last selected tab for selected data item
|
||||
if ( mIndex.isValid() )
|
||||
{
|
||||
QObject* ptr = (QObject*) mIndex.internalPointer();
|
||||
QgsDebugMsg( QString("save last tab %1 : %2").arg( typeid(*ptr).name() ).arg(tabWidget->currentIndex()) );
|
||||
mLastTab[typeid(*ptr).name()] = tabWidget->currentIndex();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBrowser::on_mActionRefresh_triggered()
|
||||
{
|
||||
QgsDebugMsg( "Entered" );
|
||||
refresh();
|
||||
}
|
||||
|
||||
void QgsBrowser::refresh( const QModelIndex& index )
|
||||
{
|
||||
QgsDebugMsg( "Entered" );
|
||||
if ( index.isValid() )
|
||||
{
|
||||
QgsDataItem* item = (QgsDataItem*) index.internalPointer();
|
||||
QgsDebugMsg( "path = " + item->mPath );
|
||||
}
|
||||
mModel->refresh( index );
|
||||
for ( int i = 0 ; i < mModel->rowCount(index); i++ )
|
||||
{
|
||||
QModelIndex idx = mModel->index(i, 0, index);
|
||||
if ( treeView->isExpanded ( idx ) )
|
||||
{
|
||||
refresh( idx );
|
||||
}
|
||||
}
|
||||
}
|
81
src/browser/qgsbrowser.h
Normal file
@ -0,0 +1,81 @@
|
||||
/***************************************************************************
|
||||
qgsbrowser.h - Data sources browser
|
||||
-------------------
|
||||
begin : 2011-04-01
|
||||
copyright : (C) 2011 Radim Blazek
|
||||
email : radim dot blazek at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
/* $Id$ */
|
||||
#ifndef QGSBROWSER_H
|
||||
#define QGSBROWSER_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QMap>
|
||||
#include <QModelIndex>
|
||||
#include "ui_qgsbrowserbase.h"
|
||||
|
||||
class QgsBrowserModel;
|
||||
class QgsMapLayer;
|
||||
|
||||
class QgsBrowser : public QMainWindow, private Ui::QgsBrowserBase
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
QgsBrowser( QWidget *parent = 0, Qt::WFlags flags = 0 );
|
||||
~QgsBrowser();
|
||||
|
||||
// Expand to given path
|
||||
void expand ( QString path, const QModelIndex& index = QModelIndex() );
|
||||
|
||||
|
||||
|
||||
public slots:
|
||||
void itemClicked(const QModelIndex& index);
|
||||
void itemDoubleClicked(const QModelIndex& index);
|
||||
void itemExpanded(const QModelIndex& index);
|
||||
void on_mActionSetProjection_triggered();
|
||||
void on_mActionWmsConnections_triggered();
|
||||
void on_mActionRefresh_triggered();
|
||||
void newVectorLayer();
|
||||
|
||||
void saveWindowState();
|
||||
void restoreWindowState();
|
||||
|
||||
void tabChanged();
|
||||
void updateCurrentTab();
|
||||
void stopRendering();
|
||||
|
||||
// Refresh all leaf or expanded items
|
||||
void refresh ( const QModelIndex& index= QModelIndex() );
|
||||
|
||||
protected:
|
||||
void keyPressEvent( QKeyEvent * e );
|
||||
|
||||
enum Tab
|
||||
{
|
||||
Metadata,
|
||||
Preview,
|
||||
Attributes
|
||||
};
|
||||
Tab activeTab();
|
||||
|
||||
bool mDirtyMetadata, mDirtyPreview, mDirtyAttributes;
|
||||
|
||||
QgsBrowserModel* mModel;
|
||||
QgsMapLayer *mLayer;
|
||||
QModelIndex mIndex;
|
||||
QWidget *mParamWidget;
|
||||
// last (selected) tab for each
|
||||
QMap<QString,int> mLastTab;
|
||||
};
|
||||
|
||||
#endif // QGSBROWSER_H
|
246
src/browser/qgsbrowserbase.ui
Normal file
@ -0,0 +1,246 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>QgsBrowserBase</class>
|
||||
<widget class="QMainWindow" name="QgsBrowserBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>714</width>
|
||||
<height>471</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>QGIS Browser</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>696</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QTreeView" name="treeView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>1</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>3</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="paramTab">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Param</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="paramLayout"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="metaTab">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Metadata</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="metaTextBrowser"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="previewTab">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Preview</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QgsMapCanvas" name="mapCanvas"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="widget" native="true">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>370</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="stopRenderingButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Stop rendering</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="attributesTab">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>Attributes</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QgsAttributeTableView" name="attributeTable"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="windowTitle">
|
||||
<string>toolBar</string>
|
||||
</property>
|
||||
<property name="movable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
<property name="floatable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="mActionRefresh"/>
|
||||
<addaction name="mActionWmsConnections"/>
|
||||
<addaction name="mActionNewVectorLayer"/>
|
||||
<addaction name="mActionSetProjection"/>
|
||||
</widget>
|
||||
<action name="mActionNewVectorLayer">
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mActionNewVectorLayer.png</normaloff>:/images/themes/default/mActionNewVectorLayer.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>New Shapefile</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+N</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="mActionRefresh">
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mActionDraw.png</normaloff>:/images/themes/default/mActionDraw.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Refresh</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+R</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="mActionSetProjection">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mActionCustomProjection.png</normaloff>:/images/themes/default/mActionCustomProjection.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set layer CRS</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Set layer CRS</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="mActionWmsConnections">
|
||||
<property name="icon">
|
||||
<iconset resource="../../images/images.qrc">
|
||||
<normaloff>:/images/themes/default/mActionAddWmsLayer.png</normaloff>:/images/themes/default/mActionAddWmsLayer.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Manage WMS</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Manage WMS Connections</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+W</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>QgsMapCanvas</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header>qgsmapcanvas.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>QgsAttributeTableView</class>
|
||||
<extends>QTableView</extends>
|
||||
<header>qgsattributetableview.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../../images/images.qrc"/>
|
||||
</resources>
|
||||
<connections/>
|
||||
</ui>
|
314
src/browser/qgsbrowsermodel.cpp
Normal file
@ -0,0 +1,314 @@
|
||||
#include <QDir>
|
||||
#include <QApplication>
|
||||
#include <QStyle>
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsdataprovider.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
|
||||
#include "qgsbrowsermodel.h"
|
||||
|
||||
// TODO: bad place, where to put this? qgsproviderregistry?
|
||||
typedef int dataCapabilities_t();
|
||||
typedef QgsDataItem * dataItem_t(QString);
|
||||
|
||||
QgsBrowserModel::QgsBrowserModel(QObject *parent) :
|
||||
QAbstractItemModel(parent)
|
||||
{
|
||||
QStyle *style = QApplication::style();
|
||||
mIconDirectory = QIcon( style->standardPixmap( QStyle::SP_DirClosedIcon ) );
|
||||
mIconDirectory.addPixmap( style->standardPixmap( QStyle::SP_DirOpenIcon ),
|
||||
QIcon::Normal, QIcon::On );
|
||||
|
||||
foreach (QFileInfo drive, QDir::drives())
|
||||
{
|
||||
QString path = drive.absolutePath();
|
||||
QgsDirectoryItem *item = new QgsDirectoryItem(NULL, path, path);
|
||||
|
||||
connectItem(item);
|
||||
mRootItems << item;
|
||||
}
|
||||
|
||||
// Add non file top level items
|
||||
foreach ( QString key, QgsProviderRegistry::instance()->providerList() )
|
||||
{
|
||||
QLibrary *library = QgsProviderRegistry::instance()->getLibrary(key);
|
||||
if ( !library ) continue;
|
||||
|
||||
dataCapabilities_t * dataCapabilities = (dataCapabilities_t *) cast_to_fptr( library->resolve ("dataCapabilities") );
|
||||
if ( !dataCapabilities ) {
|
||||
QgsDebugMsg ( library->fileName() + " does not have dataCapabilities" );
|
||||
continue;
|
||||
}
|
||||
|
||||
int capabilities = dataCapabilities();
|
||||
if ( capabilities == QgsDataProvider::NoDataCapabilities )
|
||||
{
|
||||
QgsDebugMsg ( library->fileName() + " does not have any dataCapabilities" );
|
||||
continue;
|
||||
}
|
||||
|
||||
dataItem_t * dataItem = (dataItem_t *) cast_to_fptr( library->resolve ("dataItem" ) );
|
||||
if ( ! dataItem )
|
||||
{
|
||||
QgsDebugMsg ( library->fileName() + " does not have dataItem" );
|
||||
continue;
|
||||
}
|
||||
|
||||
QgsDataItem * item = dataItem ( "" ); // empty path -> top level
|
||||
if ( item )
|
||||
{
|
||||
QgsDebugMsg ( "Add new top level item : " + item->mName );
|
||||
connectItem(item);
|
||||
mRootItems << item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QgsBrowserModel::~QgsBrowserModel()
|
||||
{
|
||||
foreach (QgsDataItem* item, mRootItems)
|
||||
delete item;
|
||||
}
|
||||
|
||||
|
||||
Qt::ItemFlags QgsBrowserModel::flags( const QModelIndex & index ) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return 0;
|
||||
|
||||
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||
}
|
||||
|
||||
QVariant QgsBrowserModel::data( const QModelIndex & index, int role ) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
QgsDataItem* ptr = (QgsDataItem*) index.internalPointer();
|
||||
|
||||
if (role == Qt::DisplayRole)
|
||||
{
|
||||
return QVariant(ptr->mName);
|
||||
}
|
||||
else if (role == Qt::DecorationRole && index.column() == 0)
|
||||
{
|
||||
return QVariant( ptr->icon() );
|
||||
}
|
||||
|
||||
// unsupported role
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant QgsBrowserModel::headerData( int section, Qt::Orientation orientation, int role ) const
|
||||
{
|
||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||
{
|
||||
return QVariant("header");
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int QgsBrowserModel::rowCount( const QModelIndex & parent ) const
|
||||
{
|
||||
//qDebug("rowCount: idx: (valid %d) %d %d", parent.isValid(), parent.row(), parent.column());
|
||||
|
||||
if (!parent.isValid())
|
||||
{
|
||||
// root item: its children are top level items
|
||||
return mRootItems.count(); // mRoot
|
||||
}
|
||||
else
|
||||
{
|
||||
// ordinary item: number of its children
|
||||
QgsDataItem* ptr = (QgsDataItem*) parent.internalPointer();
|
||||
|
||||
return ptr->rowCount();
|
||||
}
|
||||
}
|
||||
|
||||
bool QgsBrowserModel::hasChildren ( const QModelIndex & parent ) const
|
||||
{
|
||||
if (!parent.isValid())
|
||||
{
|
||||
return true; // root item: its children are top level items
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDataItem* ptr = (QgsDataItem*) parent.internalPointer();
|
||||
|
||||
return ptr->hasChildren();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int QgsBrowserModel::columnCount ( const QModelIndex & parent ) const
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
QModelIndex QgsBrowserModel::index( int row, int column, const QModelIndex & parent ) const
|
||||
{
|
||||
//qDebug("index: idx: (valid %d) %d %d", parent.isValid(), parent.row(), parent.column());
|
||||
|
||||
if (!parent.isValid())
|
||||
{
|
||||
// this is the root item, parent of the top level items
|
||||
Q_ASSERT(column == 0 && row >= 0 && row < mRootItems.count());
|
||||
return createIndex(row,column, mRootItems[row]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// this is ordinary item: return a valid index if the requested child exists
|
||||
QgsDataItem* ptr = (QgsDataItem*) parent.internalPointer();
|
||||
if (ptr->mType == QgsDataItem::Directory || ptr->mType == QgsDataItem::Collection)
|
||||
{
|
||||
// this is a directory: get index of its subdir!
|
||||
QgsDirectoryItem* di = (QgsDirectoryItem*) ptr;
|
||||
return createIndex(row, column, di->mChildren.at(row));
|
||||
}
|
||||
if (ptr->mType == QgsDataItem::Layer)
|
||||
{
|
||||
return QModelIndex(); // has no children
|
||||
}
|
||||
|
||||
Q_ASSERT(false && "unknown item in index()");
|
||||
}
|
||||
|
||||
return QModelIndex(); // if the child does not exist
|
||||
}
|
||||
|
||||
QModelIndex QgsBrowserModel::index( QgsDataItem *item )
|
||||
{
|
||||
// Item index
|
||||
QModelIndex index = QModelIndex();
|
||||
|
||||
const QVector<QgsDataItem*>& children = item->mParent ? item->mParent->mChildren : mRootItems;
|
||||
|
||||
Q_ASSERT( children.size() > 0 );
|
||||
int row = -1;
|
||||
for ( int i = 0; i < children.size(); i++ )
|
||||
{
|
||||
if ( item == children[i] )
|
||||
{
|
||||
row = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
QgsDebugMsg( QString ( "row = %1").arg(row) );
|
||||
Q_ASSERT( row >= 0 );
|
||||
index = createIndex( row, 0, item );
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
QModelIndex QgsBrowserModel::parent( const QModelIndex & index ) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QModelIndex();
|
||||
|
||||
// return QModelInde of parent, i.e. where the parent is within its parent :-)
|
||||
|
||||
//qDebug("parent of: %d %d", index.row(), index.column());
|
||||
|
||||
QgsDataItem* ptr = (QgsDataItem*) index.internalPointer();
|
||||
QgsDataItem* parentItem = ptr->mParent;
|
||||
|
||||
if (parentItem == NULL)
|
||||
{
|
||||
// parent of our root is invalid index
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
const QVector<QgsDataItem*>& children =
|
||||
parentItem->mParent ? ((QgsDirectoryItem*)parentItem->mParent)->mChildren : mRootItems;
|
||||
Q_ASSERT(children.count() > 0);
|
||||
|
||||
for (int i = 0; i < children.count(); i++)
|
||||
{
|
||||
if (children[i] == parentItem)
|
||||
return createIndex(i, 0, parentItem);
|
||||
}
|
||||
|
||||
Q_ASSERT(false && "parent not found!");
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
/* Refresh dir path */
|
||||
void QgsBrowserModel::refresh( QString path, const QModelIndex& theIndex )
|
||||
{
|
||||
QStringList paths = path.split('/');
|
||||
for ( int i = 0; i < rowCount(theIndex); i++ )
|
||||
{
|
||||
QModelIndex idx = index(i, 0, theIndex);
|
||||
QgsDataItem* ptr = (QgsDataItem*) idx.internalPointer();
|
||||
if ( ptr->mPath == path )
|
||||
{
|
||||
QgsDebugMsg( "Arrived " + ptr->mPath );
|
||||
ptr->refresh();
|
||||
return;
|
||||
}
|
||||
if ( path.indexOf ( ptr->mPath ) == 0 )
|
||||
{
|
||||
refresh( path, idx );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Refresh item */
|
||||
void QgsBrowserModel::refresh( const QModelIndex& theIndex )
|
||||
{
|
||||
if ( !theIndex.isValid () ) // root
|
||||
{
|
||||
// Nothing to do I believe, mRootItems are always the same
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDataItem* ptr = (QgsDataItem*) theIndex.internalPointer();
|
||||
QgsDebugMsg( "Refresh " + ptr->mPath );
|
||||
ptr->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
void QgsBrowserModel::beginInsertItems( QgsDataItem* parent, int first, int last )
|
||||
{
|
||||
QgsDebugMsg( "parent mPath = " + parent->mPath );
|
||||
QModelIndex idx = index( parent );
|
||||
if ( !idx.isValid() ) return;
|
||||
QgsDebugMsg( "valid");
|
||||
beginInsertRows( idx, first, last );
|
||||
QgsDebugMsg( "end");
|
||||
}
|
||||
void QgsBrowserModel::endInsertItems()
|
||||
{
|
||||
QgsDebugMsg( "Entered");
|
||||
endInsertRows();
|
||||
}
|
||||
void QgsBrowserModel::beginRemoveItems( QgsDataItem* parent, int first, int last )
|
||||
{
|
||||
QgsDebugMsg( "parent mPath = " + parent->mPath );
|
||||
QModelIndex idx = index( parent );
|
||||
if ( !idx.isValid() ) return;
|
||||
beginRemoveRows( idx, first, last );
|
||||
}
|
||||
void QgsBrowserModel::endRemoveItems()
|
||||
{
|
||||
QgsDebugMsg( "Entered");
|
||||
endRemoveRows();
|
||||
}
|
||||
void QgsBrowserModel::connectItem ( QgsDataItem* item )
|
||||
{
|
||||
connect ( item, SIGNAL(beginInsertItems ( QgsDataItem*, int, int )),
|
||||
this, SLOT(beginInsertItems( QgsDataItem*, int, int )) );
|
||||
connect ( item, SIGNAL(endInsertItems ()),
|
||||
this, SLOT(endInsertItems()) );
|
||||
connect ( item, SIGNAL(beginRemoveItems ( QgsDataItem*, int, int )),
|
||||
this, SLOT(beginRemoveItems( QgsDataItem*, int, int )) );
|
||||
connect ( item, SIGNAL(endRemoveItems ()),
|
||||
this, SLOT(endRemoveItems()) );
|
||||
}
|
70
src/browser/qgsbrowsermodel.h
Normal file
@ -0,0 +1,70 @@
|
||||
#ifndef QGSBROWSERMODEL_H
|
||||
#define QGSBROWSERMODEL_H
|
||||
|
||||
#include <QAbstractItemModel>
|
||||
#include <QIcon>
|
||||
|
||||
#include "qgsdataitem.h"
|
||||
|
||||
class QgsBrowserModel : public QAbstractItemModel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit QgsBrowserModel(QObject *parent = 0);
|
||||
~QgsBrowserModel();
|
||||
|
||||
// implemented methods from QAbstractItemModel for read-only access
|
||||
|
||||
/** Used by other components to obtain information about each item provided by the model.
|
||||
In many models, the combination of flags should include Qt::ItemIsEnabled and Qt::ItemIsSelectable. */
|
||||
virtual Qt::ItemFlags flags( const QModelIndex & index ) const;
|
||||
/** Used to supply item data to views and delegates. Generally, models only need to supply data
|
||||
for Qt::DisplayRole and any application-specific user roles, but it is also good practice
|
||||
to provide data for Qt::ToolTipRole, Qt::AccessibleTextRole, and Qt::AccessibleDescriptionRole.
|
||||
See the Qt::ItemDataRole enum documentation for information about the types associated with each role. */
|
||||
virtual QVariant data( const QModelIndex & index, int role = Qt::DisplayRole ) const;
|
||||
/** Provides views with information to show in their headers. The information is only retrieved
|
||||
by views that can display header information. */
|
||||
virtual QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const;
|
||||
|
||||
/** Provides the number of rows of data exposed by the model. */
|
||||
virtual int rowCount( const QModelIndex & parent = QModelIndex() ) const;
|
||||
/** Provides the number of columns of data exposed by the model. List models do not provide this function
|
||||
because it is already implemented in QAbstractListModel. */
|
||||
virtual int columnCount ( const QModelIndex & parent = QModelIndex() ) const;
|
||||
|
||||
/** Returns the index of the item in the model specified by the given row, column and parent index. */
|
||||
virtual QModelIndex index( int row, int column, const QModelIndex & parent = QModelIndex() ) const;
|
||||
|
||||
QModelIndex index( QgsDataItem *item );
|
||||
|
||||
/** Returns the parent of the model item with the given index. If the item has no parent, an invalid QModelIndex is returned. */
|
||||
virtual QModelIndex parent( const QModelIndex & index ) const;
|
||||
|
||||
|
||||
bool hasChildren ( const QModelIndex & parent = QModelIndex() ) const;
|
||||
|
||||
// Refresh item specified by path
|
||||
void refresh( QString path, const QModelIndex& index = QModelIndex() );
|
||||
// Refresh item childs
|
||||
void refresh( const QModelIndex& index = QModelIndex() );
|
||||
|
||||
void connectItem ( QgsDataItem * item );
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
//void removeItems( QgsDataItem * parent, QVector<QgsDataItem *>items );
|
||||
//void addItems( QgsDataItem * parent, QVector<QgsDataItem *>items );
|
||||
//void refreshItems( QgsDataItem * parent, QVector<QgsDataItem *>items );
|
||||
|
||||
void beginInsertItems( QgsDataItem* parent, int first, int last );
|
||||
void endInsertItems();
|
||||
void beginRemoveItems( QgsDataItem* parent, int first, int last );
|
||||
void endRemoveItems();
|
||||
|
||||
protected:
|
||||
QVector<QgsDataItem*> mRootItems;
|
||||
QIcon mIconDirectory;
|
||||
};
|
||||
|
||||
#endif // QGSBROWSERMODEL_H
|
18
src/browser/template.cpp
Normal file
@ -0,0 +1,18 @@
|
||||
/***************************************************************************
|
||||
qgs.cpp -
|
||||
-------------------
|
||||
begin : 2011-04-01
|
||||
copyright : (C) 2011 Radim Blazek
|
||||
email : radim dot blazek at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
/* $Id$ */
|
||||
|
22
src/browser/template.h
Normal file
@ -0,0 +1,22 @@
|
||||
/***************************************************************************
|
||||
qgs.h -
|
||||
-------------------
|
||||
begin : 2011-04-01
|
||||
copyright : (C) 2011 Radim Blazek
|
||||
email : radim dot blazek at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
/* $Id$ */
|
||||
#ifndef QGS_H
|
||||
#define QGS_H
|
||||
|
||||
|
||||
#endif // QGS_H
|
@ -46,6 +46,7 @@ SET(QGIS_CORE_SRCS
|
||||
qgscontexthelp.cpp
|
||||
qgscoordinatetransform.cpp
|
||||
qgsdatasourceuri.cpp
|
||||
qgsdataitem.cpp
|
||||
qgsdiagram.cpp
|
||||
qgsdiagramrendererv2.cpp
|
||||
qgsdistancearea.cpp
|
||||
@ -78,6 +79,7 @@ SET(QGIS_CORE_SRCS
|
||||
qgsproviderextentcalcevent.cpp
|
||||
qgsprovidermetadata.cpp
|
||||
qgsproviderregistry.cpp
|
||||
qgspythonrunner.cpp
|
||||
qgsrasterprojector.cpp
|
||||
qgsrasterdataprovider.cpp
|
||||
qgsrendercontext.cpp
|
||||
@ -219,6 +221,7 @@ SET(QGIS_CORE_MOC_HDRS
|
||||
qgsapplication.h
|
||||
qgscontexthelp.h
|
||||
qgscoordinatetransform.h
|
||||
qgsdataitem.h
|
||||
qgsdataprovider.h
|
||||
qgshttptransaction.h
|
||||
qgsmaplayer.h
|
||||
@ -381,6 +384,7 @@ SET(QGIS_CORE_HDRS
|
||||
qgscontexthelp.h
|
||||
qgscoordinatetransform.h
|
||||
qgsdatasourceuri.h
|
||||
qgsdataitem.h
|
||||
qgsdistancearea.h
|
||||
qgscsexception.h
|
||||
qgsexception.h
|
||||
@ -411,6 +415,7 @@ SET(QGIS_CORE_HDRS
|
||||
qgsproviderextentcalcevent.h
|
||||
qgsprovidermetadata.h
|
||||
qgsproviderregistry.h
|
||||
qgspythonrunner.h
|
||||
qgsrasterprojector.h
|
||||
qgsrasterdataprovider.h
|
||||
qgsrectangle.h
|
||||
|
@ -15,6 +15,7 @@
|
||||
/* $Id$ */
|
||||
|
||||
#include "qgsapplication.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsmaplayerregistry.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
#include "qgsexception.h"
|
||||
@ -111,8 +112,13 @@ bool QgsApplication::event( QEvent * event )
|
||||
|
||||
bool QgsApplication::notify( QObject * receiver, QEvent * event )
|
||||
{
|
||||
bool done = false;
|
||||
emit preNotify( receiver, event, &done );
|
||||
|
||||
if ( done ) return true;
|
||||
|
||||
// Send event to receiver and catch unhandled exceptions
|
||||
bool done = true;
|
||||
done = true;
|
||||
try
|
||||
{
|
||||
done = QApplication::notify( receiver, event );
|
||||
@ -129,6 +135,7 @@ bool QgsApplication::notify( QObject * receiver, QEvent * event )
|
||||
{
|
||||
QMessageBox::critical( activeWindow(), tr( "Exception" ), tr( "unknown exception" ) );
|
||||
}
|
||||
|
||||
return done;
|
||||
}
|
||||
|
||||
|
@ -201,6 +201,9 @@ class CORE_EXPORT QgsApplication: public QApplication
|
||||
@note: this method was added in version 1.6*/
|
||||
static QString relativePathToAbsolutePath( QString rpath, QString targetPath );
|
||||
|
||||
signals:
|
||||
void preNotify( QObject * receiver, QEvent * event, bool * done );
|
||||
|
||||
private:
|
||||
static QObject* mFileOpenEventReceiver;
|
||||
static QStringList mFileOpenEventList;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include <QDomElement>
|
||||
|
||||
#include "qgsattributeaction.h"
|
||||
#include "qgspythonrunner.h"
|
||||
#include "qgsrunprocess.h"
|
||||
#include "qgsvectorlayer.h"
|
||||
|
||||
@ -67,12 +68,18 @@ void QgsAttributeAction::doAction( int index, const QgsAttributeMap &attributes,
|
||||
{
|
||||
if ( executePython )
|
||||
{
|
||||
// deprecated
|
||||
executePython( expandedAction );
|
||||
}
|
||||
else if ( smPythonExecute )
|
||||
{
|
||||
// deprecated
|
||||
smPythonExecute( expandedAction );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsPythonRunner::run( expandedAction );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -136,6 +136,7 @@ class CORE_EXPORT QgsAttributeAction
|
||||
QgsAction &at( int idx ) { return mActions[idx]; }
|
||||
QgsAction &operator[]( int idx ) { return mActions[idx]; }
|
||||
|
||||
//! @deprecated Initialize QgsPythonRunner instead
|
||||
static void setPythonExecute( void ( * )( const QString & ) );
|
||||
|
||||
private:
|
||||
|
514
src/core/qgsdataitem.cpp
Normal file
@ -0,0 +1,514 @@
|
||||
/***************************************************************************
|
||||
qgsdataitem.cpp - Data items
|
||||
-------------------
|
||||
begin : 2011-04-01
|
||||
copyright : (C) 2011 Radim Blazek
|
||||
email : radim dot blazek at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
/* $Id$ */
|
||||
|
||||
#include <typeinfo>
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QMenu>
|
||||
#include <QMouseEvent>
|
||||
#include <QTreeWidget>
|
||||
#include <QTreeWidgetItem>
|
||||
#include <QVector>
|
||||
#include <QStyle>
|
||||
#include <QSettings>
|
||||
|
||||
#include "qgis.h"
|
||||
#include "qgsapplication.h"
|
||||
#include "qgsdataitem.h"
|
||||
|
||||
#include "qgsdataprovider.h"
|
||||
#include "qgslogger.h"
|
||||
#include "qgsproviderregistry.h"
|
||||
|
||||
QgsDataItem::QgsDataItem(QgsDataItem::Type type, QgsDataItem* parent, QString name, QString path)
|
||||
: QObject(parent), mType(type), mParent(parent), mPopulated(false), mName(name), mPath(path)
|
||||
{
|
||||
}
|
||||
|
||||
QIcon QgsDataItem::icon()
|
||||
{
|
||||
if ( !mIcon.isNull() ) return mIcon;
|
||||
return mDefaultIcon;
|
||||
}
|
||||
|
||||
// TODO: This is copy from QgisApp, bad
|
||||
// TODO: add some caching mechanism ?
|
||||
QPixmap QgsDataItem::getThemePixmap( const QString theName )
|
||||
{
|
||||
QString myPreferredPath = QgsApplication::activeThemePath() + QDir::separator() + theName;
|
||||
QString myDefaultPath = QgsApplication::defaultThemePath() + QDir::separator() + theName;
|
||||
//QgsDebugMsg( "myPreferredPath = " + myPreferredPath );
|
||||
//QgsDebugMsg( "myDefaultPath = " + myDefaultPath );
|
||||
if ( QFile::exists( myPreferredPath ) )
|
||||
{
|
||||
return QPixmap( myPreferredPath );
|
||||
}
|
||||
else
|
||||
{
|
||||
//could still return an empty icon if it
|
||||
//doesnt exist in the default theme either!
|
||||
return QPixmap( myDefaultPath );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsDataItem::doubleClick()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void QgsDataItem::emitBeginInsertItems( QgsDataItem* parent, int first, int last )
|
||||
{
|
||||
emit beginInsertItems ( parent, first, last );
|
||||
}
|
||||
void QgsDataItem::emitEndInsertItems()
|
||||
{
|
||||
emit endInsertItems();
|
||||
}
|
||||
void QgsDataItem::emitBeginRemoveItems( QgsDataItem* parent, int first, int last )
|
||||
{
|
||||
emit beginRemoveItems ( parent, first, last );
|
||||
}
|
||||
void QgsDataItem::emitEndRemoveItems()
|
||||
{
|
||||
emit endRemoveItems();
|
||||
}
|
||||
|
||||
QVector<QgsDataItem*> QgsDataItem::createChildren( )
|
||||
{
|
||||
QVector<QgsDataItem*> children;
|
||||
return children;
|
||||
}
|
||||
|
||||
void QgsDataItem::populate()
|
||||
{
|
||||
QVector<QgsDataItem*> children = createChildren( );
|
||||
foreach ( QgsDataItem *child, children )
|
||||
{
|
||||
// initialization, do not refresh! That would result in infinite loop (beginInsertItems->rowCount->populate)
|
||||
addChildItem ( child);
|
||||
}
|
||||
mPopulated = true;
|
||||
}
|
||||
|
||||
int QgsDataItem::rowCount()
|
||||
{
|
||||
if (!mPopulated) populate();
|
||||
return mChildren.size();
|
||||
}
|
||||
bool QgsDataItem::hasChildren()
|
||||
{
|
||||
return ( mPopulated ? mChildren.count() > 0 : true);
|
||||
}
|
||||
|
||||
void QgsDataItem::addChildItem ( QgsDataItem * child, bool refresh )
|
||||
{
|
||||
QgsDebugMsg( "mName = " + child->mName );
|
||||
int i;
|
||||
for ( i = 0; i < mChildren.size(); i++ )
|
||||
{
|
||||
if ( mChildren[i]->mName.localeAwareCompare ( child->mName ) >= 0 ) break;
|
||||
}
|
||||
|
||||
if ( refresh ) emit beginInsertItems ( this, i, i );
|
||||
child->setParent(this);
|
||||
mChildren.insert ( i, child );
|
||||
|
||||
connect ( child, SIGNAL(beginInsertItems ( QgsDataItem*, int, int )),
|
||||
this, SLOT(emitBeginInsertItems( QgsDataItem*, int, int )) );
|
||||
connect ( child, SIGNAL(endInsertItems ()),
|
||||
this, SLOT(emitEndInsertItems()) );
|
||||
connect ( child, SIGNAL(beginRemoveItems ( QgsDataItem*, int, int )),
|
||||
this, SLOT(emitBeginRemoveItems( QgsDataItem*, int, int )) );
|
||||
connect ( child, SIGNAL(endRemoveItems ()),
|
||||
this, SLOT(emitEndRemoveItems()) );
|
||||
|
||||
if ( refresh ) emit endInsertItems();
|
||||
|
||||
}
|
||||
void QgsDataItem::deleteChildItem ( QgsDataItem * child )
|
||||
{
|
||||
QgsDebugMsg( "mName = " + child->mName );
|
||||
int i = mChildren.indexOf( child );
|
||||
Q_ASSERT( i >= 0 );
|
||||
emit beginRemoveItems ( this, i, i );
|
||||
mChildren.remove(i);
|
||||
delete child;
|
||||
emit endRemoveItems ();
|
||||
}
|
||||
|
||||
int QgsDataItem::findItem ( QVector<QgsDataItem*> items, QgsDataItem * item )
|
||||
{
|
||||
for ( int i = 0; i < items.size(); i++ )
|
||||
{
|
||||
QgsDebugMsg( QString::number(i) + " : " + items[i]->mPath + " x " + item->mPath );
|
||||
if ( items[i]->equal ( item ) ) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void QgsDataItem::refresh()
|
||||
{
|
||||
QgsDebugMsg ( "mPath = " + mPath );
|
||||
|
||||
QVector<QgsDataItem*> items = createChildren( );
|
||||
|
||||
// Remove no more present items
|
||||
QVector<QgsDataItem*> remove;
|
||||
foreach ( QgsDataItem *child, mChildren )
|
||||
{
|
||||
if ( findItem(items, child ) >= 0 ) continue;
|
||||
remove.append ( child );
|
||||
}
|
||||
foreach ( QgsDataItem *child, remove )
|
||||
{
|
||||
deleteChildItem ( child );
|
||||
}
|
||||
|
||||
// Add new items
|
||||
foreach ( QgsDataItem *item, items )
|
||||
{
|
||||
// Is it present in childs?
|
||||
if ( findItem ( mChildren, item ) >= 0 )
|
||||
{
|
||||
delete item;
|
||||
continue;
|
||||
}
|
||||
addChildItem ( item, true );
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
QgsLayerItem::QgsLayerItem(QgsDataItem* parent, QString name, QString path)
|
||||
: QgsDataItem(Layer, parent, name, path)
|
||||
{
|
||||
}
|
||||
|
||||
QgsLayerItem::QgsLayerItem(QgsDataItem* parent, QgsDataItem::Type type, QString name, QString path, QString uri)
|
||||
: QgsDataItem(type, parent, name, path), mUri(uri)
|
||||
{
|
||||
|
||||
}
|
||||
QIcon QgsLayerItem::icon()
|
||||
{
|
||||
if ( !mIcon.isNull() ) return mIcon;
|
||||
|
||||
QString name;
|
||||
switch ( mType )
|
||||
{
|
||||
case QgsDataItem::Point:
|
||||
name = "/mIconPointLayer.png";
|
||||
break;
|
||||
case QgsDataItem::Line:
|
||||
name = "/mIconLineLayer.png";
|
||||
break;
|
||||
case QgsDataItem::Polygon:
|
||||
name = "/mIconPolygonLayer.png";
|
||||
break;
|
||||
case QgsDataItem::TableLayer:
|
||||
name = "/mIconTableLayer.png";
|
||||
break;
|
||||
default:
|
||||
name = "/mIconLayer.png";
|
||||
break;
|
||||
}
|
||||
//QgsDebugMsg( QString ( "mType = %1 name = %2").arg ( mType).arg (name ) );
|
||||
if ( !name.isEmpty() )
|
||||
{
|
||||
QPixmap pixmap = getThemePixmap ( name );
|
||||
//QgsDebugMsg( QString ( "pixmap.isNull = %1").arg(pixmap.isNull() ) );
|
||||
return QIcon ( pixmap );
|
||||
}
|
||||
return mDefaultIcon;
|
||||
}
|
||||
|
||||
bool QgsLayerItem::equal(const QgsDataItem *other)
|
||||
{
|
||||
//QgsDebugMsg ( mPath + " x " + other->mPath );
|
||||
if ( typeid ( *this ) != typeid ( *other ) )
|
||||
{
|
||||
//QgsDebugMsg ( "different typeid" );
|
||||
return false;
|
||||
}
|
||||
//const QgsLayerItem *o = qobject_cast<const QgsLayerItem *> ( other );
|
||||
const QgsLayerItem *o = dynamic_cast<const QgsLayerItem *> ( other );
|
||||
return ( mPath == o->mPath && mName == o->mName && mUri == o->mUri && mProvider == o->mProvider );
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
QgsDataCollectionItem::QgsDataCollectionItem( QgsDataItem::Type type, QgsDataItem* parent, QString name, QString path)
|
||||
: QgsDataItem( type, parent, name, path)
|
||||
{
|
||||
QStyle *style = QApplication::style();
|
||||
mDefaultIcon = QIcon( style->standardPixmap( QStyle::SP_DirClosedIcon ) );
|
||||
mDefaultIcon.addPixmap( style->standardPixmap( QStyle::SP_DirOpenIcon ),
|
||||
QIcon::Normal, QIcon::On );
|
||||
}
|
||||
QgsDataCollectionItem::~QgsDataCollectionItem()
|
||||
{
|
||||
foreach (QgsDataItem* i, mChildren)
|
||||
delete i;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
QVector<QgsDataProvider*> QgsDirectoryItem::mProviders = QVector<QgsDataProvider*>();
|
||||
QVector<QLibrary*> QgsDirectoryItem::mLibraries = QVector<QLibrary*>();
|
||||
|
||||
// TODO: bad place, where to put this? qgsproviderregistry.h?
|
||||
typedef int dataCapabilities_t();
|
||||
typedef QgsDataItem * dataItem_t(QString);
|
||||
|
||||
QgsDirectoryItem::QgsDirectoryItem(QgsDataItem* parent, QString name, QString path)
|
||||
: QgsDataCollectionItem(Directory, parent, name, path)
|
||||
{
|
||||
if ( mLibraries.size() == 0 ) {
|
||||
QStringList keys = QgsProviderRegistry::instance()->providerList();
|
||||
QStringList::const_iterator i;
|
||||
for ( i = keys.begin(); i != keys.end(); ++i)
|
||||
{
|
||||
QString k(*i);
|
||||
// some providers hangs with empty uri (Postgis) etc...
|
||||
// -> using libraries directly
|
||||
QLibrary *library = QgsProviderRegistry::instance()->getLibrary(k);
|
||||
if ( library )
|
||||
{
|
||||
dataCapabilities_t * dataCapabilities = (dataCapabilities_t *) cast_to_fptr( library->resolve ("dataCapabilities") );
|
||||
if ( !dataCapabilities )
|
||||
{
|
||||
QgsDebugMsg ( library->fileName() + " does not have dataCapabilities" );
|
||||
continue;
|
||||
}
|
||||
if ( dataCapabilities() == QgsDataProvider::NoDataCapabilities )
|
||||
{
|
||||
QgsDebugMsg ( library->fileName() + " does not have File capability" );
|
||||
continue;
|
||||
}
|
||||
mLibraries.append( library );
|
||||
}
|
||||
else
|
||||
{
|
||||
//QgsDebugMsg ( "Cannot get provider " + k );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QgsDirectoryItem::~QgsDirectoryItem()
|
||||
{
|
||||
}
|
||||
|
||||
QVector<QgsDataItem*> QgsDirectoryItem::createChildren( )
|
||||
{
|
||||
QVector<QgsDataItem*> children;
|
||||
QDir dir(mPath);
|
||||
QStringList entries = dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase);
|
||||
foreach (QString subdir, entries)
|
||||
{
|
||||
QString subdirPath = dir.absoluteFilePath(subdir);
|
||||
qDebug("creating subdir: %s", subdirPath.toAscii().data());
|
||||
|
||||
QgsDirectoryItem *item = new QgsDirectoryItem(this, subdir, subdirPath);
|
||||
// propagate signals up to top
|
||||
|
||||
children.append( item );
|
||||
}
|
||||
|
||||
QStringList fileEntries = dir.entryList( QDir::Files, QDir::Name);
|
||||
foreach (QString name, fileEntries)
|
||||
{
|
||||
QString path = dir.absoluteFilePath( name );
|
||||
foreach ( QLibrary *library, mLibraries )
|
||||
{
|
||||
// we could/should create separate list of providers for each purpose
|
||||
|
||||
// TODO: use existing fileVectorFilters(),directoryDrivers() ?
|
||||
dataCapabilities_t * dataCapabilities = (dataCapabilities_t *) cast_to_fptr( library->resolve ("dataCapabilities") );
|
||||
if ( !dataCapabilities ) continue;
|
||||
|
||||
int capabilities = dataCapabilities();
|
||||
|
||||
if ( ! (capabilities & QgsDataProvider::File) ) continue;
|
||||
|
||||
dataItem_t * dataItem = (dataItem_t *) cast_to_fptr( library->resolve ("dataItem" ) );
|
||||
if ( ! dataItem )
|
||||
{
|
||||
QgsDebugMsg ( library->fileName() + " does not have dataItem" );
|
||||
continue;
|
||||
}
|
||||
|
||||
QgsDataItem * item = dataItem ( path );
|
||||
if ( item )
|
||||
{
|
||||
children.append( item );
|
||||
}
|
||||
}
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
bool QgsDirectoryItem::equal(const QgsDataItem *other)
|
||||
{
|
||||
//QgsDebugMsg ( mPath + " x " + other->mPath );
|
||||
if ( typeid ( *this ) != typeid ( *other ) )
|
||||
{
|
||||
//QgsDebugMsg ( "different typeid" );
|
||||
return false;
|
||||
}
|
||||
return ( mPath == other->mPath );
|
||||
}
|
||||
|
||||
QWidget * QgsDirectoryItem::paramWidget()
|
||||
{
|
||||
return new QgsDirectoryParamWidget(mPath);
|
||||
}
|
||||
|
||||
QgsDirectoryParamWidget::QgsDirectoryParamWidget(QString path, QWidget* parent)
|
||||
: QTreeWidget(parent)
|
||||
{
|
||||
setRootIsDecorated(false);
|
||||
|
||||
// name, size, date, permissions, owner, group, type
|
||||
setColumnCount (7);
|
||||
QStringList labels;
|
||||
labels << tr("Name") << tr("Size") << tr("Date") << tr("Permissions") << tr("Owner") << tr("Group") << tr("Type");
|
||||
setHeaderLabels ( labels );
|
||||
|
||||
QStyle* style = QApplication::style();
|
||||
QIcon iconDirectory = QIcon( style->standardPixmap( QStyle::SP_DirClosedIcon ) );
|
||||
QIcon iconFile = QIcon( style->standardPixmap( QStyle::SP_FileIcon ) );
|
||||
QIcon iconLink = QIcon( style->standardPixmap( QStyle::SP_FileLinkIcon ) ); // TODO: symlink to directory?
|
||||
|
||||
QList<QTreeWidgetItem *> items;
|
||||
|
||||
QDir dir(path);
|
||||
QStringList entries = dir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot, QDir::Name | QDir::IgnoreCase);
|
||||
foreach (QString name, entries)
|
||||
{
|
||||
QFileInfo fi ( dir.absoluteFilePath(name) );
|
||||
QStringList texts;
|
||||
texts << name;
|
||||
QString size;
|
||||
if ( fi.size() > 1024 )
|
||||
{
|
||||
size = size.sprintf ( "%.1f KiB", fi.size()/1024.0 );
|
||||
}
|
||||
else if ( fi.size() > 1.048576e6 )
|
||||
{
|
||||
size = size.sprintf ( "%.1f MiB", fi.size()/1.048576e6 );
|
||||
}
|
||||
else
|
||||
{
|
||||
size = QString( "%1 B" ).arg( fi.size() );
|
||||
}
|
||||
texts << size;
|
||||
texts << fi.lastModified().toString (Qt::SystemLocaleShortDate);
|
||||
QString perm;
|
||||
perm += fi.permission( QFile::ReadOwner ) ? 'r' : '-';
|
||||
perm += fi.permission( QFile::WriteOwner ) ? 'w' : '-';
|
||||
perm += fi.permission( QFile::ExeOwner ) ? 'x' : '-';
|
||||
// QFile::ReadUser, QFile::WriteUser, QFile::ExeUser
|
||||
perm += fi.permission( QFile::ReadGroup ) ? 'r' : '-';
|
||||
perm += fi.permission( QFile::WriteGroup ) ? 'w' : '-';
|
||||
perm += fi.permission( QFile::ExeGroup ) ? 'x' : '-';
|
||||
perm += fi.permission( QFile::ReadOther ) ? 'r' : '-';
|
||||
perm += fi.permission( QFile::WriteOther ) ? 'w' : '-';
|
||||
perm += fi.permission( QFile::ExeOther ) ? 'x' : '-';
|
||||
texts << perm;
|
||||
|
||||
texts << fi.owner();
|
||||
texts << fi.group();
|
||||
|
||||
QString type;
|
||||
QIcon icon;
|
||||
if ( fi.isDir() )
|
||||
{
|
||||
type = tr ( "folder" );
|
||||
icon = iconDirectory;
|
||||
}
|
||||
else if ( fi.isFile() )
|
||||
{
|
||||
type = tr ( "file" );
|
||||
icon = iconFile;
|
||||
}
|
||||
else if ( fi.isSymLink() )
|
||||
{
|
||||
type = tr ( "link" );
|
||||
icon = iconLink;
|
||||
}
|
||||
|
||||
texts << type;
|
||||
|
||||
QTreeWidgetItem *item = new QTreeWidgetItem (texts);
|
||||
item->setIcon(0, icon);
|
||||
items << item;
|
||||
}
|
||||
|
||||
addTopLevelItems(items);
|
||||
|
||||
// hide columns that are not requested
|
||||
QSettings settings;
|
||||
QList<QVariant> lst = settings.value("/dataitem/directoryHiddenColumns").toList();
|
||||
foreach (QVariant colVariant, lst)
|
||||
{
|
||||
setColumnHidden( colVariant.toInt(), true );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsDirectoryParamWidget::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
if ( event->button() == Qt::RightButton )
|
||||
{
|
||||
// show the popup menu
|
||||
QMenu popupMenu;
|
||||
|
||||
QStringList labels;
|
||||
labels << tr("Name") << tr("Size") << tr("Date") << tr("Permissions") << tr("Owner") << tr("Group") << tr("Type");
|
||||
for (int i = 0; i < labels.count(); i++)
|
||||
{
|
||||
QAction* action = popupMenu.addAction( labels[i], this, SLOT(showHideColumn()) );
|
||||
action->setObjectName(QString::number(i));
|
||||
action->setCheckable(true);
|
||||
action->setChecked( !isColumnHidden(i) );
|
||||
}
|
||||
|
||||
popupMenu.exec( event->globalPos() );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsDirectoryParamWidget::showHideColumn()
|
||||
{
|
||||
QAction* action = qobject_cast<QAction*>(sender());
|
||||
if (!action)
|
||||
return; // something is wrong
|
||||
|
||||
int columnIndex = action->objectName().toInt();
|
||||
setColumnHidden(columnIndex, !isColumnHidden(columnIndex));
|
||||
|
||||
// save in settings
|
||||
QSettings settings;
|
||||
QList<QVariant> lst;
|
||||
for (int i = 0; i < columnCount(); i++)
|
||||
{
|
||||
if (isColumnHidden(i))
|
||||
lst.append(QVariant(i));
|
||||
}
|
||||
settings.setValue("/dataitem/directoryHiddenColumns", lst);
|
||||
}
|
197
src/core/qgsdataitem.h
Normal file
@ -0,0 +1,197 @@
|
||||
/***************************************************************************
|
||||
qgsdataitem.h - Items representing data
|
||||
-------------------
|
||||
begin : 2011-04-01
|
||||
copyright : (C) 2011 Radim Blazek
|
||||
email : radim dot blazek at gmail dot com
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* *
|
||||
* This program is free software; you can redistribute it and/or modify *
|
||||
* it under the terms of the GNU General Public License as published by *
|
||||
* the Free Software Foundation; either version 2 of the License, or *
|
||||
* (at your option) any later version. *
|
||||
* *
|
||||
***************************************************************************/
|
||||
/* $Id$ */
|
||||
#ifndef QGSDATAITEM_H
|
||||
#define QGSDATAITEM_H
|
||||
|
||||
#include <QIcon>
|
||||
#include <QLibrary>
|
||||
#include <QObject>
|
||||
#include <QPixmap>
|
||||
#include <QString>
|
||||
#include <QVector>
|
||||
#include <QTreeWidget>
|
||||
|
||||
#include "qgsmaplayer.h"
|
||||
#include "qgscoordinatereferencesystem.h"
|
||||
|
||||
class QgsDataProvider;
|
||||
|
||||
/** base class for all items in the model */
|
||||
class CORE_EXPORT QgsDataItem : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
Collection,
|
||||
Directory,
|
||||
Layer,
|
||||
Vector,
|
||||
Raster,
|
||||
Point,
|
||||
Line,
|
||||
Polygon,
|
||||
TableLayer,
|
||||
Database,
|
||||
Table
|
||||
};
|
||||
enum Capability
|
||||
{
|
||||
NoCapabilities = 0,
|
||||
SetCrs = 1 //Can set CRS on layer or group of layers
|
||||
};
|
||||
|
||||
QgsDataItem(QgsDataItem::Type type, QgsDataItem* parent, QString name, QString path);
|
||||
virtual ~QgsDataItem() {}
|
||||
|
||||
virtual bool hasChildren();
|
||||
|
||||
virtual int rowCount();
|
||||
|
||||
virtual QIcon icon ();
|
||||
|
||||
void setParent ( QgsDataItem *parent ) { mParent = parent; }
|
||||
|
||||
QPixmap getThemePixmap( const QString theName );
|
||||
|
||||
// Sets info about layer which can be created for this item
|
||||
// returns true if layer can be created
|
||||
virtual bool layerInfo ( QgsMapLayer::LayerType & type,
|
||||
QString & providerKey, QString & uri ) { return false; }
|
||||
|
||||
virtual void refresh();
|
||||
|
||||
// This will _write_ selected crs in data source
|
||||
virtual bool setCrs ( QgsCoordinateReferenceSystem crs ) { return false; }
|
||||
|
||||
virtual Capability capabilities() { return NoCapabilities; }
|
||||
|
||||
// Create vector of children
|
||||
virtual QVector<QgsDataItem*> createChildren();
|
||||
|
||||
// Populate children using children vector created by createChildren()
|
||||
virtual void populate();
|
||||
|
||||
// Insert new child using alphabetical order based on mName, emits necessary signal to model before and after, sets parent and connects signals
|
||||
// refresh - refresh populated item, emit signals to model
|
||||
virtual void addChildItem ( QgsDataItem * child, bool refresh = false );
|
||||
|
||||
// remove and delete child item, signals to browser are emited
|
||||
virtual void deleteChildItem ( QgsDataItem * child );
|
||||
|
||||
// Find child index in vector of items using '==' operator
|
||||
int findItem ( QVector<QgsDataItem*> items, QgsDataItem * item );
|
||||
|
||||
Type mType;
|
||||
QgsDataItem* mParent;
|
||||
QVector<QgsDataItem*> mChildren; // easier to have it always
|
||||
bool mPopulated;
|
||||
QString mName;
|
||||
// Are the data shared? Cannot be static because each child has different.
|
||||
QIcon mDefaultIcon;
|
||||
QIcon mIcon;
|
||||
QString mPath; // it is also used to identify item in tree
|
||||
|
||||
virtual bool equal(const QgsDataItem *other) { return false; }
|
||||
|
||||
virtual QWidget * paramWidget() { return 0; }
|
||||
|
||||
public slots:
|
||||
virtual void doubleClick();
|
||||
void emitBeginInsertItems( QgsDataItem* parent, int first, int last );
|
||||
void emitEndInsertItems();
|
||||
void emitBeginRemoveItems( QgsDataItem* parent, int first, int last );
|
||||
void emitEndRemoveItems();
|
||||
|
||||
signals:
|
||||
void beginInsertItems( QgsDataItem* parent, int first, int last );
|
||||
void endInsertItems();
|
||||
void beginRemoveItems( QgsDataItem* parent, int first, int last );
|
||||
void endRemoveItems();
|
||||
};
|
||||
|
||||
/** Item that represents a layer that can be opened with one of the providers */
|
||||
class CORE_EXPORT QgsLayerItem : public QgsDataItem
|
||||
{
|
||||
public:
|
||||
QgsLayerItem(QgsDataItem* parent, QString name, QString path);
|
||||
QgsLayerItem(QgsDataItem* parent, QgsDataItem::Type type, QString name, QString path, QString uri);
|
||||
|
||||
virtual QIcon icon ();
|
||||
|
||||
virtual bool equal(const QgsDataItem *other);
|
||||
|
||||
QString mProvider;
|
||||
QString mUri;
|
||||
};
|
||||
|
||||
|
||||
/** A Collection: logical collection of layers or subcollections, e.g. GRASS location/mapset, database? wms source? */
|
||||
class CORE_EXPORT QgsDataCollectionItem : public QgsDataItem
|
||||
{
|
||||
public:
|
||||
QgsDataCollectionItem( QgsDataItem::Type type, QgsDataItem* parent, QString name, QString path =0);
|
||||
~QgsDataCollectionItem();
|
||||
|
||||
void setPopulated() { mPopulated = true; }
|
||||
void addChild( QgsDataItem *item ) { mChildren.append(item); }
|
||||
};
|
||||
|
||||
/** A directory: contains subdirectories and layers */
|
||||
class CORE_EXPORT QgsDirectoryItem : public QgsDataCollectionItem
|
||||
{
|
||||
public:
|
||||
enum Column
|
||||
{
|
||||
Name,
|
||||
Size,
|
||||
Date,
|
||||
Permissions,
|
||||
Owner,
|
||||
Group,
|
||||
Type
|
||||
};
|
||||
QgsDirectoryItem(QgsDataItem* parent, QString name, QString path);
|
||||
~QgsDirectoryItem();
|
||||
|
||||
QVector<QgsDataItem*> createChildren();
|
||||
|
||||
virtual bool equal(const QgsDataItem *other);
|
||||
|
||||
virtual QWidget * paramWidget();
|
||||
|
||||
static QVector<QgsDataProvider*> mProviders;
|
||||
static QVector<QLibrary*> mLibraries;
|
||||
};
|
||||
|
||||
class QgsDirectoryParamWidget : public QTreeWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QgsDirectoryParamWidget(QString path, QWidget* parent = NULL);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
|
||||
public slots:
|
||||
void showHideColumn();
|
||||
};
|
||||
|
||||
#endif // QGSDATAITEM_H
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
//#include "qgsdataitem.h"
|
||||
|
||||
class QgsRectangle;
|
||||
class QgsCoordinateReferenceSystem;
|
||||
|
||||
@ -45,6 +47,17 @@ class CORE_EXPORT QgsDataProvider : public QObject
|
||||
|
||||
public:
|
||||
|
||||
Q_ENUMS( DataCapability )
|
||||
|
||||
enum DataCapability
|
||||
{
|
||||
NoDataCapabilities = 0,
|
||||
File = 1,
|
||||
Dir = 1 << 1,
|
||||
Database = 1 << 2,
|
||||
Net = 1 << 3 // Internet source
|
||||
};
|
||||
|
||||
QgsDataProvider( QString const & uri = "" )
|
||||
: mDataSourceURI( uri )
|
||||
{}
|
||||
|
@ -909,3 +909,8 @@ void QgsMapLayer::clearCacheImage()
|
||||
{
|
||||
setCacheImage( 0 );
|
||||
}
|
||||
|
||||
QString QgsMapLayer::metadata()
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
@ -332,6 +332,9 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
* added in 1.5 */
|
||||
void clearCacheImage();
|
||||
|
||||
/** \brief Obtain Metadata for this layer */
|
||||
virtual QString metadata();
|
||||
|
||||
/** Time stamp of data source in the moment when data/metadata were loaded by provider */
|
||||
virtual QDateTime timestamp() const { return QDateTime() ; }
|
||||
|
||||
|
@ -41,6 +41,8 @@ typedef QString fileVectorFilters_t();
|
||||
typedef QString databaseDrivers_t();
|
||||
typedef QString directoryDrivers_t();
|
||||
typedef QString protocolDrivers_t();
|
||||
//typedef int dataCapabilities_t();
|
||||
//typedef QgsDataItem * dataItem_t(QString);
|
||||
|
||||
QgsProviderRegistry *QgsProviderRegistry::_instance = 0;
|
||||
|
||||
@ -425,6 +427,64 @@ QgsDataProvider* QgsProviderRegistry::getProvider( QString const & providerKey,
|
||||
|
||||
} // QgsProviderRegistry::setDataProvider
|
||||
|
||||
// This should be QWidget, not QDialog
|
||||
typedef QWidget * selectFactoryFunction_t( QWidget * parent, Qt::WFlags fl );
|
||||
|
||||
QWidget* QgsProviderRegistry::getSelectWidget( const QString & providerKey,
|
||||
QWidget * parent, Qt::WFlags fl )
|
||||
{
|
||||
QLibrary *myLib = getLibrary( providerKey );
|
||||
if ( !myLib ) return 0;
|
||||
|
||||
selectFactoryFunction_t * selectFactory =
|
||||
( selectFactoryFunction_t * ) cast_to_fptr( myLib->resolve( "selectWidget" ) );
|
||||
|
||||
if ( !selectFactory ) return 0;
|
||||
|
||||
QWidget *widget = ( *selectFactory )( parent, fl );
|
||||
return widget;
|
||||
}
|
||||
|
||||
|
||||
void * QgsProviderRegistry::getFunction( QString const & providerKey,
|
||||
QString const & functionName )
|
||||
{
|
||||
QString lib = library( providerKey );
|
||||
|
||||
QLibrary* myLib = new QLibrary( lib );
|
||||
|
||||
QgsDebugMsg( "Library name is " + myLib->fileName() );
|
||||
|
||||
bool loaded = myLib->load();
|
||||
|
||||
if ( loaded )
|
||||
{
|
||||
void * ptr = myLib->resolve( functionName.toAscii().data() );
|
||||
delete myLib;
|
||||
return ptr;
|
||||
}
|
||||
delete myLib;
|
||||
return 0;
|
||||
}
|
||||
|
||||
QLibrary * QgsProviderRegistry::getLibrary( QString const & providerKey )
|
||||
{
|
||||
QString lib = library( providerKey );
|
||||
|
||||
QLibrary* myLib = new QLibrary( lib );
|
||||
|
||||
QgsDebugMsg( "Library name is " + myLib->fileName() );
|
||||
|
||||
bool loaded = myLib->load();
|
||||
|
||||
if ( loaded )
|
||||
{
|
||||
return myLib;
|
||||
}
|
||||
delete myLib;
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString QgsProviderRegistry::fileVectorFilters() const
|
||||
{
|
||||
return mVectorFileFilters;
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include <map>
|
||||
|
||||
#include <QDir>
|
||||
#include <QLibrary>
|
||||
#include <QString>
|
||||
|
||||
|
||||
@ -67,6 +68,19 @@ class CORE_EXPORT QgsProviderRegistry
|
||||
QgsDataProvider * getProvider( const QString & providerKey,
|
||||
const QString & dataSource );
|
||||
|
||||
QWidget * getSelectWidget ( const QString & providerKey,
|
||||
QWidget * parent=0, Qt::WFlags fl=0 );
|
||||
|
||||
/** Get pointer to provider function
|
||||
@param providerKey identificator of the provider
|
||||
@param functionName name of function
|
||||
@return pointer to function or NULL on error
|
||||
*/
|
||||
void * getFunction( const QString & providerKey,
|
||||
const QString & functionName );
|
||||
|
||||
QLibrary * getLibrary ( const QString & providerKey );
|
||||
|
||||
/** Return list of available providers by their keys */
|
||||
QStringList providerList() const;
|
||||
|
||||
|
43
src/core/qgspythonrunner.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "qgspythonrunner.h"
|
||||
#include "qgslogger.h"
|
||||
|
||||
QgsPythonRunner* QgsPythonRunner::mInstance = NULL;
|
||||
|
||||
///////////////////////////
|
||||
// static methods
|
||||
|
||||
bool QgsPythonRunner::isValid()
|
||||
{
|
||||
return mInstance != NULL;
|
||||
}
|
||||
|
||||
bool QgsPythonRunner::run( QString command, QString messageOnError )
|
||||
{
|
||||
if ( mInstance )
|
||||
{
|
||||
return mInstance->runCommand( command, messageOnError );
|
||||
}
|
||||
else
|
||||
{
|
||||
QgsDebugMsg("Unable to run Python command: runner not available!");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void QgsPythonRunner::setInstance( QgsPythonRunner* runner )
|
||||
{
|
||||
delete mInstance;
|
||||
mInstance = runner;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
// non-static methods
|
||||
|
||||
QgsPythonRunner::QgsPythonRunner()
|
||||
{
|
||||
}
|
||||
|
||||
QgsPythonRunner::~QgsPythonRunner()
|
||||
{
|
||||
|
||||
}
|
41
src/core/qgspythonrunner.h
Normal file
@ -0,0 +1,41 @@
|
||||
#ifndef QGSPYTHONRUNNER_H
|
||||
#define QGSPYTHONRUNNER_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
/**
|
||||
Utility class for running python commands from various parts of QGIS.
|
||||
There is no direct python support in the core library, so it is expected
|
||||
that application with python support creates a subclass that implements
|
||||
pure virtual function(s) during the initialization. The static methods
|
||||
will then work as expected.
|
||||
|
||||
Added in QGIS v?
|
||||
*/
|
||||
class CORE_EXPORT QgsPythonRunner
|
||||
{
|
||||
public:
|
||||
|
||||
/** returns true if the runner has an instance
|
||||
(and thus is able to run commands) */
|
||||
static bool isValid();
|
||||
|
||||
/** execute a python statement */
|
||||
static bool run( QString command, QString messageOnError = QString() );
|
||||
|
||||
/** assign an instance of python runner so that run() can be used.
|
||||
This method should be called during app initialization.
|
||||
Takes ownership of the object, deletes previous instance. */
|
||||
static void setInstance( QgsPythonRunner* runner );
|
||||
|
||||
protected:
|
||||
/** protected constructor: can be instantiated only from children */
|
||||
QgsPythonRunner();
|
||||
virtual ~QgsPythonRunner();
|
||||
|
||||
virtual bool runCommand( QString command, QString messageOnError = QString() ) = 0;
|
||||
|
||||
static QgsPythonRunner* mInstance;
|
||||
};
|
||||
|
||||
#endif // QGSPYTHONRUNNER_H
|
@ -5261,3 +5261,236 @@ void QgsVectorLayer::setDiagramLayerSettings( const QgsDiagramLayerSettings& s )
|
||||
mDiagramLayerSettings = new QgsDiagramLayerSettings();
|
||||
*mDiagramLayerSettings = s;
|
||||
}
|
||||
|
||||
QString QgsVectorLayer::metadata()
|
||||
{
|
||||
QString myMetadata = "<html><body>";
|
||||
myMetadata += "<table width=\"100%\">";
|
||||
|
||||
//-------------
|
||||
|
||||
myMetadata += "<tr class=\"glossy\"><td>";
|
||||
myMetadata += tr( "General:" );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
// data comment
|
||||
if ( !( dataComment().isEmpty() ) )
|
||||
{
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "Layer comment: %1" ).arg( dataComment() );
|
||||
myMetadata += "</td></tr>";
|
||||
}
|
||||
|
||||
//storage type
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "Storage type of this layer: %1" ).arg( storageType() );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
// data source
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "Source for this layer: %1" ).arg( publicSource() );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
//geom type
|
||||
|
||||
QGis::GeometryType type = geometryType();
|
||||
|
||||
if ( type < 0 || type > QGis::NoGeometry )
|
||||
{
|
||||
QgsDebugMsg( "Invalid vector type" );
|
||||
}
|
||||
else
|
||||
{
|
||||
QString typeString( QGis::qgisVectorGeometryType[geometryType()] );
|
||||
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "Geometry type of the features in this layer: %1" ).arg( typeString );
|
||||
myMetadata += "</td></tr>";
|
||||
}
|
||||
|
||||
|
||||
//feature count
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "The number of features in this layer: %1" ).arg( featureCount() );
|
||||
myMetadata += "</td></tr>";
|
||||
//capabilities
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "Editing capabilities of this layer: %1" ).arg( capabilitiesString() );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
//-------------
|
||||
|
||||
QgsRectangle myExtent = extent();
|
||||
myMetadata += "<tr class=\"glossy\"><td>";
|
||||
myMetadata += tr( "Extents:" );
|
||||
myMetadata += "</td></tr>";
|
||||
//extents in layer cs TODO...maybe make a little nested table to improve layout...
|
||||
myMetadata += "<tr><td>";
|
||||
|
||||
// Try to be a bit clever over what number format we use for the
|
||||
// extents. Some people don't like it using scientific notation when the
|
||||
// numbers get large, but for small numbers this is the more practical
|
||||
// option (so we can't force the format to 'f' for all values).
|
||||
// The scheme:
|
||||
// - for all numbers with more than 5 digits, force non-scientific notation
|
||||
// and 2 digits after the decimal point.
|
||||
// - for all smaller numbers let the OS decide which format to use (it will
|
||||
// generally use non-scientific unless the number gets much less than 1).
|
||||
|
||||
QString xMin, yMin, xMax, yMax;
|
||||
double changeoverValue = 99999; // The 'largest' 5 digit number
|
||||
if ( qAbs( myExtent.xMinimum() ) > changeoverValue )
|
||||
{
|
||||
xMin = QString( "%1" ).arg( myExtent.xMinimum(), 0, 'f', 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
xMin = QString( "%1" ).arg( myExtent.xMinimum() );
|
||||
}
|
||||
if ( qAbs( myExtent.yMinimum() ) > changeoverValue )
|
||||
{
|
||||
yMin = QString( "%1" ).arg( myExtent.yMinimum(), 0, 'f', 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
yMin = QString( "%1" ).arg( myExtent.yMinimum() );
|
||||
}
|
||||
if ( qAbs( myExtent.xMaximum() ) > changeoverValue )
|
||||
{
|
||||
xMax = QString( "%1" ).arg( myExtent.xMaximum(), 0, 'f', 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
xMax = QString( "%1" ).arg( myExtent.xMaximum() );
|
||||
}
|
||||
if ( qAbs( myExtent.yMaximum() ) > changeoverValue )
|
||||
{
|
||||
yMax = QString( "%1" ).arg( myExtent.yMaximum(), 0, 'f', 2 );
|
||||
}
|
||||
else
|
||||
{
|
||||
yMax = QString( "%1" ).arg( myExtent.yMaximum() );
|
||||
}
|
||||
|
||||
myMetadata += tr( "In layer spatial reference system units : " )
|
||||
+ tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" )
|
||||
.arg( xMin ).arg( yMin ).arg( xMax ).arg( yMax );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
//extents in project cs
|
||||
|
||||
try
|
||||
{
|
||||
#if 0
|
||||
// TODO: currently disabled, will revisit later [MD]
|
||||
QgsRectangle myProjectedExtent = coordinateTransform->transformBoundingBox( extent() );
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "In project spatial reference system units : " )
|
||||
+ tr( "xMin,yMin %1,%2 : xMax,yMax %3,%4" )
|
||||
.arg( myProjectedExtent.xMinimum() )
|
||||
.arg( myProjectedExtent.yMinimum() )
|
||||
.arg( myProjectedExtent.xMaximum() )
|
||||
.arg( myProjectedExtent.yMaximum() );
|
||||
myMetadata += "</td></tr>";
|
||||
#endif
|
||||
|
||||
//
|
||||
// Display layer spatial ref system
|
||||
//
|
||||
myMetadata += "<tr class=\"glossy\"><td>";
|
||||
myMetadata += tr( "Layer Spatial Reference System:" );
|
||||
myMetadata += "</td></tr>";
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += crs().toProj4().replace( QRegExp( "\"" ), " \"" );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
//
|
||||
// Display project (output) spatial ref system
|
||||
//
|
||||
#if 0
|
||||
// TODO: disabled for now, will revisit later [MD]
|
||||
myMetadata += "<tr><td bgcolor=\"gray\">";
|
||||
myMetadata += tr( "Project (Output) Spatial Reference System:" );
|
||||
myMetadata += "</td></tr>";
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += coordinateTransform->destCRS().toProj4().replace( QRegExp( "\"" ), " \"" );
|
||||
myMetadata += "</td></tr>";
|
||||
#endif
|
||||
}
|
||||
catch ( QgsCsException &cse )
|
||||
{
|
||||
Q_UNUSED( cse );
|
||||
QgsDebugMsg( cse.what() );
|
||||
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += tr( "In project spatial reference system units : " )
|
||||
+ tr( "(Invalid transformation of layer extents)" );
|
||||
myMetadata += "</td></tr>";
|
||||
|
||||
}
|
||||
|
||||
#if 0
|
||||
//
|
||||
// Add the info about each field in the attribute table
|
||||
//
|
||||
myMetadata += "<tr class=\"glossy\"><td>";
|
||||
myMetadata += tr( "Attribute field info:" );
|
||||
myMetadata += "</td></tr>";
|
||||
myMetadata += "<tr><td>";
|
||||
|
||||
// Start a nested table in this trow
|
||||
myMetadata += "<table width=\"100%\">";
|
||||
myMetadata += "<tr><th>";
|
||||
myMetadata += tr( "Field" );
|
||||
myMetadata += "</th>";
|
||||
myMetadata += "<th>";
|
||||
myMetadata += tr( "Type" );
|
||||
myMetadata += "</th>";
|
||||
myMetadata += "<th>";
|
||||
myMetadata += tr( "Length" );
|
||||
myMetadata += "</th>";
|
||||
myMetadata += "<th>";
|
||||
myMetadata += tr( "Precision" );
|
||||
myMetadata += "</th>";
|
||||
myMetadata += "<th>";
|
||||
myMetadata += tr( "Comment" );
|
||||
myMetadata += "</th>";
|
||||
|
||||
//get info for each field by looping through them
|
||||
const QgsFieldMap& myFields = pendingFields();
|
||||
for ( QgsFieldMap::const_iterator it = myFields.begin(); it != myFields.end(); ++it )
|
||||
{
|
||||
const QgsField& myField = *it;
|
||||
|
||||
myMetadata += "<tr><td>";
|
||||
myMetadata += myField.name();
|
||||
myMetadata += "</td>";
|
||||
myMetadata += "<td>";
|
||||
myMetadata += myField.typeName();
|
||||
myMetadata += "</td>";
|
||||
myMetadata += "<td>";
|
||||
myMetadata += QString( "%1" ).arg( myField.length() );
|
||||
myMetadata += "</td>";
|
||||
myMetadata += "<td>";
|
||||
myMetadata += QString( "%1" ).arg( myField.precision() );
|
||||
myMetadata += "</td>";
|
||||
myMetadata += "<td>";
|
||||
myMetadata += QString( "%1" ).arg( myField.comment() );
|
||||
myMetadata += "</td></tr>";
|
||||
}
|
||||
|
||||
//close field list
|
||||
myMetadata += "</table>"; //end of nested table
|
||||
#endif
|
||||
|
||||
myMetadata += "</td></tr>"; //end of stats container table row
|
||||
//
|
||||
// Close the table
|
||||
//
|
||||
|
||||
myMetadata += "</table>";
|
||||
|
||||
myMetadata += "</body></html>";
|
||||
return myMetadata;
|
||||
|
||||
}
|
||||
|
@ -688,6 +688,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
|
||||
@note added in 1.7 */
|
||||
void checkJoinLayerRemove( QString theLayerId );
|
||||
|
||||
QString metadata();
|
||||
|
||||
signals:
|
||||
|
||||
/** This signal is emited when selection was changed */
|
||||
|
@ -22,6 +22,13 @@ symbology-ng/qgsvectorcolorbrewercolorrampv2dialog.cpp
|
||||
symbology-ng/characterwidget.cpp
|
||||
symbology-ng/qgsstylev2exportimportdialog.cpp
|
||||
|
||||
attributetable/qgsattributetablemodel.cpp
|
||||
attributetable/qgsattributetablememorymodel.cpp
|
||||
attributetable/qgsattributetableview.cpp
|
||||
attributetable/qgsattributetablefiltermodel.cpp
|
||||
attributetable/qgsattributetableidcolumnpair.cpp
|
||||
attributetable/qgsattributetabledelegate.cpp
|
||||
|
||||
qgisgui.cpp
|
||||
qgisinterface.cpp
|
||||
qgsannotationitem.cpp
|
||||
@ -38,6 +45,7 @@ qgsfiledropedit.cpp
|
||||
qgsfieldvalidator.cpp
|
||||
qgsformannotationitem.cpp
|
||||
qgsgenericprojectionselector.cpp
|
||||
qgsmanageconnectionsdialog.cpp
|
||||
qgsmapcanvas.cpp
|
||||
qgsmapcanvasitem.cpp
|
||||
qgsmapcanvasmap.cpp
|
||||
@ -49,6 +57,9 @@ qgsmaptoolemitpoint.cpp
|
||||
qgsmaptoolpan.cpp
|
||||
qgsmaptoolzoom.cpp
|
||||
qgsmessageviewer.cpp
|
||||
qgsnewhttpconnection.cpp
|
||||
qgsnewvectorlayerdialog.cpp
|
||||
qgsnumericsortlistviewitem.cpp
|
||||
qgscredentialdialog.cpp
|
||||
qgsprojectbadlayerguihandler.cpp
|
||||
qgsprojectionselector.cpp
|
||||
@ -83,6 +94,11 @@ symbology-ng/qgspenstylecombobox.h
|
||||
symbology-ng/qgsbrushstylecombobox.h
|
||||
symbology-ng/qgsstylev2exportimportdialog.h
|
||||
|
||||
attributetable/qgsattributetableview.h
|
||||
attributetable/qgsattributetablemodel.h
|
||||
attributetable/qgsattributetablememorymodel.h
|
||||
attributetable/qgsattributetabledelegate.h
|
||||
|
||||
qgsattributeeditor.h
|
||||
qgscomposerview.h
|
||||
qgsdetaileditemdelegate.h
|
||||
@ -93,10 +109,14 @@ qgsencodingfiledialog.h
|
||||
qgsfieldvalidator.h
|
||||
qgsformannotationitem.h
|
||||
qgsgenericprojectionselector.h
|
||||
qgsmanageconnectionsdialog.h
|
||||
qgsmapcanvas.h
|
||||
qgsmapoverviewcanvas.h
|
||||
qgsmaptoolemitpoint.h
|
||||
qgsmessageviewer.h
|
||||
qgsnewhttpconnection.h
|
||||
qgsnewvectorlayerdialog.h
|
||||
qgsnumericsortlistviewitem.h
|
||||
qgscredentialdialog.h
|
||||
qgsprojectionselector.h
|
||||
qgsquickprint.h
|
||||
@ -211,6 +231,13 @@ qgssearchquerybuilder.h
|
||||
qgsattributeeditor.h
|
||||
qgsfieldvalidator.h
|
||||
|
||||
attributetable/qgsattributetablemodel.h
|
||||
attributetable/qgsattributetablememorymodel.h
|
||||
attributetable/qgsattributetableview.h
|
||||
attributetable/qgsattributetablefiltermodel.h
|
||||
attributetable/qgsattributetableidcolumnpair.h
|
||||
attributetable/qgsattributetabledelegate.h
|
||||
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsdetaileditemwidgetbase.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsgenericprojectionselectorbase.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsmessageviewer.h
|
||||
|