Skip to content
Permalink
Browse files

Allow sorting attribute table by expression

  • Loading branch information
m-kuhn committed May 16, 2016
1 parent 11ee2fc commit d07d9edda6a2c2f7482500ca37b0333353984bd1
@@ -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>
@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
id="svg5477"
viewBox="0 0 4.2333333 4.2333335"
height="16"
width="16"
inkscape:version="0.91 r13725"
sodipodi:docname="sort.svg">
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1016"
id="namedview13"
showgrid="true"
inkscape:zoom="39.333334"
inkscape:cx="1.7617969"
inkscape:cy="7.4154532"
inkscape:window-x="0"
inkscape:window-y="27"
inkscape:window-maximized="1"
inkscape:current-layer="svg5477">
<inkscape:grid
type="xygrid"
id="grid3341" />
</sodipodi:namedview>
<defs
id="defs5479" />
<metadata
id="metadata5482">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<path
inkscape:connector-curvature="0"
style="display:inline;fill:#6d97c4;fill-opacity:1;fill-rule:evenodd;stroke:#415a75;stroke-width:0.19843751;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;enable-background:new"
d="m 2.9088665,3.7628126 -1.0794756,-1.2402344 0.7733851,0 0.2887393,-2.12183447 0.3139285,2.12183447 0.7828981,0 z"
id="path2848-7-3-9-4"
sodipodi:nodetypes="ccccccc" />
<path
inkscape:connector-curvature="0"
id="path31772"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:tb-rl;text-anchor:start;fill:#f79191;fill-opacity:1;stroke:#a40000;stroke-width:0.19843751;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 1.2400171,1.4925339 -0.54129826,0 -0.0854208,0.2668105 -0.3479775,0 0.49723917,-1.46451483 0.41271749,0 0.4972392,1.46451483 -0.3479775,0 -0.084522,-0.2668105 m -0.45497826,-0.271715 0.36775916,0 L 0.969368,0.63815188 0.78503884,1.2208189"
sodipodi:nodetypes="ccccccccccccc" />
<path
inkscape:connector-curvature="0"
id="path31774"
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:medium;line-height:125%;font-family:'DejaVu Sans';-inkscape-font-specification:'DejaVu Sans, Bold';text-align:start;letter-spacing:0px;word-spacing:0px;writing-mode:tb-rl;text-anchor:start;fill:#91bbf7;fill-opacity:1;stroke:#0044a4;stroke-width:0.19843751;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 0.40469133,2.2147734 1.12845407,0 0,0.2285545 -0.72023241,0.9505123 0.74091331,0 0,0.285448 -1.16981581,0 0,-0.2285546 0.72023251,-0.9505123 -0.69955167,0 0,-0.2854479"
sodipodi:nodetypes="ccccccccccc" />
</svg>
@@ -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 );

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

@@ -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
@@ -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.
@@ -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:

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

0 comments on commit d07d9ed

Please sign in to comment.