diff --git a/python/core/composer/qgsatlascomposition.sip b/python/core/composer/qgsatlascomposition.sip index 4591baae6f1a..17084fb8d408 100644 --- a/python/core/composer/qgsatlascomposition.sip +++ b/python/core/composer/qgsatlascomposition.sip @@ -68,8 +68,11 @@ public: QString featureFilter() const; void setFeatureFilter( const QString& expression ); - int sortKeyAttributeIndex() const; - void setSortKeyAttributeIndex( int idx ); + QString sortKeyAttributeName() const; + void setSortKeyAttributeName( QString fieldName ); + + int sortKeyAttributeIndex() const /Deprecated/; + void setSortKeyAttributeIndex( int idx ) /Deprecated/; /** Begins the rendering. Returns true if successful, false if no matching atlas features found.*/ diff --git a/python/gui/gui.sip b/python/gui/gui.sip index 470ce9de12f9..0b7a6cf2c772 100644 --- a/python/gui/gui.sip +++ b/python/gui/gui.sip @@ -28,6 +28,8 @@ %Include qgsexpressionbuilderdialog.sip %Include qgsexpressionbuilderwidget.sip %Include qgsexpressionhighlighter.sip +%Include qgsfieldcombobox.sip +%Include qgsfieldmodel.sip %Include qgsfieldvalidator.sip %Include qgsfiledropedit.sip %Include qgsfilterlineedit.sip @@ -44,6 +46,9 @@ %Include qgsmapcanvasmap.sip %Include qgsmapcanvassnapper.sip %Include qgsmaplayeractionregistry.sip +%Include qgsmaplayercombobox.sip +%Include qgsmaplayermodel.sip +%Include qgsmaplayerproxymodel.sip %Include qgsmapoverviewcanvas.sip %Include qgsmaptip.sip %Include qgsmaptool.sip diff --git a/python/gui/qgsfieldcombobox.sip b/python/gui/qgsfieldcombobox.sip new file mode 100644 index 000000000000..0946f566823f --- /dev/null +++ b/python/gui/qgsfieldcombobox.sip @@ -0,0 +1,40 @@ +/** + * @brief The QgsFieldComboBox is a combo box which displays the list of fields of a given layer. + * @note added in 2.3 + */ +class QgsFieldComboBox : QComboBox +{ + +%TypeHeaderCode +#include "qgsfieldcombobox.h" +%End + + public: + /** + * @brief QgsFieldComboBox creates a combo box to display the fields of a layer. + * The layer can be either manually given or dynamically set by connecting the signal QgsMapLayerComboBox::layerChanged to the slot setLayer. + */ + explicit QgsFieldComboBox( QWidget *parent /TransferThis/ = 0 ); + + /** + * @brief currentField returns the currently selected field + */ + QString currentField(); + + signals: + /** + * @brief fieldChanged the signal is emitted when the currently selected field changes + */ + void fieldChanged( QString fieldName ); + + public slots: + /** + * @brief setLayer sets the layer of which the fields are listed + */ + void setLayer( QgsMapLayer* layer ); + /** + * @brief setField sets the currently selected field + */ + void setField( QString fieldName ); + +}; diff --git a/python/gui/qgsfieldmodel.sip b/python/gui/qgsfieldmodel.sip new file mode 100644 index 000000000000..8c6d6e3bd034 --- /dev/null +++ b/python/gui/qgsfieldmodel.sip @@ -0,0 +1,42 @@ + +/** + * @brief The QgsFieldModel class is a model to display the list of fields of a layer in widgets. + * It can be associated with a QgsMapLayerModel to dynamically display a layer and its fields. + * @note added in 2.3 + */ + +class QgsFieldModel : QAbstractItemModel +{ +%TypeHeaderCode +#include "qgsfieldmodel.h" +%End + + public: + static const int FieldNameRole; + static const int FieldIndexRole; + + /** + * @brief QgsFieldModel creates a model to display the fields of a given layer + */ + explicit QgsFieldModel( QObject *parent /TransferThis/ = 0 ); + + /** + * @brief indexFromName returns the index corresponding to a given fieldName + */ + QModelIndex indexFromName( QString fieldName ); + + public slots: + /** + * @brief setLayer sets the layer of whch fields are displayed + */ + void setLayer( QgsMapLayer *layer ); + + // QAbstractItemModel interface + public: + QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const; + QModelIndex parent( const QModelIndex &child ) const; + int rowCount( const QModelIndex &parent ) const; + int columnCount( const QModelIndex &parent ) const; + QVariant data( const QModelIndex &index, int role ) const; + +}; diff --git a/python/gui/qgsmaplayercombobox.sip b/python/gui/qgsmaplayercombobox.sip new file mode 100644 index 000000000000..2ede4e94cbc6 --- /dev/null +++ b/python/gui/qgsmaplayercombobox.sip @@ -0,0 +1,40 @@ +/** + * @brief The QgsMapLayerComboBox class is a combo box which displays the list of layers + * @note added in 2.3 + */ +class QgsMapLayerComboBox : QComboBox +{ + +%TypeHeaderCode +#include "qgsmaplayercombobox.h" +%End + + public: + /** + * @brief QgsMapLayerComboBox creates a combo box to dislpay the list of layers (currently in the registry). + * The layers can be filtered and/or ordered. + */ + explicit QgsMapLayerComboBox( QWidget *parent /TransferThis/ = 0 ); + + /** + * @brief setFilters allows fitering according to layer type and/or geometry type. + */ + void setFilters( QgsMapLayerProxyModel::Filters filters ); + + /** + * @brief currentLayer returns the current layer selected in the combo box + */ + QgsMapLayer* currentLayer(); + + public slots: + /** + * @brief setLayer set the current layer selected in the combo + */ + void setLayer( QgsMapLayer* layer ); + + signals: + /** + * @brief layerChanged this signal is emitted whenever the currently selected layer changes + */ + void layerChanged( QgsMapLayer* layer ); +}; diff --git a/python/gui/qgsmaplayermodel.sip b/python/gui/qgsmaplayermodel.sip new file mode 100644 index 000000000000..7f3e54f40eeb --- /dev/null +++ b/python/gui/qgsmaplayermodel.sip @@ -0,0 +1,58 @@ + +/** + * @brief The QgsMapLayerModel class is a model to display layers in widgets. + * @see QgsMapLayerProxyModel to sort and/filter the layers + * @see QgsFieldModel to combine in with a field selector. + * @note added in 2.3 + */ +class QgsMapLayerModel : QAbstractItemModel +{ + +%TypeHeaderCode +#include "qgsmaplayermodel.h" +%End + + public: + static const int LayerIdRole; + + /** + * @brief QgsMapLayerModel creates a model to display layers in widgets. + */ + explicit QgsMapLayerModel( QObject *parent /TransferThis/ = 0 ); + /** + * @brief QgsMapLayerModel creates a model to display a specific list of layers in a widget. + */ + explicit QgsMapLayerModel( QList layers, QObject *parent /TransferThis/ = 0 ); + + /** + * @brief setItemsCheckable defines if layers should be selectable in the widget + */ + void setItemsCheckable( bool checkable ); + /** + * @brief checkAll changes the checkstate for all the layers + */ + void checkAll( Qt::CheckState checkState ); + /** + * @brief layersChecked returns the list of layers which are checked (or unchecked) + */ + QList layersChecked( Qt::CheckState checkState = Qt::Checked ); + //! returns if the items can be checked or not + bool itemsCheckable() ; + + /** + * @brief indexFromLayer returns the model index for a given layer + */ + QModelIndex indexFromLayer( QgsMapLayer* layer ); + + // QAbstractItemModel interface + public: + QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const; + QModelIndex parent( const QModelIndex &child ) const; + int rowCount( const QModelIndex &parent ) const; + int columnCount( const QModelIndex &parent ) const; + QVariant data( const QModelIndex &index, int role ) const; + bool setData( const QModelIndex &index, const QVariant &value, int role ); + Qt::ItemFlags flags( const QModelIndex &index ) const; +}; + + diff --git a/python/gui/qgsmaplayerproxymodel.sip b/python/gui/qgsmaplayerproxymodel.sip new file mode 100644 index 000000000000..b84e8866f97f --- /dev/null +++ b/python/gui/qgsmaplayerproxymodel.sip @@ -0,0 +1,50 @@ +/** + * @brief The QgsMapLayerProxModel class provides an easy to use model to display the list of layers in widgets. + * @note added in 2.3 + */ +class QgsMapLayerProxyModel : QSortFilterProxyModel +{ + +%TypeHeaderCode +#include "qgsmaplayerproxymodel.h" +%End + + public: + enum Filter + { + NoFilter = 1, + RasterLayer = 2, + NoGeometry = 4, + PointLayer = 8, + LineLayer = 16, + PolygonLayer = 32, + HasGeometry = 56, + VectorLayer = 60 + }; + typedef QFlags Filters; + + /** + * @brief QgsMapLayerProxModel creates a proxy model with a QgsMapLayerModel as source model. + * It can be used to filter the layers list in a widget. + */ + explicit QgsMapLayerProxyModel( QObject *parent /TransferThis/ = 0 ); + + /** + * @brief layerModel returns the QgsMapLayerModel used in this QSortFilterProxyModel + */ + QgsMapLayerModel* sourceLayerModel() ; + + /** + * @brief setFilters set flags that affect how layers are filtered + * @param filters are Filter flags + * @note added in 2.3 + */ + QgsMapLayerProxyModel* setFilters( Filters filters ); + const Filters& filters() const ; + + // QSortFilterProxyModel interface + public: + bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const; + bool lessThan( const QModelIndex &left, const QModelIndex &right ) const; +}; + diff --git a/src/app/composer/qgsatlascompositionwidget.cpp b/src/app/composer/qgsatlascompositionwidget.cpp index c6a707e35d17..11fa1961c290 100644 --- a/src/app/composer/qgsatlascompositionwidget.cpp +++ b/src/app/composer/qgsatlascompositionwidget.cpp @@ -19,7 +19,9 @@ #include "qgsatlascompositionwidget.h" #include "qgsatlascomposition.h" #include "qgscomposition.h" +#include "qgsfieldmodel.h" #include "qgsmaplayerregistry.h" +#include "qgsmaplayerproxymodel.h" #include "qgsexpressionbuilderdialog.h" #include "qgscomposermap.h" @@ -28,28 +30,11 @@ QgsAtlasCompositionWidget::QgsAtlasCompositionWidget( QWidget* parent, QgsCompos { setupUi( this ); - // populate the layer list - mAtlasCoverageLayerComboBox->clear(); - const QMap< QString, QgsMapLayer * >& layers = QgsMapLayerRegistry::instance()->mapLayers(); - int idx = 0; - for ( QMap::const_iterator it = layers.begin(); it != layers.end(); ++it ) - { - // Only consider vector layers - if ( dynamic_cast( it.value() ) ) - { - mAtlasCoverageLayerComboBox->insertItem( idx++, it.value()->name(), /* userdata */ qVariantFromValue(( void* )it.value() ) ); - } - } - // update sort columns - fillSortColumns(); - - // Connect to addition / removal of layers - QgsMapLayerRegistry* layerRegistry = QgsMapLayerRegistry::instance(); - if ( layerRegistry ) - { - connect( layerRegistry, SIGNAL( layerWillBeRemoved( QString ) ), this, SLOT( onLayerRemoved( QString ) ) ); - connect( layerRegistry, SIGNAL( layerWasAdded( QgsMapLayer* ) ), this, SLOT( onLayerAdded( QgsMapLayer* ) ) ); - } + mAtlasCoverageLayerComboBox->setFilters( QgsMapLayerProxyModel::HasGeometry ); + mAtlasSortFeatureKeyComboBox->setLayer( mAtlasCoverageLayerComboBox->currentLayer() ); + connect( mAtlasCoverageLayerComboBox, SIGNAL( layerChanged( QgsMapLayer* ) ), mAtlasSortFeatureKeyComboBox, SLOT( setLayer( QgsMapLayer* ) ) ); + connect( mAtlasCoverageLayerComboBox, SIGNAL( layerChanged( QgsMapLayer* ) ), this, SLOT( changeCoverageLayer( QgsMapLayer* ) ) ); + connect( mAtlasSortFeatureKeyComboBox, SIGNAL( fieldChanged( QString ) ), this, SLOT( changesSortFeatureField( QString ) ) ); // Sort direction mAtlasSortFeatureDirectionButton->setEnabled( false ); @@ -82,68 +67,24 @@ void QgsAtlasCompositionWidget::on_mUseAtlasCheckBox_stateChanged( int state ) } } -void QgsAtlasCompositionWidget::onLayerRemoved( QString layerName ) -{ - QgsAtlasComposition* atlasMap = &mComposition->atlasComposition(); - // update the atlas coverage layer combo box - for ( int i = 0; i < mAtlasCoverageLayerComboBox->count(); ++i ) - { - const QgsMapLayer* layer = reinterpret_cast( mAtlasCoverageLayerComboBox->itemData( i ).value() ); - if ( layer->id() == layerName ) - { - mAtlasCoverageLayerComboBox->removeItem( i ); - break; - } - } - if ( mAtlasCoverageLayerComboBox->count() == 0 ) - { - atlasMap->setCoverageLayer( 0 ); - } -} - -void QgsAtlasCompositionWidget::onLayerAdded( QgsMapLayer* map ) -{ - QgsAtlasComposition* atlasMap = &mComposition->atlasComposition(); - // update the atlas coverage layer combo box - QgsVectorLayer* vectorLayer = dynamic_cast( map ); - if ( vectorLayer ) - { - mAtlasCoverageLayerComboBox->addItem( map->name(), qVariantFromValue(( void* )map ) ); - - if ( mAtlasCoverageLayerComboBox->count() == 1 ) - { - atlasMap->setCoverageLayer( vectorLayer ); - updateAtlasFeatures(); - } - } -} - -void QgsAtlasCompositionWidget::on_mAtlasCoverageLayerComboBox_currentIndexChanged( int index ) +void QgsAtlasCompositionWidget::changeCoverageLayer( QgsMapLayer *layer ) { QgsAtlasComposition* atlasMap = &mComposition->atlasComposition(); if ( !atlasMap ) { return; } - if ( index == -1 ) + + QgsVectorLayer* vl = dynamic_cast( layer ); + + if ( !vl ) { atlasMap->setCoverageLayer( 0 ); - - // clean up the sorting columns - mAtlasSortFeatureKeyComboBox->clear(); } else { - QgsVectorLayer* layer = reinterpret_cast( mAtlasCoverageLayerComboBox->itemData( index ).value() ); - - if ( layer ) - { - atlasMap->setCoverageLayer( layer ); - updateAtlasFeatures(); - } - - // update sorting columns - fillSortColumns(); + atlasMap->setCoverageLayer( vl ); + updateAtlasFeatures(); } } @@ -260,18 +201,14 @@ void QgsAtlasCompositionWidget::updateAtlasFeatures() } } -void QgsAtlasCompositionWidget::on_mAtlasSortFeatureKeyComboBox_currentIndexChanged( int index ) +void QgsAtlasCompositionWidget::changesSortFeatureField( QString fieldName ) { QgsAtlasComposition* atlasMap = &mComposition->atlasComposition(); if ( !atlasMap ) { return; } - - if ( index != -1 ) - { - atlasMap->setSortKeyAttributeIndex( index ); - } + atlasMap->setSortKeyAttributeName( fieldName ); updateAtlasFeatures(); } @@ -347,23 +284,6 @@ void QgsAtlasCompositionWidget::on_mAtlasSortFeatureDirectionButton_clicked() updateAtlasFeatures(); } -void QgsAtlasCompositionWidget::fillSortColumns() -{ - QgsAtlasComposition* atlasMap = &mComposition->atlasComposition(); - if ( !atlasMap || !atlasMap->coverageLayer() ) - { - return; - } - - mAtlasSortFeatureKeyComboBox->clear(); - // Get fields of the selected coverage layer - const QgsFields& fields = atlasMap->coverageLayer()->pendingFields(); - for ( int i = 0; i < fields.count(); ++i ) - { - mAtlasSortFeatureKeyComboBox->insertItem( i, fields.at( i ).name() ); - } -} - void QgsAtlasCompositionWidget::updateGuiElements() { QgsAtlasComposition* atlasMap = &mComposition->atlasComposition(); @@ -376,17 +296,12 @@ void QgsAtlasCompositionWidget::updateGuiElements() mUseAtlasCheckBox->setCheckState( Qt::Unchecked ); } - int idx = mAtlasCoverageLayerComboBox->findData( qVariantFromValue(( void* )atlasMap->coverageLayer() ) ); - if ( idx != -1 ) - { - mAtlasCoverageLayerComboBox->setCurrentIndex( idx ); - } - + mAtlasCoverageLayerComboBox->setLayer( atlasMap->coverageLayer() ); + mAtlasSortFeatureKeyComboBox->setField( atlasMap->sortKeyAttributeName() ); mAtlasFilenamePatternEdit->setText( atlasMap->filenamePattern() ); mAtlasHideCoverageCheckBox->setCheckState( atlasMap->hideCoverage() ? Qt::Checked : Qt::Unchecked ); mAtlasSingleFileCheckBox->setCheckState( atlasMap->singleFile() ? Qt::Checked : Qt::Unchecked ); mAtlasSortFeatureCheckBox->setCheckState( atlasMap->sortFeatures() ? Qt::Checked : Qt::Unchecked ); - mAtlasSortFeatureKeyComboBox->setCurrentIndex( atlasMap->sortKeyAttributeIndex() ); mAtlasSortFeatureDirectionButton->setArrowType( atlasMap->sortAscending() ? Qt::UpArrow : Qt::DownArrow ); mAtlasFeatureFilterEdit->setText( atlasMap->featureFilter() ); mAtlasFeatureFilterCheckBox->setCheckState( atlasMap->filterFeatures() ? Qt::Checked : Qt::Unchecked ); diff --git a/src/app/composer/qgsatlascompositionwidget.h b/src/app/composer/qgsatlascompositionwidget.h index 89a922772fbc..ec1a461ddc11 100644 --- a/src/app/composer/qgsatlascompositionwidget.h +++ b/src/app/composer/qgsatlascompositionwidget.h @@ -36,25 +36,20 @@ class QgsAtlasCompositionWidget: public slots: void on_mUseAtlasCheckBox_stateChanged( int state ); - void on_mAtlasCoverageLayerComboBox_currentIndexChanged( int index ); + void changeCoverageLayer( QgsMapLayer* layer ); void on_mAtlasFilenamePatternEdit_textChanged( const QString& text ); void on_mAtlasFilenameExpressionButton_clicked(); void on_mAtlasHideCoverageCheckBox_stateChanged( int state ); void on_mAtlasSingleFileCheckBox_stateChanged( int state ); void on_mAtlasSortFeatureCheckBox_stateChanged( int state ); - void on_mAtlasSortFeatureKeyComboBox_currentIndexChanged( int index ); + void changesSortFeatureField( QString fieldName ); void on_mAtlasSortFeatureDirectionButton_clicked(); void on_mAtlasFeatureFilterEdit_editingFinished(); void on_mAtlasFeatureFilterButton_clicked(); void on_mAtlasFeatureFilterCheckBox_stateChanged( int state ); - // extract fields from the current coverage layer and populate the corresponding combo box - void fillSortColumns(); private slots: - void onLayerRemoved( QString ); - void onLayerAdded( QgsMapLayer* ); - void updateGuiElements(); void updateAtlasFeatures(); diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index d96f3bd88a00..feace81356fa 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -3758,29 +3758,11 @@ void QgisApp::fileSaveAs() void QgisApp::dxfExport() { - QgsLegend* mapLegend = legend(); - if ( !mapLegend ) - { - return; - } - - QgsDxfExportDialog d( mapLegend->layers() ); + QgsDxfExportDialog d; if ( d.exec() == QDialog::Accepted ) { QgsDxfExport dxfExport; - - QList layerList; - QList layerIdList = d.layers(); - QList::const_iterator layerIt = layerIdList.constBegin(); - for ( ; layerIt != layerIdList.constEnd(); ++layerIt ) - { - QgsMapLayer* l = QgsMapLayerRegistry::instance()->mapLayer( *layerIt ); - if ( l ) - { - layerList.append( l ); - } - } - + QList layerList = d.layers(); dxfExport.addLayers( layerList ); dxfExport.setSymbologyScaleDenominator( d.symbologyScale() ); dxfExport.setSymbologyExport( d.symbologyMode() ); diff --git a/src/app/qgsdxfexportdialog.cpp b/src/app/qgsdxfexportdialog.cpp index e3c36ae76806..7641efdb023d 100644 --- a/src/app/qgsdxfexportdialog.cpp +++ b/src/app/qgsdxfexportdialog.cpp @@ -17,6 +17,7 @@ #include "qgsdxfexportdialog.h" #include "qgsmaplayer.h" +#include "qgsmaplayermodel.h" #include "qgsmaplayerregistry.h" #include "qgsvectorlayer.h" #include "qgis.h" @@ -24,34 +25,20 @@ #include #include -QgsDxfExportDialog::QgsDxfExportDialog( const QList& layerKeys, QWidget* parent, Qt::WindowFlags f ): QDialog( parent, f ) +QgsDxfExportDialog::QgsDxfExportDialog( QWidget* parent, Qt::WindowFlags f ): QDialog( parent, f ) { setupUi( this ); + + mModel = new QgsMapLayerProxyModel( this ); + mModel->sourceLayerModel()->setItemsCheckable( true ); + mModel->setFilters( QgsMapLayerProxyModel::HasGeometry ); + mLayersListView->setModel( mModel ); + connect( mFileLineEdit, SIGNAL( textChanged( const QString& ) ), this, SLOT( setOkEnabled() ) ); connect( this, SIGNAL( accepted() ), this, SLOT( saveSettings() ) ); connect( mSelectAllButton, SIGNAL( clicked() ), this, SLOT( selectAll() ) ); connect( mUnSelectAllButton, SIGNAL( clicked() ), this, SLOT( unSelectAll() ) ); - QList::const_iterator layerIt = layerKeys.constBegin(); - for ( ; layerIt != layerKeys.constEnd(); ++layerIt ) - { - QgsMapLayer* layer = *layerIt; - if ( layer ) - { - if ( layer->type() == QgsMapLayer::VectorLayer ) - { - QgsVectorLayer* vl = dynamic_cast( layer ); - if ( !vl->hasGeometryType() ) - continue; - QListWidgetItem* layerItem = new QListWidgetItem( layer->name() ); - layerItem->setData( Qt::UserRole, layer->id() ); - layerItem->setFlags( Qt::ItemIsEnabled | Qt::ItemIsUserCheckable ); - layerItem->setCheckState( Qt::Checked ); - mLayersListWidget->addItem( layerItem ); - } - } - } - //last dxf symbology mode QSettings s; mSymbologyModeComboBox->setCurrentIndex( s.value( "qgis/lastDxfSymbologyMode", "2" ).toInt() ); @@ -64,34 +51,21 @@ QgsDxfExportDialog::QgsDxfExportDialog( const QList& layerKeys, QW QgsDxfExportDialog::~QgsDxfExportDialog() { - } void QgsDxfExportDialog::selectAll() { - for ( int r = 0; r < mLayersListWidget->count(); r++ ) - mLayersListWidget->item( r )->setCheckState( Qt::Checked ); + mModel->sourceLayerModel()->checkAll( Qt::Checked ); } void QgsDxfExportDialog::unSelectAll() { - for ( int r = 0; r < mLayersListWidget->count(); r++ ) - mLayersListWidget->item( r )->setCheckState( Qt::Unchecked ); + mModel->sourceLayerModel()->checkAll( Qt::Unchecked ); } -QList QgsDxfExportDialog::layers() const +QList QgsDxfExportDialog::layers() const { - QList layerKeyList; - int nItems = mLayersListWidget->count(); - for ( int i = 0; i < nItems; ++i ) - { - QListWidgetItem* currentItem = mLayersListWidget->item( i ); - if ( currentItem->checkState() == Qt::Checked ) - { - layerKeyList.prepend( currentItem->data( Qt::UserRole ).toString() ); - } - } - return layerKeyList; + return mModel->sourceLayerModel()->layersChecked(); } double QgsDxfExportDialog::symbologyScale() const diff --git a/src/app/qgsdxfexportdialog.h b/src/app/qgsdxfexportdialog.h index 5db41c1a3930..7ffd9678ce24 100644 --- a/src/app/qgsdxfexportdialog.h +++ b/src/app/qgsdxfexportdialog.h @@ -20,15 +20,16 @@ #include "ui_qgsdxfexportdialogbase.h" #include "qgsdxfexport.h" +#include "qgsmaplayerproxymodel.h" class QgsDxfExportDialog: public QDialog, private Ui::QgsDxfExportDialogBase { Q_OBJECT public: - QgsDxfExportDialog( const QList& layerKeys, QWidget * parent = 0, Qt::WindowFlags f = 0 ); + QgsDxfExportDialog( QWidget * parent = 0, Qt::WindowFlags f = 0 ); ~QgsDxfExportDialog(); - QList layers() const; + QList layers() const; double symbologyScale() const; QgsDxfExport::SymbologyExport symbologyMode() const; QString saveFile() const; @@ -43,6 +44,9 @@ class QgsDxfExportDialog: public QDialog, private Ui::QgsDxfExportDialogBase void on_mFileSelectionButton_clicked(); void setOkEnabled(); void saveSettings(); + + private: + QgsMapLayerProxyModel* mModel; }; #endif // QGSDXFEXPORTDIALOG_H diff --git a/src/core/composer/qgsatlascomposition.cpp b/src/core/composer/qgsatlascomposition.cpp index e9b860b16fae..82132fbf0c78 100644 --- a/src/core/composer/qgsatlascomposition.cpp +++ b/src/core/composer/qgsatlascomposition.cpp @@ -65,7 +65,7 @@ void QgsAtlasComposition::setCoverageLayer( QgsVectorLayer* layer ) QgsExpression::setSpecialColumn( "$numfeatures", QVariant(( int )mFeatureIds.size() ) ); // Grab the first feature so that user can use it to test the style in rules. - if( layer ) + if ( layer ) { QgsFeature fet; layer->getFeatures().nextFeature( fet ); @@ -155,6 +155,29 @@ void QgsAtlasComposition::setMargin( float margin ) map->setAtlasMargin(( double ) margin ); } +int QgsAtlasComposition::sortKeyAttributeIndex() const +{ + if ( !mCoverageLayer ) + { + return -1; + } + return mCoverageLayer->fieldNameIndex( mSortKeyAttributeName ); +} + +void QgsAtlasComposition::setSortKeyAttributeIndex( int idx ) +{ + if ( mCoverageLayer ) + { + const QgsFields fields = mCoverageLayer->pendingFields(); + if ( idx >= 0 && idx < fields.count() ) + { + mSortKeyAttributeName = fields[idx].name(); + return; + } + } + mSortKeyAttributeName = ""; +} + // // Private class only used for the sorting of features class FieldSorter @@ -215,6 +238,7 @@ int QgsAtlasComposition::updateFeatures() QgsFeature feat; mFeatureIds.clear(); mFeatureKeys.clear(); + int sortIdx = mCoverageLayer->fieldNameIndex( mSortKeyAttributeName ); while ( fit.nextFeature( feat ) ) { if ( mFilterFeatures && !mFeatureFilter.isEmpty() ) @@ -233,14 +257,14 @@ int QgsAtlasComposition::updateFeatures() } mFeatureIds.push_back( feat.id() ); - if ( mSortFeatures ) + if ( mSortFeatures && sortIdx != -1 ) { - mFeatureKeys.insert( feat.id(), feat.attributes()[ mSortKeyAttributeIdx ] ); + mFeatureKeys.insert( feat.id(), feat.attributes()[ sortIdx ] ); } } // sort features, if asked for - if ( mSortFeatures ) + if ( mFeatureKeys.count() ) { FieldSorter sorter( mFeatureKeys, mSortAscending ); qSort( mFeatureIds.begin(), mFeatureIds.end(), sorter ); @@ -567,7 +591,7 @@ void QgsAtlasComposition::writeXML( QDomElement& elem, QDomDocument& doc ) const atlasElem.setAttribute( "sortFeatures", mSortFeatures ? "true" : "false" ); if ( mSortFeatures ) { - atlasElem.setAttribute( "sortKey", QString::number( mSortKeyAttributeIdx ) ); + atlasElem.setAttribute( "sortKey", mSortKeyAttributeName ); atlasElem.setAttribute( "sortAscending", mSortAscending ? "true" : "false" ); } atlasElem.setAttribute( "filterFeatures", mFilterFeatures ? "true" : "false" ); @@ -637,7 +661,20 @@ void QgsAtlasComposition::readXML( const QDomElement& atlasElem, const QDomDocum mSortFeatures = atlasElem.attribute( "sortFeatures", "false" ) == "true" ? true : false; if ( mSortFeatures ) { - mSortKeyAttributeIdx = atlasElem.attribute( "sortKey", "0" ).toInt(); + mSortKeyAttributeName = atlasElem.attribute( "sortKey", "" ); + // since 2.3, the field name is saved instead of the field index + // following code keeps compatibility with version 2.2 projects + // to be removed in QGIS 3.0 + bool isIndex; + int idx = mSortKeyAttributeName.toInt( &isIndex ); + if ( isIndex && mCoverageLayer ) + { + const QgsFields fields = mCoverageLayer->pendingFields(); + if ( idx >= 0 && idx < fields.count() ) + { + mSortKeyAttributeName = fields[idx].name(); + } + } mSortAscending = atlasElem.attribute( "sortAscending", "true" ) == "true" ? true : false; } mFilterFeatures = atlasElem.attribute( "filterFeatures", "false" ) == "true" ? true : false; diff --git a/src/core/composer/qgsatlascomposition.h b/src/core/composer/qgsatlascomposition.h index 7c67a54cdcec..3c67f815bcf2 100644 --- a/src/core/composer/qgsatlascomposition.h +++ b/src/core/composer/qgsatlascomposition.h @@ -96,8 +96,11 @@ class CORE_EXPORT QgsAtlasComposition : public QObject QString featureFilter() const { return mFeatureFilter; } void setFeatureFilter( const QString& expression ) { mFeatureFilter = expression; } - int sortKeyAttributeIndex() const { return mSortKeyAttributeIdx; } - void setSortKeyAttributeIndex( int idx ) { mSortKeyAttributeIdx = idx; } + QString sortKeyAttributeName() const { return mSortKeyAttributeName; } + void setSortKeyAttributeName( QString fieldName ) { mSortKeyAttributeName = fieldName; } + + Q_DECL_DEPRECATED int sortKeyAttributeIndex() const; + Q_DECL_DEPRECATED void setSortKeyAttributeIndex( int idx ); /** Begins the rendering. Returns true if successful, false if no matching atlas features found.*/ @@ -188,7 +191,7 @@ class CORE_EXPORT QgsAtlasComposition : public QObject // value of field that is used for ordering of features SorterKeys mFeatureKeys; // key (attribute index) used for ordering - int mSortKeyAttributeIdx; + QString mSortKeyAttributeName; // feature filtering bool mFilterFeatures; diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 6af985defb1d..4d1cbd65eea1 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -88,6 +88,8 @@ qgsexpressionhighlighter.cpp qgsexpressionselectiondialog.cpp qgsextentgroupbox.cpp qgsfeatureselectiondlg.cpp +qgsfieldcombobox.cpp +qgsfieldmodel.cpp qgsfieldvalidator.cpp qgsfiledropedit.cpp qgsfilterlineedit.cpp @@ -103,6 +105,9 @@ qgsmapcanvasitem.cpp qgsmapcanvasmap.cpp qgsmapcanvassnapper.cpp qgsmaplayeractionregistry.cpp +qgsmaplayercombobox.cpp +qgsmaplayermodel.cpp +qgsmaplayerproxymodel.cpp qgsmapoverviewcanvas.cpp qgsmaptip.cpp qgsmaptool.cpp @@ -227,6 +232,8 @@ qgsexpressionhighlighter.h qgsexpressionselectiondialog.h qgsextentgroupbox.h qgsfeatureselectiondlg.h +qgsfieldcombobox.h +qgsfieldmodel.h qgsfieldvalidator.h qgsfilterlineedit.h qgsformannotationitem.h @@ -238,6 +245,9 @@ qgsludialog.h qgsmanageconnectionsdialog.h qgsmapcanvas.h qgsmaplayeractionregistry.h +qgsmaplayercombobox.h +qgsmaplayermodel.h +qgsmaplayerproxymodel.h qgsmapoverviewcanvas.h qgsmaptool.h qgsmaptoolemitpoint.h @@ -292,6 +302,8 @@ qgsexpressionbuilderwidget.h qgsexpressionhighlighter.h qgsexpressionselectiondialog.h qgsfeatureselectiondlg.h +qgsfieldcombobox.h +qgsfieldmodel.h qgsfieldvalidator.h qgsfiledropedit.h qgsfilterlineedit.h @@ -301,6 +313,9 @@ qgsmapcanvas.h qgsmapcanvasitem.h qgsmapcanvasmap.h qgsmapcanvassnapper.h +qgsmaplayercombobox.h +qgsmaplayermodel.h +qgsmaplayerproxymodel.h qgsmapoverviewcanvas.h qgsmaptip.h qgsmaptool.h diff --git a/src/gui/qgsfieldcombobox.cpp b/src/gui/qgsfieldcombobox.cpp new file mode 100644 index 000000000000..be556488aec3 --- /dev/null +++ b/src/gui/qgsfieldcombobox.cpp @@ -0,0 +1,66 @@ +/*************************************************************************** + qgsfieldcombobox.cpp + -------------------------------------- + Date : 01.04.2014 + Copyright : (C) 2014 Denis Rouzaud + Email : denis.rouzaud@gmail.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 "qgsfieldcombobox.h" +#include "qgsfieldmodel.h" +#include "qgsmaplayer.h" + +QgsFieldComboBox::QgsFieldComboBox( QWidget *parent ) : + QComboBox( parent ) +{ + mFieldModel = new QgsFieldModel( this ); + setModel( mFieldModel ); + + connect( this, SIGNAL( currentIndexChanged( int ) ), this, SLOT( indexChanged( int ) ) ); +} + +void QgsFieldComboBox::setLayer( QgsMapLayer *layer ) +{ + mFieldModel->setLayer( layer ); +} + +void QgsFieldComboBox::setField( QString fieldName ) +{ + QModelIndex idx = mFieldModel->indexFromName( fieldName ); + if ( idx.isValid() ) + { + setCurrentIndex( idx.row() ); + } + else + { + setCurrentIndex( -1 ); + } +} + +QString QgsFieldComboBox::currentField() +{ + int i = currentIndex(); + + const QModelIndex index = mFieldModel->index( i, 0 ); + if ( !index.isValid() ) + { + return ""; + } + + QString name = mFieldModel->data( index, QgsFieldModel::FieldNameRole ).toString(); + return name; +} + +void QgsFieldComboBox::indexChanged( int i ) +{ + Q_UNUSED( i ); + QString name = currentField(); + emit fieldChanged( name ); +} diff --git a/src/gui/qgsfieldcombobox.h b/src/gui/qgsfieldcombobox.h new file mode 100644 index 000000000000..3c6af39b8b08 --- /dev/null +++ b/src/gui/qgsfieldcombobox.h @@ -0,0 +1,67 @@ +/*************************************************************************** + qgsfieldcombobox.h + -------------------------------------- + Date : 01.04.2014 + Copyright : (C) 2014 Denis Rouzaud + Email : denis.rouzaud@gmail.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. * +* * +***************************************************************************/ + +#ifndef QGSFIELDCOMBOBOX_H +#define QGSFIELDCOMBOBOX_H + +#include + +class QgsFieldModel; +class QgsMapLayer; + +/** + * @brief The QgsFieldComboBox is a combo box which displays the list of fields of a given layer. + * @note added in 2.3 + */ +class GUI_EXPORT QgsFieldComboBox : public QComboBox +{ + Q_OBJECT + public: + /** + * @brief QgsFieldComboBox creates a combo box to display the fields of a layer. + * The layer can be either manually given or dynamically set by connecting the signal QgsMapLayerComboBox::layerChanged to the slot setLayer. + */ + explicit QgsFieldComboBox( QWidget *parent = 0 ); + + /** + * @brief currentField returns the currently selected field + */ + QString currentField(); + + signals: + /** + * @brief fieldChanged the signal is emitted when the currently selected field changes + */ + void fieldChanged( QString fieldName ); + + public slots: + /** + * @brief setLayer sets the layer of which the fields are listed + */ + void setLayer( QgsMapLayer* layer ); + /** + * @brief setField sets the currently selected field + */ + void setField( QString fieldName ); + + protected slots: + void indexChanged( int i ); + + private: + QgsFieldModel* mFieldModel; + +}; + +#endif // QGSFIELDCOMBOBOX_H diff --git a/src/gui/qgsfieldmodel.cpp b/src/gui/qgsfieldmodel.cpp new file mode 100644 index 000000000000..b4c2138fd7ad --- /dev/null +++ b/src/gui/qgsfieldmodel.cpp @@ -0,0 +1,126 @@ +/*************************************************************************** + qgsfieldmodel.cpp + -------------------------------------- + Date : 01.04.2014 + Copyright : (C) 2014 Denis Rouzaud + Email : denis.rouzaud@gmail.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 "qgsfieldmodel.h" +#include "qgsmaplayermodel.h" +#include "qgsmaplayerproxymodel.h" +#include "qgslogger.h" + + +const int QgsFieldModel::FieldIndexRole = Qt::UserRole + 1; +const int QgsFieldModel::FieldNameRole = Qt::UserRole + 2; + +QgsFieldModel::QgsFieldModel( QObject *parent ) + : QAbstractItemModel( parent ) + , mLayer( NULL ) +{ +} + +QModelIndex QgsFieldModel::indexFromName( QString fieldName ) +{ + int r = mFields.indexFromName( fieldName ); + return index( r, 0 ); +} + + +void QgsFieldModel::setLayer( QgsMapLayer *layer ) +{ + if ( mLayer ) + { + disconnect( mLayer, SIGNAL( updatedFields() ), this, SLOT( updateFields() ) ); + disconnect( mLayer, SIGNAL( layerDeleted() ), this, SLOT( layerDeleted() ) ); + } + QgsVectorLayer* vl = dynamic_cast( layer ); + if ( vl ) + { + mLayer = vl; + connect( mLayer, SIGNAL( updatedFields() ), this, SLOT( updateFields() ) ); + connect( mLayer, SIGNAL( layerDeleted() ), this, SLOT( layerDeleted() ) ); + } + else + { + mLayer = 0; + } + updateFields(); +} + +void QgsFieldModel::layerDeleted() +{ + mLayer = 0; + updateFields(); +} + +void QgsFieldModel::updateFields() +{ + beginResetModel(); + if ( mLayer ) + mFields = mLayer->pendingFields(); + else + mFields = QgsFields(); + endResetModel(); +} + +QModelIndex QgsFieldModel::index( int row, int column, const QModelIndex &parent ) const +{ + Q_UNUSED( parent ); + if ( row < 0 || row >= mFields.count() ) + return QModelIndex(); + + return createIndex( row, column, row ); +} + +QModelIndex QgsFieldModel::parent( const QModelIndex &child ) const +{ + Q_UNUSED( child ); + return QModelIndex(); +} + +int QgsFieldModel::rowCount( const QModelIndex &parent ) const +{ + Q_UNUSED( parent ); + return mFields.count(); +} + +int QgsFieldModel::columnCount( const QModelIndex &parent ) const +{ + Q_UNUSED( parent ); + return 1; +} + +QVariant QgsFieldModel::data( const QModelIndex &index, int role ) const +{ + if ( !index.isValid() ) + return QVariant(); + + if ( !mLayer ) + return QVariant(); + + if ( role == Qt::DisplayRole ) + { + QgsField field = mFields[index.internalId()]; + const QMap< QString, QString > aliases = mLayer->attributeAliases(); + QString alias = aliases.value( field.name(), field.name() ); + return alias; + } + + if ( role == Qt::UserRole ) + { + QgsField field = mFields[index.internalId()]; + return field.name(); + } + + return QVariant(); +} + diff --git a/src/gui/qgsfieldmodel.h b/src/gui/qgsfieldmodel.h new file mode 100644 index 000000000000..f0ecb34e4b0c --- /dev/null +++ b/src/gui/qgsfieldmodel.h @@ -0,0 +1,72 @@ +/*************************************************************************** + qgsfieldmodel.h + -------------------------------------- + Date : 01.04.2014 + Copyright : (C) 2014 Denis Rouzaud + Email : denis.rouzaud@gmail.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. * +* * +***************************************************************************/ + +#ifndef QGSFIELDMODEL_H +#define QGSFIELDMODEL_H + +#include +#include +#include + +#include "qgsvectorlayer.h" + +/** + * @brief The QgsFieldModel class is a model to display the list of fields of a layer in widgets. + * It can be associated with a QgsMapLayerModel to dynamically display a layer and its fields. + * @note added in 2.3 + */ + +class GUI_EXPORT QgsFieldModel : public QAbstractItemModel +{ + Q_OBJECT + public: + static const int FieldNameRole, FieldIndexRole; + + /** + * @brief QgsFieldModel creates a model to display the fields of a given layer + */ + explicit QgsFieldModel( QObject *parent = 0 ); + + /** + * @brief indexFromName returns the index corresponding to a given fieldName + */ + QModelIndex indexFromName( QString fieldName ); + + public slots: + /** + * @brief setLayer sets the layer of whch fields are displayed + */ + void setLayer( QgsMapLayer *layer ); + + protected slots: + void updateFields(); + void layerDeleted(); + + protected: + QgsFields mFields; + QgsVectorLayer* mLayer; + + // QAbstractItemModel interface + public: + QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const; + QModelIndex parent( const QModelIndex &child ) const; + int rowCount( const QModelIndex &parent ) const; + int columnCount( const QModelIndex &parent ) const; + QVariant data( const QModelIndex &index, int role ) const; + + +}; + +#endif // QGSFIELDMODEL_H diff --git a/src/gui/qgsmaplayercombobox.cpp b/src/gui/qgsmaplayercombobox.cpp new file mode 100644 index 000000000000..a8fd1f0133b5 --- /dev/null +++ b/src/gui/qgsmaplayercombobox.cpp @@ -0,0 +1,79 @@ +/*************************************************************************** + qgsmaplayercombobox.cpp + -------------------------------------- + Date : 01.04.2014 + Copyright : (C) 2014 Denis Rouzaud + Email : denis.rouzaud@gmail.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 "qgsmaplayercombobox.h" +#include "qgsmaplayermodel.h" + +QgsMapLayerComboBox::QgsMapLayerComboBox( QWidget *parent ) : + QComboBox( parent ) +{ + mProxyModel = new QgsMapLayerProxyModel( this ); + setModel( mProxyModel ); + + connect( this, SIGNAL( currentIndexChanged( int ) ), this, SLOT( indexChanged( int ) ) ); +} + +void QgsMapLayerComboBox::setFilters( QgsMapLayerProxyModel::Filters filters ) +{ + mProxyModel->setFilters( filters ); +} + +void QgsMapLayerComboBox::setLayer( QgsMapLayer *layer ) +{ + QModelIndex idx = mProxyModel->sourceLayerModel()->indexFromLayer( layer ); + if ( idx.isValid() ) + { + QModelIndex proxyIdx = mProxyModel->mapFromSource( idx ); + if ( proxyIdx.isValid() ) + { + setCurrentIndex( proxyIdx.row() ); + return; + } + } + setCurrentIndex( -1 ); +} + +QgsMapLayer* QgsMapLayerComboBox::currentLayer() +{ + int i = currentIndex(); + + const QModelIndex proxyIndex = mProxyModel->index( i, 0 ); + if ( !proxyIndex.isValid() ) + { + return 0; + } + + const QModelIndex index = mProxyModel->mapToSource( proxyIndex ); + if ( !index.isValid() ) + { + return 0; + } + + QgsMapLayer* layer = static_cast( index.internalPointer() ); + if ( layer ) + { + return layer; + } + return 0; +} + +void QgsMapLayerComboBox::indexChanged( int i ) +{ + Q_UNUSED( i ); + QgsMapLayer* layer = currentLayer(); + emit layerChanged( layer ); +} + + diff --git a/src/gui/qgsmaplayercombobox.h b/src/gui/qgsmaplayercombobox.h new file mode 100644 index 000000000000..7065f34cb1ba --- /dev/null +++ b/src/gui/qgsmaplayercombobox.h @@ -0,0 +1,70 @@ +/*************************************************************************** + qgsmaplayercombobox.h + -------------------------------------- + Date : 01.04.2014 + Copyright : (C) 2014 Denis Rouzaud + Email : denis.rouzaud@gmail.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. * +* * +***************************************************************************/ + +#ifndef QGSMAPLAYERCOMBOBOX_H +#define QGSMAPLAYERCOMBOBOX_H + +#include + +#include "qgsmaplayerproxymodel.h" + +class QgsMapLayer; +class QgsVectorLayer; + +/** + * @brief The QgsMapLayerComboBox class is a combo box which displays the list of layers + * @note added in 2.3 + */ +class GUI_EXPORT QgsMapLayerComboBox : public QComboBox +{ + Q_OBJECT + public: + /** + * @brief QgsMapLayerComboBox creates a combo box to dislpay the list of layers (currently in the registry). + * The layers can be filtered and/or ordered. + */ + explicit QgsMapLayerComboBox( QWidget *parent = 0 ); + + /** + * @brief setFilters allows fitering according to layer type and/or geometry type. + */ + void setFilters( QgsMapLayerProxyModel::Filters filters ); + + /** + * @brief currentLayer returns the current layer selected in the combo box + */ + QgsMapLayer* currentLayer(); + + public slots: + /** + * @brief setLayer set the current layer selected in the combo + */ + void setLayer( QgsMapLayer* layer ); + + signals: + /** + * @brief layerChanged this signal is emitted whenever the currently selected layer changes + */ + void layerChanged( QgsMapLayer* layer ); + + protected slots: + void indexChanged( int i ); + + private: + QgsMapLayerProxyModel* mProxyModel; + +}; + +#endif // QGSMAPLAYERCOMBOBOX_H diff --git a/src/gui/qgsmaplayermodel.cpp b/src/gui/qgsmaplayermodel.cpp new file mode 100644 index 000000000000..7de9958010fa --- /dev/null +++ b/src/gui/qgsmaplayermodel.cpp @@ -0,0 +1,238 @@ +/*************************************************************************** + qgsmaplayermodel.cpp + -------------------------------------- + Date : 01.04.2014 + Copyright : (C) 2014 Denis Rouzaud + Email : denis.rouzaud@gmail.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 + +#include "qgsmaplayermodel.h" +#include "qgsmaplayerregistry.h" +#include "qgsapplication.h" +#include "qgsvectorlayer.h" + + +const int QgsMapLayerModel::LayerIdRole = Qt::UserRole + 1; + +QgsMapLayerModel::QgsMapLayerModel( QList layers, QObject *parent ) + : QAbstractItemModel( parent ) + , mLayersChecked( QMap() ) + , mItemCheckable( false ) +{ + connect( QgsMapLayerRegistry::instance(), SIGNAL( removeLayers( QStringList ) ), this, SLOT( removeLayers( QStringList ) ) ); + addLayers( layers ); +} + +QgsMapLayerModel::QgsMapLayerModel( QObject *parent ) + : QAbstractItemModel( parent ) + , mLayersChecked( QMap() ) + , mItemCheckable( false ) +{ + connect( QgsMapLayerRegistry::instance(), SIGNAL( layersAdded( QList ) ), this, SLOT( addLayers( QList ) ) ); + connect( QgsMapLayerRegistry::instance(), SIGNAL( layersRemoved( QStringList ) ), this, SLOT( removeLayers( QStringList ) ) ); + addLayers( QgsMapLayerRegistry::instance()->mapLayers().values() ); +} + +void QgsMapLayerModel::setItemsCheckable( bool checkable ) +{ + mItemCheckable = checkable; +} + +void QgsMapLayerModel::checkAll( Qt::CheckState checkState ) +{ + foreach ( const QString key, mLayersChecked.keys() ) + { + mLayersChecked[key] = checkState; + } + emit dataChanged( index( 0, 0 ), index( mLayers.length() - 1, 0 ) ); +} + +QList QgsMapLayerModel::layersChecked( Qt::CheckState checkState ) +{ + QList layers; + foreach ( QgsMapLayer* layer, mLayers ) + { + if ( mLayersChecked[layer->id()] == checkState ) + { + layers.append( layer ); + } + } + return layers; +} + +QModelIndex QgsMapLayerModel::indexFromLayer( QgsMapLayer *layer ) +{ + int r = mLayers.indexOf( layer ); + return index( r, 0 ); +} + +void QgsMapLayerModel::removeLayers( const QStringList layerIds ) +{ + foreach ( const QString layerId, layerIds ) + { + QModelIndex startIndex = index( 0, 0 ); + QModelIndexList list = match( startIndex, LayerIdRole, layerId, 1 ); + if ( list.count() ) + { + QModelIndex index = list[0]; + beginRemoveRows( QModelIndex(), index.row(), index.row() ); + mLayersChecked.remove( layerId ); + mLayers.removeAt( index.row() ); + endRemoveRows(); + } + } +} + +void QgsMapLayerModel::addLayers( QList layers ) +{ + beginInsertRows( QModelIndex(), mLayers.count(), mLayers.count() + layers.count() - 1 ); + foreach ( QgsMapLayer* layer, layers ) + { + mLayers.append( layer ); + mLayersChecked.insert( layer->id(), Qt::Unchecked ); + } + endInsertRows(); +} + +QModelIndex QgsMapLayerModel::index( int row, int column, const QModelIndex &parent ) const +{ + Q_UNUSED( parent ); + if ( row < 0 || row >= mLayers.length() ) + return QModelIndex(); + + return createIndex( row, column, mLayers[row] ); +} + +QModelIndex QgsMapLayerModel::parent( const QModelIndex &child ) const +{ + Q_UNUSED( child ); + return QModelIndex(); +} + +int QgsMapLayerModel::rowCount( const QModelIndex &parent ) const +{ + Q_UNUSED( parent ); + + return mLayers.length(); +} + +int QgsMapLayerModel::columnCount( const QModelIndex &parent ) const +{ + Q_UNUSED( parent ); + return 1; +} + +QVariant QgsMapLayerModel::data( const QModelIndex &index, int role ) const +{ + if ( !index.isValid() || !index.internalPointer() ) + return QVariant(); + + if ( role == Qt::DisplayRole ) + { + QgsMapLayer* layer = static_cast( index.internalPointer() ); + return layer->name(); + } + + if ( role == LayerIdRole ) + { + QgsMapLayer* layer = static_cast( index.internalPointer() ); + return layer->id(); + } + + if ( role == Qt::CheckStateRole ) + { + QgsMapLayer* layer = static_cast( index.internalPointer() ); + return mLayersChecked[layer->id()]; + } + + if ( role == Qt::DecorationRole ) + { + QgsMapLayer* layer = static_cast( index.internalPointer() ); + QgsMapLayer::LayerType type = layer->type(); + if ( role == Qt::DecorationRole ) + { + switch ( type ) + { + case QgsMapLayer::RasterLayer: + { + return QgsApplication::getThemeIcon( "/mIconRasterLayer.svg" ); + } + + case QgsMapLayer::VectorLayer: + { + QgsVectorLayer* vl = dynamic_cast( layer ); + if ( !vl ) + { + return QIcon(); + } + QGis::GeometryType geomType = vl->geometryType(); + switch ( geomType ) + { + case QGis::Point: + { + return QgsApplication::getThemeIcon( "/mIconPointLayer.svg" ); + } + case QGis::Polygon : + { + return QgsApplication::getThemeIcon( "/mIconPolygonLayer.svg" ); + } + case QGis::Line : + { + return QgsApplication::getThemeIcon( "/mIconLineLayer.svg" ); + } + case QGis::NoGeometry : + { + return QgsApplication::getThemeIcon( "/mIconTableLayer.png" ); + } + default: + { + return QIcon(); + } + } + } + default: + { + return QIcon(); + } + } + } + } + + return QVariant(); +} + + +Qt::ItemFlags QgsMapLayerModel::flags( const QModelIndex &index ) const +{ + Q_UNUSED( index ); + + Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + if ( mItemCheckable ) + { + flags |= Qt::ItemIsUserCheckable; + } + return flags; +} + + +bool QgsMapLayerModel::setData( const QModelIndex &index, const QVariant &value, int role ) +{ + if ( role == Qt::CheckStateRole ) + { + QgsMapLayer* layer = static_cast( index.internalPointer() ); + mLayersChecked[layer->id()] = ( Qt::CheckState )value.toInt(); + emit dataChanged( index, index ); + return true; + } + + return false; +} diff --git a/src/gui/qgsmaplayermodel.h b/src/gui/qgsmaplayermodel.h new file mode 100644 index 000000000000..f0437db1e355 --- /dev/null +++ b/src/gui/qgsmaplayermodel.h @@ -0,0 +1,88 @@ +/*************************************************************************** + qgsmaplayermodel.h + -------------------------------------- + Date : 01.04.2014 + Copyright : (C) 2014 Denis Rouzaud + Email : denis.rouzaud@gmail.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. * +* * +***************************************************************************/ + +#ifndef QGSMAPLAYERMODEL_H +#define QGSMAPLAYERMODEL_H + +#include +#include +#include + +class QgsMapLayer; + + +/** + * @brief The QgsMapLayerModel class is a model to display layers in widgets. + * @see QgsMapLayerProxyModel to sort and/filter the layers + * @see QgsFieldModel to combine in with a field selector. + * @note added in 2.3 + */ +class GUI_EXPORT QgsMapLayerModel : public QAbstractItemModel +{ + Q_OBJECT + public: + static const int LayerIdRole; + + /** + * @brief QgsMapLayerModel creates a model to display layers in widgets. + */ + explicit QgsMapLayerModel( QObject *parent = 0 ); + /** + * @brief QgsMapLayerModel creates a model to display a specific list of layers in a widget. + */ + explicit QgsMapLayerModel( QList layers, QObject *parent = 0 ); + + /** + * @brief setItemsCheckable defines if layers should be selectable in the widget + */ + void setItemsCheckable( bool checkable ); + /** + * @brief checkAll changes the checkstate for all the layers + */ + void checkAll( Qt::CheckState checkState ); + /** + * @brief layersChecked returns the list of layers which are checked (or unchecked) + */ + QList layersChecked( Qt::CheckState checkState = Qt::Checked ); + //! returns if the items can be checked or not + bool itemsCheckable() {return mItemCheckable;} + + /** + * @brief indexFromLayer returns the model index for a given layer + */ + QModelIndex indexFromLayer( QgsMapLayer* layer ); + + + protected slots: + void removeLayers( const QStringList layerIds ); + void addLayers( QList layers ); + + protected: + QList mLayers; + QMap mLayersChecked; + bool mItemCheckable; + + // QAbstractItemModel interface + public: + QModelIndex index( int row, int column, const QModelIndex &parent = QModelIndex() ) const; + QModelIndex parent( const QModelIndex &child ) const; + int rowCount( const QModelIndex &parent ) const; + int columnCount( const QModelIndex &parent ) const; + QVariant data( const QModelIndex &index, int role ) const; + bool setData( const QModelIndex &index, const QVariant &value, int role ); + Qt::ItemFlags flags( const QModelIndex &index ) const; +}; + +#endif // QGSMAPLAYERMODEL_H diff --git a/src/gui/qgsmaplayerproxymodel.cpp b/src/gui/qgsmaplayerproxymodel.cpp new file mode 100644 index 000000000000..95273d5013a2 --- /dev/null +++ b/src/gui/qgsmaplayerproxymodel.cpp @@ -0,0 +1,83 @@ +/*************************************************************************** + qgsmaplayerproxymodel.cpp + -------------------------------------- + Date : 01.04.2014 + Copyright : (C) 2014 Denis Rouzaud + Email : denis.rouzaud@gmail.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 "qgsmaplayerproxymodel.h" +#include "qgsmaplayermodel.h" +#include "qgsmaplayer.h" +#include "qgsvectorlayer.h" + +QgsMapLayerProxyModel::QgsMapLayerProxyModel( QObject *parent ) + : QSortFilterProxyModel( parent ) + , mFilters( NoFilter ) + , mModel( new QgsMapLayerModel( this ) ) +{ + setSourceModel( mModel ); +} + +QgsMapLayerProxyModel *QgsMapLayerProxyModel::setFilters( Filters filters ) +{ + mFilters = filters; + return this; +} + +bool QgsMapLayerProxyModel::filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const +{ + if ( mFilters.testFlag( NoFilter ) ) + return true; + + QModelIndex index = sourceModel()->index( source_row, 0, source_parent ); + QgsMapLayer* layer = static_cast( index.internalPointer() ); + if ( !layer ) + return false; + + // layer type + if (( mFilters.testFlag( RasterLayer ) && layer->type() == QgsMapLayer::RasterLayer ) || + ( mFilters.testFlag( VectorLayer ) && layer->type() == QgsMapLayer::VectorLayer ) ) + return true; + + // geometry type + bool detectGeometry = mFilters.testFlag( NoGeometry ) || + mFilters.testFlag( PointLayer ) || + mFilters.testFlag( LineLayer ) || + mFilters.testFlag( PolygonLayer ) || + mFilters.testFlag( HasGeometry ); + if ( detectGeometry && layer->type() == QgsMapLayer::VectorLayer ) + { + QgsVectorLayer* vl = dynamic_cast( layer ); + if ( vl ) + { + if ( mFilters.testFlag( HasGeometry ) && vl->hasGeometryType() ) + return true; + if ( mFilters.testFlag( NoGeometry ) && vl->geometryType() == QGis::NoGeometry ) + return true; + if ( mFilters.testFlag( PointLayer ) && vl->geometryType() == QGis::Point ) + return true; + if ( mFilters.testFlag( LineLayer ) && vl->geometryType() == QGis::Line ) + return true; + if ( mFilters.testFlag( PolygonLayer ) && vl->geometryType() == QGis::Polygon ) + return true; + } + } + + return false; +} + +bool QgsMapLayerProxyModel::lessThan( const QModelIndex &left, const QModelIndex &right ) const +{ + // default mode is alphabetical order + QString leftId = sourceModel()->data( left ).toString(); + QString rightId = sourceModel()->data( right ).toString(); + return QString::localeAwareCompare( leftId, rightId ) < 0; +} diff --git a/src/gui/qgsmaplayerproxymodel.h b/src/gui/qgsmaplayerproxymodel.h new file mode 100644 index 000000000000..bd8d1f7866f2 --- /dev/null +++ b/src/gui/qgsmaplayerproxymodel.h @@ -0,0 +1,75 @@ +/*************************************************************************** + qgsmaplayerproxymodel.h + -------------------------------------- + Date : 01.04.2014 + Copyright : (C) 2014 Denis Rouzaud + Email : denis.rouzaud@gmail.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. * +* * +***************************************************************************/ + +#ifndef QGSMAPLAYERPROXYMODEL_H +#define QGSMAPLAYERPROXYMODEL_H + +#include + +class QgsMapLayerModel; + +/** + * @brief The QgsMapLayerProxModel class provides an easy to use model to display the list of layers in widgets. + * @note added in 2.3 + */ +class GUI_EXPORT QgsMapLayerProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + public: + enum Filter + { + NoFilter = 1, + RasterLayer = 2, + NoGeometry = 4, + PointLayer = 8, + LineLayer = 16, + PolygonLayer = 32, + HasGeometry = PointLayer | LineLayer | PolygonLayer, + VectorLayer = NoGeometry | HasGeometry + }; + Q_DECLARE_FLAGS( Filters, Filter ) + + /** + * @brief QgsMapLayerProxModel creates a proxy model with a QgsMapLayerModel as source model. + * It can be used to filter the layers list in a widget. + */ + explicit QgsMapLayerProxyModel( QObject *parent = 0 ); + + /** + * @brief layerModel returns the QgsMapLayerModel used in this QSortFilterProxyModel + */ + QgsMapLayerModel* sourceLayerModel() {return mModel;} + + /** + * @brief setFilters set flags that affect how layers are filtered + * @param filters are Filter flags + * @note added in 2.3 + */ + QgsMapLayerProxyModel* setFilters( Filters filters ); + const Filters& filters() const { return mFilters; } + + private: + Filters mFilters; + QgsMapLayerModel* mModel; + + // QSortFilterProxyModel interface + public: + bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const; + bool lessThan( const QModelIndex &left, const QModelIndex &right ) const; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS( QgsMapLayerProxyModel::Filters ) + +#endif // QGSMAPLAYERPROXYMODEL_H diff --git a/src/ui/qgsatlascompositionwidgetbase.ui b/src/ui/qgsatlascompositionwidgetbase.ui index c41181b826e5..da8a92ce862d 100644 --- a/src/ui/qgsatlascompositionwidgetbase.ui +++ b/src/ui/qgsatlascompositionwidgetbase.ui @@ -131,7 +131,7 @@ - + 0 @@ -206,7 +206,7 @@ - + @@ -284,9 +284,19 @@ QgsCollapsibleGroupBoxBasic QGroupBox -
qgscollapsiblegroupbox.h
+
qgscollapsiblegroupbox.h
1
+ + QgsMapLayerComboBox + QComboBox +
qgsmaplayercombobox.h
+
+ + QgsFieldComboBox + QComboBox +
qgsfieldcombobox.h
+
diff --git a/src/ui/qgsdxfexportdialogbase.ui b/src/ui/qgsdxfexportdialogbase.ui index 0d0b217d36a7..3b17daeadaaf 100644 --- a/src/ui/qgsdxfexportdialogbase.ui +++ b/src/ui/qgsdxfexportdialogbase.ui @@ -6,8 +6,8 @@ 0 0 - 377 - 292 + 406 + 293 @@ -80,7 +80,11 @@
- + + + QAbstractItemView::NoSelection + + diff --git a/tests/src/core/testqgsatlascomposition.cpp b/tests/src/core/testqgsatlascomposition.cpp index dfb54e4f6074..81f544b5a73e 100644 --- a/tests/src/core/testqgsatlascomposition.cpp +++ b/tests/src/core/testqgsatlascomposition.cpp @@ -330,7 +330,7 @@ void TestQgsAtlasComposition::sorting_render() mAtlas->setHideCoverage( false ); mAtlas->setSortFeatures( true ); - mAtlas->setSortKeyAttributeIndex( 4 ); // departement name + mAtlas->setSortKeyAttributeName( "NAME_1" ); // departement name mAtlas->setSortAscending( false ); mAtlas->beginRender();