Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #36236 from 3nids/fix25671
[layout] allow sorting attribute table by field not listed in the table
  • Loading branch information
3nids committed May 7, 2020
2 parents 4117be9 + 51b0d5a commit 7a172b5
Show file tree
Hide file tree
Showing 19 changed files with 511 additions and 847 deletions.
Expand Up @@ -270,7 +270,6 @@ Sets the attributes to display in the table.
to accommodate the new displayed feature attributes.
%End


void setWrapString( const QString &wrapString );
%Docstring
Sets a string to wrap the contents of the table cells by. Occurrences of this string will
Expand Down
26 changes: 25 additions & 1 deletion python/core/auto_generated/layout/qgslayouttable.sip.in
Expand Up @@ -15,7 +15,10 @@ typedef QVector< QVariant > QgsLayoutTableRow;
typedef QVector< QVector< QVariant > > QgsLayoutTableContents;


typedef QVector< QgsLayoutTableColumn * > QgsLayoutTableColumns;
typedef QVector<QgsLayoutTableColumn> QgsLayoutTableColumns;

typedef QVector<QgsLayoutTableColumn> QgsLayoutTableSortColumns;




Expand Down Expand Up @@ -473,6 +476,26 @@ Replaces the columns in the table with a specified list of QgsLayoutTableColumns
:param columns: list of QgsLayoutTableColumns to show in table.

.. seealso:: :py:func:`columns`
%End

QgsLayoutTableSortColumns &sortColumns();
%Docstring
Returns a reference to the list of QgsLayoutTableSortColumns shown in the table

.. seealso:: :py:func:`setSortColumns`

.. versionadded:: 3.14
%End

void setSortColumns( const QgsLayoutTableSortColumns &sortColumns );
%Docstring
Replaces the sorting columns in the table with a specified list of QgsLayoutTableSortColumns.

:param sortColumns: list of QgsLayoutTableColumns used to sort the table.

.. seealso:: :py:func:`sortColumns`

.. versionadded:: 3.14
%End

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






virtual bool calculateMaxColumnWidths();
Expand Down
27 changes: 19 additions & 8 deletions python/core/auto_generated/layout/qgslayouttablecolumn.sip.in
Expand Up @@ -10,12 +10,13 @@



class QgsLayoutTableColumn : QObject
class QgsLayoutTableColumn
{
%Docstring
Stores properties of a column for a QgsLayoutTable. Some properties of aQgsLayoutTableColumn
are applicable only in certain contexts. For instance, the attribute and setAttribute methods only
have an effect for QgsLayoutItemAttributeTables, and have no effect for QgsLayoutItemTextTables.
Stores properties of a column for a QgsLayoutTable.
Some properties of a QgsLayoutTableColumn are applicable only in certain contexts.
For instance, the attribute and setAttribute methods only have an effect
for QgsLayoutItemAttributeTables, and have no effect for QgsLayoutItemTextTables.

.. versionadded:: 3.0
%End
Expand Down Expand Up @@ -174,7 +175,7 @@ is part of a QgsLayoutItemAttributeTable and when sortByRank() is > 0.
.. seealso:: :py:func:`setSortByRank`
%End

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

.. seealso:: :py:func:`sortOrder`

.. deprecated:: QGIS 3.14
the order is now hold in a dedicated model
%End

void setSortByRank( int rank );
void setSortByRank( int rank ) /Deprecated/;
%Docstring
Sets the sort ``rank`` for the column. If the sort rank is > 0 then the column
will be sorted in the table. The sort rank specifies the priority given to the
Expand All @@ -209,17 +213,24 @@ If the sort ``rank`` is <= 0 then the column is not being sorted.
.. seealso:: :py:func:`sortByRank`

.. seealso:: :py:func:`setSortOrder`

.. deprecated:: QGIS 3.14
the order is now hold in a dedicated model
%End

QgsLayoutTableColumn *clone() /Factory/;
QgsLayoutTableColumn *clone() /Deprecated,Factory/;
%Docstring
Creates a duplicate column which is a deep copy of this column.

:return: a new QgsLayoutTableColumn with same properties as this column.

.. deprecated:: QGIS 3.14
use a copy instead
%End

};
bool operator==( const QgsLayoutTableColumn &other );

};
/************************************************************************
* This file has been generated automatically from *
* *
Expand Down
27 changes: 18 additions & 9 deletions src/core/layout/qgscompositionconverter.cpp
Expand Up @@ -1431,6 +1431,8 @@ bool QgsCompositionConverter::readTableXml( QgsLayoutItemAttributeTable *layoutI

//restore column specifications
layoutItem->mColumns.clear();
layoutItem->mSortColumns.clear();

QDomNodeList columnsList = itemElem.elementsByTagName( QStringLiteral( "displayColumns" ) );
if ( !columnsList.isEmpty() )
{
Expand All @@ -1439,14 +1441,14 @@ bool QgsCompositionConverter::readTableXml( QgsLayoutItemAttributeTable *layoutI
for ( int i = 0; i < columnEntryList.size(); ++i )
{
QDomElement columnElem = columnEntryList.at( i ).toElement();
QgsLayoutTableColumn *column = new QgsLayoutTableColumn;
column->mHAlignment = static_cast< Qt::AlignmentFlag >( columnElem.attribute( QStringLiteral( "hAlignment" ), QString::number( Qt::AlignLeft ) ).toInt() );
column->mVAlignment = static_cast< Qt::AlignmentFlag >( columnElem.attribute( QStringLiteral( "vAlignment" ), QString::number( Qt::AlignVCenter ) ).toInt() );
column->mHeading = columnElem.attribute( QStringLiteral( "heading" ), QString() );
column->mAttribute = columnElem.attribute( QStringLiteral( "attribute" ), QString() );
column->mSortByRank = columnElem.attribute( QStringLiteral( "sortByRank" ), QStringLiteral( "0" ) ).toInt();
column->mSortOrder = static_cast< Qt::SortOrder >( columnElem.attribute( QStringLiteral( "sortOrder" ), QString::number( Qt::AscendingOrder ) ).toInt() );
column->mWidth = columnElem.attribute( QStringLiteral( "width" ), QStringLiteral( "0.0" ) ).toDouble();
QgsLayoutTableColumn column;
column.mHAlignment = static_cast< Qt::AlignmentFlag >( columnElem.attribute( QStringLiteral( "hAlignment" ), QString::number( Qt::AlignLeft ) ).toInt() );
column.mVAlignment = static_cast< Qt::AlignmentFlag >( columnElem.attribute( QStringLiteral( "vAlignment" ), QString::number( Qt::AlignVCenter ) ).toInt() );
column.mHeading = columnElem.attribute( QStringLiteral( "heading" ), QString() );
column.mAttribute = columnElem.attribute( QStringLiteral( "attribute" ), QString() );
column.mSortByRank = columnElem.attribute( QStringLiteral( "sortByRank" ), QStringLiteral( "0" ) ).toInt();
column.mSortOrder = static_cast< Qt::SortOrder >( columnElem.attribute( QStringLiteral( "sortOrder" ), QString::number( Qt::AscendingOrder ) ).toInt() );
column.mWidth = columnElem.attribute( QStringLiteral( "width" ), QStringLiteral( "0.0" ) ).toDouble();

QDomNodeList bgColorList = columnElem.elementsByTagName( QStringLiteral( "backgroundColor" ) );
if ( !bgColorList.isEmpty() )
Expand All @@ -1460,10 +1462,17 @@ bool QgsCompositionConverter::readTableXml( QgsLayoutItemAttributeTable *layoutI
bgAlpha = bgColorElem.attribute( QStringLiteral( "alpha" ) ).toDouble( &alphaOk );
if ( redOk && greenOk && blueOk && alphaOk )
{
column->mBackgroundColor = QColor( bgRed, bgGreen, bgBlue, bgAlpha );
column.mBackgroundColor = QColor( bgRed, bgGreen, bgBlue, bgAlpha );
}
}
layoutItem->mColumns.append( column );

// sorting columns are now (QGIS 3.14+) handled in a dedicated list
// copy the display columns if sortByRank > 0 and then, sort them by rank
Q_NOWARN_DEPRECATED_PUSH
std::copy_if( layoutItem->mColumns.begin(), layoutItem->mColumns.end(), std::back_inserter( layoutItem->mSortColumns ), []( const QgsLayoutTableColumn & col ) {return col.sortByRank() > 0;} );
std::sort( layoutItem->mSortColumns.begin(), layoutItem->mSortColumns.end(), []( const QgsLayoutTableColumn & a, const QgsLayoutTableColumn & b ) {return a.sortByRank() < b.sortByRank();} );
Q_NOWARN_DEPRECATED_POP
}
}

Expand Down
80 changes: 22 additions & 58 deletions src/core/layout/qgslayoutitemattributetable.cpp
Expand Up @@ -170,19 +170,19 @@ void QgsLayoutItemAttributeTable::resetColumns()
}

//remove existing columns
qDeleteAll( mColumns );
mColumns.clear();
mSortColumns.clear();

//rebuild columns list from vector layer fields
int idx = 0;
const QgsFields sourceFields = source->fields();
for ( const auto &field : sourceFields )
{
QString currentAlias = source->attributeDisplayName( idx );
std::unique_ptr< QgsLayoutTableColumn > col = qgis::make_unique< QgsLayoutTableColumn >();
col->setAttribute( field.name() );
col->setHeading( currentAlias );
mColumns.append( col.release() );
QgsLayoutTableColumn col;
col.setAttribute( field.name() );
col.setHeading( currentAlias );
mColumns.append( col );
idx++;
}
}
Expand Down Expand Up @@ -319,7 +319,6 @@ void QgsLayoutItemAttributeTable::setDisplayedFields( const QStringList &fields,
}

//rebuild columns list, taking only fields contained in supplied list
qDeleteAll( mColumns );
mColumns.clear();

const QgsFields layerFields = source->fields();
Expand All @@ -333,10 +332,10 @@ void QgsLayoutItemAttributeTable::setDisplayedFields( const QStringList &fields,
continue;

QString currentAlias = source->attributeDisplayName( attrIdx );
std::unique_ptr< QgsLayoutTableColumn > col = qgis::make_unique< QgsLayoutTableColumn >();
col->setAttribute( layerFields.at( attrIdx ).name() );
col->setHeading( currentAlias );
mColumns.append( col.release() );
QgsLayoutTableColumn col;
col.setAttribute( layerFields.at( attrIdx ).name() );
col.setHeading( currentAlias );
mColumns.append( col );
}
}
else
Expand All @@ -346,10 +345,10 @@ void QgsLayoutItemAttributeTable::setDisplayedFields( const QStringList &fields,
for ( const QgsField &field : layerFields )
{
QString currentAlias = source->attributeDisplayName( idx );
std::unique_ptr< QgsLayoutTableColumn > col = qgis::make_unique< QgsLayoutTableColumn >();
col->setAttribute( field.name() );
col->setHeading( currentAlias );
mColumns.append( col.release() );
QgsLayoutTableColumn col;
col.setAttribute( field.name() );
col.setHeading( currentAlias );
mColumns.append( col );
idx++;
}
}
Expand All @@ -368,16 +367,16 @@ void QgsLayoutItemAttributeTable::restoreFieldAliasMap( const QMap<int, QString>
return;
}

for ( QgsLayoutTableColumn *column : qgis::as_const( mColumns ) )
for ( int i = 0; i < mColumns.count(); i++ )
{
int attrIdx = source->fields().lookupField( column->attribute() );
int attrIdx = source->fields().lookupField( mColumns[i].attribute() );
if ( map.contains( attrIdx ) )
{
column->setHeading( map.value( attrIdx ) );
mColumns[i].setHeading( map.value( attrIdx ) );
}
else
{
column->setHeading( source->attributeDisplayName( attrIdx ) );
mColumns[i].setHeading( source->attributeDisplayName( attrIdx ) );
}
}
}
Expand Down Expand Up @@ -480,10 +479,9 @@ bool QgsLayoutItemAttributeTable::getTableContents( QgsLayoutTableContents &cont
req.setFilterFid( atlasFeature.id() );
}

QVector< QPair<int, bool> > sortColumns = sortAttributes();
for ( int i = sortColumns.size() - 1; i >= 0; --i )
for ( const QgsLayoutTableColumn &column : qgis::as_const( mSortColumns ) )
{
req = req.addOrderBy( mColumns.at( sortColumns.at( i ).first )->attribute(), sortColumns.at( i ).second );
req = req.addOrderBy( column.attribute(), column.sortOrder() == Qt::AscendingOrder );
}

QgsFeature f;
Expand Down Expand Up @@ -549,9 +547,9 @@ bool QgsLayoutItemAttributeTable::getTableContents( QgsLayoutTableContents &cont
QgsLayoutTableRow rowContents;
rowContents.reserve( mColumns.count() );

for ( QgsLayoutTableColumn *column : qgis::as_const( mColumns ) )
for ( const QgsLayoutTableColumn &column : qgis::as_const( mColumns ) )
{
int idx = layer->fields().lookupField( column->attribute() );
int idx = layer->fields().lookupField( column.attribute() );

QgsConditionalStyle style;

Expand All @@ -574,7 +572,7 @@ bool QgsLayoutItemAttributeTable::getTableContents( QgsLayoutTableContents &cont
else
{
// Lets assume it's an expression
std::unique_ptr< QgsExpression > expression = qgis::make_unique< QgsExpression >( column->attribute() );
std::unique_ptr< QgsExpression > expression = qgis::make_unique< QgsExpression >( column.attribute() );
context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "row_number" ), counter + 1, true ) );
expression->prepare( &context );
QVariant value = expression->evaluate( &context );
Expand Down Expand Up @@ -716,45 +714,11 @@ void QgsLayoutItemAttributeTable::removeLayer( const QString &layerId )
{
mVectorLayer.setLayer( nullptr );
//remove existing columns
qDeleteAll( mColumns );
mColumns.clear();
}
}
}

static bool columnsBySortRank( QPair<int, QgsLayoutTableColumn * > a, QPair<int, QgsLayoutTableColumn * > b )
{
return a.second->sortByRank() < b.second->sortByRank();
}

QVector<QPair<int, bool> > QgsLayoutItemAttributeTable::sortAttributes() const
{
//generate list of all sorted columns
QVector< QPair<int, QgsLayoutTableColumn * > > sortedColumns;
int idx = 0;
for ( QgsLayoutTableColumn *column : mColumns )
{
if ( column->sortByRank() > 0 )
{
sortedColumns.append( qMakePair( idx, column ) );
}
idx++;
}

//sort columns by rank
std::sort( sortedColumns.begin(), sortedColumns.end(), columnsBySortRank );

//generate list of column index, bool for sort direction (to match 2.0 api)
QVector<QPair<int, bool> > attributesBySortRank;
attributesBySortRank.reserve( sortedColumns.size() );
for ( auto &column : qgis::as_const( sortedColumns ) )
{
attributesBySortRank.append( qMakePair( column.first,
column.second->sortOrder() == Qt::AscendingOrder ) );
}
return attributesBySortRank;
}

void QgsLayoutItemAttributeTable::setWrapString( const QString &wrapString )
{
if ( wrapString == mWrapString )
Expand Down
9 changes: 0 additions & 9 deletions src/core/layout/qgslayoutitemattributetable.h
Expand Up @@ -256,15 +256,6 @@ class CORE_EXPORT QgsLayoutItemAttributeTable: public QgsLayoutTable
*/
void setDisplayedFields( const QStringList &fields, bool refresh = true );

/**
* Returns the attributes used to sort the table's features.
* \returns a QList of integer/bool pairs, where the integer refers to the attribute index and
* the bool to the sort order for the attribute. If TRUE the attribute is sorted ascending,
* if FALSE, the attribute is sorted in descending order.
* \note not available in Python bindings
*/
QVector< QPair<int, bool> > sortAttributes() const SIP_SKIP;

/**
* Sets a string to wrap the contents of the table cells by. Occurrences of this string will
* be replaced by a line break.
Expand Down

0 comments on commit 7a172b5

Please sign in to comment.