31 #include <QFileDialog>
32 #include <QHeaderView>
33 #include <QMessageBox>
35 #include <QImageWriter>
36 #include <QTableWidget>
40 , mLayer( actions.layer() )
43 QHeaderView *header = mAttributeActionTable->horizontalHeader();
44 header->setHighlightSections(
false );
45 header->setStretchLastSection(
true );
46 mAttributeActionTable->setColumnWidth( 0, 100 );
47 mAttributeActionTable->setColumnWidth( 1, 230 );
48 mAttributeActionTable->setCornerButtonEnabled(
false );
49 mAttributeActionTable->setEditTriggers( QAbstractItemView::AnyKeyPressed | QAbstractItemView::SelectedClicked );
51 connect( mAttributeActionTable, &QTableWidget::itemDoubleClicked,
this, &QgsAttributeActionDialog::itemDoubleClicked );
52 connect( mAttributeActionTable, &QTableWidget::itemSelectionChanged,
this, &QgsAttributeActionDialog::updateButtons );
53 connect( mMoveUpButton, &QAbstractButton::clicked,
this, &QgsAttributeActionDialog::moveUp );
54 connect( mMoveDownButton, &QAbstractButton::clicked,
this, &QgsAttributeActionDialog::moveDown );
55 connect( mRemoveButton, &QAbstractButton::clicked,
this, &QgsAttributeActionDialog::remove );
56 connect( mAddButton, &QAbstractButton::clicked,
this, &QgsAttributeActionDialog::insert );
57 connect( mAddDefaultActionsButton, &QAbstractButton::clicked,
this, &QgsAttributeActionDialog::addDefaultActions );
65 mAttributeActionTable->setRowCount( 0 );
69 const auto constActions =
actions.actions();
70 for (
const QgsAction &action : constActions )
72 insertRow( i++, action );
79 visibleActionWidgetConfig.
hidden =
false;
82 mAttributeTableWidgetType->setCurrentIndex( attributeTableConfig.
actionWidgetStyle() );
89 for (
int i = 0; i < mAttributeActionTable->rowCount(); ++i )
91 actions.append( rowToAction( i ) );
99 return mShowInAttributeTable->isChecked();
107 void QgsAttributeActionDialog::insertRow(
int row,
const QgsAction &action )
109 QTableWidgetItem *item =
nullptr;
110 mAttributeActionTable->insertRow( row );
113 item =
new QTableWidgetItem( textForType( action.
type() ) );
114 item->setData( Role::ActionType, action.
type() );
115 item->setData( Role::ActionId, action.
id() );
116 item->setFlags( item->flags() & ~Qt::ItemIsEditable );
117 mAttributeActionTable->setItem( row, Type, item );
120 mAttributeActionTable->setItem( row, Description,
new QTableWidgetItem( action.
name() ) );
123 mAttributeActionTable->setItem( row, ShortTitle,
new QTableWidgetItem( action.
shortTitle() ) );
126 item =
new QTableWidgetItem( action.
command().length() > 30 ? action.
command().left( 27 ) +
"…" : action.
command() );
127 item->setData( Qt::UserRole, action.
command() );
128 mAttributeActionTable->setItem( row, ActionText, item );
131 item =
new QTableWidgetItem();
132 item->setFlags( item->flags() & ~( Qt::ItemIsEditable ) );
133 item->setCheckState( action.
capture() ? Qt::Checked : Qt::Unchecked );
134 mAttributeActionTable->setItem( row, Capture, item );
137 item =
new QTableWidgetItem();
138 item->setFlags( item->flags() & ~( Qt::ItemIsEditable ) );
139 QStringList actionScopes = qgis::setToList( action.
actionScopes() );
140 std::sort( actionScopes.begin(), actionScopes.end() );
141 item->setText( actionScopes.join( QLatin1String(
", " ) ) );
142 item->setData( Qt::UserRole, QVariant::fromValue<QSet<QString>>( action.
actionScopes() ) );
143 mAttributeActionTable->setItem( row, ActionScopes, item );
146 const QIcon icon = action.
icon();
147 QTableWidgetItem *headerItem =
new QTableWidgetItem( icon, QString() );
148 headerItem->setData( Qt::UserRole, action.
iconPath() );
149 mAttributeActionTable->setVerticalHeaderItem( row, headerItem );
152 mAttributeActionTable->setItem( row, NotificationMessage,
new QTableWidgetItem( action.
notificationMessage() ) );
155 item =
new QTableWidgetItem();
156 item->setFlags( item->flags() & ~( Qt::ItemIsEditable ) );
158 mAttributeActionTable->setItem( row, EnabledOnlyWhenEditable, item );
163 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 ¬ificationMessage,
bool isEnabledOnlyWhenEditable )
165 if ( uniqueName( name ) == name )
166 insertRow( row,
QgsAction( type, name, actionText, iconPath, capture, shortTitle, actionScopes, notificationMessage, isEnabledOnlyWhenEditable ) );
169 void QgsAttributeActionDialog::moveUp()
173 int row1 = -1, row2 = -1;
174 QList<QTableWidgetItem *> selection = mAttributeActionTable->selectedItems();
175 if ( !selection.isEmpty() )
177 row1 = selection.first()->row();
183 if ( row1 != -1 && row2 != -1 )
185 swapRows( row1, row2 );
187 mAttributeActionTable->selectRow( row2 );
191 void QgsAttributeActionDialog::moveDown()
194 int row1 = -1, row2 = -1;
195 QList<QTableWidgetItem *> selection = mAttributeActionTable->selectedItems();
196 if ( !selection.isEmpty() )
198 row1 = selection.first()->row();
201 if ( row1 < mAttributeActionTable->rowCount() - 1 )
204 if ( row1 != -1 && row2 != -1 )
206 swapRows( row1, row2 );
208 mAttributeActionTable->selectRow( row2 );
212 void QgsAttributeActionDialog::swapRows(
int row1,
int row2 )
214 const int colCount = mAttributeActionTable->columnCount();
215 for (
int col = 0; col < colCount; col++ )
217 QTableWidgetItem *item = mAttributeActionTable->takeItem( row1, col );
218 mAttributeActionTable->setItem( row1, col, mAttributeActionTable->takeItem( row2, col ) );
219 mAttributeActionTable->setItem( row2, col, item );
221 QTableWidgetItem *header = mAttributeActionTable->takeVerticalHeaderItem( row1 );
222 mAttributeActionTable->setVerticalHeaderItem( row1, mAttributeActionTable->takeVerticalHeaderItem( row2 ) );
223 mAttributeActionTable->setVerticalHeaderItem( row2, header );
226 QgsAction QgsAttributeActionDialog::rowToAction(
int row )
const
228 const QUuid
id { mAttributeActionTable->item( row, Type )->data( Role::ActionId ).toUuid() };
230 static_cast<QgsAction::ActionType>( mAttributeActionTable->item( row, Type )->data( Role::ActionType ).toInt() ),
231 mAttributeActionTable->item( row, Description )->text(),
232 mAttributeActionTable->item( row, ActionText )->data( Qt::UserRole ).toString(),
233 mAttributeActionTable->verticalHeaderItem( row )->data( Qt::UserRole ).toString(),
234 mAttributeActionTable->item( row, Capture )->checkState() == Qt::Checked,
235 mAttributeActionTable->item( row, ShortTitle )->text(),
236 mAttributeActionTable->item( row, ActionScopes )->data( Qt::UserRole ).value<QSet<QString>>(),
237 mAttributeActionTable->item( row, NotificationMessage )->text(),
238 mAttributeActionTable->item( row, EnabledOnlyWhenEditable )->checkState() == Qt::Checked
248 return tr(
"Generic" );
250 return tr(
"Python" );
254 return tr(
"Windows" );
258 return tr(
"Open URL" );
263 void QgsAttributeActionDialog::remove()
265 QList<QTableWidgetItem *> selection = mAttributeActionTable->selectedItems();
266 if ( !selection.isEmpty() )
269 int row = selection.first()->row();
270 mAttributeActionTable->removeRow( row );
273 if ( row >= mAttributeActionTable->rowCount() )
274 row = mAttributeActionTable->rowCount() - 1;
275 mAttributeActionTable->selectRow( row );
281 void QgsAttributeActionDialog::insert()
284 const int pos = mAttributeActionTable->rowCount();
287 dlg.setWindowTitle( tr(
"Add New Action" ) );
291 const QString name = uniqueName( dlg.description() );
293 insertRow( pos, dlg.type(), name, dlg.actionText(), dlg.iconPath(), dlg.capture(), dlg.shortTitle(), dlg.actionScopes(), dlg.notificationMessage(), dlg.isEnabledOnlyWhenEditable() );
297 void QgsAttributeActionDialog::updateButtons()
299 QList<QTableWidgetItem *> selection = mAttributeActionTable->selectedItems();
300 const bool hasSelection = !selection.isEmpty();
304 const int row = selection.first()->row();
305 mMoveUpButton->setEnabled( row >= 1 );
306 mMoveDownButton->setEnabled( row >= 0 && row < mAttributeActionTable->rowCount() - 1 );
310 mMoveUpButton->setEnabled(
false );
311 mMoveDownButton->setEnabled(
false );
314 mRemoveButton->setEnabled( hasSelection );
317 void QgsAttributeActionDialog::addDefaultActions()
320 insertRow( pos++,
QgsAction::Generic, tr(
"Echo attribute's value" ), QStringLiteral(
"echo \"[% \"MY_FIELD\" %]\"" ), QString(),
true, tr(
"Attribute Value" ), QSet<QString>() << QStringLiteral(
"Field" ), QString() );
321 insertRow( pos++,
QgsAction::Generic, tr(
"Run an application" ), QStringLiteral(
"ogr2ogr -f \"GPKG\" \"[% \"OUTPUT_PATH\" %]\" \"[% \"INPUT_FILE\" %]\"" ), QString(),
true, tr(
"Run application" ), QSet<QString>() << QStringLiteral(
"Feature" ) << QStringLiteral(
"Canvas" ), QString() );
322 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 %]\")" ), QString(),
false, tr(
"Feature ID" ), QSet<QString>() << QStringLiteral(
"Feature" ) << QStringLiteral(
"Canvas" ), QString() );
323 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\", \"[% @field_value %]\")" ), QString(),
false, tr(
"Field Value" ), QSet<QString>() << QStringLiteral(
"Field" ), QString() );
324 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 %])\")" ), QString(),
false, tr(
"Clicked Coordinate" ), QSet<QString>() << QStringLiteral(
"Canvas" ), QString() );
325 insertRow( pos++,
QgsAction::OpenUrl, tr(
"Open file" ), QStringLiteral(
"[% \"PATH\" %]" ), QString(),
false, tr(
"Open file" ), QSet<QString>() << QStringLiteral(
"Feature" ) << QStringLiteral(
"Canvas" ), QString() );
326 insertRow( pos++,
QgsAction::OpenUrl, tr(
"Search on web based on attribute's value" ), QStringLiteral(
"http://www.google.com/search?q=[% \"ATTRIBUTE\" %]" ), QString(),
false, tr(
"Search Web" ), QSet<QString>() << QStringLiteral(
"Field" ), QString() );
327 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]))" ), QString(),
false, tr(
"List feature ids" ), QSet<QString>() << QStringLiteral(
"Layer" ), QString() );
328 insertRow( pos++,
QgsAction::GenericPython, tr(
"Duplicate selected features" ), QStringLiteral(
"project = QgsProject.instance()\nlayer = QgsProject.instance().mapLayer('[% @layer_id %]')\nif not layer.isEditable():\n qgis.utils.iface.messageBar().pushMessage( 'Cannot duplicate feature in not editable mode on layer {layer}'.format( layer=layer.name() ) )\nelse:\n features=[]\n if len('[% $id %]')>0:\n features.append( layer.getFeature( [% $id %] ) )\n else:\n for x in layer.selectedFeatures():\n features.append( x )\n feature_count=0\n children_info=''\n featureids=[]\n for f in features:\n result=QgsVectorLayerUtils.duplicateFeature(layer, f, project, 0 )\n featureids.append( result[0].id() )\n feature_count+=1\n for ch_layer in result[1].layers():\n children_info+='{number_of_children} children on layer {children_layer}\\n'.format( number_of_children=str( len( result[1].duplicatedFeatures(ch_layer) ) ), children_layer=ch_layer.name() )\n ch_layer.selectByIds( result[1].duplicatedFeatures(ch_layer) )\n layer.selectByIds( featureids )\n qgis.utils.iface.messageBar().pushMessage( '{number_of_features} features on layer {layer} duplicated with\\n{children_info}'.format( number_of_features=str( feature_count ), layer=layer.name(), children_info=children_info ) )" ), QString(),
false, tr(
"Duplicate selected" ), QSet<QString>() << QStringLiteral(
"Layer" ), QString(),
true );
332 void QgsAttributeActionDialog::itemDoubleClicked( QTableWidgetItem *item )
334 const int row = item->row();
337 static_cast<QgsAction::ActionType>( mAttributeActionTable->item( row, Type )->data( Role::ActionType ).toInt() ),
338 mAttributeActionTable->item( row, Description )->text(),
339 mAttributeActionTable->item( row, ShortTitle )->text(),
340 mAttributeActionTable->verticalHeaderItem( row )->data( Qt::UserRole ).toString(),
341 mAttributeActionTable->item( row, ActionText )->data( Qt::UserRole ).toString(),
342 mAttributeActionTable->item( row, Capture )->checkState() == Qt::Checked,
343 mAttributeActionTable->item( row, ActionScopes )->data( Qt::UserRole ).value<QSet<QString>>(),
344 mAttributeActionTable->item( row, NotificationMessage )->text(),
345 mAttributeActionTable->item( row, EnabledOnlyWhenEditable )->checkState() == Qt::Checked,
349 actionProperties.setWindowTitle( tr(
"Edit Action" ) );
351 if ( actionProperties.exec() )
353 mAttributeActionTable->item( row, Type )->setData( Role::ActionType, actionProperties.type() );
354 mAttributeActionTable->item( row, Type )->setText( textForType( actionProperties.type() ) );
355 mAttributeActionTable->item( row, Description )->setText( actionProperties.description() );
356 mAttributeActionTable->item( row, ShortTitle )->setText( actionProperties.shortTitle() );
357 mAttributeActionTable->item( row, ActionText )->setText( actionProperties.actionText().length() > 30 ? actionProperties.actionText().left( 27 ) +
"…" : actionProperties.actionText() );
358 mAttributeActionTable->item( row, ActionText )->setData( Qt::UserRole, actionProperties.actionText() );
359 mAttributeActionTable->item( row, Capture )->setCheckState( actionProperties.capture() ? Qt::Checked : Qt::Unchecked );
360 mAttributeActionTable->item( row, NotificationMessage )->setText( actionProperties.notificationMessage() );
361 mAttributeActionTable->item( row, EnabledOnlyWhenEditable )->setCheckState( actionProperties.isEnabledOnlyWhenEditable() ? Qt::Checked : Qt::Unchecked );
363 QTableWidgetItem *item = mAttributeActionTable->item( row, ActionScopes );
364 QStringList actionScopes = qgis::setToList( actionProperties.actionScopes() );
365 std::sort( actionScopes.begin(), actionScopes.end() );
366 item->setText( actionScopes.join( QLatin1String(
", " ) ) );
367 item->setData( Qt::UserRole, QVariant::fromValue<QSet<QString>>( actionProperties.actionScopes() ) );
369 mAttributeActionTable->verticalHeaderItem( row )->setData( Qt::UserRole, actionProperties.iconPath() );
370 mAttributeActionTable->verticalHeaderItem( row )->setIcon( QIcon( actionProperties.iconPath() ) );
374 QString QgsAttributeActionDialog::uniqueName( QString name )
379 const int pos = mAttributeActionTable->rowCount();
382 for (
int i = 0; i < pos; ++i )
384 if ( mAttributeActionTable->item( i, Description )->text() == name )
394 const QString suffix = QString::number( suffix_num );
395 new_name = name +
'_' + suffix;
397 for (
int i = 0; i < pos; ++i )
398 if ( mAttributeActionTable->item( i, 0 )->text() == new_name )
Storage and management of actions associated with a layer.
Utility class that encapsulates an action based on vector attributes.
QString notificationMessage() const
Returns the notification message that triggers the action.
QString name() const
The name of the action. This may be a longer description.
QSet< QString > actionScopes() const
The action scopes define where an action will be available.
QIcon icon() const
The icon.
QString iconPath() const
The path to the icon.
ActionType type() const
The action type.
QString command() const
Returns the command that is executed by this action.
QString shortTitle() const
The short title is used to label user interface elements like buttons.
bool isEnabledOnlyWhenEditable() const
Returns whether only enabled in editable mode.
bool capture() const
Whether to capture output for display when this action is run.
QUuid id() const
Returns a unique id for this action.
void init(const QgsActionManager &action, const QgsAttributeTableConfig &attributeTableConfig)
bool showWidgetInAttributeTable() const
QgsAttributeActionDialog(const QgsActionManager &actions, QWidget *parent=nullptr)
QList< QgsAction > actions() const
QgsAttributeTableConfig::ActionWidgetStyle attributeTableWidgetStyle() const
This is a container for configuration of the attribute table.
@ Action
This column represents an action widget.
ActionWidgetStyle
The style of the action widget in the attribute table.
bool actionWidgetVisible() const
Returns true if the action widget is visible.
ActionWidgetStyle actionWidgetStyle() const
Gets the style of the action widget.
QgsAttributeTableConfig attributeTableConfig() const
Returns the attribute table configuration object.
Defines the configuration of a column in the attribute table.
QgsAttributeTableConfig::Type type
The type of this column.
bool hidden
Flag that controls if the column is hidden.