Skip to content

Commit dd88fa9

Browse files
committedMay 2, 2016
[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
1 parent aa9010e commit dd88fa9

27 files changed

+738
-105
lines changed
 

‎python/core/core.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
%Include qgsaction.sip
2323
%Include qgsactionmanager.sip
2424
%Include qgsattributeaction.sip
25+
%Include qgsattributetableconfig.sip
2526
%Include qgsbrowsermodel.sip
2627
%Include qgsclipper.sip
2728
%Include qgscolorscheme.sip
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/***************************************************************************
2+
qgsattributetableconfig.h - QgsAttributeTableConfig
3+
4+
---------------------
5+
begin : 27.4.2016
6+
copyright : (C) 2016 by Matthias Kuhn
7+
email : matthias@opengis.ch
8+
***************************************************************************
9+
* *
10+
* This program is free software; you can redistribute it and/or modify *
11+
* it under the terms of the GNU General Public License as published by *
12+
* the Free Software Foundation; either version 2 of the License, or *
13+
* (at your option) any later version. *
14+
* *
15+
***************************************************************************/
16+
17+
/**
18+
* This is a container for configuration of the attribute table.
19+
* The configuration is specific for one vector layer.
20+
*/
21+
22+
class QgsAttributeTableConfig
23+
{
24+
%TypeHeaderCode
25+
#include <qgsattributetableconfig.h>
26+
%End
27+
public:
28+
/**
29+
* The type of an attribute table column.
30+
*/
31+
enum Type
32+
{
33+
Field, //!< This column represents a field
34+
Action //!< This column represents an action widget
35+
};
36+
37+
/**
38+
* Defines the configuration of a column in the attribute table.
39+
*/
40+
struct ColumnConfig
41+
{
42+
QgsAttributeTableConfig::Type mType; //!< The type of this column.
43+
QString mName; //!< The name of the attribute if this column represents a field
44+
bool mHidden; //!< Flag that controls if the column is hidden
45+
};
46+
47+
QgsAttributeTableConfig();
48+
49+
/**
50+
* Get the list with all columns and their configuration.
51+
* The list order defines the order of appearance.
52+
*/
53+
QVector<QgsAttributeTableConfig::ColumnConfig> columns() const;
54+
55+
/**
56+
* Set the list of columns visible in the attribute table.
57+
* The list order defines the order of appearance.
58+
*/
59+
void setColumns( const QVector<QgsAttributeTableConfig::ColumnConfig>& columns );
60+
61+
/**
62+
* Update the configuration with the given fields.
63+
* Any field which is present in the configuration but not present in the
64+
* parameter fields will be removed. Any field which is in the parameter
65+
* fields but not in the configuration will be appended.
66+
*/
67+
void update( const QgsFields& fields );
68+
69+
/**
70+
* Serialize to XML on layer save
71+
*/
72+
void writeXml( QDomNode& node ) const;
73+
74+
/**
75+
* Deserialize to XML on layer load
76+
*/
77+
void readXml( const QDomNode& node );
78+
};

‎python/core/qgsvectorlayer.sip

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,18 @@ class QgsVectorLayer : QgsMapLayer
13211321
*/
13221322
QgsConditionalLayerStyles *conditionalStyles() const;
13231323

1324+
/**
1325+
* Get the attribute table configuration object.
1326+
* This defines the appearance of the attribute table.
1327+
*/
1328+
QgsAttributeTableConfig attributeTableConfig() const;
1329+
1330+
/**
1331+
* Set the attribute table configuration object.
1332+
* This defines the appearance of the attribute table.
1333+
*/
1334+
void setAttributeTableConfig( const QgsAttributeTableConfig& attributeTableConfig );
1335+
13241336
public slots:
13251337
/**
13261338
* Select feature by its ID

‎python/gui/attributetable/qgsattributetablefiltermodel.sip

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,18 @@ class QgsAttributeTableFilterModel: QSortFilterProxyModel, QgsFeatureModel
1313
ShowEdited
1414
};
1515

16+
enum ColumnType
17+
{
18+
ColumnTypeField, //!< This column shows a field
19+
ColumnTypeActionButton //!< This column shows action buttons
20+
};
21+
22+
enum Role
23+
{
24+
TypeRole = QgsAttributeTableModel::UserRole //!< The type of a given column
25+
};
26+
27+
1628
/**
1729
*
1830
* Make sure, the master model is already loaded, so the selection will get synchronized.
@@ -99,6 +111,25 @@ class QgsAttributeTableFilterModel: QSortFilterProxyModel, QgsFeatureModel
99111
/** Returns the map canvas*/
100112
QgsMapCanvas* mapCanvas() const;
101113

114+
virtual QVariant data( const QModelIndex& index, int role ) const;
115+
116+
QVariant headerData( int section, Qt::Orientation orientation, int role ) const;
117+
118+
/**
119+
* Get the index of the first column that contains an action widget.
120+
* Returns -1 if none is defined.
121+
*/
122+
int actionColumnIndex() const;
123+
124+
int columnCount( const QModelIndex &parent ) const;
125+
126+
/**
127+
* Set the attribute table configuration to control which fields are shown,
128+
* in which order they are shown as well as if and where an action column
129+
* is shown.
130+
*/
131+
void setAttributeTableConfig( const QgsAttributeTableConfig& config );
132+
102133
protected:
103134
/**
104135
* Returns true if the source row will be accepted

‎python/gui/attributetable/qgsattributetableview.sip

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ class QgsAttributeTableView : QTableView
1919
/**
2020
* This event filter is installed on the verticalHeader to intercept mouse press and release
2121
* events. These are used to disable / enable live synchronisation with the map canvas selection
22-
* which can be slow due to recurring canvas repaints. Updating the
22+
* which can be slow due to recurring canvas repaints.
2323
*
2424
* @param object The object which is the target of the event.
2525
* @param event The intercepted event

‎python/gui/attributetable/qgsdualview.sip

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ class QgsDualView : QStackedWidget
6565
*/
6666
void setFilterMode( QgsAttributeTableFilterModel::FilterMode filterMode );
6767

68+
/**
69+
* Get the filter mode
70+
*
71+
* @return the filter mode
72+
*/
6873
QgsAttributeTableFilterModel::FilterMode filterMode();
6974

7075
/**
@@ -98,6 +103,9 @@ class QgsDualView : QStackedWidget
98103
*/
99104
void setFilteredFeatures( const QgsFeatureIds& filteredFeatures );
100105

106+
/**
107+
* Get a list of currently visible feature ids.
108+
*/
101109
QgsFeatureIds filteredFeatures();
102110

103111
/**
@@ -112,6 +120,11 @@ class QgsDualView : QStackedWidget
112120
void setFeatureSelectionManager( QgsIFeatureSelectionManager* featureSelectionManager );
113121

114122
QgsAttributeTableView* tableView();
123+
/**
124+
* Set the attribute table config which should be used to control
125+
* the appearance of the attribute table.
126+
*/
127+
void setAttributeTableConfig( const QgsAttributeTableConfig& config );
115128

116129
protected:
117130
/**

‎python/gui/attributetable/qgsorganizetablecolumnsdialog.sip

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,19 @@ class QgsOrganizeTableColumnsDialog : QDialog
88
/**
99
* Constructor
1010
* @param vl The concerned vector layer
11-
* @param visible the cuurent list of visible fields name
11+
* @param visible the current list of visible fields name
1212
* @param parent parent object
1313
* @param flags window flags
1414
*/
15-
QgsOrganizeTableColumnsDialog( const QgsVectorLayer* vl, QStringList visible, QWidget *parent /TransferThis/ = nullptr, Qt::WindowFlags flags = Qt::Window );
15+
QgsOrganizeTableColumnsDialog(const QgsVectorLayer* vl, QWidget* parent = nullptr, Qt::WindowFlags flags = Qt::Window );
16+
17+
/**
18+
* Destructor
19+
*/
1620
~QgsOrganizeTableColumnsDialog();
1721

1822
/**
19-
* Get the selected fields name
20-
* @return The selected fields name
23+
* Get the updated configuration
2124
*/
22-
QStringList selectedFields();
25+
QgsAttributeTableConfig config() const;
2326
};

‎src/app/qgsattributetabledialog.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ QgsAttributeTableDialog::QgsAttributeTableDialog( QgsVectorLayer *theLayer, QWid
125125

126126
// Initialize dual view
127127
mMainView->init( mLayer, QgisApp::instance()->mapCanvas(), r, context );
128+
mMainView->setAttributeTableConfig( mLayer->attributeTableConfig() );
128129

129130
// Initialize filter gui elements
130131
mFilterActionMapper = new QSignalMapper( this );
@@ -776,17 +777,12 @@ void QgsAttributeTableDialog::on_mFilterTableFields_clicked()
776777
return;
777778
}
778779

779-
QgsOrganizeTableColumnsDialog dialog( mLayer, mVisibleFields );
780+
QgsOrganizeTableColumnsDialog dialog( mLayer );
780781
if ( dialog.exec() == QDialog::Accepted )
781782
{
782-
mVisibleFields = dialog.selectedFields();
783-
784-
const QgsFields layerAttributes = mLayer->fields();
785-
for ( int idx = 0; idx < layerAttributes.count(); ++idx )
786-
{
787-
mMainView->tableView()->setColumnHidden(
788-
idx, !mVisibleFields.contains( layerAttributes[idx].name() ) );
789-
}
783+
QgsAttributeTableConfig config = dialog.config();
784+
mLayer->setAttributeTableConfig( config );
785+
mMainView->setAttributeTableConfig( config );
790786
}
791787
}
792788

‎src/core/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ SET(QGIS_CORE_SRCS
7979
qgsapplication.cpp
8080
qgsaction.cpp
8181
qgsactionmanager.cpp
82+
qgsattributetableconfig.cpp
8283
qgsbrowsermodel.cpp
8384
qgscachedfeatureiterator.cpp
8485
qgscacheindex.cpp
@@ -591,7 +592,7 @@ SET(QGIS_CORE_HDRS
591592

592593
qgis.h
593594
qgsaction.h
594-
qgsactionmanager.h
595+
qgsattributetableconfig.h
595596
qgsattributeaction.h
596597
qgscachedfeatureiterator.h
597598
qgscacheindex.h

‎src/core/geometry/qgsabstractgeometryv2.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ email : marco.hugentobler at sourcepole dot com
2323

2424
#include <QString>
2525

26-
class QgsCoordinateTransform;
2726
class QgsMapToPixel;
2827
class QgsCurveV2;
2928
class QgsMultiCurveV2;

‎src/core/qgsattributetableconfig.cpp

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/***************************************************************************
2+
qgsattributetableconfig.cpp - QgsAttributeTableConfig
3+
4+
---------------------
5+
begin : 27.4.2016
6+
copyright : (C) 2016 by mku
7+
email : [your-email-here]
8+
***************************************************************************
9+
* *
10+
* This program is free software; you can redistribute it and/or modify *
11+
* it under the terms of the GNU General Public License as published by *
12+
* the Free Software Foundation; either version 2 of the License, or *
13+
* (at your option) any later version. *
14+
* *
15+
***************************************************************************/
16+
#include "qgsattributetableconfig.h"
17+
18+
#include <QStringList>
19+
20+
QgsAttributeTableConfig::QgsAttributeTableConfig()
21+
{
22+
23+
}
24+
25+
QVector<QgsAttributeTableConfig::ColumnConfig> QgsAttributeTableConfig::columns() const
26+
{
27+
return mColumns;
28+
}
29+
30+
void QgsAttributeTableConfig::setColumns( const QVector<ColumnConfig>& columns )
31+
{
32+
mColumns = columns;
33+
}
34+
35+
void QgsAttributeTableConfig::update( const QgsFields& fields )
36+
{
37+
QStringList columns;
38+
39+
bool containsActionColumn = false;
40+
41+
for ( int i = mColumns.count() - 1; i >= 0; --i )
42+
{
43+
const ColumnConfig& column = mColumns.at( i );
44+
if ( column.mType == Field )
45+
{
46+
if ( fields.fieldNameIndex( column.mName ) == -1 )
47+
{
48+
mColumns.remove( i );
49+
}
50+
else
51+
{
52+
columns.append( column.mName );
53+
}
54+
}
55+
else if ( column.mType == Action )
56+
{
57+
containsActionColumn = true;
58+
}
59+
}
60+
61+
Q_FOREACH ( const QgsField& field, fields )
62+
{
63+
if ( !columns.contains( field.name() ) )
64+
{
65+
ColumnConfig newColumn;
66+
newColumn.mHidden = false;
67+
newColumn.mType = Field;
68+
newColumn.mName = field.name();
69+
70+
mColumns.append( newColumn );
71+
}
72+
}
73+
74+
if ( !containsActionColumn )
75+
{
76+
ColumnConfig actionConfig;
77+
78+
actionConfig.mType = Action;
79+
actionConfig.mHidden = true;
80+
81+
mColumns.append( actionConfig );
82+
}
83+
}
84+
85+
86+
void QgsAttributeTableConfig::readXml( const QDomNode& node )
87+
{
88+
mColumns.clear();
89+
90+
QDomNode configNode = node.namedItem( "attributetableconfig" );
91+
if ( !configNode.isNull() )
92+
{
93+
QDomNode columnsNode = configNode.toElement().namedItem( "columns" );
94+
95+
QDomNodeList columns = columnsNode.childNodes();
96+
97+
for ( int i = 0; i < columns.size(); ++i )
98+
{
99+
QDomElement columnElement = columns.at( i ).toElement();
100+
101+
ColumnConfig column;
102+
103+
if ( columnElement.attribute( "type" ) == "actions" )
104+
{
105+
column.mType = Action;
106+
}
107+
else
108+
{
109+
column.mType = Field;
110+
column.mName = columnElement.attribute( "name" );
111+
}
112+
113+
column.mHidden = columnElement.attribute( "hidden" ) == "1";
114+
115+
mColumns.append( column );
116+
}
117+
}
118+
}
119+
120+
void QgsAttributeTableConfig::writeXml( QDomNode& node ) const
121+
{
122+
QDomDocument doc( node.ownerDocument() );
123+
124+
QDomElement configElement = doc.createElement( "attributetableconfig" );
125+
126+
QDomElement columnsElement = doc.createElement( "columns" );
127+
128+
Q_FOREACH ( const ColumnConfig& column, mColumns )
129+
{
130+
QDomElement columnElement = doc.createElement( "column" );
131+
132+
if ( column.mType == Action )
133+
{
134+
columnElement.setAttribute( "type", "actions" );
135+
}
136+
else
137+
{
138+
columnElement.setAttribute( "type", "field" );
139+
columnElement.setAttribute( "name", column.mName );
140+
}
141+
142+
columnElement.setAttribute( "hidden", column.mHidden );
143+
144+
columnsElement.appendChild( columnElement );
145+
}
146+
147+
configElement.appendChild( columnsElement );
148+
149+
node.appendChild( configElement );
150+
}

‎src/core/qgsattributetableconfig.h

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
/***************************************************************************
2+
qgsattributetableconfig.h - QgsAttributeTableConfig
3+
4+
---------------------
5+
begin : 27.4.2016
6+
copyright : (C) 2016 by Matthias Kuhn
7+
email : matthias@opengis.ch
8+
***************************************************************************
9+
* *
10+
* This program is free software; you can redistribute it and/or modify *
11+
* it under the terms of the GNU General Public License as published by *
12+
* the Free Software Foundation; either version 2 of the License, or *
13+
* (at your option) any later version. *
14+
* *
15+
***************************************************************************/
16+
#ifndef QGSATTRIBUTETABLECONFIG_H
17+
#define QGSATTRIBUTETABLECONFIG_H
18+
19+
#include <QString>
20+
#include <QVector>
21+
#include <QDomNode>
22+
23+
#include "qgsfield.h"
24+
25+
/**
26+
* This is a container for configuration of the attribute table.
27+
* The configuration is specific for one vector layer.
28+
*/
29+
30+
class CORE_EXPORT QgsAttributeTableConfig
31+
{
32+
public:
33+
/**
34+
* The type of an attribute table column.
35+
*/
36+
enum Type
37+
{
38+
Field, //!< This column represents a field
39+
Action //!< This column represents an action widget
40+
};
41+
42+
/**
43+
* Defines the configuration of a column in the attribute table.
44+
*/
45+
struct ColumnConfig
46+
{
47+
Type mType; //!< The type of this column.
48+
QString mName; //!< The name of the attribute if this column represents a field
49+
bool mHidden; //!< Flag that controls if the column is hidden
50+
};
51+
52+
QgsAttributeTableConfig();
53+
54+
/**
55+
* Get the list with all columns and their configuration.
56+
* The list order defines the order of appearance.
57+
*/
58+
QVector<ColumnConfig> columns() const;
59+
60+
/**
61+
* Set the list of columns visible in the attribute table.
62+
* The list order defines the order of appearance.
63+
*/
64+
void setColumns( const QVector<ColumnConfig>& columns );
65+
66+
/**
67+
* Update the configuration with the given fields.
68+
* Any field which is present in the configuration but not present in the
69+
* parameter fields will be removed. Any field which is in the parameter
70+
* fields but not in the configuration will be appended.
71+
*/
72+
void update( const QgsFields& fields );
73+
74+
/**
75+
* Serialize to XML on layer save
76+
*/
77+
void writeXml( QDomNode& node ) const;
78+
79+
/**
80+
* Deserialize to XML on layer load
81+
*/
82+
void readXml( const QDomNode& node );
83+
84+
private:
85+
QVector<ColumnConfig> mColumns;
86+
};
87+
88+
Q_DECLARE_METATYPE( QgsAttributeTableConfig::ColumnConfig )
89+
90+
#endif // QGSATTRIBUTETABLECONFIG_H

‎src/core/qgscrscache.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ class CORE_EXPORT QgsCoordinateTransformCache
4242
void invalidateCrs( const QString& crsAuthId );
4343

4444
private:
45-
static QgsCoordinateTransformCache* mInstance;
4645
QMultiHash< QPair< QString, QString >, QgsCoordinateTransform* > mTransforms; //same auth_id pairs might have different datum transformations
4746

4847
QgsCoordinateTransformCache();

‎src/core/qgsvectorlayer.cpp

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,8 +1926,6 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage
19261926
// process the attribute actions
19271927
mActions->readXML( node );
19281928

1929-
mEditFormConfig->readXml( node );
1930-
19311929
QDomNode annotationFormNode = node.namedItem( "annotationform" );
19321930
if ( !annotationFormNode.isNull() )
19331931
{
@@ -1988,6 +1986,8 @@ bool QgsVectorLayer::readSymbology( const QDomNode& node, QString& errorMessage
19881986

19891987
mEditFormConfig->readXml( node );
19901988

1989+
mAttributeTableConfig.readXml( node );
1990+
19911991
mConditionalStyles->readXml( node );
19921992

19931993
return true;
@@ -2154,6 +2154,8 @@ bool QgsVectorLayer::writeSymbology( QDomNode& node, QDomDocument& doc, QString&
21542154

21552155
mEditFormConfig->writeXml( node );
21562156

2157+
mAttributeTableConfig.writeXml( node );
2158+
21572159
mConditionalStyles->writeXml( node, doc );
21582160

21592161
return true;
@@ -2266,11 +2268,11 @@ void QgsVectorLayer::addAttributeAlias( int attIndex, const QString& aliasString
22662268
QString QgsVectorLayer::attributeAlias( int attributeIndex ) const
22672269
{
22682270
if ( attributeIndex < 0 || attributeIndex >= fields().count() )
2269-
return "";
2271+
return QString();
22702272

22712273
QString name = fields().at( attributeIndex ).name();
22722274

2273-
return mAttributeAliasMap.value( name, "" );
2275+
return mAttributeAliasMap.value( name, QString() );
22742276
}
22752277

22762278
QString QgsVectorLayer::attributeDisplayName( int attributeIndex ) const
@@ -3591,6 +3593,16 @@ void QgsVectorLayer::readSldLabeling( const QDomNode& node )
35913593
}
35923594
}
35933595

3596+
QgsAttributeTableConfig QgsVectorLayer::attributeTableConfig() const
3597+
{
3598+
return mAttributeTableConfig;
3599+
}
3600+
3601+
void QgsVectorLayer::setAttributeTableConfig( const QgsAttributeTableConfig& attributeTableConfig )
3602+
{
3603+
mAttributeTableConfig = attributeTableConfig;
3604+
}
3605+
35943606
void QgsVectorLayer::setDiagramLayerSettings( const QgsDiagramLayerSettings& s )
35953607
{
35963608
if ( !mDiagramLayerSettings )

‎src/core/qgsvectorlayer.h

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "qgssnapper.h"
3535
#include "qgsvectorsimplifymethod.h"
3636
#include "qgseditformconfig.h"
37+
#include "qgsattributetableconfig.h"
3738

3839
class QPainter;
3940
class QImage;
@@ -631,7 +632,7 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
631632
* The pointer which is returned directly points to the actions object
632633
* which is used by the layer, so any changes are immediately applied.
633634
*/
634-
QgsActionManager *actions() { return mActions; }
635+
QgsActionManager* actions() { return mActions; }
635636

636637
/**
637638
* The number of features that are selected in this layer
@@ -1321,7 +1322,12 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
13211322
*/
13221323
void clearAttributeEditorWidgets() { mEditFormConfig->clearTabs(); }
13231324

1324-
/** Returns the alias of an attribute name or an empty string if there is no alias */
1325+
/**
1326+
* Returns the alias of an attribute name or a null string if there is no alias.
1327+
*
1328+
* @see {@attributeDisplayName( int attributeIndex )} which returns the field name
1329+
* if no alias is defined.
1330+
*/
13251331
QString attributeAlias( int attributeIndex ) const;
13261332

13271333
/** Convenience function that returns the attribute alias if defined or the field name else */
@@ -1686,6 +1692,18 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
16861692
*/
16871693
QgsConditionalLayerStyles *conditionalStyles() const;
16881694

1695+
/**
1696+
* Get the attribute table configuration object.
1697+
* This defines the appearance of the attribute table.
1698+
*/
1699+
QgsAttributeTableConfig attributeTableConfig() const;
1700+
1701+
/**
1702+
* Set the attribute table configuration object.
1703+
* This defines the appearance of the attribute table.
1704+
*/
1705+
void setAttributeTableConfig( const QgsAttributeTableConfig& attributeTableConfig );
1706+
16891707
public slots:
16901708
/**
16911709
* Select feature by its ID
@@ -2088,6 +2106,8 @@ class CORE_EXPORT QgsVectorLayer : public QgsMapLayer
20882106

20892107
QgsFeatureIds mDeletedFids;
20902108

2109+
QgsAttributeTableConfig mAttributeTableConfig;
2110+
20912111
friend class QgsVectorLayerFeatureSource;
20922112
};
20932113

‎src/gui/attributetable/qgsattributetabledelegate.cpp

Lines changed: 21 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -118,29 +118,36 @@ void QgsAttributeTableDelegate::setFeatureSelectionModel( QgsFeatureSelectionMod
118118
mFeatureSelectionModel = featureSelectionModel;
119119
}
120120

121+
void QgsAttributeTableDelegate::setActionWidgetImage( const QImage& image )
122+
{
123+
mActionWidgetImage = image;
124+
}
125+
121126

122127
void QgsAttributeTableDelegate::paint( QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index ) const
123128
{
124-
QgsFeatureId fid = index.model()->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong();
125-
126-
QStyleOptionViewItem myOpt = option;
129+
QgsAttributeTableFilterModel::ColumnType columnType = static_cast<QgsAttributeTableFilterModel::ColumnType>( index.model()->data( index, QgsAttributeTableFilterModel::TypeRole ).toInt() );
127130

128-
if ( index.model()->data( index, Qt::EditRole ).isNull() )
131+
if ( columnType == QgsAttributeTableFilterModel::ColumnTypeActionButton )
129132
{
130-
myOpt.font.setItalic( true );
131-
myOpt.palette.setColor( QPalette::Text, QColor( "gray" ) );
133+
QRect r = option.rect.adjusted( -1, 0, 0, 0 );
134+
painter->drawImage( r.x(), r.y(), mActionWidgetImage );
132135
}
136+
else
137+
{
138+
QgsFeatureId fid = index.model()->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong();
133139

134-
if ( mFeatureSelectionModel && mFeatureSelectionModel->isSelected( fid ) )
135-
myOpt.state |= QStyle::State_Selected;
140+
QStyleOptionViewItem myOpt = option;
136141

142+
if ( index.model()->data( index, Qt::EditRole ).isNull() )
143+
{
144+
myOpt.font.setItalic( true );
145+
myOpt.palette.setColor( QPalette::Text, QColor( "gray" ) );
146+
}
147+
148+
if ( mFeatureSelectionModel && mFeatureSelectionModel->isSelected( fid ) )
149+
myOpt.state |= QStyle::State_Selected;
137150

138-
if ( index.column() == 0 )
139-
{
140-
painter->drawImage( QPoint( 0, 0 ), mActionButtonImage );
141-
}
142-
else
143-
{
144151
QItemDelegate::paint( painter, myOpt, index );
145152

146153
if ( option.state & QStyle::State_HasFocus )

‎src/gui/attributetable/qgsattributetabledelegate.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ class GUI_EXPORT QgsAttributeTableDelegate : public QItemDelegate
4646
: QItemDelegate( parent )
4747
, mLayer( nullptr )
4848
, mFeatureSelectionModel( nullptr )
49-
, mActionButtonWidget( nullptr )
5049
{
5150
}
5251

@@ -80,13 +79,15 @@ class GUI_EXPORT QgsAttributeTableDelegate : public QItemDelegate
8079

8180
void setFeatureSelectionModel( QgsFeatureSelectionModel* featureSelectionModel );
8281

83-
private:
84-
QWidget* createActionWidget( QWidget* parent, QgsVectorLayer* layer ) const;
82+
/**
83+
* Set an image that represents an action widget
84+
*/
85+
void setActionWidgetImage( const QImage& image );
8586

87+
private:
8688
QgsVectorLayer* mLayer;
8789
QgsFeatureSelectionModel* mFeatureSelectionModel;
88-
QWidget* mActionButtonWidget;
89-
QImage mActionButtonImage;
90+
QImage mActionWidgetImage;
9091
};
9192

9293
#endif //QGSATTRIBUTETABLEDELEGATE_H

‎src/gui/attributetable/qgsattributetablefiltermodel.cpp

Lines changed: 105 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,13 +69,93 @@ void QgsAttributeTableFilterModel::sort( int column, Qt::SortOrder order )
6969

7070
QVariant QgsAttributeTableFilterModel::data( const QModelIndex& index, int role ) const
7171
{
72-
if ( index.column() == 0 )
73-
return "Wow";
72+
if ( mColumnMapping.at( index.column() ) == -1 ) // actions
73+
{
74+
if ( role == TypeRole )
75+
return ColumnTypeActionButton;
76+
else if ( role == QgsAttributeTableModel::FeatureIdRole )
77+
{
78+
QModelIndex fieldIndex = QSortFilterProxyModel::mapToSource( QSortFilterProxyModel::index( index.row(), 0, index.parent() ) );
79+
return sourceModel()->data( fieldIndex, QgsAttributeTableModel::FeatureIdRole );
80+
}
81+
}
82+
else if ( role == TypeRole )
83+
return ColumnTypeField;
84+
85+
return QSortFilterProxyModel::data( index, role );
86+
}
87+
88+
QVariant QgsAttributeTableFilterModel::headerData( int section, Qt::Orientation orientation, int role ) const
89+
{
90+
if ( orientation == Qt::Horizontal )
91+
{
92+
if ( mColumnMapping.at( section ) == -1 && role == Qt::DisplayRole )
93+
return tr( "Actions" );
94+
else
95+
return QSortFilterProxyModel::headerData( section, orientation, role );
96+
}
7497
else
98+
return QSortFilterProxyModel::headerData( section, orientation, role );
99+
}
100+
101+
int QgsAttributeTableFilterModel::actionColumnIndex() const
102+
{
103+
return mColumnMapping.indexOf( -1 );
104+
}
105+
106+
int QgsAttributeTableFilterModel::columnCount( const QModelIndex& parent ) const
107+
{
108+
Q_UNUSED( parent );
109+
return mColumnMapping.count();
110+
}
111+
112+
void QgsAttributeTableFilterModel::setAttributeTableConfig( const QgsAttributeTableConfig& config )
113+
{
114+
int columnIndex = 0;
115+
int configIndex = 0;
116+
bool resetModel = false;
117+
118+
for ( ; configIndex < config.columns().size(); ++configIndex )
75119
{
76-
QModelIndex sourceIndex = QSortFilterProxyModel::index( index.row(), index.column() - 1, index.parent() );
77-
return QSortFilterProxyModel::data( sourceIndex, role );
120+
const QgsAttributeTableConfig::ColumnConfig& columnConfig = config.columns().at( configIndex );
121+
122+
// Hidden? No reason for further checks
123+
if ( columnConfig.mHidden )
124+
continue;
125+
126+
// Do the previous and current definition match?
127+
if ( mColumnMapping.size() > columnIndex )
128+
{
129+
if (( columnConfig.mType == QgsAttributeTableConfig::Action && mColumnMapping.at( columnIndex ) == -1 ) ||
130+
( columnConfig.mType == QgsAttributeTableConfig::Field && mColumnMapping.at( columnIndex ) == layer()->fieldNameIndex( columnConfig.mName ) ) )
131+
{
132+
++columnIndex;
133+
continue;
134+
}
135+
else // There is a mismatch between previous and current configuration: remove all remaining columns, they will be readded
136+
{
137+
mColumnMapping.remove( columnIndex, mColumnMapping.count() - columnIndex );
138+
}
139+
}
140+
141+
if ( ! resetModel )
142+
{
143+
beginResetModel();
144+
resetModel = true;
145+
}
146+
147+
148+
// New column? append
149+
Q_ASSERT( mColumnMapping.size() == columnIndex );
150+
if ( columnConfig.mType == QgsAttributeTableConfig::Action )
151+
mColumnMapping.append( -1 );
152+
else
153+
mColumnMapping.append( layer()->fieldNameIndex( columnConfig.mName ) );
154+
155+
++columnIndex;
78156
}
157+
if ( resetModel )
158+
endResetModel();
79159
}
80160

81161
void QgsAttributeTableFilterModel::setSelectedOnTop( bool selectedOnTop )
@@ -96,6 +176,12 @@ void QgsAttributeTableFilterModel::setSourceModel( QgsAttributeTableModel* sourc
96176
{
97177
mTableModel = sourceModel;
98178

179+
mColumnMapping.append( -1 ); // -1 for actions column
180+
for ( int i = 0; i < mTableModel->columnCount(); ++i )
181+
{
182+
mColumnMapping.append( i );
183+
}
184+
99185
QSortFilterProxyModel::setSourceModel( sourceModel );
100186
}
101187

@@ -310,14 +396,23 @@ QModelIndexList QgsAttributeTableFilterModel::fidToIndexList( QgsFeatureId fid )
310396
return indexes;
311397
}
312398

313-
QModelIndex QgsAttributeTableFilterModel::mapToMaster( const QModelIndex &proxyIndex ) const
399+
QModelIndex QgsAttributeTableFilterModel::mapToSource( const QModelIndex& proxyIndex ) const
314400
{
315-
// Master is source
316-
return mapToSource( proxyIndex );
401+
if ( !proxyIndex.isValid() )
402+
return QModelIndex();
403+
404+
int sourceColumn = mColumnMapping.at( proxyIndex.column() );
405+
406+
// For the action column there is no matching column in the source model: invalid
407+
if ( sourceColumn == -1 )
408+
return QModelIndex();
409+
410+
return QSortFilterProxyModel::mapToSource( index( proxyIndex.row(), mColumnMapping.at( proxyIndex.column() ), proxyIndex.parent() ) );
317411
}
318412

319-
QModelIndex QgsAttributeTableFilterModel::mapFromMaster( const QModelIndex &sourceIndex ) const
413+
QModelIndex QgsAttributeTableFilterModel::mapFromSource( const QModelIndex& sourceIndex ) const
320414
{
321-
// Master is source
322-
return mapFromSource( sourceIndex );
415+
QModelIndex proxyIndex = QSortFilterProxyModel::mapFromSource( sourceIndex );
416+
417+
return index( proxyIndex.row(), mColumnMapping.indexOf( proxyIndex.column() ), proxyIndex.parent() );
323418
}

‎src/gui/attributetable/qgsattributetablefiltermodel.h

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,17 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
4242
ShowEdited
4343
};
4444

45+
enum ColumnType
46+
{
47+
ColumnTypeField, //!< This column shows a field
48+
ColumnTypeActionButton //!< This column shows action buttons
49+
};
50+
51+
enum Role
52+
{
53+
TypeRole = QgsAttributeTableModel::UserRole //!< The type of a given column
54+
};
55+
4556

4657
/**
4758
*
@@ -137,11 +148,16 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
137148
QgsFeatureId rowToId( const QModelIndex& row );
138149

139150
QModelIndex fidToIndex( QgsFeatureId fid ) override;
151+
140152
QModelIndexList fidToIndexList( QgsFeatureId fid );
141153

142-
virtual QModelIndex mapToMaster( const QModelIndex &proxyIndex ) const;
154+
inline QModelIndex mapToMaster( const QModelIndex& proxyIndex ) const { return mapToSource( proxyIndex ); }
155+
156+
inline QModelIndex mapFromMaster( const QModelIndex& sourceIndex ) const { return mapFromSource( sourceIndex ); }
157+
158+
virtual QModelIndex mapToSource( const QModelIndex& proxyIndex ) const override;
143159

144-
virtual QModelIndex mapFromMaster( const QModelIndex &sourceIndex ) const;
160+
virtual QModelIndex mapFromSource( const QModelIndex& sourceIndex ) const override;
145161

146162
/**
147163
* Sort by the given column using the given order.
@@ -157,6 +173,23 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
157173

158174
virtual QVariant data( const QModelIndex& index, int role ) const override;
159175

176+
QVariant headerData( int section, Qt::Orientation orientation, int role ) const override;
177+
178+
/**
179+
* Get the index of the first column that contains an action widget.
180+
* Returns -1 if none is defined.
181+
*/
182+
int actionColumnIndex() const;
183+
184+
int columnCount( const QModelIndex &parent ) const override;
185+
186+
/**
187+
* Set the attribute table configuration to control which fields are shown,
188+
* in which order they are shown as well as if and where an action column
189+
* is shown.
190+
*/
191+
void setAttributeTableConfig( const QgsAttributeTableConfig& config );
192+
160193
protected:
161194
/**
162195
* Returns true if the source row will be accepted
@@ -195,6 +228,8 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
195228
FilterMode mFilterMode;
196229
bool mSelectedOnTop;
197230
QgsAttributeTableModel* mTableModel;
231+
232+
QVector<int> mColumnMapping;
198233
};
199234

200235
#endif

‎src/gui/attributetable/qgsattributetablemodel.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,10 @@ class GUI_EXPORT QgsAttributeTableModel: public QAbstractTableModel
5151
public:
5252
enum Role
5353
{
54-
SortRole = Qt::UserRole + 1,
55-
FeatureIdRole = Qt::UserRole + 2,
56-
FieldIndexRole = Qt::UserRole + 3
54+
SortRole = Qt::UserRole + 1, //!< Role used for sorting
55+
FeatureIdRole, //!< Get the feature id of the feature in this row
56+
FieldIndexRole, //!< Get the field index of this column
57+
UserRole //!< Start further roles starting from this role
5758
};
5859

5960
public:

‎src/gui/attributetable/qgsattributetableview.cpp

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -64,14 +64,10 @@ QgsAttributeTableView::QgsAttributeTableView( QWidget *parent )
6464

6565
connect( verticalHeader(), SIGNAL( sectionPressed( int ) ), this, SLOT( selectRow( int ) ) );
6666
connect( verticalHeader(), SIGNAL( sectionEntered( int ) ), this, SLOT( _q_selectRow( int ) ) );
67+
connect( horizontalHeader(), SIGNAL( sectionResized( int, int, int ) ), this, SLOT( columnSizeChanged( int, int, int ) ) );
6768
connect( horizontalHeader(), SIGNAL( sortIndicatorChanged( int, Qt::SortOrder ) ), this, SLOT( showHorizontalSortIndicator() ) );
6869
}
6970

70-
QgsAttributeTableView::~QgsAttributeTableView()
71-
{
72-
delete mActionPopup;
73-
}
74-
7571
bool QgsAttributeTableView::eventFilter( QObject *object, QEvent *event )
7672
{
7773
if ( object == verticalHeader()->viewport() )
@@ -123,6 +119,9 @@ void QgsAttributeTableView::setModel( QgsAttributeTableFilterModel* filterModel
123119
connect( mFeatureSelectionModel, SIGNAL( requestRepaint( QModelIndexList ) ), this, SLOT( repaintRequested( QModelIndexList ) ) );
124120
connect( mFeatureSelectionModel, SIGNAL( requestRepaint() ), this, SLOT( repaintRequested() ) );
125121
}
122+
123+
mActionWidget = createActionWidget( 0 );
124+
mActionWidget->setVisible( false );
126125
}
127126

128127
void QgsAttributeTableView::setFeatureSelectionManager( QgsIFeatureSelectionManager* featureSelectionManager )
@@ -136,19 +135,35 @@ void QgsAttributeTableView::setFeatureSelectionManager( QgsIFeatureSelectionMana
136135
mFeatureSelectionModel->setFeatureSelectionManager( mFeatureSelectionManager );
137136
}
138137

139-
QWidget* QgsAttributeTableView::createActionWidget()
138+
QWidget* QgsAttributeTableView::createActionWidget( QgsFeatureId fid )
140139
{
141140
QToolButton* toolButton = new QToolButton( this );
141+
toolButton->setPopupMode( QToolButton::MenuButtonPopup );
142+
143+
QgsActionManager* actions = mFilterModel->layer()->actions();
142144

143-
for ( int i = 0; i < mFilterModel->layer()->actions()->size(); ++i )
145+
for ( int i = 0; i < actions->size(); ++i )
144146
{
145-
const QgsAction& action = mFilterModel->layer()->actions()->at( i );
147+
const QgsAction& action = actions->at( i );
146148

147-
QAction* act = new QAction( action.icon(), action.shortTitle(), toolButton );
149+
QAction* act = new QAction( action.icon(), action.shortTitle().isEmpty() ? action.name() : action.shortTitle(), toolButton );
150+
act->setToolTip( action.name() );
151+
act->setData( i );
152+
act->setProperty( "fid", fid );
153+
154+
connect( act, SIGNAL( triggered( bool ) ), this, SLOT( actionTriggered() ) );
148155

149156
toolButton->addAction( act );
157+
158+
if ( actions->defaultAction() == i )
159+
toolButton->setDefaultAction( act );
150160
}
151161

162+
if ( !toolButton->actions().isEmpty() && actions->defaultAction() == -1 )
163+
toolButton->setDefaultAction( toolButton->actions().first() );
164+
165+
updateActionImage( toolButton );
166+
152167
return toolButton;
153168
}
154169

@@ -176,12 +191,12 @@ void QgsAttributeTableView::mouseReleaseEvent( QMouseEvent *event )
176191
void QgsAttributeTableView::mouseMoveEvent( QMouseEvent *event )
177192
{
178193
QModelIndex index = indexAt( event->pos() );
179-
if ( index.column() == 0 )
194+
if ( index.data( QgsAttributeTableFilterModel::TypeRole ) == QgsAttributeTableFilterModel::ColumnTypeActionButton )
180195
{
181196
Q_ASSERT( index.isValid() );
182197

183198
if ( !indexWidget( index ) )
184-
setIndexWidget( index, createActionWidget() );
199+
setIndexWidget( index, createActionWidget( mFilterModel->data( index, QgsAttributeTableModel::FeatureIdRole ).toLongLong() ) );
185200
}
186201

187202
setSelectionMode( QAbstractItemView::NoSelection );
@@ -246,7 +261,7 @@ void QgsAttributeTableView::contextMenuEvent( QContextMenuEvent* event )
246261
if ( !vlayer )
247262
return;
248263

249-
mActionPopup = new QMenu();
264+
mActionPopup = new QMenu( this );
250265

251266
mActionPopup->addAction( tr( "Select All" ), this, SLOT( selectAll() ), QKeySequence::SelectAll );
252267

@@ -318,3 +333,32 @@ void QgsAttributeTableView::showHorizontalSortIndicator()
318333
{
319334
horizontalHeader()->setSortIndicatorShown( true );
320335
}
336+
337+
void QgsAttributeTableView::actionTriggered()
338+
{
339+
QAction* action = qobject_cast<QAction*>( sender() );
340+
QgsFeatureId fid = action->property( "fid" ).toLongLong();
341+
342+
QgsFeature f;
343+
mFilterModel->layerCache()->getFeatures( QgsFeatureRequest( fid ) ).nextFeature( f );
344+
345+
mFilterModel->layer()->actions()->doAction( action->data().toInt(), f );
346+
}
347+
348+
void QgsAttributeTableView::columnSizeChanged( int index, int oldWidth, int newWidth )
349+
{
350+
Q_UNUSED( oldWidth )
351+
if ( mFilterModel->actionColumnIndex() == index )
352+
{
353+
mActionWidget->resize( newWidth, mActionWidget->height() );
354+
updateActionImage( mActionWidget );
355+
}
356+
}
357+
358+
void QgsAttributeTableView::updateActionImage( QWidget* widget )
359+
{
360+
QImage image( widget->size(), QImage::Format_ARGB32_Premultiplied );
361+
QPainter painter( &image );
362+
widget->render( &painter );
363+
mTableDelegate->setActionWidgetImage( image );
364+
}

‎src/gui/attributetable/qgsattributetableview.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ class GUI_EXPORT QgsAttributeTableView : public QTableView
4747

4848
public:
4949
QgsAttributeTableView( QWidget* parent = nullptr );
50-
virtual ~QgsAttributeTableView();
5150

5251
virtual void setModel( QgsAttributeTableFilterModel* filterModel );
5352

@@ -140,9 +139,12 @@ class GUI_EXPORT QgsAttributeTableView : public QTableView
140139
private slots:
141140
void modelDeleted();
142141
void showHorizontalSortIndicator();
142+
void actionTriggered();
143+
void columnSizeChanged( int index, int oldWidth, int newWidth );
143144

144145
private:
145-
QWidget* createActionWidget();
146+
void updateActionImage( QWidget* widget );
147+
QWidget* createActionWidget( QgsFeatureId fid );
146148

147149
void selectRow( int row, bool anchor );
148150
QgsAttributeTableModel* mMasterModel;
@@ -154,6 +156,7 @@ class GUI_EXPORT QgsAttributeTableView : public QTableView
154156
QMenu *mActionPopup;
155157
int mRowSectionAnchor;
156158
QItemSelectionModel::SelectionFlag mCtrlDragSelectionFlag;
159+
QWidget* mActionWidget;
157160
};
158161

159162
#endif

‎src/gui/attributetable/qgsdualview.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,6 +464,11 @@ void QgsDualView::setFeatureSelectionManager( QgsIFeatureSelectionManager* featu
464464
mFeatureSelectionManager = featureSelectionManager;
465465
}
466466

467+
void QgsDualView::setAttributeTableConfig( const QgsAttributeTableConfig& config )
468+
{
469+
mFilterModel->setAttributeTableConfig( config );
470+
}
471+
467472
void QgsDualView::progress( int i, bool& cancel )
468473
{
469474
if ( !mProgressDlg )

‎src/gui/attributetable/qgsdualview.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,9 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
141141
*/
142142
void setFilteredFeatures( const QgsFeatureIds& filteredFeatures );
143143

144+
/**
145+
* Get a list of currently visible feature ids.
146+
*/
144147
QgsFeatureIds filteredFeatures() { return mFilterModel->filteredFeatures(); }
145148

146149
/**
@@ -169,7 +172,13 @@ class GUI_EXPORT QgsDualView : public QStackedWidget, private Ui::QgsDualViewBas
169172
*
170173
* @return The table view
171174
*/
172-
QgsAttributeTableView* tableView() { return mTableView; };
175+
QgsAttributeTableView* tableView() { return mTableView; }
176+
177+
/**
178+
* Set the attribute table config which should be used to control
179+
* the appearance of the attribute table.
180+
*/
181+
void setAttributeTableConfig( const QgsAttributeTableConfig& config );
173182

174183
protected:
175184
/**

‎src/gui/attributetable/qgsorganizetablecolumnsdialog.cpp

Lines changed: 44 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,57 +41,76 @@
4141
#include "qgseditorwidgetregistry.h"
4242

4343

44-
QgsOrganizeTableColumnsDialog::QgsOrganizeTableColumnsDialog( const QgsVectorLayer* vl, const QStringList visble, QWidget *parent, Qt::WindowFlags flags )
44+
QgsOrganizeTableColumnsDialog::QgsOrganizeTableColumnsDialog( const QgsVectorLayer* vl, QWidget* parent, Qt::WindowFlags flags )
4545
: QDialog( parent, flags )
4646
{
4747
setupUi( this );
4848
if ( vl )
4949
{
50+
QgsAttributeTableConfig config = vl->attributeTableConfig();
51+
config.update( vl->fields() );
52+
5053
mFieldsList->clear();
51-
const QgsFields& layerAttributes = vl->fields();
52-
for ( int idx = 0; idx < layerAttributes.count(); ++idx )
54+
55+
Q_FOREACH ( const QgsAttributeTableConfig::ColumnConfig& columnConfig, config.columns() )
5356
{
54-
QListWidgetItem* item = new QListWidgetItem( layerAttributes[idx].name(), mFieldsList );
55-
item->setCheckState( visble.contains( layerAttributes[idx].name() ) ? Qt::Checked : Qt::Unchecked );
56-
switch ( vl->fields().fieldOrigin( idx ) )
57+
QListWidgetItem* item;
58+
if ( columnConfig.mType == QgsAttributeTableConfig::Action )
59+
{
60+
item = new QListWidgetItem( tr( "[Action Widget]" ), mFieldsList );
61+
item->setIcon( QgsApplication::getThemeIcon( "/propertyicons/action.svg" ) );
62+
}
63+
else
5764
{
58-
case QgsFields::OriginExpression:
59-
item->setIcon( QgsApplication::getThemeIcon( "/mIconExpression.svg" ) );
60-
break;
65+
int idx = vl->fieldNameIndex( columnConfig.mName );
66+
item = new QListWidgetItem( vl->attributeDisplayName( idx ), mFieldsList );
67+
68+
switch ( vl->fields().fieldOrigin( idx ) )
69+
{
70+
case QgsFields::OriginExpression:
71+
item->setIcon( QgsApplication::getThemeIcon( "/mIconExpression.svg" ) );
72+
break;
6173

62-
case QgsFields::OriginJoin:
63-
item->setIcon( QgsApplication::getThemeIcon( "/propertyicons/join.png" ) );
64-
break;
74+
case QgsFields::OriginJoin:
75+
item->setIcon( QgsApplication::getThemeIcon( "/propertyicons/join.png" ) );
76+
break;
6577

66-
default:
67-
item->setIcon( QgsApplication::getThemeIcon( "/propertyicons/attributes.png" ) );
68-
break;
78+
default:
79+
item->setIcon( QgsApplication::getThemeIcon( "/propertyicons/attributes.png" ) );
80+
break;
81+
}
6982
}
7083

71-
item->setData( Qt::UserRole, idx );
84+
item->setCheckState( columnConfig.mHidden ? Qt::Unchecked : Qt::Checked );
85+
item->setData( Qt::UserRole, QVariant::fromValue( columnConfig ) );
7286
}
7387
}
7488

7589
QSettings settings;
76-
restoreGeometry( settings.value( "/Windows/QgsFilterTableFieldsDialog/geometry" ).toByteArray() );
90+
restoreGeometry( settings.value( "/Windows/QgsOrganizeTableColumnsDialog/geometry" ).toByteArray() );
7791
}
7892

7993
QgsOrganizeTableColumnsDialog::~QgsOrganizeTableColumnsDialog()
8094
{
8195
QSettings settings;
82-
settings.setValue( "/Windows/QgsFilterTableFieldsDialog/geometry", saveGeometry() );
96+
settings.setValue( "/Windows/QgsOrganizeTableColumnsDialog/geometry", saveGeometry() );
8397
}
8498

85-
QStringList QgsOrganizeTableColumnsDialog::selectedFields() const
99+
QgsAttributeTableConfig QgsOrganizeTableColumnsDialog::config() const
86100
{
87-
QStringList selectionList;
101+
QVector<QgsAttributeTableConfig::ColumnConfig> columns;
102+
88103
for ( int i = 0 ; i < mFieldsList->count() ; i++ )
89104
{
90105
const QListWidgetItem* item = mFieldsList->item( i );
91-
if ( item->checkState() == Qt::Checked )
92-
{
93-
selectionList.push_back( item->text() );
94-
}
106+
QgsAttributeTableConfig::ColumnConfig columnConfig = item->data( Qt::UserRole ).value<QgsAttributeTableConfig::ColumnConfig>();
107+
108+
columnConfig.mHidden = item->checkState() == Qt::Unchecked;
109+
110+
columns.append( columnConfig );
95111
}
96-
return selectionList;
112+
113+
QgsAttributeTableConfig config;
114+
config.setColumns( columns );
115+
return config;
97116
}

‎src/gui/attributetable/qgsorganizetablecolumnsdialog.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
#include "ui_qgsorganizetablecolumnsdialog.h"
2323

24+
#include "qgsattributetableconfig.h"
25+
2426
class QgsVectorLayer;
2527

2628
class GUI_EXPORT QgsOrganizeTableColumnsDialog : public QDialog, private Ui::QgsOrganizeTableColumnsDialog
@@ -35,17 +37,17 @@ class GUI_EXPORT QgsOrganizeTableColumnsDialog : public QDialog, private Ui::Qgs
3537
* @param parent parent object
3638
* @param flags window flags
3739
*/
38-
QgsOrganizeTableColumnsDialog( const QgsVectorLayer* vl, QStringList visible, QWidget *parent = nullptr, Qt::WindowFlags flags = Qt::Window );
40+
QgsOrganizeTableColumnsDialog( const QgsVectorLayer* vl, QWidget* parent = nullptr, Qt::WindowFlags flags = Qt::Window );
41+
3942
/**
4043
* Destructor
4144
*/
4245
~QgsOrganizeTableColumnsDialog();
4346

4447
/**
45-
* Get the selected fields name
46-
* @return The selected fields name
48+
* Get the updated configuration
4749
*/
48-
QStringList selectedFields() const;
50+
QgsAttributeTableConfig config() const;
4951
};
5052

5153
#endif

‎src/ui/qgsorganizetablecolumnsdialog.ui

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,23 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>240</width>
10-
<height>219</height>
9+
<width>392</width>
10+
<height>357</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
1414
<string>Filter table column</string>
1515
</property>
1616
<layout class="QVBoxLayout" name="verticalLayout">
1717
<item>
18-
<widget class="QListWidget" name="mFieldsList"/>
18+
<widget class="QListWidget" name="mFieldsList">
19+
<property name="dragDropMode">
20+
<enum>QAbstractItemView::DragDrop</enum>
21+
</property>
22+
<property name="defaultDropAction">
23+
<enum>Qt::MoveAction</enum>
24+
</property>
25+
</widget>
1926
</item>
2027
<item>
2128
<widget class="QDialogButtonBox" name="buttonBox">

0 commit comments

Comments
 (0)
Please sign in to comment.