From dd88fa99f39ee039f0e6a387eeba5b5be62bb045 Mon Sep 17 00:00:00 2001 From: Matthias Kuhn Date: Thu, 28 Apr 2016 15:47:43 +0200 Subject: [PATCH] [feature] New configuration options for attribute table * Allow reordering the attribute table columns * Allow adding a new column to trigger an action to the attribute table --- python/core/core.sip | 1 + python/core/qgsattributetableconfig.sip | 78 +++++++++ python/core/qgsvectorlayer.sip | 12 ++ .../qgsattributetablefiltermodel.sip | 31 ++++ .../attributetable/qgsattributetableview.sip | 2 +- python/gui/attributetable/qgsdualview.sip | 13 ++ .../qgsorganizetablecolumnsdialog.sip | 13 +- src/app/qgsattributetabledialog.cpp | 14 +- src/core/CMakeLists.txt | 3 +- src/core/geometry/qgsabstractgeometryv2.h | 1 - src/core/qgsattributetableconfig.cpp | 150 ++++++++++++++++++ src/core/qgsattributetableconfig.h | 90 +++++++++++ src/core/qgscrscache.h | 1 - src/core/qgsvectorlayer.cpp | 20 ++- src/core/qgsvectorlayer.h | 24 ++- .../qgsattributetabledelegate.cpp | 37 +++-- .../qgsattributetabledelegate.h | 11 +- .../qgsattributetablefiltermodel.cpp | 117 ++++++++++++-- .../qgsattributetablefiltermodel.h | 39 ++++- .../attributetable/qgsattributetablemodel.h | 7 +- .../attributetable/qgsattributetableview.cpp | 68 ++++++-- .../attributetable/qgsattributetableview.h | 7 +- src/gui/attributetable/qgsdualview.cpp | 5 + src/gui/attributetable/qgsdualview.h | 11 +- .../qgsorganizetablecolumnsdialog.cpp | 69 +++++--- .../qgsorganizetablecolumnsdialog.h | 10 +- src/ui/qgsorganizetablecolumnsdialog.ui | 13 +- 27 files changed, 740 insertions(+), 107 deletions(-) create mode 100644 python/core/qgsattributetableconfig.sip create mode 100644 src/core/qgsattributetableconfig.cpp create mode 100644 src/core/qgsattributetableconfig.h diff --git a/python/core/core.sip b/python/core/core.sip index 1c180a06233..d644ef44014 100644 --- a/python/core/core.sip +++ b/python/core/core.sip @@ -22,6 +22,7 @@ %Include qgsaction.sip %Include qgsactionmanager.sip %Include qgsattributeaction.sip +%Include qgsattributetableconfig.sip %Include qgsbrowsermodel.sip %Include qgsclipper.sip %Include qgscolorscheme.sip diff --git a/python/core/qgsattributetableconfig.sip b/python/core/qgsattributetableconfig.sip new file mode 100644 index 00000000000..95294e77e99 --- /dev/null +++ b/python/core/qgsattributetableconfig.sip @@ -0,0 +1,78 @@ +/*************************************************************************** + qgsattributetableconfig.h - QgsAttributeTableConfig + + --------------------- + begin : 27.4.2016 + copyright : (C) 2016 by Matthias Kuhn + email : matthias@opengis.ch + *************************************************************************** + * * + * 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. * + * * + ***************************************************************************/ + +/** + * This is a container for configuration of the attribute table. + * The configuration is specific for one vector layer. + */ + +class QgsAttributeTableConfig +{ +%TypeHeaderCode +#include +%End + public: + /** + * The type of an attribute table column. + */ + enum Type + { + Field, //!< This column represents a field + Action //!< This column represents an action widget + }; + + /** + * Defines the configuration of a column in the attribute table. + */ + struct ColumnConfig + { + QgsAttributeTableConfig::Type mType; //!< The type of this column. + QString mName; //!< The name of the attribute if this column represents a field + bool mHidden; //!< Flag that controls if the column is hidden + }; + + QgsAttributeTableConfig(); + + /** + * Get the list with all columns and their configuration. + * The list order defines the order of appearance. + */ + QVector columns() const; + + /** + * Set the list of columns visible in the attribute table. + * The list order defines the order of appearance. + */ + void setColumns( const QVector& columns ); + + /** + * Update the configuration with the given fields. + * Any field which is present in the configuration but not present in the + * parameter fields will be removed. Any field which is in the parameter + * fields but not in the configuration will be appended. + */ + void update( const QgsFields& fields ); + + /** + * Serialize to XML on layer save + */ + void writeXml( QDomNode& node ) const; + + /** + * Deserialize to XML on layer load + */ + void readXml( const QDomNode& node ); +}; diff --git a/python/core/qgsvectorlayer.sip b/python/core/qgsvectorlayer.sip index 6018129b0e2..67c75877564 100644 --- a/python/core/qgsvectorlayer.sip +++ b/python/core/qgsvectorlayer.sip @@ -1321,6 +1321,18 @@ class QgsVectorLayer : QgsMapLayer */ QgsConditionalLayerStyles *conditionalStyles() const; + /** + * Get the attribute table configuration object. + * This defines the appearance of the attribute table. + */ + QgsAttributeTableConfig attributeTableConfig() const; + + /** + * Set the attribute table configuration object. + * This defines the appearance of the attribute table. + */ + void setAttributeTableConfig( const QgsAttributeTableConfig& attributeTableConfig ); + public slots: /** * Select feature by its ID diff --git a/python/gui/attributetable/qgsattributetablefiltermodel.sip b/python/gui/attributetable/qgsattributetablefiltermodel.sip index dd85e9aeeba..128b615d529 100644 --- a/python/gui/attributetable/qgsattributetablefiltermodel.sip +++ b/python/gui/attributetable/qgsattributetablefiltermodel.sip @@ -13,6 +13,18 @@ class QgsAttributeTableFilterModel: QSortFilterProxyModel, QgsFeatureModel ShowEdited }; + enum ColumnType + { + ColumnTypeField, //!< This column shows a field + ColumnTypeActionButton //!< This column shows action buttons + }; + + enum Role + { + TypeRole = QgsAttributeTableModel::UserRole //!< The type of a given column + }; + + /** * * Make sure, the master model is already loaded, so the selection will get synchronized. @@ -99,6 +111,25 @@ class QgsAttributeTableFilterModel: QSortFilterProxyModel, QgsFeatureModel /** Returns the map canvas*/ QgsMapCanvas* mapCanvas() const; + virtual QVariant data( const QModelIndex& index, int role ) const; + + QVariant headerData( int section, Qt::Orientation orientation, int role ) const; + + /** + * Get the index of the first column that contains an action widget. + * Returns -1 if none is defined. + */ + int actionColumnIndex() const; + + int columnCount( const QModelIndex &parent ) const; + + /** + * Set the attribute table configuration to control which fields are shown, + * in which order they are shown as well as if and where an action column + * is shown. + */ + void setAttributeTableConfig( const QgsAttributeTableConfig& config ); + protected: /** * Returns true if the source row will be accepted diff --git a/python/gui/attributetable/qgsattributetableview.sip b/python/gui/attributetable/qgsattributetableview.sip index 5a3eca777a3..3637099b0dc 100644 --- a/python/gui/attributetable/qgsattributetableview.sip +++ b/python/gui/attributetable/qgsattributetableview.sip @@ -19,7 +19,7 @@ class QgsAttributeTableView : QTableView /** * This event filter is installed on the verticalHeader to intercept mouse press and release * events. These are used to disable / enable live synchronisation with the map canvas selection - * which can be slow due to recurring canvas repaints. Updating the + * which can be slow due to recurring canvas repaints. * * @param object The object which is the target of the event. * @param event The intercepted event diff --git a/python/gui/attributetable/qgsdualview.sip b/python/gui/attributetable/qgsdualview.sip index c660d6da117..1ca535b4c8f 100644 --- a/python/gui/attributetable/qgsdualview.sip +++ b/python/gui/attributetable/qgsdualview.sip @@ -65,6 +65,11 @@ class QgsDualView : QStackedWidget */ void setFilterMode( QgsAttributeTableFilterModel::FilterMode filterMode ); + /** + * Get the filter mode + * + * @return the filter mode + */ QgsAttributeTableFilterModel::FilterMode filterMode(); /** @@ -98,6 +103,9 @@ class QgsDualView : QStackedWidget */ void setFilteredFeatures( const QgsFeatureIds& filteredFeatures ); + /** + * Get a list of currently visible feature ids. + */ QgsFeatureIds filteredFeatures(); /** @@ -112,6 +120,11 @@ class QgsDualView : QStackedWidget void setFeatureSelectionManager( QgsIFeatureSelectionManager* featureSelectionManager ); QgsAttributeTableView* tableView(); + /** + * Set the attribute table config which should be used to control + * the appearance of the attribute table. + */ + void setAttributeTableConfig( const QgsAttributeTableConfig& config ); protected: /** diff --git a/python/gui/attributetable/qgsorganizetablecolumnsdialog.sip b/python/gui/attributetable/qgsorganizetablecolumnsdialog.sip index 48751a940e4..43db7c84737 100644 --- a/python/gui/attributetable/qgsorganizetablecolumnsdialog.sip +++ b/python/gui/attributetable/qgsorganizetablecolumnsdialog.sip @@ -8,16 +8,19 @@ class QgsOrganizeTableColumnsDialog : QDialog /** * Constructor * @param vl The concerned vector layer - * @param visible the cuurent list of visible fields name + * @param visible the current list of visible fields name * @param parent parent object * @param flags window flags */ - QgsOrganizeTableColumnsDialog( const QgsVectorLayer* vl, QStringList visible, QWidget *parent /TransferThis/ = nullptr, Qt::WindowFlags flags = Qt::Window ); + QgsOrganizeTableColumnsDialog(const QgsVectorLayer* vl, QWidget* parent = nullptr, Qt::WindowFlags flags = Qt::Window ); + + /** + * Destructor + */ ~QgsOrganizeTableColumnsDialog(); /** - * Get the selected fields name - * @return The selected fields name + * Get the updated configuration */ - QStringList selectedFields(); + QgsAttributeTableConfig config() const; }; diff --git a/src/app/qgsattributetabledialog.cpp b/src/app/qgsattributetabledialog.cpp index 5c1cc05bacd..fa8aedb8baf 100644 --- a/src/app/qgsattributetabledialog.cpp +++ b/src/app/qgsattributetabledialog.cpp @@ -125,6 +125,7 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid // Initialize dual view mMainView->init( mLayer, QgisApp::instance()->mapCanvas(), r, context ); + mMainView->setAttributeTableConfig( mLayer->attributeTableConfig() ); // Initialize filter gui elements mFilterActionMapper = new QSignalMapper( this ); @@ -776,17 +777,12 @@ void QgsAttributeTableDialog::on_mFilterTableFields_clicked() return; } - QgsOrganizeTableColumnsDialog dialog( mLayer, mVisibleFields ); + QgsOrganizeTableColumnsDialog dialog( mLayer ); if ( dialog.exec() == QDialog::Accepted ) { - mVisibleFields = dialog.selectedFields(); - - const QgsFields layerAttributes = mLayer->fields(); - for ( int idx = 0; idx < layerAttributes.count(); ++idx ) - { - mMainView->tableView()->setColumnHidden( - idx, !mVisibleFields.contains( layerAttributes[idx].name() ) ); - } + QgsAttributeTableConfig config = dialog.config(); + mLayer->setAttributeTableConfig( config ); + mMainView->setAttributeTableConfig( config ); } } diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 139f8f05aa4..9b92f40ddcc 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -79,6 +79,7 @@ SET(QGIS_CORE_SRCS qgsapplication.cpp qgsaction.cpp qgsactionmanager.cpp + qgsattributetableconfig.cpp qgsbrowsermodel.cpp qgscachedfeatureiterator.cpp qgscacheindex.cpp @@ -591,7 +592,7 @@ SET(QGIS_CORE_HDRS qgis.h qgsaction.h - qgsactionmanager.h + qgsattributetableconfig.h qgsattributeaction.h qgscachedfeatureiterator.h qgscacheindex.h diff --git a/src/core/geometry/qgsabstractgeometryv2.h b/src/core/geometry/qgsabstractgeometryv2.h index e6f72d6a555..0e52e38242a 100644 --- a/src/core/geometry/qgsabstractgeometryv2.h +++ b/src/core/geometry/qgsabstractgeometryv2.h @@ -23,7 +23,6 @@ email : marco.hugentobler at sourcepole dot com #include -class QgsCoordinateTransform; class QgsMapToPixel; class QgsCurveV2; class QgsMultiCurveV2; diff --git a/src/core/qgsattributetableconfig.cpp b/src/core/qgsattributetableconfig.cpp new file mode 100644 index 00000000000..54228e900c6 --- /dev/null +++ b/src/core/qgsattributetableconfig.cpp @@ -0,0 +1,150 @@ +/*************************************************************************** + qgsattributetableconfig.cpp - QgsAttributeTableConfig + + --------------------- + begin : 27.4.2016 + copyright : (C) 2016 by mku + email : [your-email-here] + *************************************************************************** + * * + * 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 "qgsattributetableconfig.h" + +#include + +QgsAttributeTableConfig::QgsAttributeTableConfig() +{ + +} + +QVector QgsAttributeTableConfig::columns() const +{ + return mColumns; +} + +void QgsAttributeTableConfig::setColumns( const QVector& columns ) +{ + mColumns = columns; +} + +void QgsAttributeTableConfig::update( const QgsFields& fields ) +{ + QStringList columns; + + bool containsActionColumn = false; + + for ( int i = mColumns.count() - 1; i >= 0; --i ) + { + const ColumnConfig& column = mColumns.at( i ); + if ( column.mType == Field ) + { + if ( fields.fieldNameIndex( column.mName ) == -1 ) + { + mColumns.remove( i ); + } + else + { + columns.append( column.mName ); + } + } + else if ( column.mType == Action ) + { + containsActionColumn = true; + } + } + + Q_FOREACH ( const QgsField& field, fields ) + { + if ( !columns.contains( field.name() ) ) + { + ColumnConfig newColumn; + newColumn.mHidden = false; + newColumn.mType = Field; + newColumn.mName = field.name(); + + mColumns.append( newColumn ); + } + } + + if ( !containsActionColumn ) + { + ColumnConfig actionConfig; + + actionConfig.mType = Action; + actionConfig.mHidden = true; + + mColumns.append( actionConfig ); + } +} + + +void QgsAttributeTableConfig::readXml( const QDomNode& node ) +{ + mColumns.clear(); + + QDomNode configNode = node.namedItem( "attributetableconfig" ); + if ( !configNode.isNull() ) + { + QDomNode columnsNode = configNode.toElement().namedItem( "columns" ); + + QDomNodeList columns = columnsNode.childNodes(); + + for ( int i = 0; i < columns.size(); ++i ) + { + QDomElement columnElement = columns.at( i ).toElement(); + + ColumnConfig column; + + if ( columnElement.attribute( "type" ) == "actions" ) + { + column.mType = Action; + } + else + { + column.mType = Field; + column.mName = columnElement.attribute( "name" ); + } + + column.mHidden = columnElement.attribute( "hidden" ) == "1"; + + mColumns.append( column ); + } + } +} + +void QgsAttributeTableConfig::writeXml( QDomNode& node ) const +{ + QDomDocument doc( node.ownerDocument() ); + + QDomElement configElement = doc.createElement( "attributetableconfig" ); + + QDomElement columnsElement = doc.createElement( "columns" ); + + Q_FOREACH ( const ColumnConfig& column, mColumns ) + { + QDomElement columnElement = doc.createElement( "column" ); + + if ( column.mType == Action ) + { + columnElement.setAttribute( "type", "actions" ); + } + else + { + columnElement.setAttribute( "type", "field" ); + columnElement.setAttribute( "name", column.mName ); + } + + columnElement.setAttribute( "hidden", column.mHidden ); + + columnsElement.appendChild( columnElement ); + } + + configElement.appendChild( columnsElement ); + + node.appendChild( configElement ); +} diff --git a/src/core/qgsattributetableconfig.h b/src/core/qgsattributetableconfig.h new file mode 100644 index 00000000000..15391bc33a6 --- /dev/null +++ b/src/core/qgsattributetableconfig.h @@ -0,0 +1,90 @@ +/*************************************************************************** + qgsattributetableconfig.h - QgsAttributeTableConfig + + --------------------- + begin : 27.4.2016 + copyright : (C) 2016 by Matthias Kuhn + email : matthias@opengis.ch + *************************************************************************** + * * + * 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 QGSATTRIBUTETABLECONFIG_H +#define QGSATTRIBUTETABLECONFIG_H + +#include +#include +#include + +#include "qgsfield.h" + +/** + * This is a container for configuration of the attribute table. + * The configuration is specific for one vector layer. + */ + +class CORE_EXPORT QgsAttributeTableConfig +{ + public: + /** + * The type of an attribute table column. + */ + enum Type + { + Field, //!< This column represents a field + Action //!< This column represents an action widget + }; + + /** + * Defines the configuration of a column in the attribute table. + */ + struct ColumnConfig + { + Type mType; //!< The type of this column. + QString mName; //!< The name of the attribute if this column represents a field + bool mHidden; //!< Flag that controls if the column is hidden + }; + + QgsAttributeTableConfig(); + + /** + * Get the list with all columns and their configuration. + * The list order defines the order of appearance. + */ + QVector columns() const; + + /** + * Set the list of columns visible in the attribute table. + * The list order defines the order of appearance. + */ + void setColumns( const QVector& columns ); + + /** + * Update the configuration with the given fields. + * Any field which is present in the configuration but not present in the + * parameter fields will be removed. Any field which is in the parameter + * fields but not in the configuration will be appended. + */ + void update( const QgsFields& fields ); + + /** + * Serialize to XML on layer save + */ + void writeXml( QDomNode& node ) const; + + /** + * Deserialize to XML on layer load + */ + void readXml( const QDomNode& node ); + + private: + QVector mColumns; +}; + +Q_DECLARE_METATYPE( QgsAttributeTableConfig::ColumnConfig ) + +#endif // QGSATTRIBUTETABLECONFIG_H diff --git a/src/core/qgscrscache.h b/src/core/qgscrscache.h index 077dcbc2d11..14c4a8e6e73 100644 --- a/src/core/qgscrscache.h +++ b/src/core/qgscrscache.h @@ -42,7 +42,6 @@ class CORE_EXPORT QgsCoordinateTransformCache void invalidateCrs( const QString& crsAuthId ); private: - static QgsCoordinateTransformCache* mInstance; QMultiHash< QPair< QString, QString >, QgsCoordinateTransform* > mTransforms; //same auth_id pairs might have different datum transformations QgsCoordinateTransformCache(); diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index 81656aef89a..8c20f119e04 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -1926,8 +1926,6 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage // process the attribute actions mActions->readXML( node ); - mEditFormConfig->readXml( node ); - QDomNode annotationFormNode = node.namedItem( "annotationform" ); if ( !annotationFormNode.isNull() ) { @@ -1988,6 +1986,8 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage mEditFormConfig->readXml( node ); + mAttributeTableConfig.readXml( node ); + mConditionalStyles->readXml( node ); return true; @@ -2154,6 +2154,8 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString& mEditFormConfig->writeXml( node ); + mAttributeTableConfig.writeXml( node ); + mConditionalStyles->writeXml( node, doc ); return true; @@ -2266,11 +2268,11 @@ void QgsVectorLayer::addAttributeAlias( int attIndex, const QString& aliasString QString QgsVectorLayer::attributeAlias( int attributeIndex ) const { if ( attributeIndex < 0 || attributeIndex >= fields().count() ) - return ""; + return QString(); QString name = fields().at( attributeIndex ).name(); - return mAttributeAliasMap.value( name, "" ); + return mAttributeAliasMap.value( name, QString() ); } QString QgsVectorLayer::attributeDisplayName( int attributeIndex ) const @@ -3591,6 +3593,16 @@ void QgsVectorLayer::readSldLabeling( const QDomNode& node ) } } +QgsAttributeTableConfig QgsVectorLayer::attributeTableConfig() const +{ + return mAttributeTableConfig; +} + +void QgsVectorLayer::setAttributeTableConfig( const QgsAttributeTableConfig& attributeTableConfig ) +{ + mAttributeTableConfig = attributeTableConfig; +} + void QgsVectorLayer::setDiagramLayerSettings( const QgsDiagramLayerSettings& s ) { if ( !mDiagramLayerSettings ) diff --git a/src/core/qgsvectorlayer.h b/src/core/qgsvectorlayer.h index 36c4bacfd6c..70616daed98 100644 --- a/src/core/qgsvectorlayer.h +++ b/src/core/qgsvectorlayer.h @@ -34,6 +34,7 @@ #include "qgssnapper.h" #include "qgsvectorsimplifymethod.h" #include "qgseditformconfig.h" +#include "qgsattributetableconfig.h" class QPainter; class QImage; @@ -631,7 +632,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer * The pointer which is returned directly points to the actions object * which is used by the layer, so any changes are immediately applied. */ - QgsActionManager *actions() { return mActions; } + QgsActionManager* actions() { return mActions; } /** * The number of features that are selected in this layer @@ -1321,7 +1322,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer */ void clearAttributeEditorWidgets() { mEditFormConfig->clearTabs(); } - /** Returns the alias of an attribute name or an empty string if there is no alias */ + /** + * Returns the alias of an attribute name or a null string if there is no alias. + * + * @see {@attributeDisplayName( int attributeIndex )} which returns the field name + * if no alias is defined. + */ QString attributeAlias( int attributeIndex ) const; /** Convenience function that returns the attribute alias if defined or the field name else */ @@ -1686,6 +1692,18 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer */ QgsConditionalLayerStyles *conditionalStyles() const; + /** + * Get the attribute table configuration object. + * This defines the appearance of the attribute table. + */ + QgsAttributeTableConfig attributeTableConfig() const; + + /** + * Set the attribute table configuration object. + * This defines the appearance of the attribute table. + */ + void setAttributeTableConfig( const QgsAttributeTableConfig& attributeTableConfig ); + public slots: /** * Select feature by its ID @@ -2088,6 +2106,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer QgsFeatureIds mDeletedFids; + QgsAttributeTableConfig mAttributeTableConfig; + friend class QgsVectorLayerFeatureSource; }; diff --git a/src/gui/attributetable/qgsattributetabledelegate.cpp b/src/gui/attributetable/qgsattributetabledelegate.cpp index 4e60d74f3ec..2dd28198aa4 100644 --- a/src/gui/attributetable/qgsattributetabledelegate.cpp +++ b/src/gui/attributetable/qgsattributetabledelegate.cpp @@ -118,29 +118,36 @@ void QgsAttributeTableDelegate::setFeatureSelectionModel( QgsFeatureSelectionMod mFeatureSelectionModel = featureSelectionModel; } +void QgsAttributeTableDelegate::setActionWidgetImage( const QImage& image ) +{ + mActionWidgetImage = image; +} + void QgsAttributeTableDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const { - QgsFeatureId fid = index.model()->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong(); + QgsAttributeTableFilterModel::ColumnType columnType = static_cast( index.model()->data( index, QgsAttributeTableFilterModel::TypeRole ).toInt() ); - QStyleOptionViewItem myOpt = option; - - if ( index.model()->data( index, Qt::EditRole ).isNull() ) + if ( columnType == QgsAttributeTableFilterModel::ColumnTypeActionButton ) { - myOpt.font.setItalic( true ); - myOpt.palette.setColor( QPalette::Text, QColor( "gray" ) ); - } - - if ( mFeatureSelectionModel && mFeatureSelectionModel->isSelected( fid ) ) - myOpt.state |= QStyle::State_Selected; - - - if ( index.column() == 0 ) - { - painter->drawImage( QPoint( 0, 0 ), mActionButtonImage ); + QRect r = option.rect.adjusted( -1, 0, 0, 0 ); + painter->drawImage( r.x(), r.y(), mActionWidgetImage ); } else { + QgsFeatureId fid = index.model()->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong(); + + QStyleOptionViewItem myOpt = option; + + if ( index.model()->data( index, Qt::EditRole ).isNull() ) + { + myOpt.font.setItalic( true ); + myOpt.palette.setColor( QPalette::Text, QColor( "gray" ) ); + } + + if ( mFeatureSelectionModel && mFeatureSelectionModel->isSelected( fid ) ) + myOpt.state |= QStyle::State_Selected; + QItemDelegate::paint( painter, myOpt, index ); if ( option.state & QStyle::State_HasFocus ) diff --git a/src/gui/attributetable/qgsattributetabledelegate.h b/src/gui/attributetable/qgsattributetabledelegate.h index d91821af1d7..319913820b7 100644 --- a/src/gui/attributetable/qgsattributetabledelegate.h +++ b/src/gui/attributetable/qgsattributetabledelegate.h @@ -46,7 +46,6 @@ class GUI_EXPORT QgsAttributeTableDelegate : public QItemDelegate : QItemDelegate( parent ) , mLayer( nullptr ) , mFeatureSelectionModel( nullptr ) - , mActionButtonWidget( nullptr ) { } @@ -80,13 +79,15 @@ class GUI_EXPORT QgsAttributeTableDelegate : public QItemDelegate void setFeatureSelectionModel( QgsFeatureSelectionModel* featureSelectionModel ); - private: - QWidget* createActionWidget( QWidget* parent, QgsVectorLayer* layer ) const; + /** + * Set an image that represents an action widget + */ + void setActionWidgetImage( const QImage& image ); + private: QgsVectorLayer* mLayer; QgsFeatureSelectionModel* mFeatureSelectionModel; - QWidget* mActionButtonWidget; - QImage mActionButtonImage; + QImage mActionWidgetImage; }; #endif //QGSATTRIBUTETABLEDELEGATE_H diff --git a/src/gui/attributetable/qgsattributetablefiltermodel.cpp b/src/gui/attributetable/qgsattributetablefiltermodel.cpp index a804fdd1bf5..389abf6705b 100644 --- a/src/gui/attributetable/qgsattributetablefiltermodel.cpp +++ b/src/gui/attributetable/qgsattributetablefiltermodel.cpp @@ -69,13 +69,93 @@ void QgsAttributeTableFilterModel::sort( int column, Qt::SortOrder order ) QVariant QgsAttributeTableFilterModel::data( const QModelIndex& index, int role ) const { - if ( index.column() == 0 ) - return "Wow"; - else + if ( mColumnMapping.at( index.column() ) == -1 ) // actions { - QModelIndex sourceIndex = QSortFilterProxyModel::index( index.row(), index.column() - 1, index.parent() ); - return QSortFilterProxyModel::data( sourceIndex, role ); + if ( role == TypeRole ) + return ColumnTypeActionButton; + else if ( role == QgsAttributeTableModel::FeatureIdRole ) + { + QModelIndex fieldIndex = QSortFilterProxyModel::mapToSource( QSortFilterProxyModel::index( index.row(), 0, index.parent() ) ); + return sourceModel()->data( fieldIndex, QgsAttributeTableModel::FeatureIdRole ); + } } + else if ( role == TypeRole ) + return ColumnTypeField; + + return QSortFilterProxyModel::data( index, role ); +} + +QVariant QgsAttributeTableFilterModel::headerData( int section, Qt::Orientation orientation, int role ) const +{ + if ( orientation == Qt::Horizontal ) + { + if ( mColumnMapping.at( section ) == -1 && role == Qt::DisplayRole ) + return tr( "Actions" ); + else + return QSortFilterProxyModel::headerData( section, orientation, role ); + } + else + return QSortFilterProxyModel::headerData( section, orientation, role ); +} + +int QgsAttributeTableFilterModel::actionColumnIndex() const +{ + return mColumnMapping.indexOf( -1 ); +} + +int QgsAttributeTableFilterModel::columnCount( const QModelIndex& parent ) const +{ + Q_UNUSED( parent ); + return mColumnMapping.count(); +} + +void QgsAttributeTableFilterModel::setAttributeTableConfig( const QgsAttributeTableConfig& config ) +{ + int columnIndex = 0; + int configIndex = 0; + bool resetModel = false; + + for ( ; configIndex < config.columns().size(); ++configIndex ) + { + const QgsAttributeTableConfig::ColumnConfig& columnConfig = config.columns().at( configIndex ); + + // Hidden? No reason for further checks + if ( columnConfig.mHidden ) + continue; + + // Do the previous and current definition match? + if ( mColumnMapping.size() > columnIndex ) + { + if (( columnConfig.mType == QgsAttributeTableConfig::Action && mColumnMapping.at( columnIndex ) == -1 ) || + ( columnConfig.mType == QgsAttributeTableConfig::Field && mColumnMapping.at( columnIndex ) == layer()->fieldNameIndex( columnConfig.mName ) ) ) + { + ++columnIndex; + continue; + } + else // There is a mismatch between previous and current configuration: remove all remaining columns, they will be readded + { + mColumnMapping.remove( columnIndex, mColumnMapping.count() - columnIndex ); + } + } + + if ( ! resetModel ) + { + beginResetModel(); + resetModel = true; + } + + + // New column? append + Q_ASSERT( mColumnMapping.size() == columnIndex ); + if ( columnConfig.mType == QgsAttributeTableConfig::Action ) + mColumnMapping.append( -1 ); + else + mColumnMapping.append( layer()->fieldNameIndex( columnConfig.mName ) ); + + ++columnIndex; + } + if ( resetModel ) + endResetModel(); } void QgsAttributeTableFilterModel::setSelectedOnTop( bool selectedOnTop ) @@ -96,6 +176,12 @@ void QgsAttributeTableFilterModel::setSourceModel( QgsAttributeTableModel* sourc { mTableModel = sourceModel; + mColumnMapping.append( -1 ); // -1 for actions column + for ( int i = 0; i < mTableModel->columnCount(); ++i ) + { + mColumnMapping.append( i ); + } + QSortFilterProxyModel::setSourceModel( sourceModel ); } @@ -310,14 +396,23 @@ QModelIndexList QgsAttributeTableFilterModel::fidToIndexList( QgsFeatureId fid ) return indexes; } -QModelIndex QgsAttributeTableFilterModel::mapToMaster( const QModelIndex &proxyIndex ) const +QModelIndex QgsAttributeTableFilterModel::mapToSource( const QModelIndex& proxyIndex ) const { - // Master is source - return mapToSource( proxyIndex ); + if ( !proxyIndex.isValid() ) + return QModelIndex(); + + int sourceColumn = mColumnMapping.at( proxyIndex.column() ); + + // For the action column there is no matching column in the source model: invalid + if ( sourceColumn == -1 ) + return QModelIndex(); + + return QSortFilterProxyModel::mapToSource( index( proxyIndex.row(), mColumnMapping.at( proxyIndex.column() ), proxyIndex.parent() ) ); } -QModelIndex QgsAttributeTableFilterModel::mapFromMaster( const QModelIndex &sourceIndex ) const +QModelIndex QgsAttributeTableFilterModel::mapFromSource( const QModelIndex& sourceIndex ) const { - // Master is source - return mapFromSource( sourceIndex ); + QModelIndex proxyIndex = QSortFilterProxyModel::mapFromSource( sourceIndex ); + + return index( proxyIndex.row(), mColumnMapping.indexOf( proxyIndex.column() ), proxyIndex.parent() ); } diff --git a/src/gui/attributetable/qgsattributetablefiltermodel.h b/src/gui/attributetable/qgsattributetablefiltermodel.h index 894e854860a..18e6b612db6 100644 --- a/src/gui/attributetable/qgsattributetablefiltermodel.h +++ b/src/gui/attributetable/qgsattributetablefiltermodel.h @@ -42,6 +42,17 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub ShowEdited }; + enum ColumnType + { + ColumnTypeField, //!< This column shows a field + ColumnTypeActionButton //!< This column shows action buttons + }; + + enum Role + { + TypeRole = QgsAttributeTableModel::UserRole //!< The type of a given column + }; + /** * @@ -137,11 +148,16 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub QgsFeatureId rowToId( const QModelIndex& row ); QModelIndex fidToIndex( QgsFeatureId fid ) override; + QModelIndexList fidToIndexList( QgsFeatureId fid ); - virtual QModelIndex mapToMaster( const QModelIndex &proxyIndex ) const; + inline QModelIndex mapToMaster( const QModelIndex& proxyIndex ) const { return mapToSource( proxyIndex ); } - virtual QModelIndex mapFromMaster( const QModelIndex &sourceIndex ) const; + inline QModelIndex mapFromMaster( const QModelIndex& sourceIndex ) const { return mapFromSource( sourceIndex ); } + + virtual QModelIndex mapToSource( const QModelIndex& proxyIndex ) const override; + + virtual QModelIndex mapFromSource( const QModelIndex& sourceIndex ) const override; /** * Sort by the given column using the given order. @@ -157,6 +173,23 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub virtual QVariant data( const QModelIndex& index, int role ) const override; + QVariant headerData( int section, Qt::Orientation orientation, int role ) const override; + + /** + * Get the index of the first column that contains an action widget. + * Returns -1 if none is defined. + */ + int actionColumnIndex() const; + + int columnCount( const QModelIndex &parent ) const override; + + /** + * Set the attribute table configuration to control which fields are shown, + * in which order they are shown as well as if and where an action column + * is shown. + */ + void setAttributeTableConfig( const QgsAttributeTableConfig& config ); + protected: /** * Returns true if the source row will be accepted @@ -195,6 +228,8 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub FilterMode mFilterMode; bool mSelectedOnTop; QgsAttributeTableModel* mTableModel; + + QVector mColumnMapping; }; #endif diff --git a/src/gui/attributetable/qgsattributetablemodel.h b/src/gui/attributetable/qgsattributetablemodel.h index 01a96be865d..f587f6d31a1 100644 --- a/src/gui/attributetable/qgsattributetablemodel.h +++ b/src/gui/attributetable/qgsattributetablemodel.h @@ -51,9 +51,10 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel public: enum Role { - SortRole = Qt::UserRole + 1, - FeatureIdRole = Qt::UserRole + 2, - FieldIndexRole = Qt::UserRole + 3 + SortRole = Qt::UserRole + 1, //!< Role used for sorting + FeatureIdRole, //!< Get the feature id of the feature in this row + FieldIndexRole, //!< Get the field index of this column + UserRole //!< Start further roles starting from this role }; public: diff --git a/src/gui/attributetable/qgsattributetableview.cpp b/src/gui/attributetable/qgsattributetableview.cpp index 4fa3afc7224..b0033e710b4 100644 --- a/src/gui/attributetable/qgsattributetableview.cpp +++ b/src/gui/attributetable/qgsattributetableview.cpp @@ -64,14 +64,10 @@ QgsAttributeTableView::QgsAttributeTableView( QWidget *parent ) connect( verticalHeader(), SIGNAL( sectionPressed( int ) ), this, SLOT( selectRow( int ) ) ); connect( verticalHeader(), SIGNAL( sectionEntered( int ) ), this, SLOT( _q_selectRow( int ) ) ); + connect( horizontalHeader(), SIGNAL( sectionResized( int, int, int ) ), this, SLOT( columnSizeChanged( int, int, int ) ) ); connect( horizontalHeader(), SIGNAL( sortIndicatorChanged( int, Qt::SortOrder ) ), this, SLOT( showHorizontalSortIndicator() ) ); } -QgsAttributeTableView::~QgsAttributeTableView() -{ - delete mActionPopup; -} - bool QgsAttributeTableView::eventFilter( QObject *object, QEvent *event ) { if ( object == verticalHeader()->viewport() ) @@ -123,6 +119,9 @@ void QgsAttributeTableView::setModel( QgsAttributeTableFilterModel* filterModel connect( mFeatureSelectionModel, SIGNAL( requestRepaint( QModelIndexList ) ), this, SLOT( repaintRequested( QModelIndexList ) ) ); connect( mFeatureSelectionModel, SIGNAL( requestRepaint() ), this, SLOT( repaintRequested() ) ); } + + mActionWidget = createActionWidget( 0 ); + mActionWidget->setVisible( false ); } void QgsAttributeTableView::setFeatureSelectionManager( QgsIFeatureSelectionManager* featureSelectionManager ) @@ -136,19 +135,35 @@ void QgsAttributeTableView::setFeatureSelectionManager( QgsIFeatureSelectionMana mFeatureSelectionModel->setFeatureSelectionManager( mFeatureSelectionManager ); } -QWidget* QgsAttributeTableView::createActionWidget() +QWidget* QgsAttributeTableView::createActionWidget( QgsFeatureId fid ) { QToolButton* toolButton = new QToolButton( this ); + toolButton->setPopupMode( QToolButton::MenuButtonPopup ); - for ( int i = 0; i < mFilterModel->layer()->actions()->size(); ++i ) + QgsActionManager* actions = mFilterModel->layer()->actions(); + + for ( int i = 0; i < actions->size(); ++i ) { - const QgsAction& action = mFilterModel->layer()->actions()->at( i ); + const QgsAction& action = actions->at( i ); - QAction* act = new QAction( action.icon(), action.shortTitle(), toolButton ); + QAction* act = new QAction( action.icon(), action.shortTitle().isEmpty() ? action.name() : action.shortTitle(), toolButton ); + act->setToolTip( action.name() ); + act->setData( i ); + act->setProperty( "fid", fid ); + + connect( act, SIGNAL( triggered( bool ) ), this, SLOT( actionTriggered() ) ); toolButton->addAction( act ); + + if ( actions->defaultAction() == i ) + toolButton->setDefaultAction( act ); } + if ( !toolButton->actions().isEmpty() && actions->defaultAction() == -1 ) + toolButton->setDefaultAction( toolButton->actions().first() ); + + updateActionImage( toolButton ); + return toolButton; } @@ -176,12 +191,12 @@ void QgsAttributeTableView::mouseReleaseEvent( QMouseEvent *event ) void QgsAttributeTableView::mouseMoveEvent( QMouseEvent *event ) { QModelIndex index = indexAt( event->pos() ); - if ( index.column() == 0 ) + if ( index.data( QgsAttributeTableFilterModel::TypeRole ) == QgsAttributeTableFilterModel::ColumnTypeActionButton ) { Q_ASSERT( index.isValid() ); if ( !indexWidget( index ) ) - setIndexWidget( index, createActionWidget() ); + setIndexWidget( index, createActionWidget( mFilterModel->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong() ) ); } setSelectionMode( QAbstractItemView::NoSelection ); @@ -246,7 +261,7 @@ void QgsAttributeTableView::contextMenuEvent( QContextMenuEvent* event ) if ( !vlayer ) return; - mActionPopup = new QMenu(); + mActionPopup = new QMenu( this ); mActionPopup->addAction( tr( "Select All" ), this, SLOT( selectAll() ), QKeySequence::SelectAll ); @@ -318,3 +333,32 @@ void QgsAttributeTableView::showHorizontalSortIndicator() { horizontalHeader()->setSortIndicatorShown( true ); } + +void QgsAttributeTableView::actionTriggered() +{ + QAction* action = qobject_cast( sender() ); + QgsFeatureId fid = action->property( "fid" ).toLongLong(); + + QgsFeature f; + mFilterModel->layerCache()->getFeatures( QgsFeatureRequest( fid ) ).nextFeature( f ); + + mFilterModel->layer()->actions()->doAction( action->data().toInt(), f ); +} + +void QgsAttributeTableView::columnSizeChanged( int index, int oldWidth, int newWidth ) +{ + Q_UNUSED( oldWidth ) + if ( mFilterModel->actionColumnIndex() == index ) + { + mActionWidget->resize( newWidth, mActionWidget->height() ); + updateActionImage( mActionWidget ); + } +} + +void QgsAttributeTableView::updateActionImage( QWidget* widget ) +{ + QImage image( widget->size(), QImage::Format_ARGB32_Premultiplied ); + QPainter painter( &image ); + widget->render( &painter ); + mTableDelegate->setActionWidgetImage( image ); +} diff --git a/src/gui/attributetable/qgsattributetableview.h b/src/gui/attributetable/qgsattributetableview.h index b4f287c5b89..8a6523ad7fd 100644 --- a/src/gui/attributetable/qgsattributetableview.h +++ b/src/gui/attributetable/qgsattributetableview.h @@ -47,7 +47,6 @@ class GUI_EXPORT QgsAttributeTableView : public QTableView public: QgsAttributeTableView( QWidget* parent = nullptr ); - virtual ~QgsAttributeTableView(); virtual void setModel( QgsAttributeTableFilterModel* filterModel ); @@ -140,9 +139,12 @@ class GUI_EXPORT QgsAttributeTableView : public QTableView private slots: void modelDeleted(); void showHorizontalSortIndicator(); + void actionTriggered(); + void columnSizeChanged( int index, int oldWidth, int newWidth ); private: - QWidget* createActionWidget(); + void updateActionImage( QWidget* widget ); + QWidget* createActionWidget( QgsFeatureId fid ); void selectRow( int row, bool anchor ); QgsAttributeTableModel* mMasterModel; @@ -154,6 +156,7 @@ class GUI_EXPORT QgsAttributeTableView : public QTableView QMenu *mActionPopup; int mRowSectionAnchor; QItemSelectionModel::SelectionFlag mCtrlDragSelectionFlag; + QWidget* mActionWidget; }; #endif diff --git a/src/gui/attributetable/qgsdualview.cpp b/src/gui/attributetable/qgsdualview.cpp index d4dd2811d8c..fe5ace09002 100644 --- a/src/gui/attributetable/qgsdualview.cpp +++ b/src/gui/attributetable/qgsdualview.cpp @@ -464,6 +464,11 @@ void QgsDualView::setFeatureSelectionManager( QgsIFeatureSelectionManager* featu mFeatureSelectionManager = featureSelectionManager; } +void QgsDualView::setAttributeTableConfig( const QgsAttributeTableConfig& config ) +{ + mFilterModel->setAttributeTableConfig( config ); +} + void QgsDualView::progress( int i, bool& cancel ) { if ( !mProgressDlg ) diff --git a/src/gui/attributetable/qgsdualview.h b/src/gui/attributetable/qgsdualview.h index 61083e112c0..b1cc57a746e 100644 --- a/src/gui/attributetable/qgsdualview.h +++ b/src/gui/attributetable/qgsdualview.h @@ -141,6 +141,9 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas */ void setFilteredFeatures( const QgsFeatureIds& filteredFeatures ); + /** + * Get a list of currently visible feature ids. + */ QgsFeatureIds filteredFeatures() { return mFilterModel->filteredFeatures(); } /** @@ -169,7 +172,13 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas * * @return The table view */ - QgsAttributeTableView* tableView() { return mTableView; }; + QgsAttributeTableView* tableView() { return mTableView; } + + /** + * Set the attribute table config which should be used to control + * the appearance of the attribute table. + */ + void setAttributeTableConfig( const QgsAttributeTableConfig& config ); protected: /** diff --git a/src/gui/attributetable/qgsorganizetablecolumnsdialog.cpp b/src/gui/attributetable/qgsorganizetablecolumnsdialog.cpp index 69c582ecbca..eda4a345d31 100644 --- a/src/gui/attributetable/qgsorganizetablecolumnsdialog.cpp +++ b/src/gui/attributetable/qgsorganizetablecolumnsdialog.cpp @@ -41,57 +41,76 @@ #include "qgseditorwidgetregistry.h" -QgsOrganizeTableColumnsDialog::QgsOrganizeTableColumnsDialog( const QgsVectorLayer* vl, const QStringList visble, QWidget *parent, Qt::WindowFlags flags ) +QgsOrganizeTableColumnsDialog::QgsOrganizeTableColumnsDialog( const QgsVectorLayer* vl, QWidget* parent, Qt::WindowFlags flags ) : QDialog( parent, flags ) { setupUi( this ); if ( vl ) { + QgsAttributeTableConfig config = vl->attributeTableConfig(); + config.update( vl->fields() ); + mFieldsList->clear(); - const QgsFields& layerAttributes = vl->fields(); - for ( int idx = 0; idx < layerAttributes.count(); ++idx ) + + Q_FOREACH ( const QgsAttributeTableConfig::ColumnConfig& columnConfig, config.columns() ) { - QListWidgetItem* item = new QListWidgetItem( layerAttributes[idx].name(), mFieldsList ); - item->setCheckState( visble.contains( layerAttributes[idx].name() ) ? Qt::Checked : Qt::Unchecked ); - switch ( vl->fields().fieldOrigin( idx ) ) + QListWidgetItem* item; + if ( columnConfig.mType == QgsAttributeTableConfig::Action ) { - case QgsFields::OriginExpression: - item->setIcon( QgsApplication::getThemeIcon( "/mIconExpression.svg" ) ); - break; + item = new QListWidgetItem( tr( "[Action Widget]" ), mFieldsList ); + item->setIcon( QgsApplication::getThemeIcon( "/propertyicons/action.svg" ) ); + } + else + { + int idx = vl->fieldNameIndex( columnConfig.mName ); + item = new QListWidgetItem( vl->attributeDisplayName( idx ), mFieldsList ); - case QgsFields::OriginJoin: - item->setIcon( QgsApplication::getThemeIcon( "/propertyicons/join.png" ) ); - break; + switch ( vl->fields().fieldOrigin( idx ) ) + { + case QgsFields::OriginExpression: + item->setIcon( QgsApplication::getThemeIcon( "/mIconExpression.svg" ) ); + break; - default: - item->setIcon( QgsApplication::getThemeIcon( "/propertyicons/attributes.png" ) ); - break; + case QgsFields::OriginJoin: + item->setIcon( QgsApplication::getThemeIcon( "/propertyicons/join.png" ) ); + break; + + default: + item->setIcon( QgsApplication::getThemeIcon( "/propertyicons/attributes.png" ) ); + break; + } } - item->setData( Qt::UserRole, idx ); + item->setCheckState( columnConfig.mHidden ? Qt::Unchecked : Qt::Checked ); + item->setData( Qt::UserRole, QVariant::fromValue( columnConfig ) ); } } QSettings settings; - restoreGeometry( settings.value( "/Windows/QgsFilterTableFieldsDialog/geometry" ).toByteArray() ); + restoreGeometry( settings.value( "/Windows/QgsOrganizeTableColumnsDialog/geometry" ).toByteArray() ); } QgsOrganizeTableColumnsDialog::~QgsOrganizeTableColumnsDialog() { QSettings settings; - settings.setValue( "/Windows/QgsFilterTableFieldsDialog/geometry", saveGeometry() ); + settings.setValue( "/Windows/QgsOrganizeTableColumnsDialog/geometry", saveGeometry() ); } -QStringList QgsOrganizeTableColumnsDialog::selectedFields() const +QgsAttributeTableConfig QgsOrganizeTableColumnsDialog::config() const { - QStringList selectionList; + QVector columns; + for ( int i = 0 ; i < mFieldsList->count() ; i++ ) { const QListWidgetItem* item = mFieldsList->item( i ); - if ( item->checkState() == Qt::Checked ) - { - selectionList.push_back( item->text() ); - } + QgsAttributeTableConfig::ColumnConfig columnConfig = item->data( Qt::UserRole ).value(); + + columnConfig.mHidden = item->checkState() == Qt::Unchecked; + + columns.append( columnConfig ); } - return selectionList; + + QgsAttributeTableConfig config; + config.setColumns( columns ); + return config; } diff --git a/src/gui/attributetable/qgsorganizetablecolumnsdialog.h b/src/gui/attributetable/qgsorganizetablecolumnsdialog.h index 7063a90ebd1..3e55d5ac443 100644 --- a/src/gui/attributetable/qgsorganizetablecolumnsdialog.h +++ b/src/gui/attributetable/qgsorganizetablecolumnsdialog.h @@ -21,6 +21,8 @@ #include "ui_qgsorganizetablecolumnsdialog.h" +#include "qgsattributetableconfig.h" + class QgsVectorLayer; class GUI_EXPORT QgsOrganizeTableColumnsDialog : public QDialog, private Ui::QgsOrganizeTableColumnsDialog @@ -35,17 +37,17 @@ class GUI_EXPORT QgsOrganizeTableColumnsDialog : public QDialog, private Ui::Qgs * @param parent parent object * @param flags window flags */ - QgsOrganizeTableColumnsDialog( const QgsVectorLayer* vl, QStringList visible, QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::Window ); + QgsOrganizeTableColumnsDialog( const QgsVectorLayer* vl, QWidget* parent = nullptr, Qt::WindowFlags flags = Qt::Window ); + /** * Destructor */ ~QgsOrganizeTableColumnsDialog(); /** - * Get the selected fields name - * @return The selected fields name + * Get the updated configuration */ - QStringList selectedFields() const; + QgsAttributeTableConfig config() const; }; #endif diff --git a/src/ui/qgsorganizetablecolumnsdialog.ui b/src/ui/qgsorganizetablecolumnsdialog.ui index 0dc4693737e..abcefedacc0 100644 --- a/src/ui/qgsorganizetablecolumnsdialog.ui +++ b/src/ui/qgsorganizetablecolumnsdialog.ui @@ -6,8 +6,8 @@ 0 0 - 240 - 219 + 392 + 357 @@ -15,7 +15,14 @@ - + + + QAbstractItemView::DragDrop + + + Qt::MoveAction + +