Skip to content
Permalink
Browse files

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 7a172b5756d63620bc59a68906e60593618ad317
@@ -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
@@ -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;




@@ -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 );
@@ -562,6 +585,7 @@ new data.






virtual bool calculateMaxColumnWidths();
@@ -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
@@ -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
@@ -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
@@ -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 *
* *
@@ -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() )
{
@@ -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() )
@@ -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
}
}

@@ -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++;
}
}
@@ -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();
@@ -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
@@ -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++;
}
}
@@ -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 ) );
}
}
}
@@ -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;
@@ -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;

@@ -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 );
@@ -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 )
@@ -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.

0 comments on commit 7a172b5

Please sign in to comment.
You can’t perform that action at this time.