Skip to content

Commit

Permalink
Allow sorting attribute table by expression
Browse files Browse the repository at this point in the history
  • Loading branch information
m-kuhn committed May 16, 2016
1 parent 11ee2fc commit d07d9ed
Show file tree
Hide file tree
Showing 17 changed files with 399 additions and 56 deletions.
1 change: 1 addition & 0 deletions images/images.qrc
Expand Up @@ -583,6 +583,7 @@
<file>themes/default/multieditMixedValues.svg</file>
<file>themes/default/multieditSameValues.svg</file>
<file>themes/default/locked_repeating.svg</file>
<file>themes/default/sort.svg</file>
</qresource>
<qresource prefix="/images/tips">
<file alias="symbol_levels.png">qgis_tips/symbol_levels.png</file>
Expand Down
73 changes: 73 additions & 0 deletions images/themes/default/sort.svg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
11 changes: 11 additions & 0 deletions python/core/qgsattributetableconfig.sip
Expand Up @@ -104,4 +104,15 @@ class QgsAttributeTableConfig
* Deserialize to XML on layer load
*/
void readXml( const QDomNode& node );

/**
* Get the expression used for sorting.
*/
QString sortExpression() const;

/**
* Set the sort expression used for sorting.
*/
void setSortExpression( const QString& sortExpression );

};
14 changes: 14 additions & 0 deletions python/gui/attributetable/qgsattributetablefiltermodel.sip
Expand Up @@ -142,6 +142,20 @@ class QgsAttributeTableFilterModel: QSortFilterProxyModel, QgsFeatureModel
*/
virtual void sort( int column, Qt::SortOrder order = Qt::AscendingOrder );

/**
* Sort by the given expression using the given order.
* Prefetches all the data from the layer to speed up sorting.
*
* @param column The expression which should be used for sorting
* @param order The order ( Qt::AscendingOrder or Qt::DescendingOrder )
*/
void sort( QString expression, Qt::SortOrder order = Qt::AscendingOrder );

/**
* The expression which is used to sort the attribute table.
*/
QString sortExpression() const;

/** Returns the map canvas*/
QgsMapCanvas* mapCanvas() const;

Expand Down
19 changes: 16 additions & 3 deletions python/gui/attributetable/qgsattributetablemodel.sip
Expand Up @@ -148,6 +148,19 @@ class QgsAttributeTableModel : QAbstractTableModel
*/
void prefetchColumnData( int column );

/**
* Prefetches the entire data for one expression. Based on this cached information
* the sorting can later be done in a performant way.
*
* @param expression The expression to cache
*/
void prefetchSortData( const QString& expression );

/**
* The expression which was used to fill the sorting cache
*/
QString sortCacheExpression() const;

/**
* Set a request that will be used to fill this attribute table model.
* In contrast to a filter, the request will constrain the data shown without the possibility
Expand All @@ -160,7 +173,7 @@ class QgsAttributeTableModel : QAbstractTableModel
/**
* Get the the feature request
*/
const QgsFeatureRequest &request() const;
const QgsFeatureRequest& request() const;

/**
* Sets the context in which this table is shown.
Expand Down Expand Up @@ -188,7 +201,7 @@ class QgsAttributeTableModel : QAbstractTableModel
* Empty extra columns to announce from this model.
* Any extra columns need to be implemented by proxy models in front of this model.
*/
void setExtraColumns(int extraColumns);
void setExtraColumns( int extraColumns );

public slots:

Expand Down Expand Up @@ -226,7 +239,7 @@ class QgsAttributeTableModel : QAbstractTableModel
* Launched when eatures have been deleted
* @param fids feature ids
*/
virtual void featuresDeleted( const QgsFeatureIds& fid );
virtual void featuresDeleted( const QgsFeatureIds& fids );
/**
* Launched when a feature has been added
* @param fid feature id
Expand Down
25 changes: 25 additions & 0 deletions python/gui/attributetable/qgsdualview.sip
Expand Up @@ -115,17 +115,42 @@ class QgsDualView : QStackedWidget
*/
QgsAttributeTableModel* masterModel() const;

/**
* Set the request
*
* @param request The request
*/
void setRequest( const QgsFeatureRequest& request );

/**
* Set the feature selection model
*
* @param featureSelectionManager the feature selection model
*/
void setFeatureSelectionManager( QgsIFeatureSelectionManager* featureSelectionManager );

/**
* Returns the table view
*
* @return The table view
*/
QgsAttributeTableView* tableView();
/**
* Set the attribute table config which should be used to control
* the appearance of the attribute table.
*/
void setAttributeTableConfig( const QgsAttributeTableConfig& config );

/**
* Set the expression used for sorting the table and feature list.
*/
void setSortExpression( const QString& sortExpression );

/**
* Get the expression used for sorting the table and feature list.
*/
QString sortExpression() const;

protected:
/**
* Initializes widgets which depend on the attributes of this layer
Expand Down
58 changes: 53 additions & 5 deletions src/app/qgsattributetabledialog.cpp
Expand Up @@ -16,18 +16,20 @@

#include <QDockWidget>
#include <QMessageBox>
#include <QGridLayout>
#include <QDialogButtonBox>

#include "qgsattributetabledialog.h"
#include "qgsattributetablemodel.h"
#include "qgsattributetablefiltermodel.h"
#include "qgsattributetableview.h"
#include "qgsorganizetablecolumnsdialog.h"

#include <qgsapplication.h>
#include <qgsvectordataprovider.h>
#include <qgsvectorlayer.h>
#include <qgsexpression.h>

#include "qgsapplication.h"
#include "qgsvectorlayer.h"
#include "qgsvectordataprovider.h"
#include "qgsexpression.h"
#include "qgsexpressionbuilderwidget.h"
#include "qgisapp.h"
#include "qgsaddattrdialog.h"
#include "qgsdelattrdialog.h"
Expand Down Expand Up @@ -616,6 +618,52 @@ void QgsAttributeTableDialog::on_mAddFeature_clicked()
}
}

void QgsAttributeTableDialog::on_mSortButton_clicked()
{
QgsAttributeTableConfig config = mLayer->attributeTableConfig();

QDialog orderByDlg;
orderByDlg.setWindowTitle( tr( "Configure attribute table sort order" ) );
QDialogButtonBox* dialogButtonBox = new QDialogButtonBox( QDialogButtonBox::Ok | QDialogButtonBox::Cancel );
QGridLayout* layout = new QGridLayout();
connect( dialogButtonBox, SIGNAL( accepted() ), &orderByDlg, SLOT( accept() ) );
connect( dialogButtonBox, SIGNAL( rejected() ), &orderByDlg, SLOT( reject() ) );
orderByDlg.setLayout( layout );

QGroupBox* sortingGroupBox = new QGroupBox();
sortingGroupBox->setTitle( tr( "Enable sorting order in attribute table" ) );
sortingGroupBox->setCheckable( true );
sortingGroupBox->setChecked( !mMainView->sortExpression().isEmpty() );
layout->addWidget( sortingGroupBox );
sortingGroupBox->setLayout( new QGridLayout() );

QgsExpressionBuilderWidget* expressionBuilder = new QgsExpressionBuilderWidget();
expressionBuilder->setExpressionText( mMainView->sortExpression().isEmpty() ? mLayer->displayExpression() : mMainView->sortExpression() );
QgsExpressionContext context;
context << QgsExpressionContextUtils::globalScope()
<< QgsExpressionContextUtils::projectScope();
expressionBuilder->setExpressionContext( context );
expressionBuilder->setLayer( mLayer );
sortingGroupBox->layout()->addWidget( expressionBuilder );

layout->addWidget( dialogButtonBox );
if ( orderByDlg.exec() )
{
if ( sortingGroupBox->isChecked() )
{
mMainView->setSortExpression( expressionBuilder->expressionText() );
config.setSortExpression( expressionBuilder->expressionText() );
}
else
{
mMainView->setSortExpression( QString() );
config.setSortExpression( QString() );
}

mLayer->setAttributeTableConfig( config );
}
}

void QgsAttributeTableDialog::on_mExpressionSelectButton_clicked()
{
QgsExpressionSelectionDialog* dlg = new QgsExpressionSelectionDialog( mLayer );
Expand Down
2 changes: 2 additions & 0 deletions src/app/qgsattributetabledialog.h
Expand Up @@ -154,6 +154,8 @@ class APP_EXPORT QgsAttributeTableDialog : public QDialog, private Ui::QgsAttrib

void on_mHelpButton_clicked() { QgsContextHelp::run( metaObject()->className() ); }

void on_mSortButton_clicked();

void on_mExpressionSelectButton_clicked();
void filterColumnChanged( QObject* filterAction );
void filterExpressionBuilder();
Expand Down
14 changes: 14 additions & 0 deletions src/core/qgsattributetableconfig.cpp
Expand Up @@ -173,6 +173,18 @@ void QgsAttributeTableConfig::readXml( const QDomNode& node )
}
}
}

mSortExpression = configNode.toElement().attribute( "sortExpression" );
}

QString QgsAttributeTableConfig::sortExpression() const
{
return mSortExpression;
}

void QgsAttributeTableConfig::setSortExpression( const QString& sortExpression )
{
mSortExpression = sortExpression;
}

void QgsAttributeTableConfig::writeXml( QDomNode& node ) const
Expand All @@ -182,6 +194,8 @@ void QgsAttributeTableConfig::writeXml( QDomNode& node ) const
QDomElement configElement = doc.createElement( "attributetableconfig" );
configElement.setAttribute( "actionWidgetStyle", mActionWidgetStyle == ButtonList ? "buttonList" : "dropDown" );

configElement.setAttribute( "sortExpression", mSortExpression );

QDomElement columnsElement = doc.createElement( "columns" );

Q_FOREACH ( const ColumnConfig& column, mColumns )
Expand Down
10 changes: 10 additions & 0 deletions src/core/qgsattributetableconfig.h
Expand Up @@ -110,10 +110,20 @@ class CORE_EXPORT QgsAttributeTableConfig
*/
void readXml( const QDomNode& node );

/**
* Get the expression used for sorting.
*/
QString sortExpression() const;

/**
* Set the sort expression used for sorting.
*/
void setSortExpression( const QString& sortExpression );

private:
QVector<ColumnConfig> mColumns;
ActionWidgetStyle mActionWidgetStyle;
QString mSortExpression;
};

Q_DECLARE_METATYPE( QgsAttributeTableConfig::ColumnConfig )
Expand Down
14 changes: 14 additions & 0 deletions src/gui/attributetable/qgsattributetablefiltermodel.cpp
Expand Up @@ -194,6 +194,20 @@ void QgsAttributeTableFilterModel::setAttributeTableConfig( const QgsAttributeTa
endResetModel();
}
}

sort( config.sortExpression() );
}

void QgsAttributeTableFilterModel::sort( QString expression, Qt::SortOrder order )
{
QSortFilterProxyModel::sort( -1 );
masterModel()->prefetchSortData( expression );
QSortFilterProxyModel::sort( 0, order ) ;
}

QString QgsAttributeTableFilterModel::sortExpression() const
{
return masterModel()->sortCacheExpression();
}

void QgsAttributeTableFilterModel::setSelectedOnTop( bool selectedOnTop )
Expand Down
14 changes: 14 additions & 0 deletions src/gui/attributetable/qgsattributetablefiltermodel.h
Expand Up @@ -178,6 +178,20 @@ class GUI_EXPORT QgsAttributeTableFilterModel: public QSortFilterProxyModel, pub
*/
virtual void sort( int column, Qt::SortOrder order = Qt::AscendingOrder ) override;

/**
* Sort by the given expression using the given order.
* Prefetches all the data from the layer to speed up sorting.
*
* @param expression The expression which should be used for sorting
* @param order The order ( Qt::AscendingOrder or Qt::DescendingOrder )
*/
void sort( QString expression, Qt::SortOrder order = Qt::AscendingOrder );

/**
* The expression which is used to sort the attribute table.
*/
QString sortExpression() const;

/** Returns the map canvas*/
QgsMapCanvas* mapCanvas() const { return mCanvas; }

Expand Down

0 comments on commit d07d9ed

Please sign in to comment.