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" );
260 return tr(
"Submit URL (urlencoded or JSON)" );
262 return tr(
"Submit URL (multipart)" );
267 void QgsAttributeActionDialog::remove()
269 QList<QTableWidgetItem *> selection = mAttributeActionTable->selectedItems();
270 if ( !selection.isEmpty() )
273 int row = selection.first()->row();
274 mAttributeActionTable->removeRow( row );
277 if ( row >= mAttributeActionTable->rowCount() )
278 row = mAttributeActionTable->rowCount() - 1;
279 mAttributeActionTable->selectRow( row );
285 void QgsAttributeActionDialog::insert()
288 const int pos = mAttributeActionTable->rowCount();
291 dlg.setWindowTitle( tr(
"Add New Action" ) );
295 const QString name = uniqueName( dlg.description() );
297 insertRow( pos, dlg.type(), name, dlg.actionText(), dlg.iconPath(), dlg.capture(), dlg.shortTitle(), dlg.actionScopes(), dlg.notificationMessage(), dlg.isEnabledOnlyWhenEditable() );
301 void QgsAttributeActionDialog::updateButtons()
303 QList<QTableWidgetItem *> selection = mAttributeActionTable->selectedItems();
304 const bool hasSelection = !selection.isEmpty();
308 const int row = selection.first()->row();
309 mMoveUpButton->setEnabled( row >= 1 );
310 mMoveDownButton->setEnabled( row >= 0 && row < mAttributeActionTable->rowCount() - 1 );
314 mMoveUpButton->setEnabled(
false );
315 mMoveDownButton->setEnabled(
false );
318 mRemoveButton->setEnabled( hasSelection );
321 void QgsAttributeActionDialog::addDefaultActions()
324 insertRow( pos++,
QgsAction::Generic, tr(
"Echo attribute's value" ), QStringLiteral(
"echo \"[% \"MY_FIELD\" %]\"" ), QString(),
true, tr(
"Attribute Value" ), QSet<QString>() << QStringLiteral(
"Field" ), QString() );
325 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() );
326 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() );
327 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() );
328 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() );
329 insertRow( pos++,
QgsAction::OpenUrl, tr(
"Open file" ), QStringLiteral(
"[% \"PATH\" %]" ), QString(),
false, tr(
"Open file" ), QSet<QString>() << QStringLiteral(
"Feature" ) << QStringLiteral(
"Canvas" ), QString() );
330 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() );
331 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() );
332 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 );
336 void QgsAttributeActionDialog::itemDoubleClicked( QTableWidgetItem *item )
338 const int row = item->row();
341 static_cast<QgsAction::ActionType>( mAttributeActionTable->item( row, Type )->data( Role::ActionType ).toInt() ),
342 mAttributeActionTable->item( row, Description )->text(),
343 mAttributeActionTable->item( row, ShortTitle )->text(),
344 mAttributeActionTable->verticalHeaderItem( row )->data( Qt::UserRole ).toString(),
345 mAttributeActionTable->item( row, ActionText )->data( Qt::UserRole ).toString(),
346 mAttributeActionTable->item( row, Capture )->checkState() == Qt::Checked,
347 mAttributeActionTable->item( row, ActionScopes )->data( Qt::UserRole ).value<QSet<QString>>(),
348 mAttributeActionTable->item( row, NotificationMessage )->text(),
349 mAttributeActionTable->item( row, EnabledOnlyWhenEditable )->checkState() == Qt::Checked,
353 actionProperties.setWindowTitle( tr(
"Edit Action" ) );
355 if ( actionProperties.exec() )
357 mAttributeActionTable->item( row, Type )->setData( Role::ActionType, actionProperties.type() );
358 mAttributeActionTable->item( row, Type )->setText( textForType( actionProperties.type() ) );
359 mAttributeActionTable->item( row, Description )->setText( actionProperties.description() );
360 mAttributeActionTable->item( row, ShortTitle )->setText( actionProperties.shortTitle() );
361 mAttributeActionTable->item( row, ActionText )->setText( actionProperties.actionText().length() > 30 ? actionProperties.actionText().left( 27 ) +
"…" : actionProperties.actionText() );
362 mAttributeActionTable->item( row, ActionText )->setData( Qt::UserRole, actionProperties.actionText() );
363 mAttributeActionTable->item( row, Capture )->setCheckState( actionProperties.capture() ? Qt::Checked : Qt::Unchecked );
364 mAttributeActionTable->item( row, NotificationMessage )->setText( actionProperties.notificationMessage() );
365 mAttributeActionTable->item( row, EnabledOnlyWhenEditable )->setCheckState( actionProperties.isEnabledOnlyWhenEditable() ? Qt::Checked : Qt::Unchecked );
367 QTableWidgetItem *item = mAttributeActionTable->item( row, ActionScopes );
368 QStringList actionScopes = qgis::setToList( actionProperties.actionScopes() );
369 std::sort( actionScopes.begin(), actionScopes.end() );
370 item->setText( actionScopes.join( QLatin1String(
", " ) ) );
371 item->setData( Qt::UserRole, QVariant::fromValue<QSet<QString>>( actionProperties.actionScopes() ) );
373 mAttributeActionTable->verticalHeaderItem( row )->setData( Qt::UserRole, actionProperties.iconPath() );
374 mAttributeActionTable->verticalHeaderItem( row )->setIcon( QIcon( actionProperties.iconPath() ) );
378 QString QgsAttributeActionDialog::uniqueName( QString name )
383 const int pos = mAttributeActionTable->rowCount();
386 for (
int i = 0; i < pos; ++i )
388 if ( mAttributeActionTable->item( i, Description )->text() == name )
398 const QString suffix = QString::number( suffix_num );
399 new_name = name +
'_' + suffix;
401 for (
int i = 0; i < pos; ++i )
402 if ( mAttributeActionTable->item( i, 0 )->text() == new_name )