diff --git a/images/images.qrc b/images/images.qrc index 1a82ba76185..0231feb7df6 100644 --- a/images/images.qrc +++ b/images/images.qrc @@ -596,6 +596,7 @@ themes/default/mIconAms.svg themes/default/mActionAddAmsLayer.svg themes/default/mActionAddAfsLayer.svg + themes/default/mIconFormSelect.svg qgis_tips/symbol_levels.png diff --git a/images/themes/default/mIconFormSelect.svg b/images/themes/default/mIconFormSelect.svg new file mode 100644 index 00000000000..228fa9bf293 --- /dev/null +++ b/images/themes/default/mIconFormSelect.svg @@ -0,0 +1,148 @@ + + + + + expression editor select + + + + + + + + image/svg+xml + + expression editor select + 2013-01-30 + + + Robert Szczepanek + + + + + Robert Szczepanek + + + + + expression editor select + + + GIS icons 0.2 + + + + + + + + + + + + + + + + + + + + diff --git a/python/gui/qgsattributeform.sip b/python/gui/qgsattributeform.sip index 61272409678..5259941b8ef 100644 --- a/python/gui/qgsattributeform.sip +++ b/python/gui/qgsattributeform.sip @@ -125,6 +125,13 @@ class QgsAttributeForm : QWidget */ void setMultiEditFeatureIds( const QgsFeatureIds& fids ); + /** Sets the message bar to display feedback from the form in. This is used in the search/filter + * mode to display the count of selected features. + * @param messageBar target message bar + * @note added in QGIS 2.16 + */ + void setMessageBar( QgsMessageBar* messageBar ); + signals: /** * Notifies about changes of attributes @@ -161,6 +168,11 @@ class QgsAttributeForm : QWidget */ void modeChanged( QgsAttributeForm::Mode mode ); + /** Emitted when the user selects the close option from the form's button bar. + * @note added in QGIS 2.16 + */ + void closed(); + public slots: /** * Call this to change the content of a given attribute. Will update the editor(s) related to this field. diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt index 6e68b411e04..60ad8dd2193 100644 --- a/src/app/CMakeLists.txt +++ b/src/app/CMakeLists.txt @@ -113,6 +113,7 @@ SET(QGIS_APP_SRCS qgsrasterlayerproperties.cpp qgsrelationmanagerdialog.cpp qgsrelationadddlg.cpp + qgsselectbyformdialog.cpp qgsstatisticalsummarydockwidget.cpp qgstextannotationdialog.cpp qgssnappingdialog.cpp @@ -287,6 +288,7 @@ SET (QGIS_APP_MOC_HDRS qgsrasterlayerproperties.h qgsrelationmanagerdialog.h qgsrelationadddlg.h + qgsselectbyformdialog.h qgssnappingdialog.h qgssponsors.h qgsstatisticalsummarydockwidget.h diff --git a/src/app/qgisapp.cpp b/src/app/qgisapp.cpp index 62c3af2ddea..f546d8ba5f9 100644 --- a/src/app/qgisapp.cpp +++ b/src/app/qgisapp.cpp @@ -210,6 +210,7 @@ #include "qgsrectangle.h" #include "qgsscalevisibilitydialog.h" #include "qgsgroupwmsdatadialog.h" +#include "qgsselectbyformdialog.h" #include "qgsshortcutsmanager.h" #include "qgssinglebandgrayrenderer.h" #include "qgssnappingdialog.h" @@ -1514,6 +1515,7 @@ void QgisApp::createActions() connect( mActionSelectAll, SIGNAL( triggered() ), this, SLOT( selectAll() ) ); connect( mActionInvertSelection, SIGNAL( triggered() ), this, SLOT( invertSelection() ) ); connect( mActionSelectByExpression, SIGNAL( triggered() ), this, SLOT( selectByExpression() ) ); + connect( mActionSelectByForm, SIGNAL( triggered() ), this, SLOT( selectByForm() ) ); connect( mActionIdentify, SIGNAL( triggered() ), this, SLOT( identify() ) ); connect( mActionFeatureAction, SIGNAL( triggered() ), this, SLOT( doFeatureAction() ) ); connect( mActionMeasure, SIGNAL( triggered() ), this, SLOT( measure() ) ); @@ -1988,7 +1990,7 @@ void QgisApp::createToolBars() QToolButton *bt = new QToolButton( mAttributesToolBar ); bt->setPopupMode( QToolButton::MenuButtonPopup ); QList selectActions; - selectActions << mActionSelectByExpression << mActionSelectAll + selectActions << mActionSelectByExpression << mActionSelectByForm << mActionSelectAll << mActionInvertSelection; bt->addActions( selectActions ); bt->setDefaultAction( mActionSelectByExpression ); @@ -2550,6 +2552,7 @@ void QgisApp::setTheme( const QString& theThemeName ) mActionSelectAll->setIcon( QgsApplication::getThemeIcon( "/mActionSelectAll.svg" ) ); mActionInvertSelection->setIcon( QgsApplication::getThemeIcon( "/mActionInvertSelection.svg" ) ); mActionSelectByExpression->setIcon( QgsApplication::getThemeIcon( "/mIconExpressionSelect.svg" ) ); + mActionSelectByForm->setIcon( QgsApplication::getThemeIcon( "/mIconFormSelect.svg" ) ); mActionOpenTable->setIcon( QgsApplication::getThemeIcon( "/mActionOpenTable.svg" ) ); mActionOpenFieldCalc->setIcon( QgsApplication::getThemeIcon( "/mActionCalculateField.png" ) ); mActionMeasure->setIcon( QgsApplication::getThemeIcon( "/mActionMeasure.png" ) ); @@ -7211,6 +7214,34 @@ void QgisApp::selectByExpression() dlg->show(); } +void QgisApp::selectByForm() +{ + QgsVectorLayer *vlayer = qobject_cast( mMapCanvas->currentLayer() ); + if ( !vlayer ) + { + messageBar()->pushMessage( + tr( "No active vector layer" ), + tr( "To select features, choose a vector layer in the legend" ), + QgsMessageBar::INFO, + messageTimeout() ); + return; + } + QgsDistanceArea myDa; + + myDa.setSourceCrs( vlayer->crs().srsid() ); + myDa.setEllipsoidalMode( mMapCanvas->mapSettings().hasCrsTransformEnabled() ); + myDa.setEllipsoid( QgsProject::instance()->readEntry( "Measure", "/Ellipsoid", GEO_NONE ) ); + + QgsAttributeEditorContext context; + context.setDistanceArea( myDa ); + context.setVectorLayerTools( mVectorLayerTools ); + + QgsSelectByFormDialog* dlg = new QgsSelectByFormDialog( vlayer, context, this ); + dlg->setMessageBar( messageBar() ); + dlg->setAttribute( Qt::WA_DeleteOnClose ); + dlg->show(); +} + void QgisApp::addRing() { mMapCanvas->setMapTool( mMapTools.mAddRing ); @@ -10315,6 +10346,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer ) mActionSelectRadius->setEnabled( false ); mActionIdentify->setEnabled( QSettings().value( "/Map/identifyMode", 0 ).toInt() != 0 ); mActionSelectByExpression->setEnabled( false ); + mActionSelectByForm->setEnabled( false ); mActionLabeling->setEnabled( false ); mActionOpenTable->setEnabled( false ); mActionSelectAll->setEnabled( false ); @@ -10419,6 +10451,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer ) mActionSelectRadius->setEnabled( true ); mActionIdentify->setEnabled( true ); mActionSelectByExpression->setEnabled( true ); + mActionSelectByForm->setEnabled( true ); mActionOpenTable->setEnabled( true ); mActionSelectAll->setEnabled( true ); mActionInvertSelection->setEnabled( true ); @@ -10606,6 +10639,7 @@ void QgisApp::activateDeactivateLayerRelatedActions( QgsMapLayer* layer ) mActionSelectAll->setEnabled( false ); mActionInvertSelection->setEnabled( false ); mActionSelectByExpression->setEnabled( false ); + mActionSelectByForm->setEnabled( false ); mActionOpenFieldCalc->setEnabled( false ); mActionToggleEditing->setEnabled( false ); mActionToggleEditing->setChecked( false ); diff --git a/src/app/qgisapp.h b/src/app/qgisapp.h index 171214d34d1..5c65e7c463b 100644 --- a/src/app/qgisapp.h +++ b/src/app/qgisapp.h @@ -1089,6 +1089,9 @@ class APP_EXPORT QgisApp : public QMainWindow, private Ui::MainWindow //! select features by expression void selectByExpression(); + //! select features by form + void selectByForm(); + //! refresh map canvas void refreshMapCanvas(); diff --git a/src/app/qgsselectbyformdialog.cpp b/src/app/qgsselectbyformdialog.cpp new file mode 100644 index 00000000000..2f43b840c95 --- /dev/null +++ b/src/app/qgsselectbyformdialog.cpp @@ -0,0 +1,54 @@ +/*************************************************************************** + qgsselectbyformdialog.cpp + ------------------------ + Date : June 2016 + Copyright : (C) 2016 nyall Dawson + Email : nyall dot dawson at gmail dot com + *************************************************************************** + * * + * 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 "qgsselectbyformdialog.h" +#include "qgsattributeform.h" +#include +#include + +QgsSelectByFormDialog::QgsSelectByFormDialog( QgsVectorLayer* layer, const QgsAttributeEditorContext& context, QWidget* parent, Qt::WindowFlags fl ) + : QDialog( parent, fl ) +{ + QgsAttributeEditorContext dlgContext = context; + dlgContext.setFormMode( QgsAttributeEditorContext::StandaloneDialog ); + + mForm = new QgsAttributeForm( layer, QgsFeature(), dlgContext, this ); + mForm->setMode( QgsAttributeForm::SearchMode ); + + QVBoxLayout* vLayout = new QVBoxLayout(); + vLayout->setMargin( 0 ); + vLayout->setContentsMargins( 0, 0, 0, 0 ); + setLayout( vLayout ); + + vLayout->addWidget( mForm ); + + connect( mForm, SIGNAL( closed() ), this, SLOT( close() ) ); + + QSettings settings; + restoreGeometry( settings.value( "/Windows/SelectByForm/geometry" ).toByteArray() ); + + setWindowTitle( tr( "Select matching features" ) ); +} + +QgsSelectByFormDialog::~QgsSelectByFormDialog() +{ + QSettings settings; + settings.setValue( "/Windows/SelectByForm/geometry", saveGeometry() ); +} + +void QgsSelectByFormDialog::setMessageBar( QgsMessageBar* messageBar ) +{ + mForm->setMessageBar( messageBar ); +} diff --git a/src/app/qgsselectbyformdialog.h b/src/app/qgsselectbyformdialog.h new file mode 100644 index 00000000000..787af3a25eb --- /dev/null +++ b/src/app/qgsselectbyformdialog.h @@ -0,0 +1,64 @@ +/*************************************************************************** + qgsselectbyformdialog.h + ---------------------- + Date : June 2016 + Copyright : (C) 2016 nyall Dawson + Email : nyall dot dawson at gmail dot com + *************************************************************************** + * * + * 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 QGSSELECTBYFORMDIALOG_H +#define QGSSELECTBYFORMDIALOG_H + +#include +#include "qgsattributeeditorcontext.h" + +class QgsAttributeForm; +class QgsMessageBar; +class QgsVectorLayer; + +/** \ingroup app + * \class QgsSelectByFormDialog + * A dialog for selecting features from a layer, using a form based off the layer's editor widgets. + * @note introduced in QGIS 2.16 + */ + +class APP_EXPORT QgsSelectByFormDialog : public QDialog +{ + Q_OBJECT + + public: + + /** Constructor for QgsSelectByFormDialog + * @param layer vector layer to select from + * @param context editor context + * @param parent parent widget + * @param fl window flags + */ + QgsSelectByFormDialog( QgsVectorLayer* layer, + const QgsAttributeEditorContext& context = QgsAttributeEditorContext(), + QWidget* parent = nullptr, Qt::WindowFlags fl = nullptr ); + + ~QgsSelectByFormDialog(); + + /** Sets the message bar to display feedback from the form in. This is used in the search/filter + * mode to display the count of selected features. + * @param messageBar target message bar + * @note added in QGIS 2.16 + */ + void setMessageBar( QgsMessageBar* messageBar ); + + private: + + QgsAttributeForm* mForm; + +}; + + +#endif // QGSSELECTBYFORMDIALOG_H diff --git a/src/gui/qgsattributeform.cpp b/src/gui/qgsattributeform.cpp index e739386146f..a806484b901 100644 --- a/src/gui/qgsattributeform.cpp +++ b/src/gui/qgsattributeform.cpp @@ -51,6 +51,7 @@ QgsAttributeForm::QgsAttributeForm( QgsVectorLayer* vl, const QgsFeature &featur : QWidget( parent ) , mLayer( vl ) , mMessageBar( nullptr ) + , mOwnsMessageBar( true ) , mMultiEditUnsavedMessageBarItem( nullptr ) , mMultiEditMessageBarItem( nullptr ) , mInvalidConstraintMessage( nullptr ) @@ -1296,7 +1297,7 @@ void QgsAttributeForm::init() else { QPushButton* closeButton = new QPushButton( tr( "Close" ), mSearchButtonBox ); - connect( closeButton, SIGNAL( clicked( bool ) ), this, SLOT( close() ) ); + connect( closeButton, SIGNAL( clicked( bool ) ), this, SIGNAL( closed() ) ); closeButton->setShortcut( Qt::Key_Escape ); boxLayout->addWidget( closeButton ); } @@ -1804,6 +1805,14 @@ void QgsAttributeForm::setMultiEditFeatureIds( const QgsFeatureIds& fids ) mIsSettingMultiEditFeatures = false; } +void QgsAttributeForm::setMessageBar( QgsMessageBar* messageBar ) +{ + if ( mOwnsMessageBar ) + delete mMessageBar; + mOwnsMessageBar = false; + mMessageBar = messageBar; +} + int QgsAttributeForm::messageTimeout() { QSettings settings; diff --git a/src/gui/qgsattributeform.h b/src/gui/qgsattributeform.h index f9a94577a2c..ed3013b03b7 100644 --- a/src/gui/qgsattributeform.h +++ b/src/gui/qgsattributeform.h @@ -147,6 +147,13 @@ class GUI_EXPORT QgsAttributeForm : public QWidget */ void setMultiEditFeatureIds( const QgsFeatureIds& fids ); + /** Sets the message bar to display feedback from the form in. This is used in the search/filter + * mode to display the count of selected features. + * @param messageBar target message bar + * @note added in QGIS 2.16 + */ + void setMessageBar( QgsMessageBar* messageBar ); + signals: /** * Notifies about changes of attributes @@ -183,6 +190,11 @@ class GUI_EXPORT QgsAttributeForm : public QWidget */ void modeChanged( QgsAttributeForm::Mode mode ); + /** Emitted when the user selects the close option from the form's button bar. + * @note added in QGIS 2.16 + */ + void closed(); + public slots: /** * Call this to change the content of a given attribute. Will update the editor(s) related to this field. @@ -317,6 +329,7 @@ class GUI_EXPORT QgsAttributeForm : public QWidget QgsVectorLayer* mLayer; QgsFeature mFeature; QgsMessageBar* mMessageBar; + bool mOwnsMessageBar; QgsMessageBarItem* mMultiEditUnsavedMessageBarItem; QgsMessageBarItem* mMultiEditMessageBarItem; QLabel* mInvalidConstraintMessage; diff --git a/src/ui/qgisapp.ui b/src/ui/qgisapp.ui index 43cb0032d8e..e863d598373 100644 --- a/src/ui/qgisapp.ui +++ b/src/ui/qgisapp.ui @@ -71,6 +71,7 @@ + @@ -2502,7 +2503,7 @@ Acts on currently active editable layer Modify the Attributes of all Selected Features Simultaneously - + :/images/themes/default/mActionAddAmsLayer.svg:/images/themes/default/mActionAddAmsLayer.svg @@ -2526,6 +2527,21 @@ Acts on currently active editable layer Add ArcGIS FeatureServer Layer + + + + :/images/themes/default/mIconFormSelect.svg:/images/themes/default/mIconFormSelect.svg + + + Select Features by Form... + + + Select Features By Form + + + F3 + +