952 changes: 952 additions & 0 deletions images/themes/gis/mIconExpressionFilter.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
974 changes: 974 additions & 0 deletions images/themes/gis/mIconExpressionPreview.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
935 changes: 935 additions & 0 deletions images/themes/gis/mIconExpressionSelect.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
947 changes: 947 additions & 0 deletions images/themes/gis/mIconSelectAdd.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
938 changes: 938 additions & 0 deletions images/themes/gis/mIconSelectIntersect.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
948 changes: 948 additions & 0 deletions images/themes/gis/mIconSelectRemove.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
23 changes: 23 additions & 0 deletions src/app/qgisapp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@
#include "qgserror.h"
#include "qgserrordialog.h"
#include "qgsexception.h"
#include "qgsexpressionselectiondialog.h"
#include "qgsfeature.h"
#include "qgsformannotationitem.h"
#include "qgshtmlannotationitem.h"
Expand Down Expand Up @@ -942,6 +943,7 @@ void QgisApp::createActions()
connect( mActionSelectFreehand, SIGNAL( triggered() ), this, SLOT( selectByFreehand() ) );
connect( mActionSelectRadius, SIGNAL( triggered() ), this, SLOT( selectByRadius() ) );
connect( mActionDeselectAll, SIGNAL( triggered() ), this, SLOT( deselectAll() ) );
connect( mActionSelectByExpression, SIGNAL( triggered() ), this, SLOT( selectByExpression() ) );
connect( mActionIdentify, SIGNAL( triggered() ), this, SLOT( identify() ) );
connect( mActionFeatureAction, SIGNAL( triggered() ), this, SLOT( doFeatureAction() ) );
connect( mActionMeasure, SIGNAL( triggered() ), this, SLOT( measure() ) );
Expand Down Expand Up @@ -1743,6 +1745,7 @@ void QgisApp::setTheme( QString theThemeName )
mActionSelectFreehand->setIcon( QgsApplication::getThemeIcon( "/mActionSelectFreehand.png" ) );
mActionSelectRadius->setIcon( QgsApplication::getThemeIcon( "/mActionSelectRadius.png" ) );
mActionDeselectAll->setIcon( QgsApplication::getThemeIcon( "/mActionDeselectAll.png" ) );
mActionSelectByExpression->setIcon( QgsApplication::getThemeIcon( "/mIconExpressionSelect.svg" ) );
mActionOpenTable->setIcon( QgsApplication::getThemeIcon( "/mActionOpenTable.png" ) );
mActionMeasure->setIcon( QgsApplication::getThemeIcon( "/mActionMeasure.png" ) );
mActionMeasureArea->setIcon( QgsApplication::getThemeIcon( "/mActionMeasureArea.png" ) );
Expand Down Expand Up @@ -5228,6 +5231,26 @@ void QgisApp::deselectAll()
mMapCanvas->setRenderFlag( true );
}

void QgisApp::selectByExpression()
{
QgsVectorLayer* vlayer = NULL;
if ( !mMapCanvas->currentLayer()
|| NULL == ( vlayer = qobject_cast<QgsVectorLayer *>( mMapCanvas->currentLayer() ) ) )
{
messageBar()->pushMessage(
QObject::tr( "No active vector layer" ),
QObject::tr( "To select features, choose a vector layer in the legend" ),
QgsMessageBar::INFO,
messageTimeout() );
}
else
{
QgsExpressionSelectionDialog* dlg = new QgsExpressionSelectionDialog( vlayer );
dlg->setAttribute( Qt::WA_DeleteOnClose );
dlg->show();
}
}

void QgisApp::addRing()
{
if ( mMapCanvas && mMapCanvas->isDrawing() )
Expand Down
3 changes: 3 additions & 0 deletions src/app/qgisapp.h
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,9 @@ class QgisApp : public QMainWindow, private Ui::MainWindow
//! deselect features from all layers
void deselectAll();

//! select features by expression
void selectByExpression();

//! refresh map canvas
void refreshMapCanvas();

Expand Down
4 changes: 4 additions & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ qgsludialog.cpp
qgssearchquerybuilder.cpp
qgsexpressionbuilderwidget.cpp
qgsexpressionbuilderdialog.cpp
qgsexpressionselectiondialog.cpp
qgsexpressionhighlighter.cpp
qgsquerybuilder.cpp
qgscollapsiblegroupbox.cpp
Expand Down Expand Up @@ -199,6 +200,7 @@ qgssearchquerybuilder.h
qgsscalecombobox.h
qgsexpressionbuilderwidget.h
qgsexpressionhighlighter.h
qgsexpressionselectiondialog.h
qgsquerybuilder.h
qgscollapsiblegroupbox.h
qgsfilterlineedit.h
Expand Down Expand Up @@ -243,6 +245,7 @@ qgsattributeeditor.h
qgsfieldvalidator.h
qgsexpressionbuilderwidget.h
qgsexpressionbuilderdialog.h
qgsexpressionselectiondialog.h
qgsexpressionhighlighter.h
qgscollapsiblegroupbox.h
qgsfilterlineedit.h
Expand Down Expand Up @@ -273,6 +276,7 @@ ${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsprojectionselectorbase.h
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsquerybuilderbase.h
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsexpressionbuilder.h
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsexpressionbuilderdialogbase.h
${CMAKE_CURRENT_BINARY_DIR}/../ui/ui_qgsexpressionselectiondialogbase.h
)

# ModelTest
Expand Down
211 changes: 211 additions & 0 deletions src/gui/qgsexpressionselectiondialog.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
/***************************************************************************
qgisexpressionselectiondialog.cpp
--------------------------------------
Date : 24.1.2013
Copyright : (C) 2013 by Matthias kuhn
Email : matthias dot kuhn at gmx dot 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 "qgsexpressionselectiondialog.h"
#include "qgsapplication.h"
#include "qgsexpression.h"

#include <QSettings>

QgsExpressionSelectionDialog::QgsExpressionSelectionDialog( QgsVectorLayer* layer, QString startText, QWidget* parent )
: QDialog( parent ),
mLayer( layer )
{
setupUi( this );

mActionSelect->setIcon( QgsApplication::getThemeIcon( "/mIconExpressionSelect.svg" ) );
mActionAddToSelection->setIcon( QgsApplication::getThemeIcon( "/mIconSelectAdd.svg" ) );
mActionRemoveFromSelection->setIcon( QgsApplication::getThemeIcon( "/mIconSelectRemove.svg" ) );
mActionSelectInstersect->setIcon( QgsApplication::getThemeIcon( "/mIconSelectIntersect.svg" ) );

mButtonSelect->addAction( mActionSelect );
mButtonSelect->addAction( mActionAddToSelection );
mButtonSelect->addAction( mActionRemoveFromSelection );
mButtonSelect->addAction( mActionSelectInstersect );
mButtonSelect->setDefaultAction( mActionSelect );

mExpressionBuilder->setLayer( layer );
mExpressionBuilder->setExpressionText( startText );
mExpressionBuilder->loadFieldNames();

QSettings settings;
restoreGeometry( settings.value( "/Windows/ExpressionSelectionDialog/geometry" ).toByteArray() );
}

QgsExpressionBuilderWidget* QgsExpressionSelectionDialog::expressionBuilder()
{
return mExpressionBuilder;
}

void QgsExpressionSelectionDialog::setExpressionText( const QString& text )
{
mExpressionBuilder->setExpressionText( text );
}

QString QgsExpressionSelectionDialog::expressionText()
{
return mExpressionBuilder->expressionText();
}

void QgsExpressionSelectionDialog::setGeomCalculator( const QgsDistanceArea & da )
{
// Store in child widget only.
mExpressionBuilder->setGeomCalculator( da );
}

void QgsExpressionSelectionDialog::on_mActionSelect_triggered()
{
QgsFeatureIds newSelection;
QgsExpression* expression = new QgsExpression( mExpressionBuilder->expressionText() );

const QgsFields fields = mLayer->pendingFields();

QgsFeatureIterator features = mLayer->getFeatures();

expression->prepare( fields );

QgsFeature feat;
while ( features.nextFeature( feat ) )
{
if ( expression->evaluate( &feat, fields ).toBool() )
{
newSelection << feat.id();
}
}

features.close();

mLayer->setSelectedFeatures( newSelection );

delete expression;
}

void QgsExpressionSelectionDialog::on_mActionAddToSelection_triggered()
{
QgsFeatureIds newSelection = mLayer->selectedFeaturesIds();
QgsExpression* expression = new QgsExpression( mExpressionBuilder->expressionText() );

const QgsFields fields = mLayer->pendingFields();

QgsFeatureIterator features = mLayer->getFeatures();

expression->prepare( fields );

QgsFeature feat;
while ( features.nextFeature( feat ) )
{
if ( expression->evaluate( &feat, fields ).toBool() )
{
newSelection << feat.id();
}
}

features.close();

mLayer->setSelectedFeatures( newSelection );

delete expression;
}

void QgsExpressionSelectionDialog::on_mActionSelectInstersect_triggered()
{
const QgsFeatureIds &oldSelection = mLayer->selectedFeaturesIds();
QgsFeatureIds newSelection;

QgsExpression* expression = new QgsExpression( mExpressionBuilder->expressionText() );

const QgsFields fields = mLayer->pendingFields();

expression->prepare( fields );

QgsFeature feat;
foreach( const QgsFeatureId fid, oldSelection )
{
QgsFeatureIterator features = mLayer->getFeatures( QgsFeatureRequest().setFilterFid( fid ) );

if ( features.nextFeature( feat ) )
{
if ( expression->evaluate( &feat, fields ).toBool() )
{
newSelection << feat.id();
}
}
else
{
Q_ASSERT( false );
}

features.close();
}

mLayer->setSelectedFeatures( newSelection );

delete expression;
}

void QgsExpressionSelectionDialog::on_mActionRemoveFromSelection_triggered()
{
const QgsFeatureIds &oldSelection = mLayer->selectedFeaturesIds();
QgsFeatureIds newSelection = mLayer->selectedFeaturesIds();

QgsExpression* expression = new QgsExpression( mExpressionBuilder->expressionText() );

const QgsFields fields = mLayer->pendingFields();

expression->prepare( fields );

QgsFeature feat;
foreach( const QgsFeatureId fid, oldSelection )
{
QgsFeatureIterator features = mLayer->getFeatures( QgsFeatureRequest().setFilterFid( fid ) );

if ( features.nextFeature( feat ) )
{
if ( expression->evaluate( &feat, fields ).toBool() )
{
newSelection.remove( feat.id() );
}
}
else
{
Q_ASSERT( false );
}

features.close();
}

mLayer->setSelectedFeatures( newSelection );

delete expression;
}

void QgsExpressionSelectionDialog::closeEvent( QCloseEvent *closeEvent )
{
QDialog::closeEvent( closeEvent );

QSettings settings;
settings.setValue( "/Windows/ExpressionSelectionDialog/geometry", saveGeometry() );
}

void QgsExpressionSelectionDialog::on_mPbnClose_clicked()
{
close();
}

void QgsExpressionSelectionDialog::done( int r )
{
QDialog::done( r );
close();
}
91 changes: 91 additions & 0 deletions src/gui/qgsexpressionselectiondialog.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/***************************************************************************
qgisexpressionselectiondialog.h
--------------------------------------
Date : 24.1.2013
Copyright : (C) 2013 by Matthias kuhn
Email : matthias dot kuhn at gmx dot 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 QGSEXPRESSIONSELECTIONDIALOG_H
#define QGSEXPRESSIONSELECTIONDIALOG_H

#include <QDialog>
#include "qgsdistancearea.h"
#include "ui_qgsexpressionselectiondialogbase.h"

/**
* This class offers a dialog to change feature selections.
* To do so, a QgsExpressionBuilderWidget is shown in a dialog.
* It offers the possibilities to create a new selection, add to the current selection
* remove from the current selection or select within the current selection.
* @note added in 2.0
*/
class GUI_EXPORT QgsExpressionSelectionDialog : public QDialog, private Ui::QgsExpressionSelectionDialogBase
{
Q_OBJECT

public:
/**
* Creates a new selection dialog.
* @param layer The layer on which the selection is to be performed.
* @param startText A default expression text to be applied (Defaults to empty)
*/
QgsExpressionSelectionDialog( QgsVectorLayer* layer, QString startText = QString(), QWidget* parent = NULL );

/**
* The builder widget that is used by the dialog
* @return The builder widget that is used by the dialog
*/
QgsExpressionBuilderWidget* expressionBuilder();

/**
* Sets the current expression text
* @param text the expression text to set
*/
void setExpressionText( const QString& text );

/**
* Returns the current expression text
* @return The expression text
*/
QString expressionText();

/**
*Sets geometry calculator used in distance/area calculations.
*/
void setGeomCalculator( const QgsDistanceArea & da );

public slots:
void on_mActionSelect_triggered();
void on_mActionAddToSelection_triggered();
void on_mActionRemoveFromSelection_triggered();
void on_mActionSelectInstersect_triggered();
void on_mPbnClose_clicked();

protected:
/**
* Implementation for closeEvent
* Saves the window geometry
* @param closeEvent Event object. Unused.
*/
virtual void closeEvent( QCloseEvent *closeEvent );

/**
* Implementation for done (default behavior when pressing esc)
* Calls close, so the window geometry gets saved and the object deleted.
* @param r Result value. Unused.
*/
virtual void done( int r );

private:
QgsVectorLayer* mLayer;
};

#endif
13 changes: 13 additions & 0 deletions src/ui/qgisapp.ui
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,7 @@
</attribute>
<addaction name="mActionIdentify"/>
<addaction name="mActionDeselectAll"/>
<addaction name="mActionSelectByExpression"/>
<addaction name="mActionOpenTable"/>
<addaction name="mActionMapTips"/>
<addaction name="mActionNewBookmark"/>
Expand Down Expand Up @@ -2055,6 +2056,18 @@ Acts on currently active editable layer</string>
<string>Decrease contrast</string>
</property>
</action>
<action name="mActionSelectByExpression">
<property name="icon">
<iconset resource="../../images/images.qrc">
<normaloff>:/images/themes/gis/mIconExpressionSelect.svg</normaloff>:/images/themes/gis/mIconExpressionSelect.svg</iconset>
</property>
<property name="text">
<string>Select By Expression</string>
</property>
<property name="toolTip">
<string>Select features using an expression</string>
</property>
</action>
</widget>
<resources>
<include location="../../images/images.qrc"/>
Expand Down
91 changes: 91 additions & 0 deletions src/ui/qgsexpressionselectiondialogbase.ui
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>QgsExpressionSelectionDialogBase</class>
<widget class="QDialog" name="QgsExpressionSelectionDialogBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>536</width>
<height>401</height>
</rect>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="1" column="0">
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="mPbnClose">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QToolButton" name="mButtonSelect">
<property name="minimumSize">
<size>
<width>0</width>
<height>31</height>
</size>
</property>
<property name="text">
<string>...</string>
</property>
<property name="popupMode">
<enum>QToolButton::MenuButtonPopup</enum>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextBesideIcon</enum>
</property>
</widget>
</item>
<item row="0" column="0" colspan="4">
<widget class="QgsExpressionBuilderWidget" name="mExpressionBuilder" native="true"/>
</item>
</layout>
<action name="mActionSelect">
<property name="text">
<string>Select</string>
</property>
</action>
<action name="mActionAddToSelection">
<property name="text">
<string>Add to selection</string>
</property>
</action>
<action name="mActionRemoveFromSelection">
<property name="text">
<string>Remove from selection</string>
</property>
</action>
<action name="mActionSelectInstersect">
<property name="text">
<string>Select within selection</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>QgsExpressionBuilderWidget</class>
<extends>QWidget</extends>
<header>qgsexpressionbuilderwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>