Skip to content

Commit fcea343

Browse files
committedMay 6, 2020
allow sorting attribute table by field not listed in the table
fixes #25671 Instead of using a sort filter proxy model on top of the columns model, this uses a dedicated model for the sorting columns
1 parent b1873a4 commit fcea343

14 files changed

+580
-418
lines changed
 

‎python/core/auto_generated/layout/qgslayoutitemattributetable.sip.in

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,6 @@ Sets the attributes to display in the table.
270270
to accommodate the new displayed feature attributes.
271271
%End
272272

273-
274273
void setWrapString( const QString &wrapString );
275274
%Docstring
276275
Sets a string to wrap the contents of the table cells by. Occurrences of this string will

‎python/core/auto_generated/layout/qgslayouttable.sip.in

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ typedef QVector< QVector< QVariant > > QgsLayoutTableContents;
1717

1818
typedef QVector< QgsLayoutTableColumn * > QgsLayoutTableColumns;
1919

20+
typedef QVector< QgsLayoutTableSortColumn * > QgsLayoutTableSortColumns;
21+
22+
2023

2124

2225
class QgsLayoutTableStyle
@@ -473,6 +476,26 @@ Replaces the columns in the table with a specified list of QgsLayoutTableColumns
473476
:param columns: list of QgsLayoutTableColumns to show in table.
474477

475478
.. seealso:: :py:func:`columns`
479+
%End
480+
481+
QgsLayoutTableSortColumns &sortColumns();
482+
%Docstring
483+
Returns a reference to the list of QgsLayoutTableSortColumns shown in the table
484+
485+
.. seealso:: :py:func:`setSortColumns`
486+
487+
.. versionadded:: 3.14
488+
%End
489+
490+
void setSortColumns( const QgsLayoutTableSortColumns &sortColumns );
491+
%Docstring
492+
Replaces the sorting columns in the table with a specified list of QgsLayoutTableSortColumns.
493+
494+
:param columns: list of QgsLayoutTableColumns used to sort the table.
495+
496+
.. seealso:: :py:func:`sortColumns`
497+
498+
.. versionadded:: 3.14
476499
%End
477500

478501
void setCellStyle( CellStyleGroup group, const QgsLayoutTableStyle &style );
@@ -562,6 +585,7 @@ new data.
562585

563586

564587

588+
565589

566590

567591
virtual bool calculateMaxColumnWidths();

‎python/core/auto_generated/layout/qgslayouttablecolumn.sip.in

Lines changed: 120 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@
1313
class QgsLayoutTableColumn : QObject
1414
{
1515
%Docstring
16-
Stores properties of a column for a QgsLayoutTable. Some properties of aQgsLayoutTableColumn
17-
are applicable only in certain contexts. For instance, the attribute and setAttribute methods only
18-
have an effect for QgsLayoutItemAttributeTables, and have no effect for QgsLayoutItemTextTables.
16+
Stores properties of a column for a QgsLayoutTable.
17+
Some properties of a QgsLayoutTableColumn are applicable only in certain contexts.
18+
For instance, the attribute and setAttribute methods only have an effect
19+
for QgsLayoutItemAttributeTables, and have no effect for QgsLayoutItemTextTables.
1920

2021
.. versionadded:: 3.0
2122
%End
@@ -146,7 +147,7 @@ is only used when the column is part of a :py:class:`QgsLayoutItemAttributeTable
146147
.. seealso:: :py:func:`attribute`
147148
%End
148149

149-
Qt::SortOrder sortOrder() const;
150+
Qt::SortOrder sortOrder() const /Deprecated/;
150151
%Docstring
151152
Returns the sort order for the column. This property is only used when the column
152153
is part of a QgsLayoutItemAttributeTable and when sortByRank is > 0.
@@ -158,9 +159,12 @@ is part of a QgsLayoutItemAttributeTable and when sortByRank is > 0.
158159
.. seealso:: :py:func:`setSortOrder`
159160

160161
.. seealso:: :py:func:`sortByRank`
162+
163+
.. deprecated:: QGIS 3.14
164+
the order is now hold in a distinct model
161165
%End
162166

163-
void setSortOrder( Qt::SortOrder order );
167+
void setSortOrder( Qt::SortOrder order ) /Deprecated/;
164168
%Docstring
165169
Sets the sort ``order`` for the column. This property is only used when the column
166170
is part of a QgsLayoutItemAttributeTable and when sortByRank() is > 0.
@@ -172,9 +176,12 @@ is part of a QgsLayoutItemAttributeTable and when sortByRank() is > 0.
172176
.. seealso:: :py:func:`sortOrder`
173177

174178
.. seealso:: :py:func:`setSortByRank`
179+
180+
.. deprecated:: QGIS 3.14
181+
the order is now hold in a distinct model
175182
%End
176183

177-
int sortByRank() const;
184+
int sortByRank() const /Deprecated/;
178185
%Docstring
179186
Returns the sort rank for the column. If the sort rank is > 0 then the column
180187
will be sorted in the table. The sort rank specifies the priority given to the
@@ -191,9 +198,12 @@ If sort rank is <= 0 then the column is not being sorted.
191198
.. seealso:: :py:func:`setSortByRank`
192199

193200
.. seealso:: :py:func:`sortOrder`
201+
202+
.. deprecated:: QGIS 3.14
203+
the order is now hold in a distinct model
194204
%End
195205

196-
void setSortByRank( int rank );
206+
void setSortByRank( int rank ) /Deprecated/;
197207
%Docstring
198208
Sets the sort ``rank`` for the column. If the sort rank is > 0 then the column
199209
will be sorted in the table. The sort rank specifies the priority given to the
@@ -209,6 +219,9 @@ If the sort ``rank`` is <= 0 then the column is not being sorted.
209219
.. seealso:: :py:func:`sortByRank`
210220

211221
.. seealso:: :py:func:`setSortOrder`
222+
223+
.. deprecated:: QGIS 3.14
224+
the order is now hold in a distinct model
212225
%End
213226

214227
QgsLayoutTableColumn *clone() /Factory/;
@@ -220,6 +233,106 @@ Creates a duplicate column which is a deep copy of this column.
220233

221234
};
222235

236+
class QgsLayoutTableSortColumn : QObject
237+
{
238+
%Docstring
239+
Stores properties of a column for the sorting of a :py:class:`QgsLayoutTable`.
240+
241+
.. versionadded:: 3.14
242+
%End
243+
244+
%TypeHeaderCode
245+
#include "qgslayouttablecolumn.h"
246+
%End
247+
public:
248+
249+
QgsLayoutTableSortColumn();
250+
%Docstring
251+
Constructor for :py:class:`QgsLayoutTableColumn`.
252+
253+
:param heading: column heading
254+
%End
255+
256+
bool writeXml( QDomElement &columnElem, QDomDocument &doc ) const;
257+
%Docstring
258+
Writes the column's properties to xml for storage.
259+
260+
:param columnElem: an existing QDomElement in which to store the column's properties.
261+
:param doc: QDomDocument for the destination xml.
262+
263+
.. seealso:: :py:func:`readXml`
264+
%End
265+
266+
bool readXml( const QDomElement &columnElem );
267+
%Docstring
268+
Reads the column's properties from xml.
269+
270+
:param columnElem: a QDomElement holding the column's desired properties.
271+
272+
.. seealso:: :py:func:`writeXml`
273+
%End
274+
275+
QString attribute() const;
276+
%Docstring
277+
Returns the attribute name or expression used for the column's values. This property
278+
is only used when the column is part of a :py:class:`QgsLayoutItemAttributeTable`.
279+
280+
.. note::
281+
282+
only applicable when used in a :py:class:`QgsLayoutItemAttributeTable`
283+
284+
.. seealso:: :py:func:`setAttribute`
285+
%End
286+
287+
void setAttribute( const QString &attribute );
288+
%Docstring
289+
Sets the ``attribute`` name or expression used for the column's values. This property
290+
is only used when the column is part of a :py:class:`QgsLayoutItemAttributeTable`.
291+
292+
.. note::
293+
294+
only applicable when used in a :py:class:`QgsLayoutItemAttributeTable`
295+
296+
.. seealso:: :py:func:`attribute`
297+
%End
298+
299+
Qt::SortOrder sortOrder() const;
300+
%Docstring
301+
Returns the sort order for the column. This property is only used when the column
302+
is part of a QgsLayoutItemAttributeTable and when sortByRank is > 0.
303+
304+
.. note::
305+
306+
only applicable when used in a :py:class:`QgsLayoutItemAttributeTable`
307+
308+
.. seealso:: :py:func:`setSortOrder`
309+
310+
.. seealso:: :py:func:`sortByRank`
311+
%End
312+
313+
void setSortOrder( Qt::SortOrder order );
314+
%Docstring
315+
Sets the sort ``order`` for the column. This property is only used when the column
316+
is part of a QgsLayoutItemAttributeTable and when sortByRank() is > 0.
317+
318+
.. note::
319+
320+
only applicable when used in a :py:class:`QgsLayoutItemAttributeTable`
321+
322+
.. seealso:: :py:func:`sortOrder`
323+
324+
.. seealso:: :py:func:`setSortByRank`
325+
%End
326+
327+
QgsLayoutTableSortColumn *clone() /Factory/;
328+
%Docstring
329+
Creates a duplicate column which is a deep copy of this column.
330+
331+
:return: a new QgsLayoutTableSortColumn with same properties as this column.
332+
%End
333+
334+
};
335+
223336
/************************************************************************
224337
* This file has been generated automatically from *
225338
* *

‎src/core/layout/qgscompositionconverter.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,14 @@ bool QgsCompositionConverter::readTableXml( QgsLayoutItemAttributeTable *layoutI
14621462
}
14631463
}
14641464
layoutItem->mColumns.append( column );
1465+
1466+
// sorting columns are now (QGIS 3.14+) handled in a dedicated list
1467+
QVector<QgsLayoutTableColumn *> sortColumns;
1468+
Q_NOWARN_DEPRECATED_PUSH
1469+
std::copy_if( layoutItem->mColumns.begin(), layoutItem->mColumns.end(), std::back_inserter( sortColumns ), []( QgsLayoutTableColumn * col ) {return col->sortByRank() > 0;} );
1470+
std::sort( sortColumns.begin(), sortColumns.end(), []( QgsLayoutTableColumn * a, QgsLayoutTableColumn * b ) {return a->sortByRank() < b->sortByRank();} );
1471+
Q_NOWARN_DEPRECATED_POP
1472+
// TODO remove comment: layoutItem->mSortColumns = sortColumns;
14651473
}
14661474
}
14671475

‎src/core/layout/qgslayoutitemattributetable.cpp

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,8 @@ void QgsLayoutItemAttributeTable::resetColumns()
172172
//remove existing columns
173173
qDeleteAll( mColumns );
174174
mColumns.clear();
175+
qDeleteAll( mSortColumns );
176+
mSortColumns.clear();
175177

176178
//rebuild columns list from vector layer fields
177179
int idx = 0;
@@ -480,10 +482,9 @@ bool QgsLayoutItemAttributeTable::getTableContents( QgsLayoutTableContents &cont
480482
req.setFilterFid( atlasFeature.id() );
481483
}
482484

483-
QVector< QPair<int, bool> > sortColumns = sortAttributes();
484-
for ( int i = sortColumns.size() - 1; i >= 0; --i )
485+
for ( const QgsLayoutTableSortColumn *column : qgis::as_const( mSortColumns ) )
485486
{
486-
req = req.addOrderBy( mColumns.at( sortColumns.at( i ).first )->attribute(), sortColumns.at( i ).second );
487+
req = req.addOrderBy( column->attribute(), column->sortOrder() == Qt::AscendingOrder );
487488
}
488489

489490
QgsFeature f;
@@ -722,39 +723,6 @@ void QgsLayoutItemAttributeTable::removeLayer( const QString &layerId )
722723
}
723724
}
724725

725-
static bool columnsBySortRank( QPair<int, QgsLayoutTableColumn * > a, QPair<int, QgsLayoutTableColumn * > b )
726-
{
727-
return a.second->sortByRank() < b.second->sortByRank();
728-
}
729-
730-
QVector<QPair<int, bool> > QgsLayoutItemAttributeTable::sortAttributes() const
731-
{
732-
//generate list of all sorted columns
733-
QVector< QPair<int, QgsLayoutTableColumn * > > sortedColumns;
734-
int idx = 0;
735-
for ( QgsLayoutTableColumn *column : mColumns )
736-
{
737-
if ( column->sortByRank() > 0 )
738-
{
739-
sortedColumns.append( qMakePair( idx, column ) );
740-
}
741-
idx++;
742-
}
743-
744-
//sort columns by rank
745-
std::sort( sortedColumns.begin(), sortedColumns.end(), columnsBySortRank );
746-
747-
//generate list of column index, bool for sort direction (to match 2.0 api)
748-
QVector<QPair<int, bool> > attributesBySortRank;
749-
attributesBySortRank.reserve( sortedColumns.size() );
750-
for ( auto &column : qgis::as_const( sortedColumns ) )
751-
{
752-
attributesBySortRank.append( qMakePair( column.first,
753-
column.second->sortOrder() == Qt::AscendingOrder ) );
754-
}
755-
return attributesBySortRank;
756-
}
757-
758726
void QgsLayoutItemAttributeTable::setWrapString( const QString &wrapString )
759727
{
760728
if ( wrapString == mWrapString )

‎src/core/layout/qgslayoutitemattributetable.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -256,15 +256,6 @@ class CORE_EXPORT QgsLayoutItemAttributeTable: public QgsLayoutTable
256256
*/
257257
void setDisplayedFields( const QStringList &fields, bool refresh = true );
258258

259-
/**
260-
* Returns the attributes used to sort the table's features.
261-
* \returns a QList of integer/bool pairs, where the integer refers to the attribute index and
262-
* the bool to the sort order for the attribute. If TRUE the attribute is sorted ascending,
263-
* if FALSE, the attribute is sorted in descending order.
264-
* \note not available in Python bindings
265-
*/
266-
QVector< QPair<int, bool> > sortAttributes() const SIP_SKIP;
267-
268259
/**
269260
* Sets a string to wrap the contents of the table cells by. Occurrences of this string will
270261
* be replaced by a line break.

‎src/core/layout/qgslayouttable.cpp

Lines changed: 50 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ QgsLayoutTable::~QgsLayoutTable()
6969
qDeleteAll( mColumns );
7070
mColumns.clear();
7171

72+
qDeleteAll( mSortColumns );
73+
mSortColumns.clear();
74+
7275
qDeleteAll( mCellStyles );
7376
mCellStyles.clear();
7477
}
@@ -93,7 +96,7 @@ bool QgsLayoutTable::writePropertiesToElement( QDomElement &elem, QDomDocument &
9396
elem.setAttribute( QStringLiteral( "backgroundColor" ), QgsSymbolLayerUtils::encodeColor( mBackgroundColor ) );
9497
elem.setAttribute( QStringLiteral( "wrapBehavior" ), QString::number( static_cast< int >( mWrapBehavior ) ) );
9598

96-
//columns
99+
// display columns
97100
QDomElement displayColumnsElem = doc.createElement( QStringLiteral( "displayColumns" ) );
98101
for ( QgsLayoutTableColumn *column : qgis::as_const( mColumns ) )
99102
{
@@ -102,6 +105,16 @@ bool QgsLayoutTable::writePropertiesToElement( QDomElement &elem, QDomDocument &
102105
displayColumnsElem.appendChild( columnElem );
103106
}
104107
elem.appendChild( displayColumnsElem );
108+
// sort columns
109+
QDomElement sortColumnsElem = doc.createElement( QStringLiteral( "sortColumns" ) );
110+
for ( QgsLayoutTableSortColumn *column : qgis::as_const( mSortColumns ) )
111+
{
112+
QDomElement columnElem = doc.createElement( QStringLiteral( "column" ) );
113+
column->writeXml( columnElem, doc );
114+
sortColumnsElem.appendChild( columnElem );
115+
}
116+
elem.appendChild( sortColumnsElem );
117+
105118

106119
//cell styles
107120
QDomElement stylesElem = doc.createElement( QStringLiteral( "cellStyles" ) );
@@ -147,7 +160,7 @@ bool QgsLayoutTable::readPropertiesFromElement( const QDomElement &itemElem, con
147160
mBackgroundColor = QgsSymbolLayerUtils::decodeColor( itemElem.attribute( QStringLiteral( "backgroundColor" ), QStringLiteral( "255,255,255,0" ) ) );
148161
mWrapBehavior = QgsLayoutTable::WrapBehavior( itemElem.attribute( QStringLiteral( "wrapBehavior" ), QStringLiteral( "0" ) ).toInt() );
149162

150-
//restore column specifications
163+
//restore display column specifications
151164
qDeleteAll( mColumns );
152165
mColumns.clear();
153166
QDomNodeList columnsList = itemElem.elementsByTagName( QStringLiteral( "displayColumns" ) );
@@ -163,6 +176,32 @@ bool QgsLayoutTable::readPropertiesFromElement( const QDomElement &itemElem, con
163176
mColumns.append( column );
164177
}
165178
}
179+
// sort columns
180+
qDeleteAll( mSortColumns );
181+
mSortColumns.clear();
182+
QDomNodeList sortColumnsList = itemElem.elementsByTagName( QStringLiteral( "sortColumns" ) );
183+
if ( !columnsList.isEmpty() )
184+
{
185+
QDomElement columnsElem = columnsList.at( 0 ).toElement();
186+
QDomNodeList columnEntryList = columnsElem.elementsByTagName( QStringLiteral( "column" ) );
187+
for ( int i = 0; i < columnEntryList.size(); ++i )
188+
{
189+
QDomElement columnElem = columnEntryList.at( i ).toElement();
190+
QgsLayoutTableSortColumn *column = new QgsLayoutTableSortColumn;
191+
column->readXml( columnElem );
192+
mSortColumns.append( column );
193+
}
194+
}
195+
else
196+
{
197+
// backward compatibility for QGIS < 3.14
198+
QVector<QgsLayoutTableColumn *> sortColumns;
199+
Q_NOWARN_DEPRECATED_PUSH
200+
std::copy_if( mColumns.begin(), mColumns.end(), std::back_inserter( sortColumns ), []( QgsLayoutTableColumn * col ) {return col->sortByRank() > 0;} );
201+
std::sort( sortColumns.begin(), sortColumns.end(), []( QgsLayoutTableColumn * a, QgsLayoutTableColumn * b ) {return a->sortByRank() < b->sortByRank();} );
202+
Q_NOWARN_DEPRECATED_POP
203+
// TODO remove comment: mSortColumns = sortColumns;
204+
}
166205

167206
//restore cell styles
168207
QDomNodeList stylesList = itemElem.elementsByTagName( QStringLiteral( "cellStyles" ) );
@@ -764,6 +803,15 @@ void QgsLayoutTable::setColumns( const QgsLayoutTableColumns &columns )
764803
mColumns.append( columns );
765804
}
766805

806+
void QgsLayoutTable::setSortColumns( const QgsLayoutTableSortColumns &sortColumns )
807+
{
808+
//remove existing columns
809+
qDeleteAll( mSortColumns );
810+
mSortColumns.clear();
811+
812+
mSortColumns.append( sortColumns );
813+
}
814+
767815
void QgsLayoutTable::setCellStyle( QgsLayoutTable::CellStyleGroup group, const QgsLayoutTableStyle &style )
768816
{
769817
if ( mCellStyles.contains( group ) )

‎src/core/layout/qgslayouttable.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <QPair>
2828

2929
class QgsLayoutTableColumn;
30+
class QgsLayoutTableSortColumn;
3031

3132
/**
3233
* \ingroup core
@@ -56,6 +57,14 @@ typedef QVector< QVector< QVariant > > QgsLayoutTableContents;
5657
*/
5758
typedef QVector< QgsLayoutTableColumn * > QgsLayoutTableColumns;
5859

60+
/**
61+
* \ingroup core
62+
* List of column definitions for sorting a QgsLayoutTable
63+
* \since QGIS 3.14
64+
*/
65+
typedef QVector< QgsLayoutTableSortColumn * > QgsLayoutTableSortColumns;
66+
67+
5968

6069
/**
6170
* \ingroup core
@@ -439,6 +448,21 @@ class CORE_EXPORT QgsLayoutTable: public QgsLayoutMultiFrame
439448
*/
440449
void setColumns( const QgsLayoutTableColumns &columns );
441450

451+
/**
452+
* Returns a reference to the list of QgsLayoutTableSortColumns shown in the table
453+
* \see setSortColumns()
454+
* \since QGIS 3.14
455+
*/
456+
QgsLayoutTableSortColumns &sortColumns() { return mSortColumns; }
457+
458+
/**
459+
* Replaces the sorting columns in the table with a specified list of QgsLayoutTableSortColumns.
460+
* \param columns list of QgsLayoutTableColumns used to sort the table.
461+
* \see sortColumns()
462+
* \since QGIS 3.14
463+
*/
464+
void setSortColumns( const QgsLayoutTableSortColumns &sortColumns );
465+
442466
/**
443467
* Sets the cell \a style for a cell \a group.
444468
* \see cellStyle()
@@ -551,6 +575,9 @@ class CORE_EXPORT QgsLayoutTable: public QgsLayoutMultiFrame
551575
//! Columns to show in table
552576
QgsLayoutTableColumns mColumns;
553577

578+
//! Columns to sort the table
579+
QgsLayoutTableSortColumns mSortColumns;
580+
554581
//! Contents to show in table
555582
QgsLayoutTableContents mTableContents;
556583

‎src/core/layout/qgslayouttablecolumn.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,37 @@ QgsLayoutTableColumn *QgsLayoutTableColumn::clone()
8383
newColumn->setHeading( mHeading );
8484
newColumn->setHAlignment( mHAlignment );
8585
newColumn->setVAlignment( mVAlignment );
86+
Q_NOWARN_DEPRECATED_PUSH
8687
newColumn->setSortByRank( mSortByRank );
8788
newColumn->setSortOrder( mSortOrder );
89+
Q_NOWARN_DEPRECATED_POP
8890
newColumn->setWidth( mWidth );
8991
return newColumn.release();
9092
}
93+
94+
QgsLayoutTableSortColumn::QgsLayoutTableSortColumn()
95+
{}
96+
97+
bool QgsLayoutTableSortColumn::writeXml( QDomElement &columnElem, QDomDocument &doc ) const
98+
{
99+
//background color
100+
QDomElement bgColorElem = doc.createElement( QStringLiteral( "backgroundColor" ) );
101+
columnElem.setAttribute( QStringLiteral( "attribute" ), mAttribute );
102+
columnElem.setAttribute( QStringLiteral( "sortOrder" ), QString::number( mSortOrder ) );
103+
return true;
104+
}
105+
106+
bool QgsLayoutTableSortColumn::readXml( const QDomElement &columnElem )
107+
{
108+
mAttribute = columnElem.attribute( QStringLiteral( "attribute" ), QString() );
109+
mSortOrder = static_cast< Qt::SortOrder >( columnElem.attribute( QStringLiteral( "sortOrder" ), QString::number( Qt::AscendingOrder ) ).toInt() );
110+
return true;
111+
}
112+
113+
QgsLayoutTableSortColumn *QgsLayoutTableSortColumn::clone()
114+
{
115+
std::unique_ptr< QgsLayoutTableSortColumn > newColumn = qgis::make_unique< QgsLayoutTableSortColumn >();
116+
newColumn->setAttribute( mAttribute );
117+
newColumn->setSortOrder( mSortOrder );
118+
return newColumn.release();
119+
}

‎src/core/layout/qgslayouttablecolumn.h

Lines changed: 90 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,10 @@
2828

2929
/**
3030
* \ingroup core
31-
* Stores properties of a column for a QgsLayoutTable. Some properties of aQgsLayoutTableColumn
32-
* are applicable only in certain contexts. For instance, the attribute and setAttribute methods only
33-
* have an effect for QgsLayoutItemAttributeTables, and have no effect for QgsLayoutItemTextTables.
31+
* Stores properties of a column for a QgsLayoutTable.
32+
* Some properties of a QgsLayoutTableColumn are applicable only in certain contexts.
33+
* For instance, the attribute and setAttribute methods only have an effect
34+
* for QgsLayoutItemAttributeTables, and have no effect for QgsLayoutItemTextTables.
3435
* \since QGIS 3.0
3536
*/
3637
class CORE_EXPORT QgsLayoutTableColumn : public QObject
@@ -141,17 +142,19 @@ class CORE_EXPORT QgsLayoutTableColumn : public QObject
141142
* \note only applicable when used in a QgsLayoutItemAttributeTable
142143
* \see setSortOrder()
143144
* \see sortByRank()
145+
* \deprecated since QGIS 3.14 the order is now hold in a distinct model
144146
*/
145-
Qt::SortOrder sortOrder() const { return mSortOrder; }
147+
Q_DECL_DEPRECATED Qt::SortOrder sortOrder() const SIP_DEPRECATED { return mSortOrder; }
146148

147149
/**
148150
* Sets the sort \a order for the column. This property is only used when the column
149151
* is part of a QgsLayoutItemAttributeTable and when sortByRank() is > 0.
150152
* \note only applicable when used in a QgsLayoutItemAttributeTable
151153
* \see sortOrder()
152154
* \see setSortByRank()
155+
* \deprecated since QGIS 3.14 the order is now hold in a distinct model
153156
*/
154-
void setSortOrder( Qt::SortOrder order ) { mSortOrder = order; }
157+
Q_DECL_DEPRECATED void setSortOrder( Qt::SortOrder order ) SIP_DEPRECATED { mSortOrder = order; }
155158

156159
/**
157160
* Returns the sort rank for the column. If the sort rank is > 0 then the column
@@ -165,8 +168,9 @@ class CORE_EXPORT QgsLayoutTableColumn : public QObject
165168
* \note only applicable when used in a QgsLayoutItemAttributeTable
166169
* \see setSortByRank()
167170
* \see sortOrder()
171+
* \deprecated since QGIS 3.14 the order is now hold in a distinct model
168172
*/
169-
int sortByRank() const { return mSortByRank; }
173+
Q_DECL_DEPRECATED int sortByRank() const SIP_DEPRECATED { return mSortByRank; }
170174

171175
/**
172176
* Sets the sort \a rank for the column. If the sort rank is > 0 then the column
@@ -179,8 +183,9 @@ class CORE_EXPORT QgsLayoutTableColumn : public QObject
179183
* \note only applicable when used in a QgsLayoutItemAttributeTable
180184
* \see sortByRank()
181185
* \see setSortOrder()
186+
* \deprecated since QGIS 3.14 the order is now hold in a distinct model
182187
*/
183-
void setSortByRank( int rank ) { mSortByRank = rank; }
188+
Q_DECL_DEPRECATED void setSortByRank( int rank ) SIP_DEPRECATED { mSortByRank = rank; }
184189

185190
/**
186191
* Creates a duplicate column which is a deep copy of this column.
@@ -203,4 +208,82 @@ class CORE_EXPORT QgsLayoutTableColumn : public QObject
203208

204209
};
205210

211+
/**
212+
* \ingroup core
213+
* Stores properties of a column for the sorting of a QgsLayoutTable.
214+
* \since QGIS 3.14
215+
*/
216+
class CORE_EXPORT QgsLayoutTableSortColumn : public QObject
217+
{
218+
Q_OBJECT
219+
220+
public:
221+
222+
/**
223+
* Constructor for QgsLayoutTableColumn.
224+
* \param heading column heading
225+
*/
226+
QgsLayoutTableSortColumn();
227+
228+
/**
229+
* Writes the column's properties to xml for storage.
230+
* \param columnElem an existing QDomElement in which to store the column's properties.
231+
* \param doc QDomDocument for the destination xml.
232+
* \see readXml()
233+
*/
234+
bool writeXml( QDomElement &columnElem, QDomDocument &doc ) const;
235+
236+
/**
237+
* Reads the column's properties from xml.
238+
* \param columnElem a QDomElement holding the column's desired properties.
239+
* \see writeXml()
240+
*/
241+
bool readXml( const QDomElement &columnElem );
242+
243+
/**
244+
* Returns the attribute name or expression used for the column's values. This property
245+
* is only used when the column is part of a QgsLayoutItemAttributeTable.
246+
* \note only applicable when used in a QgsLayoutItemAttributeTable
247+
* \see setAttribute()
248+
*/
249+
QString attribute() const { return mAttribute; }
250+
251+
/**
252+
* Sets the \a attribute name or expression used for the column's values. This property
253+
* is only used when the column is part of a QgsLayoutItemAttributeTable.
254+
* \note only applicable when used in a QgsLayoutItemAttributeTable
255+
* \see attribute()
256+
*/
257+
void setAttribute( const QString &attribute ) { mAttribute = attribute; }
258+
259+
/**
260+
* Returns the sort order for the column. This property is only used when the column
261+
* is part of a QgsLayoutItemAttributeTable and when sortByRank is > 0.
262+
* \note only applicable when used in a QgsLayoutItemAttributeTable
263+
* \see setSortOrder()
264+
* \see sortByRank()
265+
*/
266+
Qt::SortOrder sortOrder() const { return mSortOrder; }
267+
268+
/**
269+
* Sets the sort \a order for the column. This property is only used when the column
270+
* is part of a QgsLayoutItemAttributeTable and when sortByRank() is > 0.
271+
* \note only applicable when used in a QgsLayoutItemAttributeTable
272+
* \see sortOrder()
273+
* \see setSortByRank()
274+
*/
275+
void setSortOrder( Qt::SortOrder order ) { mSortOrder = order; }
276+
277+
/**
278+
* Creates a duplicate column which is a deep copy of this column.
279+
* \returns a new QgsLayoutTableSortColumn with same properties as this column.
280+
*/
281+
QgsLayoutTableSortColumn *clone() SIP_FACTORY;
282+
283+
private:
284+
285+
QString mAttribute;
286+
Qt::SortOrder mSortOrder = Qt::AscendingOrder;
287+
};
288+
206289
#endif //QGSLAYOUTTABLECOLUMN_H

‎src/gui/layout/qgslayoutattributeselectiondialog.cpp

Lines changed: 160 additions & 241 deletions
Large diffs are not rendered by default.

‎src/gui/layout/qgslayoutattributeselectiondialog.h

Lines changed: 30 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,11 @@ class QgsVectorLayer;
3737
class QPushButton;
3838
class QgsLayoutItemAttributeTable;
3939
class QgsLayoutAttributeTableColumnModel;
40-
class QgsLayoutTableSortColumnsProxyModel;
40+
class QgsLayoutTableSortModel;
4141
class QgsLayoutTableAvailableSortProxyModel;
4242
class QgsLayoutObject;
4343
class QgsLayoutTableColumn;
44+
class QgsLayoutTableSortColumn;
4445

4546
/**
4647
* \ingroup gui
@@ -109,26 +110,6 @@ class GUI_EXPORT QgsLayoutAttributeTableColumnModel: public QAbstractTableModel
109110
*/
110111
QModelIndex indexFromColumn( QgsLayoutTableColumn *column );
111112

112-
/**
113-
* Sets a specified column as a sorted column in the QgsLayoutItemAttributeTable. The column will be
114-
* added to the end of the sort rank list, ie it will take the next largest available sort rank.
115-
* \see moveColumnInSortRank()
116-
*/
117-
void setColumnAsSorted( QgsLayoutTableColumn *column, Qt::SortOrder order );
118-
119-
/**
120-
* Sets a specified column as an unsorted column in the QgsLayoutItemAttributeTable. The column will be
121-
* removed from the sort rank list.
122-
* \see setColumnAsSorted()
123-
*/
124-
void setColumnAsUnsorted( QgsLayoutTableColumn *column );
125-
126-
/**
127-
* Moves a column up or down in the sort rank for the QgsLayoutItemAttributeTable.
128-
* \see setColumnAsSorted()
129-
*/
130-
bool moveColumnInSortRank( QgsLayoutTableColumn *column, ShiftDirection direction );
131-
132113
private:
133114
QgsLayoutItemAttributeTable *mTable = nullptr;
134115

@@ -141,19 +122,19 @@ class GUI_EXPORT QgsLayoutAttributeTableColumnModel: public QAbstractTableModel
141122
* \note This class is not a part of public API
142123
* \since QGIS 3.12
143124
*/
144-
class GUI_EXPORT QgsLayoutTableSortColumnsProxyModel: public QSortFilterProxyModel
125+
class GUI_EXPORT QgsLayoutTableSortModel: public QAbstractTableModel
145126
{
146127
Q_OBJECT
147128

148129
public:
149130

150131
/**
151-
* Controls whether the proxy model shows sorted or unsorted columns
132+
* Controls whether a row/column is shifted up or down
152133
*/
153-
enum ColumnFilterType
134+
enum ShiftDirection
154135
{
155-
ShowSortedColumns, //!< Show only sorted columns
156-
ShowUnsortedColumns//!< Show only unsorted columns
136+
ShiftUp, //!< Shift the row/column up
137+
ShiftDown //!< Shift the row/column down
157138
};
158139

159140
/**
@@ -162,53 +143,42 @@ class GUI_EXPORT QgsLayoutTableSortColumnsProxyModel: public QSortFilterProxyMod
162143
* \param filterType filter for columns, controls whether sorted or unsorted columns are shown
163144
* \param parent optional parent
164145
*/
165-
QgsLayoutTableSortColumnsProxyModel( QgsLayoutItemAttributeTable *table, ColumnFilterType filterType, QObject *parent SIP_TRANSFERTHIS = nullptr );
146+
QgsLayoutTableSortModel( QgsLayoutItemAttributeTable *table, QObject *parent SIP_TRANSFERTHIS = nullptr );
166147

167-
bool lessThan( const QModelIndex &left, const QModelIndex &right ) const override;
148+
int rowCount( const QModelIndex &parent = QModelIndex() ) const override;
168149
int columnCount( const QModelIndex &parent = QModelIndex() ) const override;
169150
QVariant data( const QModelIndex &index, int role ) const override;
170151
QVariant headerData( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override;
171-
Qt::ItemFlags flags( const QModelIndex &index ) const override;
172152
bool setData( const QModelIndex &index, const QVariant &value, int role = Qt::EditRole ) override;
153+
Qt::ItemFlags flags( const QModelIndex &index ) const override;
154+
bool removeRows( int row, int count, const QModelIndex &parent = QModelIndex() ) override;
155+
bool insertRows( int row, int count, const QModelIndex &parent = QModelIndex() ) override;
156+
QModelIndex index( int row, int column, const QModelIndex &parent ) const override;
157+
QModelIndex parent( const QModelIndex &child ) const override;
173158

174159
/**
175-
* Returns the QgsLayoutTableColumn corresponding to a row in the proxy model.
176-
* \see columnFromIndex()
160+
* Moves the specified row up or down in the model. Used for rearranging the attribute tables
161+
* columns.
162+
* \returns true if the move is allowed
163+
* \param row row in model representing attribute table column to move
164+
* \param direction direction to move the attribute table column
177165
*/
178-
QgsLayoutTableColumn *columnFromRow( int row );
166+
bool moveRow( int row, ShiftDirection direction );
179167

180168
/**
181-
* Returns the QgsLayoutTableColumn corresponding to an index in the proxy model.
182-
* \see columnFromRow()
183-
* \see columnFromSourceIndex()
169+
* Returns the QgsLayoutTableSortColumn corresponding to an index in the model.
170+
* \see indexFromColumn()
184171
*/
185-
QgsLayoutTableColumn *columnFromIndex( const QModelIndex &index ) const;
172+
QgsLayoutTableSortColumn *columnFromIndex( const QModelIndex &index ) const;
186173

187174
/**
188-
* Returns the QgsLayoutTableColumn corresponding to an index from the source
189-
* QgsLayoutItemAttributeTableColumnModel model.
190-
* \see columnFromRow()
175+
* Returns a QModelIndex corresponding to a QgsLayoutTableSortColumn in the model.
191176
* \see columnFromIndex()
192177
*/
193-
QgsLayoutTableColumn *columnFromSourceIndex( const QModelIndex &sourceIndex ) const;
194-
195-
/**
196-
* Invalidates the current filter used by the proxy model
197-
*/
198-
void resetFilter();
199-
200-
protected:
201-
bool filterAcceptsRow( int source_row, const QModelIndex &source_parent ) const override;
178+
QModelIndex indexFromColumn( QgsLayoutTableSortColumn *column );
202179

203180
private:
204181
QgsLayoutItemAttributeTable *mTable = nullptr;
205-
ColumnFilterType mFilterType;
206-
207-
/**
208-
* Returns a list of QgsLayoutTableColumn without a set sort rank
209-
*/
210-
QList<QgsLayoutTableColumn *> columnsWithoutSortRank() const;
211-
212182
};
213183

214184
/**
@@ -334,16 +304,15 @@ class GUI_EXPORT QgsLayoutAttributeSelectionDialog: public QDialog, private Ui::
334304
const QgsVectorLayer *mVectorLayer = nullptr;
335305

336306
QgsLayoutAttributeTableColumnModel *mColumnModel = nullptr;
337-
338-
QgsLayoutTableSortColumnsProxyModel *mSortedProxyModel = nullptr;
339-
340-
QgsLayoutTableSortColumnsProxyModel *mAvailableSortProxyModel = nullptr;
341-
342307
QgsLayoutColumnAlignmentDelegate *mColumnAlignmentDelegate = nullptr;
343308
QgsLayoutColumnSourceDelegate *mColumnSourceDelegate = nullptr;
344-
QgsLayoutColumnSortOrderDelegate *mColumnSortOrderDelegate = nullptr;
345309
QgsLayoutColumnWidthDelegate *mColumnWidthDelegate = nullptr;
346310

311+
QgsLayoutTableSortModel *mSortColumnModel = nullptr;
312+
QgsLayoutColumnSourceDelegate *mSortColumnSourceDelegate = nullptr;
313+
QgsLayoutColumnSortOrderDelegate *mSortColumnOrderDelegate = nullptr;
314+
315+
347316
};
348317

349318
#endif // QGSLAYOUTATTRIBUTESELECTIONDIALOG_H

‎src/gui/layout/qgslayoutattributetablewidget.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,14 @@ void QgsLayoutAttributeTableWidget::mAttributesPushButton_clicked()
234234
currentColumns.append( copy );
235235
}
236236

237+
QVector<QgsLayoutTableSortColumn *> currentSortColumns;
238+
auto sit = mTable->sortColumns().constBegin();
239+
for ( ; sit != mTable->sortColumns().constEnd() ; ++sit )
240+
{
241+
QgsLayoutTableSortColumn *copy = ( *sit )->clone();
242+
currentSortColumns.append( copy );
243+
}
244+
237245
mTable->beginCommand( tr( "Change Table Attributes" ) );
238246

239247
//temporarily block updates for the window, to stop table trying to repaint under windows (#11462)
@@ -251,11 +259,14 @@ void QgsLayoutAttributeTableWidget::mAttributesPushButton_clicked()
251259
//clear currentColumns to free memory
252260
qDeleteAll( currentColumns );
253261
currentColumns.clear();
262+
qDeleteAll( currentSortColumns );
263+
currentSortColumns.clear();
254264
}
255265
else
256266
{
257267
//undo changes
258268
mTable->setColumns( currentColumns );
269+
mTable->setSortColumns( currentSortColumns );
259270
window()->setUpdatesEnabled( true );
260271
mTable->cancelCommand();
261272
}

‎src/ui/layout/qgslayoutattributeselectiondialogbase.ui

Lines changed: 27 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
<rect>
77
<x>0</x>
88
<y>0</y>
9-
<width>517</width>
9+
<width>533</width>
1010
<height>729</height>
1111
</rect>
1212
</property>
@@ -141,67 +141,56 @@
141141
</property>
142142
<layout class="QGridLayout" name="gridLayout_3">
143143
<item row="0" column="0">
144-
<layout class="QHBoxLayout" name="horizontalLayout_3">
145-
<item>
146-
<widget class="QComboBox" name="mSortColumnComboBox">
147-
<property name="minimumSize">
148-
<size>
149-
<width>180</width>
150-
<height>0</height>
151-
</size>
152-
</property>
153-
</widget>
154-
</item>
155-
<item>
156-
<widget class="QComboBox" name="mOrderComboBox">
157-
<property name="minimumSize">
158-
<size>
159-
<width>100</width>
160-
<height>0</height>
161-
</size>
162-
</property>
163-
</widget>
164-
</item>
144+
<widget class="QTableView" name="mSortColumnTableView">
145+
<property name="editTriggers">
146+
<set>QAbstractItemView::AllEditTriggers</set>
147+
</property>
148+
<property name="selectionMode">
149+
<enum>QAbstractItemView::SingleSelection</enum>
150+
</property>
151+
<property name="selectionBehavior">
152+
<enum>QAbstractItemView::SelectRows</enum>
153+
</property>
154+
</widget>
155+
</item>
156+
<item row="1" column="0">
157+
<layout class="QHBoxLayout" name="horizontalLayout">
165158
<item>
166-
<widget class="QPushButton" name="mAddSortColumnPushButton">
167-
<property name="maximumSize">
168-
<size>
169-
<width>16777215</width>
170-
<height>16777215</height>
171-
</size>
172-
</property>
159+
<widget class="QPushButton" name="mSortColumnUpPushButton">
173160
<property name="text">
174161
<string/>
175162
</property>
176163
<property name="icon">
177164
<iconset resource="../../../images/images.qrc">
178-
<normaloff>:/images/themes/default/symbologyAdd.svg</normaloff>:/images/themes/default/symbologyAdd.svg</iconset>
165+
<normaloff>:/images/themes/default/mActionArrowUp.svg</normaloff>:/images/themes/default/mActionArrowUp.svg</iconset>
179166
</property>
180167
</widget>
181168
</item>
182-
</layout>
183-
</item>
184-
<item row="2" column="0">
185-
<layout class="QHBoxLayout" name="horizontalLayout">
186169
<item>
187-
<widget class="QPushButton" name="mSortColumnUpPushButton">
170+
<widget class="QPushButton" name="mSortColumnDownPushButton">
188171
<property name="text">
189172
<string/>
190173
</property>
191174
<property name="icon">
192175
<iconset resource="../../../images/images.qrc">
193-
<normaloff>:/images/themes/default/mActionArrowUp.svg</normaloff>:/images/themes/default/mActionArrowUp.svg</iconset>
176+
<normaloff>:/images/themes/default/mActionArrowDown.svg</normaloff>:/images/themes/default/mActionArrowDown.svg</iconset>
194177
</property>
195178
</widget>
196179
</item>
197180
<item>
198-
<widget class="QPushButton" name="mSortColumnDownPushButton">
181+
<widget class="QPushButton" name="mAddSortColumnPushButton">
182+
<property name="maximumSize">
183+
<size>
184+
<width>16777215</width>
185+
<height>16777215</height>
186+
</size>
187+
</property>
199188
<property name="text">
200189
<string/>
201190
</property>
202191
<property name="icon">
203192
<iconset resource="../../../images/images.qrc">
204-
<normaloff>:/images/themes/default/mActionArrowDown.svg</normaloff>:/images/themes/default/mActionArrowDown.svg</iconset>
193+
<normaloff>:/images/themes/default/symbologyAdd.svg</normaloff>:/images/themes/default/symbologyAdd.svg</iconset>
205194
</property>
206195
</widget>
207196
</item>
@@ -231,19 +220,6 @@
231220
</item>
232221
</layout>
233222
</item>
234-
<item row="1" column="0">
235-
<widget class="QTableView" name="mSortColumnTableView">
236-
<property name="editTriggers">
237-
<set>QAbstractItemView::AllEditTriggers</set>
238-
</property>
239-
<property name="selectionMode">
240-
<enum>QAbstractItemView::SingleSelection</enum>
241-
</property>
242-
<property name="selectionBehavior">
243-
<enum>QAbstractItemView::SelectRows</enum>
244-
</property>
245-
</widget>
246-
</item>
247223
</layout>
248224
</widget>
249225
</widget>
@@ -267,9 +243,6 @@
267243
<tabstop>mAddColumnPushButton</tabstop>
268244
<tabstop>mRemoveColumnPushButton</tabstop>
269245
<tabstop>mResetColumnsPushButton</tabstop>
270-
<tabstop>mSortColumnComboBox</tabstop>
271-
<tabstop>mOrderComboBox</tabstop>
272-
<tabstop>mAddSortColumnPushButton</tabstop>
273246
<tabstop>mSortColumnTableView</tabstop>
274247
<tabstop>mSortColumnUpPushButton</tabstop>
275248
<tabstop>mSortColumnDownPushButton</tabstop>

0 commit comments

Comments
 (0)
Please sign in to comment.