[FEATURE] Allow definition of rendering order for renderers

This allows defining the order in which features are processed by
renderers.
This commit is contained in:
Matthias Kuhn 2015-12-21 10:41:35 +01:00
parent a5f88181f6
commit 73ba0e805a
16 changed files with 546 additions and 32 deletions

View File

@ -0,0 +1,34 @@
/***************************************************************************
qgsorderbydialog.h
---------------------
begin : 20.12.2015
copyright : (C) 2015 by Matthias Kuhn
email : matthias@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
class QgsOrderByDialog : QDialog
{
%TypeHeaderCode
#include "qgsorderbydialog.h"
%End
public:
QgsOrderByDialog( QgsVectorLayer* layer, QWidget* parent = nullptr );
/**
* Set the order by to manage
*/
void setOrderBys( const QList<QgsFeatureRequest::OrderByClause>& orderBys );
/**
* Get the order by defined in the dialog
*/
QgsFeatureRequest::OrderBy orderBys();
};

View File

@ -346,7 +346,7 @@ void QgsFeatureRequest::OrderBy::load( const QDomElement& elem )
for ( int i = 0; i < clauses.size(); ++i )
{
QDomElement clauseElem = clauses.at( i ).toElement();
QString expression = clauseElem.toText().data();
QString expression = clauseElem.text();
bool asc = clauseElem.attribute( "asc" ).toInt() != 0;
bool nullsFirst = clauseElem.attribute( "nullsFirst" ).toInt() != 0;

View File

@ -150,10 +150,13 @@ bool QgsVectorLayerRenderer::render()
QgsRectangle requestExtent = mContext.extent();
mRendererV2->modifyRequestExtent( requestExtent, mContext );
QgsFeatureRequest::OrderBy orderBy = mRendererV2->orderBy();
QgsFeatureRequest featureRequest = QgsFeatureRequest()
.setFilterRect( requestExtent )
.setSubsetOfAttributes( mAttrNames, mFields )
.setExpressionContext( mContext.expressionContext() );
.setExpressionContext( mContext.expressionContext() )
.setOrderBys( orderBy );
const QgsFeatureFilterProvider* featureFilterProvider = mContext.featureFilterProvider();
if ( featureFilterProvider )

View File

@ -498,7 +498,7 @@ QgsCategorizedSymbolRendererV2* QgsCategorizedSymbolRendererV2::clone() const
r->setUsingSymbolLevels( usingSymbolLevels() );
r->setSizeScaleField( sizeScaleField() );
copyPaintEffect( r );
copyRendererData( r );
return r;
}
@ -761,6 +761,13 @@ QDomElement QgsCategorizedSymbolRendererV2::save( QDomDocument& doc )
if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect ) )
mPaintEffect->saveProperties( doc, rendererElem );
if ( !mOrderBy.isEmpty() )
{
QDomElement orderBy = doc.createElement( "orderby" );
mOrderBy.save( orderBy );
rendererElem.appendChild( orderBy );
}
return rendererElem;
}

View File

@ -529,7 +529,7 @@ QgsGraduatedSymbolRendererV2* QgsGraduatedSymbolRendererV2::clone() const
r->setSizeScaleField( sizeScaleField() );
r->setLabelFormat( labelFormat() );
r->setGraduatedMethod( graduatedMethod() );
copyPaintEffect( r );
copyRendererData( r );
return r;
}
@ -1171,6 +1171,13 @@ QDomElement QgsGraduatedSymbolRendererV2::save( QDomDocument& doc )
if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect ) )
mPaintEffect->saveProperties( doc, rendererElem );
if ( !mOrderBy.isEmpty() )
{
QDomElement orderBy = doc.createElement( "orderby" );
mOrderBy.save( orderBy );
rendererElem.appendChild( orderBy );
}
return rendererElem;
}

View File

@ -297,7 +297,7 @@ QgsHeatmapRenderer* QgsHeatmapRenderer::clone() const
newRenderer->setMaximumValue( mExplicitMax );
newRenderer->setRenderQuality( mRenderQuality );
newRenderer->setWeightExpression( mWeightExpressionString );
copyPaintEffect( newRenderer );
copyRendererData( newRenderer );
return newRenderer;
}
@ -365,6 +365,13 @@ QDomElement QgsHeatmapRenderer::save( QDomDocument& doc )
if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect ) )
mPaintEffect->saveProperties( doc, rendererElem );
if ( !mOrderBy.isEmpty() )
{
QDomElement orderBy = doc.createElement( "orderby" );
mOrderBy.save( orderBy );
rendererElem.appendChild( orderBy );
}
return rendererElem;
}

View File

@ -204,6 +204,15 @@ void QgsFeatureRendererV2::setScaleMethodToSymbol( QgsSymbolV2* symbol, int scal
}
}
void QgsFeatureRendererV2::copyRendererData( QgsFeatureRendererV2* destRenderer ) const
{
if ( !destRenderer || !mPaintEffect )
return;
destRenderer->setPaintEffect( mPaintEffect->clone() );
destRenderer->mOrderBy = mOrderBy;
}
void QgsFeatureRendererV2::copyPaintEffect( QgsFeatureRendererV2 *destRenderer ) const
{
if ( !destRenderer || !mPaintEffect )
@ -212,7 +221,6 @@ void QgsFeatureRendererV2::copyPaintEffect( QgsFeatureRendererV2 *destRenderer )
destRenderer->setPaintEffect( mPaintEffect->clone() );
}
QgsFeatureRendererV2::QgsFeatureRendererV2( const QString& type )
: mType( type )
, mUsingSymbolLevels( false )
@ -331,6 +339,10 @@ QgsFeatureRendererV2* QgsFeatureRendererV2::load( QDomElement& element )
{
r->setPaintEffect( QgsPaintEffectRegistry::instance()->createEffect( effectElem ) );
}
// restore order by
QDomElement orderByElem = element.firstChildElement( "orderby" );
r->mOrderBy.load( orderByElem );
}
return r;
}
@ -344,6 +356,12 @@ QDomElement QgsFeatureRendererV2::save( QDomDocument& doc )
if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect ) )
mPaintEffect->saveProperties( doc, rendererElem );
if ( !mOrderBy.isEmpty() )
{
QDomElement orderBy = doc.createElement( "orderby" );
mOrderBy.save( orderBy );
rendererElem.appendChild( orderBy );
}
return rendererElem;
}
@ -598,6 +616,16 @@ void QgsFeatureRendererV2::setPaintEffect( QgsPaintEffect *effect )
mPaintEffect = effect;
}
QgsFeatureRequest::OrderBy QgsFeatureRendererV2::orderBy()
{
return mOrderBy;
}
void QgsFeatureRendererV2::setOrderBy( const QgsFeatureRequest::OrderBy& orderBys )
{
mOrderBy = orderBys;
}
void QgsFeatureRendererV2::convertSymbolSizeScale( QgsSymbolV2 * symbol, QgsSymbolV2::ScaleMethod method, const QString & field )
{
if ( symbol->type() == QgsSymbolV2::Marker )

View File

@ -21,6 +21,7 @@
#include "qgsrendercontext.h"
#include "qgssymbolv2.h"
#include "qgsfield.h"
#include "qgsfeaturerequest.h"
#include <QList>
#include <QString>
@ -343,6 +344,18 @@ class CORE_EXPORT QgsFeatureRendererV2
*/
void setForceRasterRender( bool forceRaster ) { mForceRaster = forceRaster; }
/**
* Get the order in which features shall be processed by this renderer.
* @note added in QGIS 2.14
*/
QgsFeatureRequest::OrderBy orderBy();
/**
* Define the order in which features shall be processed by this renderer.
* @note added in QGIS 2.14
*/
void setOrderBy( const QgsFeatureRequest::OrderBy& orderBys );
protected:
QgsFeatureRendererV2( const QString& type );
@ -366,10 +379,21 @@ class CORE_EXPORT QgsFeatureRendererV2
void setScaleMethodToSymbol( QgsSymbolV2* symbol, int scaleMethod );
/** Copies paint effect of this renderer to another renderer
/**
* Clones generic renderer data to another renderer.
* Currently clones
* * Order By
* * Paint Effect
*
* @param destRenderer destination renderer for copied effect
*/
void copyPaintEffect( QgsFeatureRendererV2 *destRenderer ) const;
void copyRendererData( QgsFeatureRendererV2 *destRenderer ) const;
/** Copies paint effect of this renderer to another renderer
* @param destRenderer destination renderer for copied effect
* @deprecated use copyRendererData instead
*/
Q_DECL_DEPRECATED void copyPaintEffect( QgsFeatureRendererV2 *destRenderer ) const;
QString mType;
@ -393,6 +417,8 @@ class CORE_EXPORT QgsFeatureRendererV2
*/
static void convertSymbolRotation( QgsSymbolV2 * symbol, const QString & field );
QgsFeatureRequest::OrderBy mOrderBy;
private:
Q_DISABLE_COPY( QgsFeatureRendererV2 )
};

View File

@ -201,7 +201,7 @@ QgsSingleSymbolRendererV2* QgsSingleSymbolRendererV2::clone() const
QgsSingleSymbolRendererV2* r = new QgsSingleSymbolRendererV2( mSymbol->clone() );
r->setUsingSymbolLevels( usingSymbolLevels() );
r->setSizeScaleField( sizeScaleField() );
copyPaintEffect( r );
copyRendererData( r );
return r;
}
@ -381,6 +381,12 @@ QDomElement QgsSingleSymbolRendererV2::save( QDomDocument& doc )
if ( mPaintEffect && !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect ) )
mPaintEffect->saveProperties( doc, rendererElem );
if ( !mOrderBy.isEmpty() )
{
QDomElement orderBy = doc.createElement( "orderby" );
mOrderBy.save( orderBy );
rendererElem.appendChild( orderBy );
}
return rendererElem;
}

View File

@ -238,6 +238,7 @@ SET(QGIS_GUI_SRCS
qgsnewvectorlayerdialog.cpp
qgsnumericsortlistviewitem.cpp
qgsoptionsdialogbase.cpp
qgsorderbydialog.cpp
qgsowssourceselect.cpp
qgspixmaplabel.cpp
qgspluginmanagerinterface.cpp
@ -367,6 +368,7 @@ SET(QGIS_GUI_MOC_HDRS
qgsnewnamedialog.h
qgsnewvectorlayerdialog.h
qgsoptionsdialogbase.h
qgsorderbydialog.h
qgsowssourceselect.h
qgspixmaplabel.h
qgspluginmanagerinterface.h

View File

@ -0,0 +1,178 @@
/***************************************************************************
qgosorderbydialog.cpp
---------------------
begin : 20.12.2015
copyright : (C) 2015 by Matthias Kuhn
email : matthias@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "qgsorderbydialog.h"
#include "qgsexpressionbuilderdialog.h"
#include <QTableWidget>
#include <QCheckBox>
#include <QKeyEvent>
QgsOrderByDialog::QgsOrderByDialog( QgsVectorLayer* layer, QWidget* parent )
: QDialog( parent )
, mLayer( layer )
{
setupUi( this );
connect( mOrderByTableWidget, SIGNAL( cellDoubleClicked( int, int ) ), this, SLOT( onCellDoubleClicked( int, int ) ) );
connect( mOrderByTableWidget, SIGNAL( cellChanged( int, int ) ), this, SLOT( onCellChanged( int, int ) ) );
mOrderByTableWidget->horizontalHeader()->setResizeMode( QHeaderView::Stretch );
mOrderByTableWidget->horizontalHeader()->setResizeMode( 1, QHeaderView::Interactive );
mOrderByTableWidget->horizontalHeader()->setResizeMode( 2, QHeaderView::Interactive );
mOrderByTableWidget->installEventFilter( this );
}
void QgsOrderByDialog::setOrderBy( const QgsFeatureRequest::OrderBy& orderBy )
{
mOrderByTableWidget->clear();
mOrderByTableWidget->setRowCount( orderBy.length() + 1 );
int i = 0;
Q_FOREACH ( const QgsFeatureRequest::OrderByClause& orderByClause, orderBy )
{
QTableWidgetItem* expressionItem = new QTableWidgetItem( orderByClause.expression().expression() );
QCheckBox* ascCheckBox = new QCheckBox();
ascCheckBox->setChecked( orderByClause.ascending() );
QCheckBox* nullsFirstCheckBox = new QCheckBox();
nullsFirstCheckBox->setChecked( orderByClause.nullsFirst() );
mOrderByTableWidget->setItem( i, 0, expressionItem );
mOrderByTableWidget->setCellWidget( i, 1, ascCheckBox );
mOrderByTableWidget->setCellWidget( i, 2, nullsFirstCheckBox );
++i;
}
// Add an empty widget at the end
QTableWidgetItem* expressionItem = new QTableWidgetItem( "" );
QCheckBox* ascCheckBox = new QCheckBox();
ascCheckBox->setChecked( true );
QCheckBox* nullsFirstCheckBox = new QCheckBox();
mOrderByTableWidget->setItem( i, 0, expressionItem );
mOrderByTableWidget->setCellWidget( i, 1, ascCheckBox );
mOrderByTableWidget->setCellWidget( i, 2, nullsFirstCheckBox );
}
QgsFeatureRequest::OrderBy QgsOrderByDialog::orderBy()
{
QgsFeatureRequest::OrderBy orderBys;
for ( int i = 0; i < mOrderByTableWidget->rowCount(); ++i )
{
QString expressionText = mOrderByTableWidget->item( i, 0 )->text();
if ( ! expressionText.isEmpty() )
{
bool asc = static_cast<QCheckBox*>( mOrderByTableWidget->cellWidget( i, 1 ) )->checkState();
bool nullsFirst = static_cast<QCheckBox*>( mOrderByTableWidget->cellWidget( i, 2 ) )->checkState();
QgsFeatureRequest::OrderByClause orderBy( expressionText, asc, nullsFirst );
orderBys << orderBy;
}
}
return orderBys;
}
void QgsOrderByDialog::onCellDoubleClicked( int row, int column )
{
// Only act on first cell where the expression text is
if ( 0 == column )
{
QgsExpressionBuilderDialog dlg( mLayer );
dlg.setExpressionText( mOrderByTableWidget->item( row, column )->text() );
if ( dlg.exec() )
{
QString expressionText = dlg.expressionText();
mOrderByTableWidget->item( row, column )->setText( expressionText );
if ( row == mOrderByTableWidget->rowCount() - 1 )
{
// Add an empty widget at the end if the last row was edited
mOrderByTableWidget->insertRow( mOrderByTableWidget->rowCount() );
QTableWidgetItem* expressionItem = new QTableWidgetItem( "" );
QCheckBox* ascCheckBox = new QCheckBox();
ascCheckBox->setChecked( true );
QCheckBox* nullsFirstCheckBox = new QCheckBox();
mOrderByTableWidget->setItem( row + 1, 0, expressionItem );
mOrderByTableWidget->setCellWidget( row + 1, 1, ascCheckBox );
mOrderByTableWidget->setCellWidget( row + 1, 2, nullsFirstCheckBox );
}
}
}
}
void QgsOrderByDialog::onCellChanged( int row, int column )
{
// If the text was cleared
if ( mOrderByTableWidget->item( row, column )->text().isEmpty() )
{
// If the first column (expression text) and not the last row was edited
if ( 0 == column && row != mOrderByTableWidget->rowCount() - 1 )
{
{
mOrderByTableWidget->removeRow( row );
}
}
}
else
{
// If it's the last row and an expression was added: add a new empty one
if ( row == mOrderByTableWidget->rowCount() - 1 && !mOrderByTableWidget->item( row, column )->text().isEmpty() )
{
// Add an empty widget at the end if the last row was edited
mOrderByTableWidget->insertRow( mOrderByTableWidget->rowCount() );
QTableWidgetItem* expressionItem = new QTableWidgetItem( "" );
QCheckBox* ascCheckBox = new QCheckBox();
ascCheckBox->setChecked( true );
QCheckBox* nullsFirstCheckBox = new QCheckBox();
mOrderByTableWidget->setItem( row + 1, 0, expressionItem );
mOrderByTableWidget->setCellWidget( row + 1, 1, ascCheckBox );
mOrderByTableWidget->setCellWidget( row + 1, 2, nullsFirstCheckBox );
}
}
}
bool QgsOrderByDialog::eventFilter( QObject* obj, QEvent* e )
{
Q_UNUSED( obj )
Q_ASSERT( obj == mOrderByTableWidget );
if ( e->type() == QEvent::KeyPress )
{
QKeyEvent* keyEvent = static_cast<QKeyEvent*>( e );
if ( keyEvent->key() == Qt::Key_Delete )
{
if ( mOrderByTableWidget->currentRow() != mOrderByTableWidget->rowCount() - 1 )
mOrderByTableWidget->removeRow( mOrderByTableWidget->currentRow() );
return true;
}
}
return false;
}

View File

@ -0,0 +1,65 @@
/***************************************************************************
qgsorderbydialog.h
---------------------
begin : 20.12.2015
copyright : (C) 2015 by Matthias Kuhn
email : matthias@opengis.ch
***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#ifndef QGSORDERBYDIALOG_H
#define QGSORDERBYDIALOG_H
#include <QDialog>
#include "qgsfeaturerequest.h"
#include "ui_qgsorderbydialogbase.h"
/**
* This is a dialog to build and manage a list of order by clauses.
*
* @note added in 2.14
*/
class GUI_EXPORT QgsOrderByDialog : public QDialog, private Ui::OrderByDialogBase
{
Q_OBJECT
public:
/**
* Create a new order by dialog. This helps building order by structures.
*
* @param layer The vector layer for which the order by should be produced
* @param parent The parent widget, optional
*/
QgsOrderByDialog( QgsVectorLayer* layer, QWidget* parent = nullptr );
/**
* Set the order by to manage
*/
void setOrderBy( const QgsFeatureRequest::OrderBy& orderBy );
/**
* Get the order by defined in the dialog
*/
QgsFeatureRequest::OrderBy orderBy();
private slots:
void onCellDoubleClicked( int row, int column );
void onCellChanged( int row, int column );
private:
QgsVectorLayer* mLayer;
bool eventFilter( QObject *obj, QEvent *e );
};
#endif // QGSORDERBYDIALOG_H

View File

@ -25,6 +25,7 @@
#include "qgspointdisplacementrendererwidget.h"
#include "qgsinvertedpolygonrendererwidget.h"
#include "qgsheatmaprendererwidget.h"
#include "qgsorderbydialog.h"
#include "qgsapplication.h"
#include "qgslogger.h"
@ -109,13 +110,17 @@ QgsRendererV2PropertiesDialog::QgsRendererV2PropertiesDialog( QgsVectorLayer* la
connect( mLayerTransparencySpnBx, SIGNAL( valueChanged( int ) ), mLayerTransparencySlider, SLOT( setValue( int ) ) );
//paint effect widget
if ( mLayer->rendererV2() && mLayer->rendererV2()->paintEffect() )
if ( mLayer->rendererV2() )
{
mPaintEffect = mLayer->rendererV2()->paintEffect()->clone();
mEffectWidget->setPaintEffect( mPaintEffect );
if ( mLayer->rendererV2()->paintEffect() )
{
mPaintEffect = mLayer->rendererV2()->paintEffect()->clone();
mEffectWidget->setPaintEffect( mPaintEffect );
}
mOrderBy = mLayer->rendererV2()->orderBy();
}
QPixmap pix;
QgsRendererV2Registry* reg = QgsRendererV2Registry::instance();
QStringList renderers = reg->renderersList();
Q_FOREACH ( const QString& name, renderers )
@ -128,21 +133,31 @@ QgsRendererV2PropertiesDialog::QgsRendererV2PropertiesDialog( QgsVectorLayer* la
// setup slot rendererChanged()
connect( cboRenderers, SIGNAL( currentIndexChanged( int ) ), this, SLOT( rendererChanged() ) );
//setup order by
if ( mOrderBy.isEmpty() )
{
btnOrderBy->setEnabled( false );
checkboxEnableOrderBy->setChecked( false );
lineEditOrderBy->setEnabled( false );
}
else
{
checkboxEnableOrderBy->setChecked( true );
}
lineEditOrderBy->setReadOnly( true );
connect( checkboxEnableOrderBy, SIGNAL( toggled( bool ) ), btnOrderBy, SLOT( setEnabled( bool ) ) );
connect( checkboxEnableOrderBy, SIGNAL( toggled( bool ) ), lineEditOrderBy, SLOT( setEnabled( bool ) ) );
connect( btnOrderBy, SIGNAL( clicked( bool ) ), this, SLOT( showOrderByDialog() ) );
lineEditOrderBy->setText( mOrderBy.dump() );
// set current renderer from layer
QString rendererName = mLayer->rendererV2()->type();
for ( int i = 0; i < cboRenderers->count(); i++ )
{
if ( cboRenderers->itemData( i ).toString() == rendererName )
{
cboRenderers->setCurrentIndex( i );
return;
}
}
int rendererIdx = cboRenderers->findData( rendererName );
cboRenderers->setCurrentIndex( rendererIdx );
// no renderer found... this mustn't happen
Q_ASSERT( false && "there must be a renderer!" );
Q_ASSERT( rendererIdx != -1 && "there must be a renderer!" );
}
QgsRendererV2PropertiesDialog::~QgsRendererV2PropertiesDialog()
@ -223,6 +238,9 @@ void QgsRendererV2PropertiesDialog::apply()
if ( renderer )
{
renderer->setPaintEffect( mPaintEffect->clone() );
// set the order by
renderer->setOrderBy( mOrderBy );
mLayer->setRendererV2( renderer->clone() );
}
@ -240,6 +258,18 @@ void QgsRendererV2PropertiesDialog::onOK()
accept();
}
void QgsRendererV2PropertiesDialog::showOrderByDialog()
{
QgsOrderByDialog dlg( mLayer );
dlg.setOrderBy( mOrderBy );
if ( dlg.exec() )
{
mOrderBy = dlg.orderBy();
lineEditOrderBy->setText( mOrderBy.dump() );
}
}
void QgsRendererV2PropertiesDialog::keyPressEvent( QKeyEvent * e )
{

View File

@ -21,6 +21,8 @@
#include "ui_qgsrendererv2propsdialogbase.h"
#include "qgsfeaturerequest.h"
class QKeyEvent;
class QgsVectorLayer;
@ -52,6 +54,9 @@ class GUI_EXPORT QgsRendererV2PropertiesDialog : public QDialog, private Ui::Qgs
void apply();
void onOK();
private slots:
void showOrderByDialog();
protected:
//! Reimplements dialog keyPress event so we can ignore it
@ -66,6 +71,8 @@ class GUI_EXPORT QgsRendererV2PropertiesDialog : public QDialog, private Ui::Qgs
QgsPaintEffect* mPaintEffect;
QgsMapCanvas* mMapCanvas;
QgsFeatureRequest::OrderBy mOrderBy;
};

View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>OrderByDialogBase</class>
<widget class="QDialog" name="OrderByDialogBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>747</width>
<height>296</height>
</rect>
</property>
<property name="windowTitle">
<string>Define order</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QTableWidget" name="mOrderByTableWidget">
<property name="selectionMode">
<enum>QAbstractItemView::SingleSelection</enum>
</property>
<property name="selectionBehavior">
<enum>QAbstractItemView::SelectRows</enum>
</property>
<column>
<property name="text">
<string>Expression</string>
</property>
</column>
<column>
<property name="text">
<string>Ascending</string>
</property>
</column>
<column>
<property name="text">
<string>Nulls First</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>OrderByDialogBase</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>OrderByDialogBase</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -85,6 +85,16 @@
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="2" column="0" colspan="4">
<widget class="QgsEffectStackCompactWidget" name="mEffectWidget" native="true">
<property name="minimumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
</item>
<item row="0" column="1" colspan="3">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
@ -133,15 +143,30 @@
<item row="1" column="1">
<widget class="QgsBlendModeComboBox" name="mBlendModeComboBox"/>
</item>
<item row="2" column="0" colspan="2">
<widget class="QgsEffectStackCompactWidget" name="mEffectWidget" native="true">
<property name="minimumSize">
<size>
<width>16</width>
<height>16</height>
</size>
</property>
</widget>
<item row="3" column="0" colspan="4">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QCheckBox" name="checkboxEnableOrderBy">
<property name="text">
<string>Control feature rendering order</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="lineEditOrderBy">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QToolButton" name="btnOrderBy">
<property name="text">
<string>...</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>