Skip to content

Commit 02e3916

Browse files
committedSep 22, 2017
[FEATURE] layer refresh and trigger actions on provider notification
[needs-docs] In vector layer properties (only usefull for postgres datasources) **in the rendering tab** A "Refresh layer on notification" checkbox has been added to refresh layer on provider notification. For a postgres datasource, if a `NOTIFY qgis;` command is issued by one of the database clients, a refresh of the layer will occur. If the "Only if message is" checkbox is checked, the notification will trigger the refresh only if the message contend is the one specified, e.g. if the user enters "refresh" in the box right next to the "Only if message is" checkbox, then a `NOTIFY qgis, 'refresh';` command in the datatabase will trigger a layer refresh, but `NOTIFY qgis;` or `NOTIFY qgis, 'something else';` won't. **in the actions tab** A column "On notification" has been added, the action editor widget a has text field "Execute if notification message matches" to specify a filter for notification from the provider. The filter is a Perl-type regex. Note that, as opposed to the "layer refresh" that Exemple: - QGIS side "Execute if notification message matches" `^trigger my action` - Postgres side: `NOTIFY qgis, 'trigger my action'` will trigger the action - Postgres side: `NOTIFY qgis, 'trigger my action some additional data'` will trigger the action - Postgres side: `NOTIFY qgis, 'do not trigger my action some additional data'` will NOT trigger the action Please note that if the `^`, which means "starts with", in `^trigger my action` had been ommited, the last notification would have triggered the action because the notification message contains the `trigger my action` A new qgis variable `notification_message` is available for use in actions, it holds the contend of the notification message. To continue with the previous exemple, if the action is of python type with the code: ```python print('[% @notification_message %]') ``` The three notifictions above will result in two printed lines ``` trigger my action trigger my action some additional data ``` User Warning: For postgres providers, if the "Refresh layer on notification" is checked, or if one layer action has "On notification" specified, a new connection to the database is made to listen to postgres notifications. This olds even if transaction groups are enabled at the project level. Note that once the notification mechanism is started in a QGIS session, it will not stop, even if there is no more need for it (Refresh layer on notification" unchecked and no "On notification" in any action). Consequently the connection listening to notification will remain open. IMPLEMENTATION DETAILS: A notify signal has been added to the abstract QgsVectorDataProvider along with a setListening function that enables/disble the notification mechanism. For the moment only the postgres provider implements the notification. QgsAction has a notificationMessage member function that holds the regex to match to trigger action QgsActionManager becomes a QObject and is doing the filtering and execute actions on notifications. The notification notion extends beyond SRGBD servers (postgres and oracle at least have the notify) and the "watch file" in the delimitedtext provider could also benefit from this interface. For the postgres provider a thread is created with a second connection to the database. This thread is responsible for listening postgres notifications. It would be nice to avoid the creation of one listening chanel per provider in the case transaction groups are enabled. Please note that when listening starts (a thread and connection is created in the postgres provider) it cannot be stopped by removing the connected actions or unchecking the refresh check box. Indeed, since we don't know who needs the signals, we dont't want to stop the service. The service will not restart in the next qgis session though. If this behavior is not deemed appropriate, we could use ``` int QObject::receivers ( const char * signal ) const ``` and have QgsDataProvider::setListening return a bool to tell the caller if the signal has actually been closed.
1 parent d6d7c6e commit 02e3916

32 files changed

+879
-450
lines changed
 

‎python/core/qgsaction.sip

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class QgsAction
4444
\param capture If this is set to true, the output will be captured when an action is run
4545
%End
4646

47-
QgsAction( ActionType type, const QString &description, const QString &action, const QString &icon, bool capture, const QString &shortTitle = QString(), const QSet<QString> &actionScopes = QSet<QString>() );
47+
QgsAction( ActionType type, const QString &description, const QString &action, const QString &icon, bool capture, const QString &shortTitle = QString(), const QSet<QString> &actionScopes = QSet<QString>(), const QString &notificationMessage = QString() );
4848
%Docstring
4949
Create a new QgsAction
5050

@@ -55,6 +55,7 @@ class QgsAction
5555
\param capture If this is set to true, the output will be captured when an action is run
5656
\param shortTitle A short string used to label user interface elements like buttons
5757
\param actionScopes A set of scopes in which this action will be available
58+
\param notificationMessage A particular message which reception will trigger the action
5859
%End
5960

6061
QString name() const;
@@ -103,6 +104,14 @@ The icon
103104
How the content is interpreted depends on the type() and
104105
the actionScope().
105106

107+
.. versionadded:: 3.0
108+
:rtype: str
109+
%End
110+
111+
QString notificationMessage() const;
112+
%Docstring
113+
Returns the notification message that triggers the action
114+
106115
.. versionadded:: 3.0
107116
:rtype: str
108117
%End

‎python/core/qgsactionmanager.sip

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313

1414

15-
class QgsActionManager
15+
class QgsActionManager: QObject
1616
{
1717
%Docstring
1818
Storage and management of actions associated with a layer.

‎python/core/qgsdataprovider.sip

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,18 @@ Current time stamp of data source
361361
:rtype: QVariant
362362
%End
363363

364+
virtual void setListening( bool isListening );
365+
%Docstring
366+
Set whether the provider will listen to datasource notifications
367+
If set, the provider will issue notify signals.
368+
369+
The default implementation does nothing.
370+
371+
.. seealso:: notify
372+
373+
.. versionadded:: 3.0
374+
%End
375+
364376
signals:
365377

366378
void fullExtentCalculated();
@@ -379,6 +391,16 @@ Current time stamp of data source
379391
feature ids should be invalidated.
380392
%End
381393

394+
void notify( const QString &msg ) const;
395+
%Docstring
396+
Emitted when datasource issues a notification
397+
398+
.. seealso:: setListening
399+
400+
.. versionadded:: 3.0
401+
%End
402+
403+
382404
protected:
383405

384406

‎python/core/qgsexpressioncontext.sip

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -940,6 +940,13 @@ class QgsExpressionContextUtils
940940
:rtype: QgsExpressionContextScope
941941
%End
942942

943+
static QgsExpressionContextScope *notificationScope( const QString &message = QString() ) /Factory/;
944+
%Docstring
945+
Creates a new scope which contains variables and functions relating to provider notifications
946+
\param message the notification message
947+
:rtype: QgsExpressionContextScope
948+
%End
949+
943950
static void registerContextFunctions();
944951
%Docstring
945952
Registers all known core functions provided by QgsExpressionContextScope objects.

‎python/core/qgsmaplayer.sip

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,39 @@ Time stamp of data source in the moment when data/metadata were loaded by provid
953953
:rtype: bool
954954
%End
955955

956+
void setRefreshOnNotifyEnabled( bool enabled );
957+
%Docstring
958+
Set whether provider notification is connected to triggerRepaint
959+
960+
.. versionadded:: 3.0
961+
%End
962+
963+
void setRefreshOnNofifyMessage( const QString &message );
964+
%Docstring
965+
Set the notification message that triggers repaine
966+
If refresh on notification is enabled, the notification will triggerRepaint only
967+
if the notification message is equal to \param message
968+
969+
.. versionadded:: 3.0
970+
%End
971+
972+
QString refreshOnNotifyMessage() const;
973+
%Docstring
974+
Returns the message that should be notified by the provider to triggerRepaint
975+
976+
.. versionadded:: 3.0
977+
:rtype: str
978+
%End
979+
980+
bool isRefreshOnNotifyEnabled() const;
981+
%Docstring
982+
Returns true if the refresh on provider nofification is enabled
983+
984+
.. versionadded:: 3.0
985+
:rtype: bool
986+
%End
987+
988+
956989
signals:
957990

958991
void statusChanged( const QString &status );
@@ -1134,6 +1167,7 @@ Checks whether a new set of dependencies will introduce a cycle
11341167
:rtype: bool
11351168
%End
11361169

1170+
11371171
};
11381172

11391173

‎src/app/qgsattributeactiondialog.cpp

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,16 @@ void QgsAttributeActionDialog::insertRow( int row, const QgsAction &action )
145145
headerItem->setData( Qt::UserRole, action.iconPath() );
146146
mAttributeActionTable->setVerticalHeaderItem( row, headerItem );
147147

148+
// Notification message
149+
mAttributeActionTable->setItem( row, NotificationMessage, new QTableWidgetItem( action.notificationMessage() ) );
150+
148151
updateButtons();
149152
}
150153

151-
void QgsAttributeActionDialog::insertRow( int row, QgsAction::ActionType type, const QString &name, const QString &actionText, const QString &iconPath, bool capture, const QString &shortTitle, const QSet<QString> &actionScopes )
154+
void QgsAttributeActionDialog::insertRow( int row, QgsAction::ActionType type, const QString &name, const QString &actionText, const QString &iconPath, bool capture, const QString &shortTitle, const QSet<QString> &actionScopes, const QString &notificationMessage )
152155
{
153156
if ( uniqueName( name ) == name )
154-
insertRow( row, QgsAction( type, name, actionText, iconPath, capture, shortTitle, actionScopes ) );
157+
insertRow( row, QgsAction( type, name, actionText, iconPath, capture, shortTitle, actionScopes, notificationMessage ) );
155158
}
156159

157160
void QgsAttributeActionDialog::moveUp()
@@ -219,7 +222,9 @@ QgsAction QgsAttributeActionDialog::rowToAction( int row ) const
219222
mAttributeActionTable->verticalHeaderItem( row )->data( Qt::UserRole ).toString(),
220223
mAttributeActionTable->item( row, Capture )->checkState() == Qt::Checked,
221224
mAttributeActionTable->item( row, ShortTitle )->text(),
222-
mAttributeActionTable->item( row, ActionScopes )->data( Qt::UserRole ).value<QSet<QString>>() );
225+
mAttributeActionTable->item( row, ActionScopes )->data( Qt::UserRole ).value<QSet<QString>>(),
226+
mAttributeActionTable->item( row, NotificationMessage )->text()
227+
);
223228
return action;
224229
}
225230

@@ -273,7 +278,7 @@ void QgsAttributeActionDialog::insert()
273278
{
274279
QString name = uniqueName( dlg.description() );
275280

276-
insertRow( pos, dlg.type(), name, dlg.actionText(), dlg.iconPath(), dlg.capture(), dlg.shortTitle(), dlg.actionScopes() );
281+
insertRow( pos, dlg.type(), name, dlg.actionText(), dlg.iconPath(), dlg.capture(), dlg.shortTitle(), dlg.actionScopes(), dlg.notificationMessage() );
277282
}
278283
}
279284

@@ -300,14 +305,14 @@ void QgsAttributeActionDialog::updateButtons()
300305
void QgsAttributeActionDialog::addDefaultActions()
301306
{
302307
int pos = 0;
303-
insertRow( pos++, QgsAction::Generic, tr( "Echo attribute's value" ), QStringLiteral( "echo \"[% \"MY_FIELD\" %]\"" ), QLatin1String( "" ), true, tr( "Attribute Value" ), QSet<QString>() << QStringLiteral( "Field" ) );
304-
insertRow( pos++, QgsAction::Generic, tr( "Run an application" ), QStringLiteral( "ogr2ogr -f \"ESRI Shapefile\" \"[% \"OUTPUT_PATH\" %]\" \"[% \"INPUT_FILE\" %]\"" ), QLatin1String( "" ), true, tr( "Run application" ), QSet<QString>() << QStringLiteral( "Feature" ) << QStringLiteral( "Canvas" ) );
305-
insertRow( pos++, QgsAction::GenericPython, tr( "Get feature id" ), QStringLiteral( "from qgis.PyQt import QtWidgets\n\nQtWidgets.QMessageBox.information(None, \"Feature id\", \"feature id is [% $id %]\")" ), QLatin1String( "" ), false, tr( "Feature ID" ), QSet<QString>() << QStringLiteral( "Feature" ) << QStringLiteral( "Canvas" ) );
306-
insertRow( pos++, QgsAction::GenericPython, tr( "Selected field's value (Identify features tool)" ), QStringLiteral( "from qgis.PyQt import QtWidgets\n\nQtWidgets.QMessageBox.information(None, \"Current field's value\", \"[% @current_field %]\")" ), QLatin1String( "" ), false, tr( "Field Value" ), QSet<QString>() << QStringLiteral( "Field" ) );
307-
insertRow( pos++, QgsAction::GenericPython, tr( "Clicked coordinates (Run feature actions tool)" ), QStringLiteral( "from qgis.PyQt import QtWidgets\n\nQtWidgets.QMessageBox.information(None, \"Clicked coords\", \"layer: [% @layer_id %]\\ncoords: ([% @click_x %],[% @click_y %])\")" ), QLatin1String( "" ), false, tr( "Clicked Coordinate" ), QSet<QString>() << QStringLiteral( "Canvas" ) );
308-
insertRow( pos++, QgsAction::OpenUrl, tr( "Open file" ), QStringLiteral( "[% \"PATH\" %]" ), QLatin1String( "" ), false, tr( "Open file" ), QSet<QString>() << QStringLiteral( "Feature" ) << QStringLiteral( "Canvas" ) );
309-
insertRow( pos++, QgsAction::OpenUrl, tr( "Search on web based on attribute's value" ), QStringLiteral( "http://www.google.com/search?q=[% \"ATTRIBUTE\" %]" ), QLatin1String( "" ), false, tr( "Search Web" ), QSet<QString>() << QStringLiteral( "Field" ) );
310-
insertRow( pos++, QgsAction::GenericPython, tr( "List feature ids" ), QStringLiteral( "from qgis.PyQt import QtWidgets\n\nlayer = QgsProject.instance().mapLayer('[% @layer_id %]')\nif layer.selectedFeatureCount():\n ids = layer.selectedFeatureIds()\nelse:\n ids = [f.id() for f in layer.getFeatures()]\n\nQtWidgets.QMessageBox.information(None, \"Feature ids\", ', '.join([str(id) for id in ids]))" ), QLatin1String( "" ), false, tr( "List feature ids" ), QSet<QString>() << QStringLiteral( "Layer" ) );
308+
insertRow( pos++, QgsAction::Generic, tr( "Echo attribute's value" ), QStringLiteral( "echo \"[% \"MY_FIELD\" %]\"" ), QLatin1String( "" ), true, tr( "Attribute Value" ), QSet<QString>() << QStringLiteral( "Field" ), QString() );
309+
insertRow( pos++, QgsAction::Generic, tr( "Run an application" ), QStringLiteral( "ogr2ogr -f \"ESRI Shapefile\" \"[% \"OUTPUT_PATH\" %]\" \"[% \"INPUT_FILE\" %]\"" ), QLatin1String( "" ), true, tr( "Run application" ), QSet<QString>() << QStringLiteral( "Feature" ) << QStringLiteral( "Canvas" ), QString() );
310+
insertRow( pos++, QgsAction::GenericPython, tr( "Get feature id" ), QStringLiteral( "from qgis.PyQt import QtWidgets\n\nQtWidgets.QMessageBox.information(None, \"Feature id\", \"feature id is [% $id %]\")" ), QLatin1String( "" ), false, tr( "Feature ID" ), QSet<QString>() << QStringLiteral( "Feature" ) << QStringLiteral( "Canvas" ), QString() );
311+
insertRow( pos++, QgsAction::GenericPython, tr( "Selected field's value (Identify features tool)" ), QStringLiteral( "from qgis.PyQt import QtWidgets\n\nQtWidgets.QMessageBox.information(None, \"Current field's value\", \"[% @current_field %]\")" ), QLatin1String( "" ), false, tr( "Field Value" ), QSet<QString>() << QStringLiteral( "Field" ), QString() );
312+
insertRow( pos++, QgsAction::GenericPython, tr( "Clicked coordinates (Run feature actions tool)" ), QStringLiteral( "from qgis.PyQt import QtWidgets\n\nQtWidgets.QMessageBox.information(None, \"Clicked coords\", \"layer: [% @layer_id %]\\ncoords: ([% @click_x %],[% @click_y %])\")" ), QLatin1String( "" ), false, tr( "Clicked Coordinate" ), QSet<QString>() << QStringLiteral( "Canvas" ), QString() );
313+
insertRow( pos++, QgsAction::OpenUrl, tr( "Open file" ), QStringLiteral( "[% \"PATH\" %]" ), QLatin1String( "" ), false, tr( "Open file" ), QSet<QString>() << QStringLiteral( "Feature" ) << QStringLiteral( "Canvas" ), QString() );
314+
insertRow( pos++, QgsAction::OpenUrl, tr( "Search on web based on attribute's value" ), QStringLiteral( "http://www.google.com/search?q=[% \"ATTRIBUTE\" %]" ), QLatin1String( "" ), false, tr( "Search Web" ), QSet<QString>() << QStringLiteral( "Field" ), QString() );
315+
insertRow( pos++, QgsAction::GenericPython, tr( "List feature ids" ), QStringLiteral( "from qgis.PyQt import QtWidgets\n\nlayer = QgsProject.instance().mapLayer('[% @layer_id %]')\nif layer.selectedFeatureCount():\n ids = layer.selectedFeatureIds()\nelse:\n ids = [f.id() for f in layer.getFeatures()]\n\nQtWidgets.QMessageBox.information(None, \"Feature ids\", ', '.join([str(id) for id in ids]))" ), QLatin1String( "" ), false, tr( "List feature ids" ), QSet<QString>() << QStringLiteral( "Layer" ), QString() );
311316
}
312317

313318
void QgsAttributeActionDialog::itemDoubleClicked( QTableWidgetItem *item )
@@ -322,6 +327,7 @@ void QgsAttributeActionDialog::itemDoubleClicked( QTableWidgetItem *item )
322327
mAttributeActionTable->item( row, ActionText )->text(),
323328
mAttributeActionTable->item( row, Capture )->checkState() == Qt::Checked,
324329
mAttributeActionTable->item( row, ActionScopes )->data( Qt::UserRole ).value<QSet<QString>>(),
330+
mAttributeActionTable->item( row, NotificationMessage )->text(),
325331
mLayer
326332
);
327333

@@ -335,6 +341,7 @@ void QgsAttributeActionDialog::itemDoubleClicked( QTableWidgetItem *item )
335341
mAttributeActionTable->item( row, ShortTitle )->setText( actionProperties.shortTitle() );
336342
mAttributeActionTable->item( row, ActionText )->setText( actionProperties.actionText() );
337343
mAttributeActionTable->item( row, Capture )->setCheckState( actionProperties.capture() ? Qt::Checked : Qt::Unchecked );
344+
mAttributeActionTable->item( row, NotificationMessage )->setText( actionProperties.notificationMessage() );
338345

339346
QTableWidgetItem *item = mAttributeActionTable->item( row, ActionScopes );
340347
QStringList actionScopes = actionProperties.actionScopes().toList();

‎src/app/qgsattributeactiondialog.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ class APP_EXPORT QgsAttributeActionDialog: public QWidget, private Ui::QgsAttrib
4343
ShortTitle,
4444
ActionText,
4545
Capture,
46-
ActionScopes
46+
ActionScopes,
47+
NotificationMessage
4748
};
4849

4950
public:
@@ -69,7 +70,7 @@ class APP_EXPORT QgsAttributeActionDialog: public QWidget, private Ui::QgsAttrib
6970

7071
private:
7172
void insertRow( int row, const QgsAction &action );
72-
void insertRow( int row, QgsAction::ActionType type, const QString &name, const QString &actionText, const QString &iconPath, bool capture, const QString &shortTitle, const QSet<QString> &actionScopes );
73+
void insertRow( int row, QgsAction::ActionType type, const QString &name, const QString &actionText, const QString &iconPath, bool capture, const QString &shortTitle, const QSet<QString> &actionScopes, const QString &notificationMessage );
7374
void swapRows( int row1, int row2 );
7475
QgsAction rowToAction( int row ) const;
7576

‎src/app/qgsattributeactionpropertiesdialog.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
#include <QFileDialog>
3232
#include <QImageWriter>
3333

34-
QgsAttributeActionPropertiesDialog::QgsAttributeActionPropertiesDialog( QgsAction::ActionType type, const QString &description, const QString &shortTitle, const QString &iconPath, const QString &actionText, bool capture, const QSet<QString> &actionScopes, QgsVectorLayer *layer, QWidget *parent )
34+
QgsAttributeActionPropertiesDialog::QgsAttributeActionPropertiesDialog( QgsAction::ActionType type, const QString &description, const QString &shortTitle, const QString &iconPath, const QString &actionText, bool capture, const QSet<QString> &actionScopes, const QString &notificationMessage, QgsVectorLayer *layer, QWidget *parent )
3535
: QDialog( parent )
3636
, mLayer( layer )
3737
{
@@ -44,6 +44,7 @@ QgsAttributeActionPropertiesDialog::QgsAttributeActionPropertiesDialog( QgsActio
4444
mIconPreview->setPixmap( QPixmap( iconPath ) );
4545
mActionText->setText( actionText );
4646
mCaptureOutput->setChecked( capture );
47+
mNotificationMessage->setText( notificationMessage );
4748

4849
init( actionScopes );
4950
}
@@ -101,6 +102,12 @@ QSet<QString> QgsAttributeActionPropertiesDialog::actionScopes() const
101102
return actionScopes;
102103
}
103104

105+
QString QgsAttributeActionPropertiesDialog::notificationMessage() const
106+
{
107+
return mNotificationMessage->text();
108+
}
109+
110+
104111
bool QgsAttributeActionPropertiesDialog::capture() const
105112
{
106113
return mCaptureOutput->isChecked();
@@ -119,6 +126,8 @@ QgsExpressionContext QgsAttributeActionPropertiesDialog::createExpressionContext
119126
}
120127
}
121128

129+
context << QgsExpressionContextUtils::notificationScope();
130+
122131
return context;
123132
}
124133

‎src/app/qgsattributeactionpropertiesdialog.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ class QgsAttributeActionPropertiesDialog: public QDialog, private Ui::QgsAttribu
2828
Q_OBJECT
2929

3030
public:
31-
QgsAttributeActionPropertiesDialog( QgsAction::ActionType type, const QString &description, const QString &shortTitle, const QString &iconPath, const QString &actionText, bool capture, const QSet<QString> &actionScopes, QgsVectorLayer *layer, QWidget *parent = nullptr );
31+
QgsAttributeActionPropertiesDialog( QgsAction::ActionType type, const QString &description, const QString &shortTitle, const QString &iconPath, const QString &actionText, bool capture, const QSet<QString> &actionScopes, const QString &notificationMessage, QgsVectorLayer *layer, QWidget *parent = nullptr );
3232

3333
QgsAttributeActionPropertiesDialog( QgsVectorLayer *layer, QWidget *parent = nullptr );
3434

@@ -44,6 +44,8 @@ class QgsAttributeActionPropertiesDialog: public QDialog, private Ui::QgsAttribu
4444

4545
QSet<QString> actionScopes() const;
4646

47+
QString notificationMessage() const;
48+
4749
bool capture() const;
4850

4951
virtual QgsExpressionContext createExpressionContext() const override;

‎src/app/qgsvectorlayerproperties.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -454,6 +454,11 @@ void QgsVectorLayerProperties::syncToLayer()
454454
mRefreshLayerIntervalSpinBox->setEnabled( mLayer->hasAutoRefreshEnabled() );
455455
mRefreshLayerIntervalSpinBox->setValue( mLayer->autoRefreshInterval() / 1000.0 );
456456

457+
mRefreshLayerNotificationCheckBox->setChecked( mLayer->isRefreshOnNotifyEnabled() );
458+
mNotificationMessageCheckBox->setChecked( !mLayer->refreshOnNotifyMessage().isEmpty() );
459+
mNotifyMessagValueLineEdit->setText( mLayer->refreshOnNotifyMessage() );
460+
461+
457462
// load appropriate symbology page (V1 or V2)
458463
updateSymbologyPage();
459464

@@ -632,6 +637,9 @@ void QgsVectorLayerProperties::apply()
632637
mLayer->setAutoRefreshInterval( mRefreshLayerIntervalSpinBox->value() * 1000.0 );
633638
mLayer->setAutoRefreshEnabled( mRefreshLayerCheckBox->isChecked() );
634639

640+
mLayer->setRefreshOnNotifyEnabled( mRefreshLayerNotificationCheckBox->isChecked() );
641+
mLayer->setRefreshOnNofifyMessage( mNotificationMessageCheckBox->isChecked() ? mNotifyMessagValueLineEdit->text() : QString() );
642+
635643
mOldJoins = mLayer->vectorJoins();
636644

637645
//save variables

‎src/core/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -562,6 +562,7 @@ ENDIF(NOT MSVC)
562562

563563
SET(QGIS_CORE_MOC_HDRS
564564
qgsapplication.h
565+
qgsactionmanager.h
565566
qgsactionscoperegistry.h
566567
qgsanimatedicon.h
567568
qgsbrowsermodel.h

‎src/core/expression/qgsexpression.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,9 @@ void QgsExpression::initVariableHelp()
703703

704704
//processing variables
705705
sVariableHelpTexts.insert( QStringLiteral( "algorithm_id" ), QCoreApplication::translate( "algorithm_id", "Unique ID for algorithm." ) );
706+
707+
//provider notification
708+
sVariableHelpTexts.insert( QStringLiteral( "notification_message" ), QCoreApplication::translate( "notification_message", "Contend of the notification message sent by the provider (available only for actions triggered by provider notifications)." ) );
706709
}
707710

708711
QString QgsExpression::variableHelpText( const QString &variableName )

‎src/core/qgsaction.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ void QgsAction::readXml( const QDomNode &actionNode )
119119
mIcon = actionElement.attributeNode( QStringLiteral( "icon" ) ).value();
120120
mCaptureOutput = actionElement.attributeNode( QStringLiteral( "capture" ) ).value().toInt() != 0;
121121
mShortTitle = actionElement.attributeNode( QStringLiteral( "shortTitle" ) ).value();
122+
mNotificationMessage = actionElement.attributeNode( QStringLiteral( "notificationMessage" ) ).value();
122123
mId = QUuid( actionElement.attributeNode( QStringLiteral( "id" ) ).value() );
123124
if ( mId.isNull() )
124125
mId = QUuid::createUuid();
@@ -133,6 +134,7 @@ void QgsAction::writeXml( QDomNode &actionsNode ) const
133134
actionSetting.setAttribute( QStringLiteral( "icon" ), mIcon );
134135
actionSetting.setAttribute( QStringLiteral( "action" ), mCommand );
135136
actionSetting.setAttribute( QStringLiteral( "capture" ), mCaptureOutput );
137+
actionSetting.setAttribute( QStringLiteral( "notificationMessage" ), mNotificationMessage );
136138
actionSetting.setAttribute( QStringLiteral( "id" ), mId.toString() );
137139

138140
Q_FOREACH ( const QString &scope, mActionScopes )

0 commit comments

Comments
 (0)
Please sign in to comment.