QGIS API Documentation  3.27.0-Master (aef1b1ec20)
qgsvectorlayerproperties.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsdlgvectorlayerproperties.cpp
3  Unified property dialog for vector layers
4  -------------------
5  begin : 2004-01-28
6  copyright : (C) 2004 by Gary E.Sherman
7  email : sherman at mrcc.com
8 ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
19 #include <memory>
20 #include <limits>
21 
22 #include "qgsactionmanager.h"
23 #include "qgsjoindialog.h"
24 #include "qgswmsdimensiondialog.h"
25 #include "qgsapplication.h"
27 #include "qgscoordinatetransform.h"
29 #include "qgsdiagramproperties.h"
30 #include "qgsdiagramrenderer.h"
32 #include "qgsfieldcalculator.h"
35 #include "qgslabelingwidget.h"
37 #include "qgslogger.h"
38 #include "qgsmapcanvas.h"
41 #include "qgsmetadatawidget.h"
43 #include "qgsnative.h"
44 #include "qgsproject.h"
45 #include "qgsvectorlayer.h"
46 #include "qgsvectorlayerjoininfo.h"
48 #include "qgsconfig.h"
49 #include "qgsvectordataprovider.h"
53 #include "qgsdatasourceuri.h"
54 #include "qgsrenderer.h"
55 #include "qgsexpressioncontext.h"
56 #include "qgssettings.h"
58 #include "qgsstyle.h"
59 #include "qgsauxiliarystorage.h"
63 #include "qgslabelinggui.h"
64 #include "qgssymbollayer.h"
65 #include "qgsgeometryoptions.h"
68 #include "qgsmessagebar.h"
69 #include "qgssymbolwidgetcontext.h"
71 #include "qgsmaskingwidget.h"
75 #include "qgsproviderregistry.h"
76 
78 #include "qgslayertree.h"
79 
80 #include <QDesktopServices>
81 #include <QMessageBox>
82 #include <QDir>
83 #include <QFile>
84 #include <QFileDialog>
85 #include <QFileInfo>
86 #include <QFontDialog>
87 #include <QComboBox>
88 #include <QCheckBox>
89 #include <QHeaderView>
90 #include <QColorDialog>
91 #include <QMenu>
92 #include <QUrl>
93 #include <QRegularExpressionValidator>
94 
96 #include "qgsstyle.h"
97 
98 
100  QgsMapCanvas *canvas,
101  QgsMessageBar *messageBar,
102  QgsVectorLayer *lyr,
103  QWidget *parent,
104  Qt::WindowFlags fl
105 )
106  : QgsOptionsDialogBase( QStringLiteral( "VectorLayerProperties" ), parent, fl )
107  , mCanvas( canvas )
108  , mMessageBar( messageBar )
109  , mLayer( lyr )
110  , mOriginalSubsetSQL( lyr->subsetString() )
111 {
112  setupUi( this );
113  connect( pbnQueryBuilder, &QPushButton::clicked, this, &QgsVectorLayerProperties::pbnQueryBuilder_clicked );
114  connect( pbnIndex, &QPushButton::clicked, this, &QgsVectorLayerProperties::pbnIndex_clicked );
115  connect( mCrsSelector, &QgsProjectionSelectionWidget::crsChanged, this, &QgsVectorLayerProperties::mCrsSelector_crsChanged );
116  connect( pbnUpdateExtents, &QPushButton::clicked, this, &QgsVectorLayerProperties::pbnUpdateExtents_clicked );
117  connect( mButtonAddJoin, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonAddJoin_clicked );
118  connect( mButtonEditJoin, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonEditJoin_clicked );
119  connect( mJoinTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QgsVectorLayerProperties::mJoinTreeWidget_itemDoubleClicked );
120  connect( mButtonRemoveJoin, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonRemoveJoin_clicked );
121  connect( mButtonAddWmsDimension, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonAddWmsDimension_clicked );
122  connect( mButtonEditWmsDimension, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonEditWmsDimension_clicked );
123  connect( mWmsDimensionsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QgsVectorLayerProperties::mWmsDimensionsTreeWidget_itemDoubleClicked );
124  connect( mButtonRemoveWmsDimension, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonRemoveWmsDimension_clicked );
125  connect( mSimplifyDrawingGroupBox, &QGroupBox::toggled, this, &QgsVectorLayerProperties::mSimplifyDrawingGroupBox_toggled );
126  connect( buttonRemoveMetadataUrl, &QPushButton::clicked, this, &QgsVectorLayerProperties::removeSelectedMetadataUrl );
127  connect( buttonAddMetadataUrl, &QPushButton::clicked, this, &QgsVectorLayerProperties::addMetadataUrl );
128  connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsVectorLayerProperties::showHelp );
129 
130  // QgsOptionsDialogBase handles saving/restoring of geometry, splitter and current tab states,
131  // switching vertical tabs between icon/text to icon-only modes (splitter collapsed to left),
132  // and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
133  initOptionsBase( false );
134 
135  mBtnStyle = new QPushButton( tr( "Style" ), this );
136  QMenu *menuStyle = new QMenu( this );
137  mActionLoadStyle = new QAction( tr( "Load Style…" ), this );
138  connect( mActionLoadStyle, &QAction::triggered, this, &QgsVectorLayerProperties::loadStyle );
139 
140  mActionSaveStyle = new QAction( tr( "Save Current Style…" ), this );
141  connect( mActionSaveStyle, &QAction::triggered, this, &QgsVectorLayerProperties::saveStyleAs );
142 
143  mActionSaveMultipleStyles = new QAction( tr( "Save Multiple Styles…" ), this );
144  connect( mActionSaveMultipleStyles, &QAction::triggered, this, &QgsVectorLayerProperties::saveMultipleStylesAs );
145 
146  mSourceGroupBox->hide();
147 
148  mBtnStyle->setMenu( menuStyle );
149  connect( menuStyle, &QMenu::aboutToShow, this, &QgsVectorLayerProperties::aboutToShowStyleMenu );
150  buttonBox->addButton( mBtnStyle, QDialogButtonBox::ResetRole );
151 
152  mBtnMetadata = new QPushButton( tr( "Metadata" ), this );
153  QMenu *menuMetadata = new QMenu( this );
154  mActionLoadMetadata = menuMetadata->addAction( tr( "Load Metadata…" ), this, &QgsVectorLayerProperties::loadMetadata );
155  mActionSaveMetadataAs = menuMetadata->addAction( tr( "Save Metadata…" ), this, &QgsVectorLayerProperties::saveMetadataAs );
156  menuMetadata->addSeparator();
157  menuMetadata->addAction( tr( "Save as Default" ), this, &QgsVectorLayerProperties::saveDefaultMetadata );
158  menuMetadata->addAction( tr( "Restore Default" ), this, &QgsVectorLayerProperties::loadDefaultMetadata );
159  mBtnMetadata->setMenu( menuMetadata );
160  buttonBox->addButton( mBtnMetadata, QDialogButtonBox::ResetRole );
161 
162  connect( lyr->styleManager(), &QgsMapLayerStyleManager::currentStyleChanged, this, &QgsVectorLayerProperties::syncToLayer );
163 
164  connect( buttonBox->button( QDialogButtonBox::Apply ), &QAbstractButton::clicked, this, &QgsVectorLayerProperties::apply );
165  connect( this, &QDialog::accepted, this, &QgsVectorLayerProperties::apply );
166  connect( this, &QDialog::rejected, this, &QgsVectorLayerProperties::onCancel );
167 
173 
174  mMapTipExpressionFieldWidget->setLayer( lyr );
175  mMapTipExpressionFieldWidget->registerExpressionContextGenerator( this );
176  mDisplayExpressionWidget->setLayer( lyr );
177  mDisplayExpressionWidget->registerExpressionContextGenerator( this );
178 
179  connect( mInsertExpressionButton, &QAbstractButton::clicked, this, &QgsVectorLayerProperties::insertFieldOrExpression );
180 
181  if ( !mLayer )
182  return;
183 
184  QVBoxLayout *layout = nullptr;
185 
186  if ( mLayer->isSpatial() )
187  {
188  // Create the Labeling dialog tab
189  layout = new QVBoxLayout( labelingFrame );
190  layout->setContentsMargins( 0, 0, 0, 0 );
191  labelingDialog = new QgsLabelingWidget( mLayer, mCanvas, labelingFrame );
192  labelingDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
193  connect( labelingDialog, &QgsLabelingWidget::auxiliaryFieldCreated, this, [ = ] { updateAuxiliaryStoragePage(); } );
194  layout->addWidget( labelingDialog );
195  labelingFrame->setLayout( layout );
196 
197  // Create the masking dialog tab
198  layout = new QVBoxLayout( mMaskingFrame );
199  layout->setContentsMargins( 0, 0, 0, 0 );
200  mMaskingWidget = new QgsMaskingWidget( mMaskingFrame );
201  mMaskingWidget->setLayer( mLayer );
202  mMaskingWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
203  layout->addWidget( mMaskingWidget );
204  mMaskingFrame->setLayout( layout );
205  }
206  else
207  {
208  labelingDialog = nullptr;
209  mOptsPage_Labels->setEnabled( false ); // disable labeling item
210  mOptsPage_Masks->setEnabled( false ); // disable masking item
211  mGeomGroupBox->setEnabled( false );
212  mGeomGroupBox->setVisible( false );
213  mCrsGroupBox->setEnabled( false );
214  mCrsGroupBox->setVisible( false );
215  }
216 
217  // Create the Actions dialog tab
218  QVBoxLayout *actionLayout = new QVBoxLayout( actionOptionsFrame );
219  actionLayout->setContentsMargins( 0, 0, 0, 0 );
220  mActionDialog = new QgsAttributeActionDialog( *mLayer->actions(), actionOptionsFrame );
221  mActionDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
222  actionLayout->addWidget( mActionDialog );
223 
224  mSourceFieldsPropertiesDialog = new QgsSourceFieldsProperties( mLayer, mSourceFieldsFrame );
225  mSourceFieldsPropertiesDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
226  mSourceFieldsFrame->setLayout( new QVBoxLayout( mSourceFieldsFrame ) );
227  mSourceFieldsFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
228  mSourceFieldsFrame->layout()->addWidget( mSourceFieldsPropertiesDialog );
229 
230  connect( mSourceFieldsPropertiesDialog, &QgsSourceFieldsProperties::toggleEditing, this, static_cast<void ( QgsVectorLayerProperties::* )()>( &QgsVectorLayerProperties::toggleEditing ) );
231 
232  mAttributesFormPropertiesDialog = new QgsAttributesFormProperties( mLayer, mAttributesFormFrame );
233  mAttributesFormPropertiesDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
234  mAttributesFormFrame->setLayout( new QVBoxLayout( mAttributesFormFrame ) );
235  mAttributesFormFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
236  mAttributesFormFrame->layout()->addWidget( mAttributesFormPropertiesDialog );
237 
238  // Metadata tab, before the syncToLayer
239  QVBoxLayout *metadataLayout = new QVBoxLayout( metadataFrame );
240  metadataLayout->setContentsMargins( 0, 0, 0, 0 );
241  mMetadataWidget = new QgsMetadataWidget( this, mLayer );
242  mMetadataWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
243  mMetadataWidget->setMapCanvas( mCanvas );
244  metadataLayout->addWidget( mMetadataWidget );
245  metadataFrame->setLayout( metadataLayout );
246 
247  QVBoxLayout *temporalLayout = new QVBoxLayout( temporalFrame );
248  temporalLayout->setContentsMargins( 0, 0, 0, 0 );
249  mTemporalWidget = new QgsVectorLayerTemporalPropertiesWidget( this, mLayer );
250  temporalLayout->addWidget( mTemporalWidget );
251 
252  syncToLayer();
253 
254  if ( mLayer->dataProvider() )
255  {
256  //enable spatial index button group if supported by provider, or if one already exists
257  QgsVectorDataProvider::Capabilities capabilities = mLayer->dataProvider()->capabilities();
258  if ( !( capabilities & QgsVectorDataProvider::CreateSpatialIndex ) )
259  {
260  pbnIndex->setEnabled( false );
261  }
263  {
264  pbnIndex->setEnabled( false );
265  pbnIndex->setText( tr( "Spatial Index Exists" ) );
266  }
267 
268  if ( capabilities & QgsVectorDataProvider::SelectEncoding )
269  {
270  cboProviderEncoding->addItems( QgsVectorDataProvider::availableEncodings() );
271  QString enc = mLayer->dataProvider()->encoding();
272  int encindex = cboProviderEncoding->findText( enc );
273  if ( encindex < 0 )
274  {
275  cboProviderEncoding->insertItem( 0, enc );
276  encindex = 0;
277  }
278  cboProviderEncoding->setCurrentIndex( encindex );
279  }
280  else if ( mLayer->providerType() == QLatin1String( "ogr" ) )
281  {
282  // if OGR_L_TestCapability(OLCStringsAsUTF8) returns true, OGR provider encoding can be set to only UTF-8
283  // so make encoding box grayed out
284  cboProviderEncoding->addItem( mLayer->dataProvider()->encoding() );
285  cboProviderEncoding->setEnabled( false );
286  }
287  else
288  {
289  // other providers do not use mEncoding, so hide the group completely
290  mDataSourceEncodingFrame->hide();
291  }
292  }
293 
294  mCrsSelector->setCrs( mLayer->crs() );
295 
296  //insert existing join info
297  const QList< QgsVectorLayerJoinInfo > &joins = mLayer->vectorJoins();
298  for ( const QgsVectorLayerJoinInfo &join : joins )
299  {
300  addJoinToTreeWidget( join );
301  }
302 
303  mOldJoins = mLayer->vectorJoins();
304 
305  QVBoxLayout *diagLayout = new QVBoxLayout( mDiagramFrame );
306  diagLayout->setContentsMargins( 0, 0, 0, 0 );
307  diagramPropertiesDialog = new QgsDiagramProperties( mLayer, mDiagramFrame, mCanvas );
308  diagramPropertiesDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
309  connect( diagramPropertiesDialog, &QgsDiagramProperties::auxiliaryFieldCreated, this, [ = ] { updateAuxiliaryStoragePage(); } );
310  diagLayout->addWidget( diagramPropertiesDialog );
311  mDiagramFrame->setLayout( diagLayout );
312 
313  // Legend tab
314  mLegendWidget->setMapCanvas( mCanvas );
315  mLegendWidget->setLayer( mLayer );
316  mLegendConfigEmbeddedWidget->setLayer( mLayer );
317 
318  // WMS Name as layer short name
319  mLayerShortNameLineEdit->setText( mLayer->shortName() );
320  // WMS Name validator
321  QValidator *shortNameValidator = new QRegularExpressionValidator( QgsApplication::shortNameRegularExpression(), this );
322  mLayerShortNameLineEdit->setValidator( shortNameValidator );
323 
324  //layer title and abstract
325  mLayerTitleLineEdit->setText( mLayer->title() );
326  mLayerAbstractTextEdit->setPlainText( mLayer->abstract() );
327  mLayerKeywordListLineEdit->setText( mLayer->keywordList() );
328  mLayerDataUrlLineEdit->setText( mLayer->dataUrl() );
329  mLayerDataUrlFormatComboBox->setCurrentIndex(
330  mLayerDataUrlFormatComboBox->findText(
331  mLayer->dataUrlFormat()
332  )
333  );
334  //layer attribution
335  mLayerAttributionLineEdit->setText( mLayer->attribution() );
336  mLayerAttributionUrlLineEdit->setText( mLayer->attributionUrl() );
337 
338  // Setup the layer metadata URL
339  tableViewMetadataUrl->setSelectionMode( QAbstractItemView::SingleSelection );
340  tableViewMetadataUrl->setSelectionBehavior( QAbstractItemView::SelectRows );
341  tableViewMetadataUrl->horizontalHeader()->setStretchLastSection( true );
342  tableViewMetadataUrl->horizontalHeader()->setSectionResizeMode( QHeaderView::Stretch );
343 
344  mMetadataUrlModel = new QStandardItemModel( tableViewMetadataUrl );
345  mMetadataUrlModel->clear();
346  mMetadataUrlModel->setColumnCount( 3 );
347  QStringList metadataUrlHeaders;
348  metadataUrlHeaders << tr( "URL" ) << tr( "Type" ) << tr( "Format" );
349  mMetadataUrlModel->setHorizontalHeaderLabels( metadataUrlHeaders );
350  tableViewMetadataUrl->setModel( mMetadataUrlModel );
351  tableViewMetadataUrl->setItemDelegate( new MetadataUrlItemDelegate( this ) );
352 
353  const QList<QgsMapLayerServerProperties::MetadataUrl> &metaUrls = mLayer->serverProperties()->metadataUrls();
354  for ( const QgsMapLayerServerProperties::MetadataUrl &metaUrl : metaUrls )
355  {
356  const int row = mMetadataUrlModel->rowCount();
357  mMetadataUrlModel->setItem( row, 0, new QStandardItem( metaUrl.url ) );
358  mMetadataUrlModel->setItem( row, 1, new QStandardItem( metaUrl.type ) );
359  mMetadataUrlModel->setItem( row, 2, new QStandardItem( metaUrl.format ) );
360  }
361 
362  // layer legend url
363  mLayerLegendUrlLineEdit->setText( mLayer->legendUrl() );
364  mLayerLegendUrlFormatComboBox->setCurrentIndex(
365  mLayerLegendUrlFormatComboBox->findText(
366  mLayer->legendUrlFormat()
367  )
368  );
369 
370  //insert existing dimension info
371  QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
372  const QList<QgsMapLayerServerProperties::WmsDimensionInfo> &wmsDims = serverProperties->wmsDimensions();
373  for ( const QgsMapLayerServerProperties::WmsDimensionInfo &dim : wmsDims )
374  {
375  addWmsDimensionInfoToTreeWidget( dim );
376  }
377 
378  QString myStyle = QgsApplication::reportStyleSheet();
379  myStyle.append( QStringLiteral( "body { margin: 10px; }\n " ) );
380  teMetadataViewer->clear();
381  teMetadataViewer->document()->setDefaultStyleSheet( myStyle );
382  teMetadataViewer->setHtml( htmlMetadata() );
383  teMetadataViewer->setOpenLinks( false );
384  connect( teMetadataViewer, &QTextBrowser::anchorClicked, this, &QgsVectorLayerProperties::urlClicked );
385  mMetadataFilled = true;
386 
387  QgsSettings settings;
388  // if dialog hasn't been opened/closed yet, default to Styles tab, which is used most often
389  // this will be read by restoreOptionsBaseUi()
390  if ( !settings.contains( QStringLiteral( "/Windows/VectorLayerProperties/tab" ) ) )
391  {
392  settings.setValue( QStringLiteral( "Windows/VectorLayerProperties/tab" ),
393  mOptStackedWidget->indexOf( mOptsPage_Style ) );
394  }
395 
396  QString title = tr( "Layer Properties — %1" ).arg( mLayer->name() );
397  if ( !mLayer->styleManager()->isDefault( mLayer->styleManager()->currentStyle() ) )
398  title += QStringLiteral( " (%1)" ).arg( mLayer->styleManager()->currentStyle() );
399  restoreOptionsBaseUi( title );
400 
401  QList<QgsMapLayer *> dependencySources;
402  const QSet<QgsMapLayerDependency> constDependencies = mLayer->dependencies();
403  for ( const QgsMapLayerDependency &dep : constDependencies )
404  {
405  QgsMapLayer *layer = QgsProject::instance()->mapLayer( dep.layerId() );
406  if ( layer )
407  dependencySources << layer;
408  }
409 
410  mLayersDependenciesTreeModel = new QgsLayerTreeFilterProxyModel( this );
411  mLayersDependenciesTreeModel->setLayerTreeModel( new QgsLayerTreeModel( QgsProject::instance()->layerTreeRoot(), mLayersDependenciesTreeModel ) );
412  mLayersDependenciesTreeModel->setCheckedLayers( dependencySources );
413  connect( QgsProject::instance(), &QObject::destroyed, this, [ = ] {mLayersDependenciesTreeView->setModel( nullptr );} );
414  mLayersDependenciesTreeView->setModel( mLayersDependenciesTreeModel );
415 
416  connect( mRefreshLayerCheckBox, &QCheckBox::toggled, mRefreshLayerIntervalSpinBox, &QDoubleSpinBox::setEnabled );
417 
418  // auxiliary layer
419  QMenu *menu = new QMenu( this );
420 
421  mAuxiliaryLayerActionNew = new QAction( tr( "Create" ), this );
422  menu->addAction( mAuxiliaryLayerActionNew );
423  connect( mAuxiliaryLayerActionNew, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerNew );
424 
425  mAuxiliaryLayerActionClear = new QAction( tr( "Clear" ), this );
426  menu->addAction( mAuxiliaryLayerActionClear );
427  connect( mAuxiliaryLayerActionClear, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerClear );
428 
429  mAuxiliaryLayerActionDelete = new QAction( tr( "Delete" ), this );
430  menu->addAction( mAuxiliaryLayerActionDelete );
431  connect( mAuxiliaryLayerActionDelete, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerDelete );
432 
433  mAuxiliaryLayerActionExport = new QAction( tr( "Export" ), this );
434  menu->addAction( mAuxiliaryLayerActionExport );
435  connect( mAuxiliaryLayerActionExport, &QAction::triggered, this, [ = ] { emit exportAuxiliaryLayer( mLayer->auxiliaryLayer() ); } );
436 
437  mAuxiliaryStorageActions->setMenu( menu );
438 
439  connect( mAuxiliaryStorageFieldsDeleteBtn, &QPushButton::clicked, this, &QgsVectorLayerProperties::onAuxiliaryLayerDeleteField );
440  connect( mAuxiliaryStorageFieldsAddBtn, &QPushButton::clicked, this, &QgsVectorLayerProperties::onAuxiliaryLayerAddField );
441 
442  updateAuxiliaryStoragePage();
443 
444  mOptsPage_Information->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#information-properties" ) );
445  mOptsPage_Source->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#source-properties" ) );
446  mOptsPage_Style->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#symbology-properties" ) );
447  mOptsPage_Labels->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#labels-properties" ) );
448  mOptsPage_Masks->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#masks-properties" ) );
449  mOptsPage_Diagrams->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#diagrams-properties" ) );
450  mOptsPage_SourceFields->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#fields-properties" ) );
451  mOptsPage_AttributesForm->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#attributes-form-properties" ) );
452  mOptsPage_Joins->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#joins-properties" ) );
453  mOptsPage_AuxiliaryStorage->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#auxiliary-storage-properties" ) );
454  mOptsPage_Actions->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#actions-properties" ) );
455  mOptsPage_Display->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#display-properties" ) );
456  mOptsPage_Rendering->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#rendering-properties" ) );
457  mOptsPage_Variables->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#variables-properties" ) );
458  mOptsPage_Metadata->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#metadata-properties" ) );
459  mOptsPage_DataDependencies->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#dependencies-properties" ) ) ;
460  mOptsPage_Legend->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#legend-properties" ) );
461  mOptsPage_Server->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#qgis-server-properties" ) );
462 
463 
465 }
466 
467 void QgsVectorLayerProperties::toggleEditing()
468 {
469  if ( !mLayer )
470  return;
471 
472  emit toggleEditing( mLayer );
473 
474  setPbnQueryBuilderEnabled();
475 }
476 
478 {
479  if ( !factory->supportsLayer( mLayer ) || !factory->supportLayerPropertiesDialog() )
480  {
481  return;
482  }
483 
484  QgsMapLayerConfigWidget *page = factory->createWidget( mLayer, nullptr, false, this );
485 
486  if ( page )
487  {
488  mLayerPropertiesPages << page;
489 
490  const QString beforePage = factory->layerPropertiesPagePositionHint();
491  if ( beforePage.isEmpty() )
492  addPage( factory->title(), factory->title(), factory->icon(), page );
493  else
494  insertPage( factory->title(), factory->title(), factory->icon(), page, beforePage );
495  }
496 }
497 
498 void QgsVectorLayerProperties::insertFieldOrExpression()
499 {
500  // Convert the selected field to an expression and
501  // insert it into the action at the cursor position
502  QString expression = QStringLiteral( "[% " );
503  expression += mMapTipExpressionFieldWidget->asExpression();
504  expression += QLatin1String( " %]" );
505 
506  mMapTipWidget->insertText( expression );
507 }
508 
509 void QgsVectorLayerProperties::addMetadataUrl()
510 {
511  const int row = mMetadataUrlModel->rowCount();
512  mMetadataUrlModel->setItem( row, 0, new QStandardItem( QLatin1String() ) );
513  mMetadataUrlModel->setItem( row, 1, new QStandardItem( QLatin1String() ) );
514  mMetadataUrlModel->setItem( row, 2, new QStandardItem( QLatin1String() ) );
515 }
516 
517 void QgsVectorLayerProperties::removeSelectedMetadataUrl()
518 {
519  const QModelIndexList selectedRows = tableViewMetadataUrl->selectionModel()->selectedRows();
520  if ( selectedRows.empty() )
521  return;
522  mMetadataUrlModel->removeRow( selectedRows[0].row() );
523 }
524 
525 // in raster props, this method is called sync()
526 void QgsVectorLayerProperties::syncToLayer()
527 {
528  if ( !mSourceWidget )
529  {
530  mSourceWidget = QgsGui::sourceWidgetProviderRegistry()->createWidget( mLayer );
531  if ( mSourceWidget )
532  {
533  QHBoxLayout *layout = new QHBoxLayout();
534  layout->addWidget( mSourceWidget );
535  mSourceGroupBox->setLayout( layout );
536  mSourceGroupBox->show();
537 
538  connect( mSourceWidget, &QgsProviderSourceWidget::validChanged, this, [ = ]( bool isValid )
539  {
540  buttonBox->button( QDialogButtonBox::Apply )->setEnabled( isValid );
541  buttonBox->button( QDialogButtonBox::Ok )->setEnabled( isValid );
542  } );
543  }
544  }
545 
546  if ( mSourceWidget )
547  mSourceWidget->setSourceUri( mLayer->source() );
548 
549  // populate the general information
550  mLayerOrigNameLineEdit->setText( mLayer->name() );
551  mBackupCrs = mLayer->crs();
552  //see if we are dealing with a pg layer here
553  mSubsetGroupBox->setEnabled( true );
554  txtSubsetSQL->setText( mLayer->subsetString() );
555  // if the user is allowed to type an adhoc query, the app will crash if the query
556  // is bad. For this reason, the sql box is disabled and the query must be built
557  // using the query builder, either by typing it in by hand or using the buttons, etc
558  // on the builder. If the ability to enter a query directly into the box is required,
559  // a mechanism to check it must be implemented.
560  txtSubsetSQL->setReadOnly( true );
561  txtSubsetSQL->setCaretWidth( 0 );
562  txtSubsetSQL->setCaretLineVisible( false );
563  setPbnQueryBuilderEnabled();
564 
565  mMapTipWidget->setText( mLayer->mapTipTemplate() );
566  mDisplayExpressionWidget->setField( mLayer->displayExpression() );
567 
568  // set up the scale based layer visibility stuff....
569  mScaleRangeWidget->setScaleRange( mLayer->minimumScale(), mLayer->maximumScale() );
570  mScaleVisibilityGroupBox->setChecked( mLayer->hasScaleBasedVisibility() );
571  mScaleRangeWidget->setMapCanvas( mCanvas );
572 
573  mUseReferenceScaleGroupBox->setChecked( mLayer->renderer() && mLayer->renderer()->referenceScale() > 0 );
574  mReferenceScaleWidget->setShowCurrentScaleButton( true );
575  mReferenceScaleWidget->setMapCanvas( mCanvas );
576  if ( mUseReferenceScaleGroupBox->isChecked() )
577  mReferenceScaleWidget->setScale( mLayer->renderer()->referenceScale() );
578  else if ( mCanvas )
579  mReferenceScaleWidget->setScale( mCanvas->scale() );
580 
581  // get simplify drawing configuration
582  const QgsVectorSimplifyMethod &simplifyMethod = mLayer->simplifyMethod();
583  mSimplifyDrawingGroupBox->setChecked( simplifyMethod.simplifyHints() != QgsVectorSimplifyMethod::NoSimplification );
584  mSimplifyDrawingSpinBox->setValue( simplifyMethod.threshold() );
585  mSimplifyDrawingSpinBox->setClearValue( 1.0 );
586 
587  QString remark = QStringLiteral( " (%1)" ).arg( tr( "Not supported" ) );
588  const QgsVectorDataProvider *provider = mLayer->dataProvider();
589  if ( !( provider && ( provider->capabilities() & QgsVectorDataProvider::SimplifyGeometries ) ) )
590  {
591  mSimplifyDrawingAtProvider->setChecked( false );
592  mSimplifyDrawingAtProvider->setEnabled( false );
593  if ( !mSimplifyDrawingAtProvider->text().endsWith( remark ) )
594  mSimplifyDrawingAtProvider->setText( mSimplifyDrawingAtProvider->text().append( remark ) );
595  }
596  else
597  {
598  mSimplifyDrawingAtProvider->setChecked( !simplifyMethod.forceLocalOptimization() );
599  mSimplifyDrawingAtProvider->setEnabled( mSimplifyDrawingGroupBox->isChecked() );
600  if ( mSimplifyDrawingAtProvider->text().endsWith( remark ) )
601  {
602  QString newText = mSimplifyDrawingAtProvider->text();
603  newText.chop( remark.size() );
604  mSimplifyDrawingAtProvider->setText( newText );
605  }
606  }
607 
608  // disable simplification for point layers, now it is not implemented
609  if ( mLayer->geometryType() == QgsWkbTypes::PointGeometry )
610  {
611  mSimplifyDrawingGroupBox->setChecked( false );
612  mSimplifyDrawingGroupBox->setEnabled( false );
613  }
614 
615  // Default local simplification algorithm
616  mSimplifyAlgorithmComboBox->addItem( tr( "Distance" ), QgsVectorSimplifyMethod::Distance );
617  mSimplifyAlgorithmComboBox->addItem( tr( "SnapToGrid" ), QgsVectorSimplifyMethod::SnapToGrid );
618  mSimplifyAlgorithmComboBox->addItem( tr( "Visvalingam" ), QgsVectorSimplifyMethod::Visvalingam );
619  mSimplifyAlgorithmComboBox->setCurrentIndex( mSimplifyAlgorithmComboBox->findData( simplifyMethod.simplifyAlgorithm() ) );
620 
621  QStringList myScalesList = Qgis::defaultProjectScales().split( ',' );
622  myScalesList.append( QStringLiteral( "1:1" ) );
623  mSimplifyMaximumScaleComboBox->updateScales( myScalesList );
624  mSimplifyMaximumScaleComboBox->setScale( simplifyMethod.maximumScale() );
625 
626  mForceRasterCheckBox->setChecked( mLayer->renderer() && mLayer->renderer()->forceRasterRender() );
627 
628  mRefreshLayerCheckBox->setChecked( mLayer->hasAutoRefreshEnabled() );
629  mRefreshLayerIntervalSpinBox->setEnabled( mLayer->hasAutoRefreshEnabled() );
630  mRefreshLayerIntervalSpinBox->setValue( mLayer->autoRefreshInterval() / 1000.0 );
631 
632  mRefreshLayerNotificationCheckBox->setChecked( mLayer->isRefreshOnNotifyEnabled() );
633  mNotificationMessageCheckBox->setChecked( !mLayer->refreshOnNotifyMessage().isEmpty() );
634  mNotifyMessagValueLineEdit->setText( mLayer->refreshOnNotifyMessage() );
635 
636 
637  // load appropriate symbology page (V1 or V2)
638  updateSymbologyPage();
639 
640  mActionDialog->init( *mLayer->actions(), mLayer->attributeTableConfig() );
641 
642  if ( labelingDialog )
643  labelingDialog->adaptToLayer();
644 
645  mSourceFieldsPropertiesDialog->init();
646  mAttributesFormPropertiesDialog->init();
647 
648  // set initial state for variable editor
649  updateVariableEditor();
650 
651  if ( diagramPropertiesDialog )
652  diagramPropertiesDialog->syncToLayer();
653 
654  // sync all plugin dialogs
655  const auto constMLayerPropertiesPages = mLayerPropertiesPages;
656  for ( QgsMapLayerConfigWidget *page : constMLayerPropertiesPages )
657  {
658  page->syncToLayer( mLayer );
659  }
660 
661  mMetadataWidget->setMetadata( &mLayer->metadata() );
662 
663  mTemporalWidget->syncToLayer();
664 
665  mLegendWidget->setLayer( mLayer );
666 
667 }
668 
669 void QgsVectorLayerProperties::apply()
670 {
671  if ( mSourceWidget )
672  {
673  const QString newSource = mSourceWidget->sourceUri();
674  if ( newSource != mLayer->source() )
675  {
676  mLayer->setDataSource( newSource, mLayer->name(), mLayer->providerType(),
677  QgsDataProvider::ProviderOptions(), QgsDataProvider::ReadFlags() );
678  }
679  }
680 
681  if ( labelingDialog )
682  {
683  labelingDialog->writeSettingsToLayer();
684  }
685  mBackupCrs = mLayer->crs();
686  // apply legend settings
687  mLegendWidget->applyToLayer();
688  mLegendConfigEmbeddedWidget->applyToLayer();
689 
690  // save metadata
691  mMetadataWidget->acceptMetadata();
692  mMetadataFilled = false;
693 
694  // save masking settings
695  if ( mMaskingWidget && mMaskingWidget->hasBeenPopulated() )
696  mMaskingWidget->apply();
697 
698  //
699  // Set up sql subset query if applicable
700  //
701  mSubsetGroupBox->setEnabled( true );
702 
703  if ( txtSubsetSQL->text() != mLayer->subsetString() )
704  {
705  // set the subset sql for the layer
706  mLayer->setSubsetString( txtSubsetSQL->text() );
707  mMetadataFilled = false;
708  }
709  mOriginalSubsetSQL = mLayer->subsetString();
710 
711  // set up the scale based layer visibility stuff....
712  mLayer->setScaleBasedVisibility( mScaleVisibilityGroupBox->isChecked() );
713  mLayer->setMaximumScale( mScaleRangeWidget->maximumScale() );
714  mLayer->setMinimumScale( mScaleRangeWidget->minimumScale() );
715 
716  // provider-specific options
717  if ( mLayer->dataProvider() )
718  {
720  {
721  mLayer->setProviderEncoding( cboProviderEncoding->currentText() );
722  }
723  }
724 
725  mLayer->setDisplayExpression( mDisplayExpressionWidget->asExpression() );
726  mLayer->setMapTipTemplate( mMapTipWidget->text() );
727 
728  mLayer->actions()->clearActions();
729  const auto constActions = mActionDialog->actions();
730  for ( const QgsAction &action : constActions )
731  {
732  mLayer->actions()->addAction( action );
733  }
734  QgsAttributeTableConfig attributeTableConfig = mLayer->attributeTableConfig();
735  attributeTableConfig.update( mLayer->fields() );
736  attributeTableConfig.setActionWidgetStyle( mActionDialog->attributeTableWidgetStyle() );
737  QVector<QgsAttributeTableConfig::ColumnConfig> columns = attributeTableConfig.columns();
738 
739  for ( int i = 0; i < columns.size(); ++i )
740  {
741  if ( columns.at( i ).type == QgsAttributeTableConfig::Action )
742  {
743  columns[i].hidden = !mActionDialog->showWidgetInAttributeTable();
744  }
745  }
746 
747  attributeTableConfig.setColumns( columns );
748 
749  mLayer->setAttributeTableConfig( attributeTableConfig );
750 
751  mLayer->setName( mLayerOrigNameLineEdit->text() );
752 
753  mAttributesFormPropertiesDialog->apply();
754  mSourceFieldsPropertiesDialog->apply();
755 
756  // Update temporal properties
757  mTemporalWidget->saveTemporalProperties();
758 
759  if ( mLayer->renderer() )
760  {
761  QgsRendererPropertiesDialog *dlg = static_cast<QgsRendererPropertiesDialog *>( widgetStackRenderers->currentWidget() );
762  dlg->apply();
763  }
764 
765  //apply diagram settings
766  diagramPropertiesDialog->apply();
767 
768  // apply all plugin dialogs
769  const auto constMLayerPropertiesPages = mLayerPropertiesPages;
770  for ( QgsMapLayerConfigWidget *page : constMLayerPropertiesPages )
771  {
772  page->apply();
773  }
774 
775  //layer title and abstract
776  if ( mLayer->shortName() != mLayerShortNameLineEdit->text() )
777  mMetadataFilled = false;
778  mLayer->setShortName( mLayerShortNameLineEdit->text() );
779 
780  if ( mLayer->title() != mLayerTitleLineEdit->text() )
781  mMetadataFilled = false;
782  mLayer->setTitle( mLayerTitleLineEdit->text() );
783 
784  if ( mLayer->abstract() != mLayerAbstractTextEdit->toPlainText() )
785  mMetadataFilled = false;
786  mLayer->setAbstract( mLayerAbstractTextEdit->toPlainText() );
787 
788  if ( mLayer->keywordList() != mLayerKeywordListLineEdit->text() )
789  mMetadataFilled = false;
790  mLayer->setKeywordList( mLayerKeywordListLineEdit->text() );
791 
792  if ( mLayer->dataUrl() != mLayerDataUrlLineEdit->text() )
793  mMetadataFilled = false;
794  mLayer->setDataUrl( mLayerDataUrlLineEdit->text() );
795 
796  if ( mLayer->dataUrlFormat() != mLayerDataUrlFormatComboBox->currentText() )
797  mMetadataFilled = false;
798  mLayer->setDataUrlFormat( mLayerDataUrlFormatComboBox->currentText() );
799 
800  //layer attribution
801  if ( mLayer->attribution() != mLayerAttributionLineEdit->text() )
802  mMetadataFilled = false;
803  mLayer->setAttribution( mLayerAttributionLineEdit->text() );
804 
805  if ( mLayer->attributionUrl() != mLayerAttributionUrlLineEdit->text() )
806  mMetadataFilled = false;
807  mLayer->setAttributionUrl( mLayerAttributionUrlLineEdit->text() );
808 
809  // Metadata URL
810  QList<QgsMapLayerServerProperties::MetadataUrl> metaUrls;
811  for ( int row = 0; row < mMetadataUrlModel->rowCount() ; row++ )
812  {
814  metaUrl.url = mMetadataUrlModel->item( row, 0 )->text();
815  metaUrl.type = mMetadataUrlModel->item( row, 1 )->text();
816  metaUrl.format = mMetadataUrlModel->item( row, 2 )->text();
817  metaUrls.append( metaUrl );
818  mMetadataFilled = false;
819  }
820  mLayer->serverProperties()->setMetadataUrls( metaUrls );
821 
822  // LegendURL
823  if ( mLayer->legendUrl() != mLayerLegendUrlLineEdit->text() )
824  mMetadataFilled = false;
825  mLayer->setLegendUrl( mLayerLegendUrlLineEdit->text() );
826 
827  if ( mLayer->legendUrlFormat() != mLayerLegendUrlFormatComboBox->currentText() )
828  mMetadataFilled = false;
829  mLayer->setLegendUrlFormat( mLayerLegendUrlFormatComboBox->currentText() );
830 
831  //layer simplify drawing configuration
832  QgsVectorSimplifyMethod::SimplifyHints simplifyHints = QgsVectorSimplifyMethod::NoSimplification;
833  if ( mSimplifyDrawingGroupBox->isChecked() )
834  {
836  if ( mSimplifyDrawingSpinBox->value() > 1 ) simplifyHints |= QgsVectorSimplifyMethod::AntialiasingSimplification;
837  }
838  QgsVectorSimplifyMethod simplifyMethod = mLayer->simplifyMethod();
839  simplifyMethod.setSimplifyHints( simplifyHints );
840  simplifyMethod.setSimplifyAlgorithm( static_cast< QgsVectorSimplifyMethod::SimplifyAlgorithm >( mSimplifyAlgorithmComboBox->currentData().toInt() ) );
841  simplifyMethod.setThreshold( mSimplifyDrawingSpinBox->value() );
842  simplifyMethod.setForceLocalOptimization( !mSimplifyDrawingAtProvider->isChecked() );
843  simplifyMethod.setMaximumScale( mSimplifyMaximumScaleComboBox->scale() );
844  mLayer->setSimplifyMethod( simplifyMethod );
845 
846  if ( mLayer->renderer() )
847  {
848  mLayer->renderer()->setForceRasterRender( mForceRasterCheckBox->isChecked() );
849  mLayer->renderer()->setReferenceScale( mUseReferenceScaleGroupBox->isChecked() ? mReferenceScaleWidget->scale() : -1 );
850  }
851 
852  mLayer->setAutoRefreshInterval( mRefreshLayerIntervalSpinBox->value() * 1000.0 );
853  mLayer->setAutoRefreshEnabled( mRefreshLayerCheckBox->isChecked() );
854 
855  mLayer->setRefreshOnNotifyEnabled( mRefreshLayerNotificationCheckBox->isChecked() );
856  mLayer->setRefreshOnNofifyMessage( mNotificationMessageCheckBox->isChecked() ? mNotifyMessagValueLineEdit->text() : QString() );
857 
858  mOldJoins = mLayer->vectorJoins();
859 
860  //save variables
861  QgsExpressionContextUtils::setLayerVariables( mLayer, mVariableEditor->variablesInActiveScope() );
862  updateVariableEditor();
863 
864  // save dependencies
865  QSet<QgsMapLayerDependency> deps;
866  const auto checkedLayers = mLayersDependenciesTreeModel->checkedLayers();
867  for ( const QgsMapLayer *layer : checkedLayers )
868  deps << QgsMapLayerDependency( layer->id() );
869  if ( ! mLayer->setDependencies( deps ) )
870  {
871  QMessageBox::warning( nullptr, tr( "Save Dependency" ), tr( "This configuration introduces a cycle in data dependencies and will be ignored." ) );
872  }
873 
874  mLayer->triggerRepaint();
875  // notify the project we've made a change
876  QgsProject::instance()->setDirty( true );
877 }
878 
879 void QgsVectorLayerProperties::onCancel()
880 {
881  if ( mOldJoins != mLayer->vectorJoins() )
882  {
883  // need to undo changes in vector layer joins - they are applied directly to the layer (not in apply())
884  // so other parts of the properties dialog can use the fields from the joined layers
885 
886  const auto constVectorJoins = mLayer->vectorJoins();
887  for ( const QgsVectorLayerJoinInfo &info : constVectorJoins )
888  mLayer->removeJoin( info.joinLayerId() );
889 
890  for ( const QgsVectorLayerJoinInfo &info : std::as_const( mOldJoins ) )
891  mLayer->addJoin( info );
892  }
893 
894  if ( mOriginalSubsetSQL != mLayer->subsetString() )
895  {
896  // need to undo changes in subset string - they are applied directly to the layer (not in apply())
897  // by QgsQueryBuilder::accept()
898 
899  mLayer->setSubsetString( mOriginalSubsetSQL );
900  }
901 
902  if ( mOldStyle.xmlData() != mLayer->styleManager()->style( mLayer->styleManager()->currentStyle() ).xmlData() )
903  {
904  // need to reset style to previous - style applied directly to the layer (not in apply())
905  QString myMessage;
906  QDomDocument doc( QStringLiteral( "qgis" ) );
907  int errorLine, errorColumn;
908  doc.setContent( mOldStyle.xmlData(), false, &myMessage, &errorLine, &errorColumn );
909  mLayer->importNamedStyle( doc, myMessage );
910  }
911 
912  if ( mBackupCrs != mLayer->crs() )
913  mLayer->setCrs( mBackupCrs );
914 }
915 
916 void QgsVectorLayerProperties::urlClicked( const QUrl &url )
917 {
918  QFileInfo file( url.toLocalFile() );
919  if ( file.exists() && !file.isDir() )
920  QgsGui::nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
921  else
922  QDesktopServices::openUrl( url );
923 }
924 
925 void QgsVectorLayerProperties::pbnQueryBuilder_clicked()
926 {
927  // launch the query builder
929 
930  // Set the sql in the query builder to the same in the prop dialog
931  // (in case the user has already changed it)
932  dialog->setSubsetString( txtSubsetSQL->text() );
933  // Open the query builder
934  if ( dialog->exec() )
935  {
936  // if the sql is changed, update it in the prop subset text box
937  txtSubsetSQL->setText( dialog->subsetString() );
938  //TODO If the sql is changed in the prop dialog, the layer extent should be recalculated
939 
940  // The datasource for the layer needs to be updated with the new sql since this gets
941  // saved to the project file. This should happen at the map layer level...
942 
943  }
944  // delete the query builder object
945  delete dialog;
946 }
947 
948 void QgsVectorLayerProperties::pbnIndex_clicked()
949 {
950  QgsVectorDataProvider *pr = mLayer->dataProvider();
951  if ( pr )
952  {
953  setCursor( Qt::WaitCursor );
954  bool errval = pr->createSpatialIndex();
955  setCursor( Qt::ArrowCursor );
956  if ( errval )
957  {
958  pbnIndex->setEnabled( false );
959  pbnIndex->setText( tr( "Spatial Index Exists" ) );
960  QMessageBox::information( this, tr( "Spatial Index" ), tr( "Creation of spatial index successful" ) );
961  }
962  else
963  {
964  QMessageBox::warning( this, tr( "Spatial Index" ), tr( "Creation of spatial index failed" ) );
965  }
966  }
967 }
968 
969 QString QgsVectorLayerProperties::htmlMetadata()
970 {
971  return mLayer->htmlMetadata();
972 }
973 
974 void QgsVectorLayerProperties::mCrsSelector_crsChanged( const QgsCoordinateReferenceSystem &crs )
975 {
976 
977  QgsDatumTransformDialog::run( crs, QgsProject::instance()->crs(), this, mCanvas, tr( "Select Transformation for the vector layer" ) );
978  mLayer->setCrs( crs );
979  mMetadataFilled = false;
980  mMetadataWidget->crsChanged();
981 }
982 
983 void QgsVectorLayerProperties::loadDefaultStyle_clicked()
984 {
985  QString msg;
986  bool defaultLoadedFlag = false;
987 
988  const QgsVectorDataProvider *provider = mLayer->dataProvider();
989  if ( !provider )
990  return;
991  if ( provider->isSaveAndLoadStyleToDatabaseSupported() )
992  {
993  QMessageBox askToUser;
994  askToUser.setText( tr( "Load default style from: " ) );
995  askToUser.setIcon( QMessageBox::Question );
996  askToUser.addButton( tr( "Cancel" ), QMessageBox::RejectRole );
997  askToUser.addButton( tr( "Local Database" ), QMessageBox::NoRole );
998  askToUser.addButton( tr( "Datasource Database" ), QMessageBox::YesRole );
999 
1000  switch ( askToUser.exec() )
1001  {
1002  case 0:
1003  return;
1004  case 2:
1005  msg = mLayer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag );
1006  if ( !defaultLoadedFlag )
1007  {
1008  //something went wrong - let them know why
1009  QMessageBox::information( this, tr( "Default Style" ), msg );
1010  }
1011  if ( msg.compare( tr( "Loaded from Provider" ) ) )
1012  {
1013  QMessageBox::information( this, tr( "Default Style" ),
1014  tr( "No default style was found for this layer." ) );
1015  }
1016  else
1017  {
1018  syncToLayer();
1019  }
1020 
1021  return;
1022  default:
1023  break;
1024  }
1025  }
1026 
1027  QString myMessage = mLayer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag, true );
1028 // QString myMessage = layer->loadDefaultStyle( defaultLoadedFlag );
1029  //reset if the default style was loaded OK only
1030  if ( defaultLoadedFlag )
1031  {
1032  // all worked OK so no need to inform user
1033  syncToLayer();
1034  }
1035  else
1036  {
1037  //something went wrong - let them know why
1038  QMessageBox::information( this, tr( "Default Style" ), myMessage );
1039  }
1040 }
1041 
1042 void QgsVectorLayerProperties::saveDefaultStyle_clicked()
1043 {
1044  apply();
1045  QString errorMsg;
1046  const QgsVectorDataProvider *provider = mLayer->dataProvider();
1047  if ( !provider )
1048  return;
1049  if ( provider->isSaveAndLoadStyleToDatabaseSupported() )
1050  {
1051  QMessageBox askToUser;
1052  askToUser.setText( tr( "Save default style to: " ) );
1053  askToUser.setIcon( QMessageBox::Question );
1054  askToUser.addButton( tr( "Cancel" ), QMessageBox::RejectRole );
1055  askToUser.addButton( tr( "Local Database" ), QMessageBox::NoRole );
1056  askToUser.addButton( tr( "Datasource Database" ), QMessageBox::YesRole );
1057 
1058  switch ( askToUser.exec() )
1059  {
1060  case 0:
1061  return;
1062  case 2:
1063  {
1064  QString errorMessage;
1065  if ( QgsProviderRegistry::instance()->styleExists( mLayer->providerType(), mLayer->source(), QString(), errorMessage ) )
1066  {
1067  if ( QMessageBox::question( nullptr, QObject::tr( "Save style in database" ),
1068  QObject::tr( "A matching style already exists in the database for this layer. Do you want to overwrite it?" ),
1069  QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
1070  {
1071  return;
1072  }
1073  }
1074  else if ( !errorMessage.isEmpty() )
1075  {
1076  QMessageBox::warning( nullptr, QObject::tr( "Save style in database" ),
1077  errorMessage );
1078  return;
1079  }
1080 
1081  mLayer->saveStyleToDatabase( QString(), QString(), true, QString(), errorMsg );
1082  if ( errorMsg.isNull() )
1083  {
1084  return;
1085  }
1086  break;
1087  }
1088  default:
1089  break;
1090  }
1091  }
1092 
1093  bool defaultSavedFlag = false;
1094  // TODO Once the deprecated `saveDefaultStyle()` method is gone, just
1095  // remove the NOWARN_DEPRECATED tags
1097  errorMsg = mLayer->saveDefaultStyle( defaultSavedFlag );
1099  if ( !defaultSavedFlag )
1100  {
1101  QMessageBox::warning( this, tr( "Default Style" ), errorMsg );
1102  }
1103 }
1104 
1105 void QgsVectorLayerProperties::loadMetadata()
1106 {
1107  QgsSettings myQSettings; // where we keep last used filter in persistent state
1108  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
1109 
1110  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load Layer Metadata from Metadata File" ), myLastUsedDir,
1111  tr( "QGIS Layer Metadata File" ) + " (*.qmd)" );
1112  if ( myFileName.isNull() )
1113  {
1114  return;
1115  }
1116 
1117  QString myMessage;
1118  bool defaultLoadedFlag = false;
1119  myMessage = mLayer->loadNamedMetadata( myFileName, defaultLoadedFlag );
1120 
1121  //reset if the default style was loaded OK only
1122  if ( defaultLoadedFlag )
1123  {
1124  mMetadataWidget->setMetadata( &mLayer->metadata() );
1125  }
1126  else
1127  {
1128  //let the user know what went wrong
1129  QMessageBox::warning( this, tr( "Load Metadata" ), myMessage );
1130  }
1131 
1132  QFileInfo myFI( myFileName );
1133  QString myPath = myFI.path();
1134  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), myPath );
1135 
1136  activateWindow(); // set focus back to properties dialog
1137 }
1138 
1139 void QgsVectorLayerProperties::saveMetadataAs()
1140 {
1141  QgsSettings myQSettings; // where we keep last used filter in persistent state
1142  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
1143 
1144  QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save Layer Metadata as QMD" ),
1145  myLastUsedDir, tr( "QMD File" ) + " (*.qmd)" );
1146  if ( myOutputFileName.isNull() ) //dialog canceled
1147  {
1148  return;
1149  }
1150 
1151  mMetadataWidget->acceptMetadata();
1152 
1153  //ensure the user never omitted the extension from the file name
1154  if ( !myOutputFileName.endsWith( QgsMapLayer::extensionPropertyType( QgsMapLayer::Metadata ), Qt::CaseInsensitive ) )
1155  {
1157  }
1158 
1159  QString myMessage;
1160  bool defaultLoadedFlag = false;
1161  myMessage = mLayer->saveNamedMetadata( myOutputFileName, defaultLoadedFlag );
1162 
1163  //reset if the default style was loaded OK only
1164  if ( defaultLoadedFlag )
1165  {
1166  syncToLayer();
1167  }
1168  else
1169  {
1170  //let the user know what went wrong
1171  QMessageBox::information( this, tr( "Save Metadata" ), myMessage );
1172  }
1173 
1174  QFileInfo myFI( myOutputFileName );
1175  QString myPath = myFI.path();
1176  // Persist last used dir
1177  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), myPath );
1178 }
1179 
1180 void QgsVectorLayerProperties::saveDefaultMetadata()
1181 {
1182  mMetadataWidget->acceptMetadata();
1183 
1184  bool defaultSavedFlag = false;
1185  QString errorMsg = mLayer->saveDefaultMetadata( defaultSavedFlag );
1186  if ( !defaultSavedFlag )
1187  {
1188  QMessageBox::warning( this, tr( "Default Metadata" ), errorMsg );
1189  }
1190 }
1191 
1192 void QgsVectorLayerProperties::loadDefaultMetadata()
1193 {
1194  bool defaultLoadedFlag = false;
1195  QString myMessage = mLayer->loadNamedMetadata( mLayer->metadataUri(), defaultLoadedFlag );
1196  //reset if the default metadata was loaded OK only
1197  if ( defaultLoadedFlag )
1198  {
1199  mMetadataWidget->setMetadata( &mLayer->metadata() );
1200  }
1201  else
1202  {
1203  QMessageBox::information( this, tr( "Default Metadata" ), myMessage );
1204  }
1205 }
1206 
1207 
1208 void QgsVectorLayerProperties::saveStyleAs()
1209 {
1210  if ( !mLayer->dataProvider() )
1211  return;
1212  QgsVectorLayerSaveStyleDialog dlg( mLayer );
1213  QgsSettings settings;
1214 
1215  if ( dlg.exec() )
1216  {
1217  apply();
1218 
1219  bool defaultLoadedFlag = false;
1220  QString errorMessage;
1221 
1222  StyleType type = dlg.currentStyleType();
1223  switch ( type )
1224  {
1225  case QML:
1226  case SLD:
1227  {
1228  QString filePath = dlg.outputFilePath();
1229  if ( type == QML )
1230  errorMessage = mLayer->saveNamedStyle( filePath, defaultLoadedFlag, dlg.styleCategories() );
1231  else
1232  errorMessage = mLayer->saveSldStyle( filePath, defaultLoadedFlag );
1233 
1234  //reset if the default style was loaded OK only
1235  if ( defaultLoadedFlag )
1236  {
1237  syncToLayer();
1238  }
1239  else
1240  {
1241  //let the user know what went wrong
1242  QMessageBox::information( this, tr( "Save Style" ), errorMessage );
1243  }
1244 
1245  break;
1246  }
1247  case DB:
1248  {
1249  QString infoWindowTitle = QObject::tr( "Save style to DB (%1)" ).arg( mLayer->providerType() );
1250 
1251  QgsVectorLayerSaveStyleDialog::SaveToDbSettings dbSettings = dlg.saveToDbSettings();
1252 
1253  if ( QgsProviderRegistry::instance()->styleExists( mLayer->providerType(), mLayer->source(), dbSettings.name, errorMessage ) )
1254  {
1255  if ( QMessageBox::question( nullptr, QObject::tr( "Save style in database" ),
1256  QObject::tr( "A matching style already exists in the database for this layer. Do you want to overwrite it?" ),
1257  QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
1258  {
1259  return;
1260  }
1261  }
1262  else if ( !errorMessage.isEmpty() )
1263  {
1264  mMessageBar->pushMessage( infoWindowTitle, errorMessage, Qgis::MessageLevel::Warning );
1265  return;
1266  }
1267 
1268  mLayer->saveStyleToDatabase( dbSettings.name, dbSettings.description, dbSettings.isDefault, dbSettings.uiFileContent, errorMessage, dlg.styleCategories() );
1269 
1270  if ( !errorMessage.isNull() )
1271  {
1272  mMessageBar->pushMessage( infoWindowTitle, errorMessage, Qgis::MessageLevel::Warning );
1273  }
1274  else
1275  {
1276  mMessageBar->pushMessage( infoWindowTitle, tr( "Style saved" ), Qgis::MessageLevel::Success );
1277  }
1278  break;
1279  }
1280  case Local:
1281  {
1282  QString infoWindowTitle = tr( "Save default style to local database" );
1283  errorMessage = mLayer->saveDefaultStyle( defaultLoadedFlag, dlg.styleCategories() );
1284  if ( !defaultLoadedFlag )
1285  {
1286  mMessageBar->pushMessage( infoWindowTitle, errorMessage, Qgis::MessageLevel::Warning );
1287  }
1288  else
1289  {
1290  mMessageBar->pushMessage( infoWindowTitle, tr( "Style saved" ), Qgis::MessageLevel::Success );
1291  }
1292  break;
1293  }
1294  }
1295  }
1296 }
1297 
1298 void QgsVectorLayerProperties::saveMultipleStylesAs()
1299 {
1300  QgsVectorLayerSaveStyleDialog dlg( mLayer );
1301  dlg.setSaveOnlyCurrentStyle( false );
1302  QgsSettings settings;
1303 
1304  if ( dlg.exec() )
1305  {
1306  apply();
1307 
1308  // Store the original style, that we can restore at the end
1309  const QString originalStyle { mLayer->styleManager()->currentStyle() };
1310  const QListWidget *stylesWidget { dlg.stylesWidget() };
1311 
1312  // Collect selected (checked) styles for export/save
1313  QStringList stylesSelected;
1314  for ( int i = 0; i < stylesWidget->count(); i++ )
1315  {
1316  if ( stylesWidget->item( i )->checkState() == Qt::CheckState::Checked )
1317  {
1318  stylesSelected.push_back( stylesWidget->item( i )->text() );
1319  }
1320  }
1321 
1322  if ( ! stylesSelected.isEmpty() )
1323  {
1324  int styleIndex = 0;
1325  for ( const QString &styleName : std::as_const( stylesSelected ) )
1326  {
1327  bool defaultLoadedFlag = false;
1328 
1329  StyleType type = dlg.currentStyleType();
1330  mLayer->styleManager()->setCurrentStyle( styleName );
1331  switch ( type )
1332  {
1333  case QML:
1334  case SLD:
1335  {
1336  QString message;
1337  const QString filePath { dlg.outputFilePath() };
1338  QString safePath { filePath };
1339  if ( styleIndex > 0 && stylesSelected.count( ) > 1 )
1340  {
1341  int i = 1;
1342  while ( QFile::exists( safePath ) )
1343  {
1344  const QFileInfo fi { filePath };
1345  safePath = QString( filePath ).replace( '.' + fi.completeSuffix(), QStringLiteral( "_%1.%2" )
1346  .arg( QString::number( i ) )
1347  .arg( fi.completeSuffix() ) );
1348  i++;
1349  }
1350  }
1351  if ( type == QML )
1352  message = mLayer->saveNamedStyle( safePath, defaultLoadedFlag, dlg.styleCategories() );
1353  else
1354  message = mLayer->saveSldStyle( safePath, defaultLoadedFlag );
1355 
1356  //reset if the default style was loaded OK only
1357  if ( defaultLoadedFlag )
1358  {
1359  syncToLayer();
1360  }
1361  else
1362  {
1363  //let the user know what went wrong
1364  QMessageBox::information( this, tr( "Save Style" ), message );
1365  }
1366 
1367  break;
1368  }
1369  case DB:
1370  {
1371  QString infoWindowTitle = QObject::tr( "Save style '%1' to DB (%2)" )
1372  .arg( styleName )
1373  .arg( mLayer->providerType() );
1374  QString msgError;
1375 
1376  QgsVectorLayerSaveStyleDialog::SaveToDbSettings dbSettings = dlg.saveToDbSettings();
1377 
1378  // If a name is defined, we add _1 etc. else we use the style name
1379  QString name { dbSettings.name };
1380  if ( name.isEmpty() )
1381  {
1382  name = styleName;
1383  }
1384  else
1385  {
1386  QStringList ids, names, descriptions;
1387  mLayer->listStylesInDatabase( ids, names, descriptions, msgError );
1388  int i = 1;
1389  while ( names.contains( name ) )
1390  {
1391  name = QStringLiteral( "%1 %2" ).arg( name ).arg( QString::number( i ) );
1392  i++;
1393  }
1394  }
1395 
1396  QString errorMessage;
1397  if ( QgsProviderRegistry::instance()->styleExists( mLayer->providerType(), mLayer->source(), dbSettings.name, errorMessage ) )
1398  {
1399  if ( QMessageBox::question( nullptr, QObject::tr( "Save style in database" ),
1400  QObject::tr( "A matching style already exists in the database for this layer. Do you want to overwrite it?" ),
1401  QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
1402  {
1403  return;
1404  }
1405  }
1406  else if ( !errorMessage.isEmpty() )
1407  {
1408  mMessageBar->pushMessage( infoWindowTitle, errorMessage, Qgis::MessageLevel::Warning );
1409  return;
1410  }
1411 
1412  mLayer->saveStyleToDatabase( name, dbSettings.description, dbSettings.isDefault, dbSettings.uiFileContent, msgError, dlg.styleCategories() );
1413 
1414  if ( !msgError.isNull() )
1415  {
1416  mMessageBar->pushMessage( infoWindowTitle, msgError, Qgis::MessageLevel::Warning );
1417  }
1418  else
1419  {
1420  mMessageBar->pushMessage( infoWindowTitle, tr( "Style '%1' saved" ).arg( styleName ),
1421  Qgis::MessageLevel::Success );
1422  }
1423  break;
1424  }
1425  case Local:
1426  break;
1427  }
1428  styleIndex ++;
1429  }
1430  // Restore original style
1431  mLayer->styleManager()->setCurrentStyle( originalStyle );
1432  }
1433  } // Nothing selected!
1434 }
1435 
1436 void QgsVectorLayerProperties::aboutToShowStyleMenu()
1437 {
1438  // this should be unified with QgsRasterLayerProperties::aboutToShowStyleMenu()
1439  QMenu *m = qobject_cast<QMenu *>( sender() );
1440  m->clear();
1441 
1442  m->addAction( mActionLoadStyle );
1443  m->addAction( mActionSaveStyle );
1444 
1445  // If we have multiple styles, offer an option to save them at once
1446  if ( mLayer->styleManager()->styles().count() > 1 )
1447  {
1448  mActionSaveStyle->setText( tr( "Save Current Style…" ) );
1449  m->addAction( mActionSaveMultipleStyles );
1450  }
1451  else
1452  {
1453  mActionSaveStyle->setText( tr( "Save Style…" ) );
1454  }
1455 
1456  m->addSeparator();
1457  m->addAction( tr( "Save as Default" ), this, &QgsVectorLayerProperties::saveDefaultStyle_clicked );
1458  m->addAction( tr( "Restore Default" ), this, &QgsVectorLayerProperties::loadDefaultStyle_clicked );
1459 
1460  // re-add style manager actions!
1461  m->addSeparator();
1463 }
1464 
1465 void QgsVectorLayerProperties::loadStyle()
1466 {
1467  QgsSettings settings; // where we keep last used filter in persistent state
1468 
1469  QString errorMsg;
1470  QStringList ids, names, descriptions;
1471 
1472  //get the list of styles in the db
1473  int sectionLimit = mLayer->listStylesInDatabase( ids, names, descriptions, errorMsg );
1474  QgsMapLayerLoadStyleDialog dlg( mLayer, this );
1475  dlg.initializeLists( ids, names, descriptions, sectionLimit );
1476 
1477  if ( dlg.exec() )
1478  {
1479  mOldStyle = mLayer->styleManager()->style( mLayer->styleManager()->currentStyle() );
1480  QgsMapLayer::StyleCategories categories = dlg.styleCategories();
1481  StyleType type = dlg.currentStyleType();
1482  bool defaultLoadedFlag = false;
1483  switch ( type )
1484  {
1485  case QML:
1486  case SLD:
1487  {
1488  QString filePath = dlg.filePath();
1489  if ( type == SLD )
1490  {
1491  errorMsg = mLayer->loadSldStyle( filePath, defaultLoadedFlag );
1492  }
1493  else
1494  {
1495  errorMsg = mLayer->loadNamedStyle( filePath, defaultLoadedFlag, true, categories );
1496  }
1497  //reset if the default style was loaded OK only
1498  if ( defaultLoadedFlag )
1499  {
1500  syncToLayer();
1501  }
1502  else
1503  {
1504  //let the user know what went wrong
1505  QMessageBox::warning( this, tr( "Load Style" ), errorMsg );
1506  }
1507  break;
1508  }
1509  case DB:
1510  {
1511  QString selectedStyleId = dlg.selectedStyleId();
1512 
1513  QString qmlStyle = mLayer->getStyleFromDatabase( selectedStyleId, errorMsg );
1514  if ( !errorMsg.isNull() )
1515  {
1516  QMessageBox::warning( this, tr( "Load Styles from Database" ), errorMsg );
1517  return;
1518  }
1519 
1520  QDomDocument myDocument( QStringLiteral( "qgis" ) );
1521  myDocument.setContent( qmlStyle );
1522 
1523  if ( mLayer->importNamedStyle( myDocument, errorMsg, categories ) )
1524  {
1525  syncToLayer();
1526  }
1527  else
1528  {
1529  QMessageBox::warning( this, tr( "Load Styles from Database" ),
1530  tr( "The retrieved style is not a valid named style. Error message: %1" )
1531  .arg( errorMsg ) );
1532  }
1533  break;
1534  }
1535  case Local:
1536  {
1537  errorMsg = mLayer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag, true, categories );
1538  //reset if the default style was loaded OK only
1539  if ( defaultLoadedFlag )
1540  {
1541  syncToLayer();
1542  }
1543  else
1544  {
1545  QMessageBox::warning( this, tr( "Load Default Style" ), errorMsg );
1546  }
1547  break;
1548  }
1549  }
1550  activateWindow(); // set focus back to properties dialog
1551  }
1552 }
1553 
1554 void QgsVectorLayerProperties::mButtonAddJoin_clicked()
1555 {
1556  if ( !mLayer )
1557  return;
1558 
1559  QList<QgsMapLayer *> joinedLayers;
1560  const QList< QgsVectorLayerJoinInfo > &joins = mLayer->vectorJoins();
1561  joinedLayers.reserve( joins.size() );
1562  for ( int i = 0; i < joins.size(); ++i )
1563  {
1564  joinedLayers.append( joins[i].joinLayer() );
1565  }
1566 
1567  QgsJoinDialog d( mLayer, joinedLayers );
1568  if ( d.exec() == QDialog::Accepted )
1569  {
1570  QgsVectorLayerJoinInfo info = d.joinInfo();
1571  //create attribute index if possible
1572  if ( d.createAttributeIndex() )
1573  {
1574  QgsVectorLayer *joinLayer = info.joinLayer();
1575  if ( joinLayer )
1576  {
1577  joinLayer->dataProvider()->createAttributeIndex( joinLayer->fields().indexFromName( info.joinFieldName() ) );
1578  }
1579  }
1580  mLayer->addJoin( info );
1581  addJoinToTreeWidget( info );
1582  setPbnQueryBuilderEnabled();
1583  mSourceFieldsPropertiesDialog->init();
1584  mAttributesFormPropertiesDialog->init();
1585  }
1586 }
1587 
1588 void QgsVectorLayerProperties::mButtonEditJoin_clicked()
1589 {
1590  QTreeWidgetItem *currentJoinItem = mJoinTreeWidget->currentItem();
1591  mJoinTreeWidget_itemDoubleClicked( currentJoinItem, 0 );
1592 }
1593 
1594 void QgsVectorLayerProperties::mJoinTreeWidget_itemDoubleClicked( QTreeWidgetItem *item, int )
1595 {
1596  if ( !mLayer || !item )
1597  {
1598  return;
1599  }
1600 
1601  QList<QgsMapLayer *> joinedLayers;
1602  QString joinLayerId = item->data( 0, Qt::UserRole ).toString();
1603  const QList< QgsVectorLayerJoinInfo > &joins = mLayer->vectorJoins();
1604  int j = -1;
1605  for ( int i = 0; i < joins.size(); ++i )
1606  {
1607  QgsVectorLayer *joinLayer = joins[i].joinLayer();
1608  if ( !joinLayer )
1609  continue; // invalid join (unresolved join layer)
1610 
1611  if ( joinLayer->id() == joinLayerId )
1612  {
1613  j = i;
1614  }
1615  else
1616  {
1617  // remove already joined layers from possible list to be displayed in dialog
1618  joinedLayers.append( joinLayer );
1619  }
1620  }
1621  if ( j == -1 )
1622  {
1623  return;
1624  }
1625 
1626  QgsJoinDialog d( mLayer, joinedLayers );
1627  d.setWindowTitle( tr( "Edit Vector Join" ) );
1628  d.setJoinInfo( joins[j] );
1629 
1630  if ( d.exec() == QDialog::Accepted )
1631  {
1632  QgsVectorLayerJoinInfo info = d.joinInfo();
1633 
1634  // remove old join
1635  mLayer->removeJoin( joinLayerId );
1636  int idx = mJoinTreeWidget->indexOfTopLevelItem( item );
1637  mJoinTreeWidget->takeTopLevelItem( idx );
1638 
1639  // add the new edited
1640 
1641  //create attribute index if possible
1642  if ( d.createAttributeIndex() )
1643  {
1644  QgsVectorLayer *joinLayer = info.joinLayer();
1645  if ( joinLayer )
1646  {
1647  joinLayer->dataProvider()->createAttributeIndex( joinLayer->fields().indexFromName( info.joinFieldName() ) );
1648  }
1649  }
1650  mLayer->addJoin( info );
1651  addJoinToTreeWidget( info, idx );
1652 
1653  setPbnQueryBuilderEnabled();
1654  mSourceFieldsPropertiesDialog->init();
1655  mAttributesFormPropertiesDialog->init();
1656  }
1657 }
1658 
1659 void QgsVectorLayerProperties::addJoinToTreeWidget( const QgsVectorLayerJoinInfo &join, const int insertIndex )
1660 {
1661  QTreeWidgetItem *joinItem = new QTreeWidgetItem();
1662  joinItem->setFlags( Qt::ItemIsEnabled );
1663 
1664  QgsVectorLayer *joinLayer = join.joinLayer();
1665  if ( !mLayer || !joinLayer )
1666  {
1667  return;
1668  }
1669 
1670  joinItem->setText( 0, tr( "Join layer" ) );
1671  if ( mLayer->auxiliaryLayer() && mLayer->auxiliaryLayer()->id() == join.joinLayerId() )
1672  {
1673  return;
1674  }
1675 
1676  joinItem->setText( 1, joinLayer->name() );
1677 
1678  QFont f = joinItem->font( 0 );
1679  f.setBold( true );
1680  joinItem->setFont( 0, f );
1681  joinItem->setFont( 1, f );
1682 
1683  joinItem->setData( 0, Qt::UserRole, join.joinLayerId() );
1684 
1685  QTreeWidgetItem *childJoinField = new QTreeWidgetItem();
1686  childJoinField->setText( 0, tr( "Join field" ) );
1687  childJoinField->setText( 1, join.joinFieldName() );
1688  childJoinField->setFlags( Qt::ItemIsEnabled );
1689  joinItem->addChild( childJoinField );
1690 
1691  QTreeWidgetItem *childTargetField = new QTreeWidgetItem();
1692  childTargetField->setText( 0, tr( "Target field" ) );
1693  childTargetField->setText( 1, join.targetFieldName() );
1694  joinItem->addChild( childTargetField );
1695 
1696  QTreeWidgetItem *childMemCache = new QTreeWidgetItem();
1697  childMemCache->setText( 0, tr( "Cache join layer in virtual memory" ) );
1698  if ( join.isUsingMemoryCache() )
1699  childMemCache->setText( 1, QChar( 0x2714 ) );
1700  joinItem->addChild( childMemCache );
1701 
1702  QTreeWidgetItem *childDynForm = new QTreeWidgetItem();
1703  childDynForm->setText( 0, tr( "Dynamic form" ) );
1704  if ( join.isDynamicFormEnabled() )
1705  childDynForm->setText( 1, QChar( 0x2714 ) );
1706  joinItem->addChild( childDynForm );
1707 
1708  QTreeWidgetItem *childEditable = new QTreeWidgetItem();
1709  childEditable->setText( 0, tr( "Editable join layer" ) );
1710  if ( join.isEditable() )
1711  childEditable->setText( 1, QChar( 0x2714 ) );
1712  joinItem->addChild( childEditable );
1713 
1714  QTreeWidgetItem *childUpsert = new QTreeWidgetItem();
1715  childUpsert->setText( 0, tr( "Upsert on edit" ) );
1716  if ( join.hasUpsertOnEdit() )
1717  childUpsert->setText( 1, QChar( 0x2714 ) );
1718  joinItem->addChild( childUpsert );
1719 
1720  QTreeWidgetItem *childCascade = new QTreeWidgetItem();
1721  childCascade->setText( 0, tr( "Delete cascade" ) );
1722  if ( join.hasCascadedDelete() )
1723  childCascade->setText( 1, QChar( 0x2714 ) );
1724  joinItem->addChild( childCascade );
1725 
1726  QTreeWidgetItem *childPrefix = new QTreeWidgetItem();
1727  childPrefix->setText( 0, tr( "Custom field name prefix" ) );
1728  childPrefix->setText( 1, join.prefix() );
1729  joinItem->addChild( childPrefix );
1730 
1731  QTreeWidgetItem *childFields = new QTreeWidgetItem();
1732  childFields->setText( 0, tr( "Joined fields" ) );
1733  const QStringList *list = join.joinFieldNamesSubset();
1734  if ( list )
1735  childFields->setText( 1, QLocale().toString( list->count() ) );
1736  else
1737  childFields->setText( 1, tr( "all" ) );
1738  joinItem->addChild( childFields );
1739 
1740  if ( insertIndex >= 0 )
1741  mJoinTreeWidget->insertTopLevelItem( insertIndex, joinItem );
1742  else
1743  mJoinTreeWidget->addTopLevelItem( joinItem );
1744 
1745  mJoinTreeWidget->setCurrentItem( joinItem );
1746  mJoinTreeWidget->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
1747 }
1748 
1749 QgsExpressionContext QgsVectorLayerProperties::createExpressionContext() const
1750 {
1751  return mContext;
1752 }
1753 
1754 void QgsVectorLayerProperties::openPanel( QgsPanelWidget *panel )
1755 {
1756  QDialog *dlg = new QDialog();
1757  QString key = QStringLiteral( "/UI/paneldialog/%1" ).arg( panel->panelTitle() );
1758  QgsSettings settings;
1759  dlg->restoreGeometry( settings.value( key ).toByteArray() );
1760  dlg->setWindowTitle( panel->panelTitle() );
1761  dlg->setLayout( new QVBoxLayout() );
1762  dlg->layout()->addWidget( panel );
1763  QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
1764  connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
1765  dlg->layout()->addWidget( buttonBox );
1766  dlg->exec();
1767  settings.setValue( key, dlg->saveGeometry() );
1768  panel->acceptPanel();
1769 }
1770 
1771 void QgsVectorLayerProperties::mButtonRemoveJoin_clicked()
1772 {
1773  QTreeWidgetItem *currentJoinItem = mJoinTreeWidget->currentItem();
1774  if ( !mLayer || !currentJoinItem )
1775  {
1776  return;
1777  }
1778 
1779  mLayer->removeJoin( currentJoinItem->data( 0, Qt::UserRole ).toString() );
1780  mJoinTreeWidget->takeTopLevelItem( mJoinTreeWidget->indexOfTopLevelItem( currentJoinItem ) );
1781  setPbnQueryBuilderEnabled();
1782  mSourceFieldsPropertiesDialog->init();
1783  mAttributesFormPropertiesDialog->init();
1784 }
1785 
1786 
1787 void QgsVectorLayerProperties::mButtonAddWmsDimension_clicked()
1788 {
1789  if ( !mLayer )
1790  return;
1791 
1792  // get wms dimensions name
1793  QStringList alreadyDefinedDimensions;
1794  QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
1795  const QList<QgsMapLayerServerProperties::WmsDimensionInfo> &dims = serverProperties->wmsDimensions();
1796  for ( const QgsMapLayerServerProperties::WmsDimensionInfo &dim : dims )
1797  {
1798  alreadyDefinedDimensions << dim.name;
1799  }
1800 
1801  QgsWmsDimensionDialog d( mLayer, alreadyDefinedDimensions );
1802  if ( d.exec() == QDialog::Accepted )
1803  {
1805  // save dimension
1806  serverProperties->addWmsDimension( info );
1807  addWmsDimensionInfoToTreeWidget( info );
1808  }
1809 }
1810 
1811 void QgsVectorLayerProperties::mButtonEditWmsDimension_clicked()
1812 {
1813  QTreeWidgetItem *currentWmsDimensionItem = mWmsDimensionsTreeWidget->currentItem();
1814  mWmsDimensionsTreeWidget_itemDoubleClicked( currentWmsDimensionItem, 0 );
1815 }
1816 
1817 void QgsVectorLayerProperties::mWmsDimensionsTreeWidget_itemDoubleClicked( QTreeWidgetItem *item, int )
1818 {
1819  if ( !mLayer || !item )
1820  {
1821  return;
1822  }
1823 
1824  QString wmsDimName = item->data( 0, Qt::UserRole ).toString();
1825  QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
1826  const QList<QgsMapLayerServerProperties::WmsDimensionInfo> &dims = serverProperties->wmsDimensions();
1827  QStringList alreadyDefinedDimensions;
1828  int j = -1;
1829  for ( int i = 0; i < dims.size(); ++i )
1830  {
1831  QString dimName = dims[i].name;
1832  if ( dimName == wmsDimName )
1833  {
1834  j = i;
1835  }
1836  else
1837  {
1838  alreadyDefinedDimensions << dimName;
1839  }
1840  }
1841  if ( j == -1 )
1842  {
1843  return;
1844  }
1845 
1846  QgsWmsDimensionDialog d( mLayer, alreadyDefinedDimensions );
1847  d.setWindowTitle( tr( "Edit WMS Dimension" ) );
1848  d.setInfo( dims[j] );
1849 
1850  if ( d.exec() == QDialog::Accepted )
1851  {
1853 
1854  // remove old
1855  QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
1856  serverProperties->removeWmsDimension( wmsDimName );
1857  int idx = mWmsDimensionsTreeWidget->indexOfTopLevelItem( item );
1858  mWmsDimensionsTreeWidget->takeTopLevelItem( idx );
1859 
1860  // save new
1861  serverProperties->addWmsDimension( info );
1862  addWmsDimensionInfoToTreeWidget( info, idx );
1863  }
1864 }
1865 
1866 void QgsVectorLayerProperties::addWmsDimensionInfoToTreeWidget( const QgsMapLayerServerProperties::WmsDimensionInfo &wmsDim, const int insertIndex )
1867 {
1868  QTreeWidgetItem *wmsDimensionItem = new QTreeWidgetItem();
1869  wmsDimensionItem->setFlags( Qt::ItemIsEnabled );
1870 
1871  wmsDimensionItem->setText( 0, tr( "Dimension" ) );
1872  wmsDimensionItem->setText( 1, wmsDim.name );
1873 
1874  QFont f = wmsDimensionItem->font( 0 );
1875  f.setBold( true );
1876  wmsDimensionItem->setFont( 0, f );
1877  wmsDimensionItem->setFont( 1, f );
1878 
1879  wmsDimensionItem->setData( 0, Qt::UserRole, wmsDim.name );
1880 
1881  QTreeWidgetItem *childWmsDimensionField = new QTreeWidgetItem();
1882  childWmsDimensionField->setText( 0, tr( "Field" ) );
1883  childWmsDimensionField->setText( 1, wmsDim.fieldName );
1884  childWmsDimensionField->setFlags( Qt::ItemIsEnabled );
1885  wmsDimensionItem->addChild( childWmsDimensionField );
1886 
1887  QTreeWidgetItem *childWmsDimensionEndField = new QTreeWidgetItem();
1888  childWmsDimensionEndField->setText( 0, tr( "End field" ) );
1889  childWmsDimensionEndField->setText( 1, wmsDim.endFieldName );
1890  childWmsDimensionEndField->setFlags( Qt::ItemIsEnabled );
1891  wmsDimensionItem->addChild( childWmsDimensionEndField );
1892 
1893  QTreeWidgetItem *childWmsDimensionUnits = new QTreeWidgetItem();
1894  childWmsDimensionUnits->setText( 0, tr( "Units" ) );
1895  childWmsDimensionUnits->setText( 1, wmsDim.units );
1896  childWmsDimensionUnits->setFlags( Qt::ItemIsEnabled );
1897  wmsDimensionItem->addChild( childWmsDimensionUnits );
1898 
1899  QTreeWidgetItem *childWmsDimensionUnitSymbol = new QTreeWidgetItem();
1900  childWmsDimensionUnitSymbol->setText( 0, tr( "Unit symbol" ) );
1901  childWmsDimensionUnitSymbol->setText( 1, wmsDim.unitSymbol );
1902  childWmsDimensionUnitSymbol->setFlags( Qt::ItemIsEnabled );
1903  wmsDimensionItem->addChild( childWmsDimensionUnitSymbol );
1904 
1905  QTreeWidgetItem *childWmsDimensionDefaultValue = new QTreeWidgetItem();
1906  childWmsDimensionDefaultValue->setText( 0, tr( "Default display" ) );
1907  childWmsDimensionDefaultValue->setText( 1, QgsMapLayerServerProperties::wmsDimensionDefaultDisplayLabels()[wmsDim.defaultDisplayType] );
1908  childWmsDimensionDefaultValue->setFlags( Qt::ItemIsEnabled );
1909  wmsDimensionItem->addChild( childWmsDimensionDefaultValue );
1910 
1911  QTreeWidgetItem *childWmsDimensionRefValue = new QTreeWidgetItem();
1912  childWmsDimensionRefValue->setText( 0, tr( "Reference value" ) );
1913  childWmsDimensionRefValue->setText( 1, wmsDim.referenceValue.toString() );
1914  childWmsDimensionRefValue->setFlags( Qt::ItemIsEnabled );
1915  wmsDimensionItem->addChild( childWmsDimensionRefValue );
1916 
1917  if ( insertIndex >= 0 )
1918  mWmsDimensionsTreeWidget->insertTopLevelItem( insertIndex, wmsDimensionItem );
1919  else
1920  mWmsDimensionsTreeWidget->addTopLevelItem( wmsDimensionItem );
1921 
1922  mWmsDimensionsTreeWidget->setCurrentItem( wmsDimensionItem );
1923  mWmsDimensionsTreeWidget->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
1924 }
1925 
1926 void QgsVectorLayerProperties::mButtonRemoveWmsDimension_clicked()
1927 {
1928  QTreeWidgetItem *currentWmsDimensionItem = mWmsDimensionsTreeWidget->currentItem();
1929  if ( !mLayer || !currentWmsDimensionItem )
1930  {
1931  return;
1932  }
1933 
1934  QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
1935  serverProperties->removeWmsDimension( currentWmsDimensionItem->data( 0, Qt::UserRole ).toString() );
1936  mWmsDimensionsTreeWidget->takeTopLevelItem( mWmsDimensionsTreeWidget->indexOfTopLevelItem( currentWmsDimensionItem ) );
1937 }
1938 
1939 
1940 void QgsVectorLayerProperties::updateSymbologyPage()
1941 {
1942 
1943  //find out the type of renderer in the vectorlayer, create a dialog with these settings and add it to the form
1944  delete mRendererDialog;
1945  mRendererDialog = nullptr;
1946 
1947  if ( mLayer->renderer() )
1948  {
1949  mRendererDialog = new QgsRendererPropertiesDialog( mLayer, QgsStyle::defaultStyle(), true, this );
1950  mRendererDialog->setDockMode( false );
1951  QgsSymbolWidgetContext context;
1952  context.setMapCanvas( mCanvas );
1953  context.setMessageBar( mMessageBar );
1954  mRendererDialog->setContext( context );
1955  connect( mRendererDialog, &QgsRendererPropertiesDialog::showPanel, this, &QgsVectorLayerProperties::openPanel );
1956  connect( mRendererDialog, &QgsRendererPropertiesDialog::layerVariablesChanged, this, &QgsVectorLayerProperties::updateVariableEditor );
1957  connect( mRendererDialog, &QgsRendererPropertiesDialog::widgetChanged, this, [ = ] { updateAuxiliaryStoragePage(); } );
1958  }
1959  else
1960  {
1961  mOptsPage_Style->setEnabled( false ); // hide symbology item
1962  }
1963 
1964  if ( mRendererDialog )
1965  {
1966  mRendererDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
1967  widgetStackRenderers->addWidget( mRendererDialog );
1968  widgetStackRenderers->setCurrentWidget( mRendererDialog );
1969  widgetStackRenderers->currentWidget()->layout()->setContentsMargins( 0, 0, 0, 0 );
1970  }
1971 }
1972 
1973 void QgsVectorLayerProperties::setPbnQueryBuilderEnabled()
1974 {
1975  pbnQueryBuilder->setEnabled( mLayer &&
1976  mLayer->dataProvider() &&
1977  mLayer->dataProvider()->supportsSubsetString() &&
1978  !mLayer->isEditable() );
1979 
1980  if ( mLayer && mLayer->isEditable() )
1981  {
1982  pbnQueryBuilder->setToolTip( tr( "Stop editing mode to enable this." ) );
1983  }
1984 
1985 }
1986 
1987 void QgsVectorLayerProperties::pbnUpdateExtents_clicked()
1988 {
1989  mLayer->updateExtents( true ); // force update whatever options activated
1990  mMetadataFilled = false;
1991 }
1992 
1994 {
1996 
1997  bool isMetadataPanel = ( index == mOptStackedWidget->indexOf( mOptsPage_Metadata ) );
1998  mBtnStyle->setVisible( ! isMetadataPanel );
1999  mBtnMetadata->setVisible( isMetadataPanel );
2000 
2001  if ( index == mOptStackedWidget->indexOf( mOptsPage_Information ) && ! mMetadataFilled )
2002  {
2003  //set the metadata contents (which can be expensive)
2004  teMetadataViewer->clear();
2005  teMetadataViewer->setHtml( htmlMetadata() );
2006  mMetadataFilled = true;
2007  }
2008 
2009  resizeAlltabs( index );
2010 }
2011 
2012 void QgsVectorLayerProperties::mSimplifyDrawingGroupBox_toggled( bool checked )
2013 {
2014  const QgsVectorDataProvider *provider = mLayer->dataProvider();
2015  if ( !( provider && ( provider->capabilities() & QgsVectorDataProvider::SimplifyGeometries ) != 0 ) )
2016  {
2017  mSimplifyDrawingAtProvider->setEnabled( false );
2018  }
2019  else
2020  {
2021  mSimplifyDrawingAtProvider->setEnabled( checked );
2022  }
2023 }
2024 
2025 void QgsVectorLayerProperties::updateVariableEditor()
2026 {
2027  QgsExpressionContext context;
2028  mVariableEditor->setContext( &context );
2029  mVariableEditor->context()->appendScope( QgsExpressionContextUtils::globalScope() );
2030  mVariableEditor->context()->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
2031  mVariableEditor->context()->appendScope( QgsExpressionContextUtils::layerScope( mLayer ) );
2032  mVariableEditor->reloadContext();
2033  mVariableEditor->setEditableScopeIndex( 2 );
2034 }
2035 
2036 void QgsVectorLayerProperties::showHelp()
2037 {
2038  const QVariant helpPage = mOptionsStackedWidget->currentWidget()->property( "helpPage" );
2039 
2040  if ( helpPage.isValid() )
2041  {
2042  QgsHelp::openHelp( helpPage.toString() );
2043  }
2044  else
2045  {
2046  QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html" ) );
2047  }
2048 }
2049 
2050 void QgsVectorLayerProperties::updateAuxiliaryStoragePage()
2051 {
2052  const QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2053 
2054  if ( alayer )
2055  {
2056  // set widgets to enable state
2057  mAuxiliaryStorageInformationGrpBox->setEnabled( true );
2058  mAuxiliaryStorageFieldsGrpBox->setEnabled( true );
2059 
2060  // update key
2061  mAuxiliaryStorageKeyLineEdit->setText( alayer->joinInfo().targetFieldName() );
2062 
2063  // update feature count
2064  const qlonglong features = alayer->featureCount();
2065  mAuxiliaryStorageFeaturesLineEdit->setText( QLocale().toString( features ) );
2066 
2067  // update actions
2068  mAuxiliaryLayerActionClear->setEnabled( true );
2069  mAuxiliaryLayerActionDelete->setEnabled( true );
2070  mAuxiliaryLayerActionExport->setEnabled( true );
2071  mAuxiliaryLayerActionNew->setEnabled( false );
2072 
2073  const QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2074  if ( alayer )
2075  {
2076  const int fields = alayer->auxiliaryFields().count();
2077  mAuxiliaryStorageFieldsLineEdit->setText( QLocale().toString( fields ) );
2078 
2079  // add fields
2080  mAuxiliaryStorageFieldsTree->clear();
2081  for ( const QgsField &field : alayer->auxiliaryFields() )
2082  {
2084  QTreeWidgetItem *item = new QTreeWidgetItem();
2085 
2086  item->setText( 0, prop.origin() );
2087  item->setText( 1, prop.name() );
2088  item->setText( 2, prop.comment() );
2089  item->setText( 3, field.typeName() );
2090  item->setText( 4, field.name() );
2091 
2092  mAuxiliaryStorageFieldsTree->addTopLevelItem( item );
2093  }
2094  }
2095  }
2096  else
2097  {
2098  mAuxiliaryStorageInformationGrpBox->setEnabled( false );
2099  mAuxiliaryStorageFieldsGrpBox->setEnabled( false );
2100 
2101  mAuxiliaryLayerActionClear->setEnabled( false );
2102  mAuxiliaryLayerActionDelete->setEnabled( false );
2103  mAuxiliaryLayerActionExport->setEnabled( false );
2104  mAuxiliaryLayerActionNew->setEnabled( true );
2105 
2106  mAuxiliaryStorageFieldsTree->clear();
2107  mAuxiliaryStorageKeyLineEdit->setText( QString() );
2108  mAuxiliaryStorageFieldsLineEdit->setText( QString() );
2109  mAuxiliaryStorageFeaturesLineEdit->setText( QString() );
2110  }
2111 }
2112 
2113 void QgsVectorLayerProperties::onAuxiliaryLayerNew()
2114 {
2115  QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2116 
2117  if ( alayer )
2118  return;
2119 
2120  QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
2121  if ( dlg.exec() == QDialog::Accepted )
2122  {
2123  updateAuxiliaryStoragePage();
2124  }
2125 }
2126 
2127 void QgsVectorLayerProperties::onAuxiliaryLayerClear()
2128 {
2129  QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2130 
2131  if ( !alayer )
2132  return;
2133 
2134  const QString msg = tr( "Are you sure you want to clear auxiliary data for %1?" ).arg( mLayer->name() );
2135  QMessageBox::StandardButton reply;
2136  reply = QMessageBox::question( this, "Clear Auxiliary Data", msg, QMessageBox::Yes | QMessageBox::No );
2137 
2138  if ( reply == QMessageBox::Yes )
2139  {
2140  QApplication::setOverrideCursor( Qt::WaitCursor );
2141  alayer->clear();
2142  QApplication::restoreOverrideCursor();
2143  updateAuxiliaryStoragePage();
2144  mLayer->triggerRepaint();
2145  }
2146 }
2147 
2148 void QgsVectorLayerProperties::onAuxiliaryLayerDelete()
2149 {
2150  QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2151  if ( !alayer )
2152  return;
2153 
2154  const QString msg = tr( "Are you sure you want to delete auxiliary storage for %1?" ).arg( mLayer->name() );
2155  QMessageBox::StandardButton reply;
2156  reply = QMessageBox::question( this, "Delete Auxiliary Storage", msg, QMessageBox::Yes | QMessageBox::No );
2157 
2158  if ( reply == QMessageBox::Yes )
2159  {
2160  QApplication::setOverrideCursor( Qt::WaitCursor );
2161  QgsDataSourceUri uri( alayer->source() );
2162 
2163  // delete each attribute to correctly update layer settings and data
2164  // defined buttons
2165  while ( alayer->auxiliaryFields().size() > 0 )
2166  {
2167  QgsField aField = alayer->auxiliaryFields()[0];
2168  deleteAuxiliaryField( alayer->fields().indexOf( aField.name() ) );
2169  }
2170 
2171  mLayer->setAuxiliaryLayer(); // remove auxiliary layer
2173  QApplication::restoreOverrideCursor();
2174  updateAuxiliaryStoragePage();
2175  mLayer->triggerRepaint();
2176  }
2177 }
2178 
2179 void QgsVectorLayerProperties::onAuxiliaryLayerDeleteField()
2180 {
2181  QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2182  if ( !alayer )
2183  return;
2184 
2185  QList<QTreeWidgetItem *> items = mAuxiliaryStorageFieldsTree->selectedItems();
2186  if ( items.count() < 1 )
2187  return;
2188 
2189  // get auxiliary field name and index from item
2190  const QTreeWidgetItem *item = items[0];
2192  def.setOrigin( item->text( 0 ) );
2193  def.setName( item->text( 1 ) );
2194  def.setComment( item->text( 2 ) );
2195 
2196  const QString fieldName = QgsAuxiliaryLayer::nameFromProperty( def );
2197 
2198  const int index = mLayer->auxiliaryLayer()->fields().indexOf( fieldName );
2199  if ( index < 0 )
2200  return;
2201 
2202  // should be only 1 field
2203  const QString msg = tr( "Are you sure you want to delete auxiliary field %1 for %2?" ).arg( item->text( 1 ), item->text( 0 ) );
2204 
2205  QMessageBox::StandardButton reply;
2206  const QString title = QObject::tr( "Delete Auxiliary Field" );
2207  reply = QMessageBox::question( this, title, msg, QMessageBox::Yes | QMessageBox::No );
2208 
2209  if ( reply == QMessageBox::Yes )
2210  {
2211  QApplication::setOverrideCursor( Qt::WaitCursor );
2212  deleteAuxiliaryField( index );
2213  mLayer->triggerRepaint();
2214  QApplication::restoreOverrideCursor();
2215  }
2216 }
2217 
2218 void QgsVectorLayerProperties::onAuxiliaryLayerAddField()
2219 {
2220  QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2221  if ( !alayer )
2222  return;
2223 
2224  QgsNewAuxiliaryFieldDialog dlg( QgsPropertyDefinition(), mLayer, false );
2225  if ( dlg.exec() == QDialog::Accepted )
2226  {
2227  updateAuxiliaryStoragePage();
2228  }
2229 }
2230 
2231 void QgsVectorLayerProperties::deleteAuxiliaryField( int index )
2232 {
2233  if ( !mLayer->auxiliaryLayer() )
2234  return;
2235 
2236  int key = mLayer->auxiliaryLayer()->propertyFromIndex( index );
2238 
2239  if ( mLayer->auxiliaryLayer()->deleteAttribute( index ) )
2240  {
2241  mLayer->updateFields();
2242 
2243  // immediately deactivate data defined button
2244  if ( key >= 0 && def.origin().compare( "labeling", Qt::CaseInsensitive ) == 0
2245  && labelingDialog
2246  && labelingDialog->labelingGui() )
2247  {
2248  labelingDialog->labelingGui()->deactivateField( static_cast<QgsPalLayerSettings::Property>( key ) );
2249  }
2250 
2251  updateAuxiliaryStoragePage();
2252  mSourceFieldsPropertiesDialog->init();
2253  }
2254  else
2255  {
2256  const QString title = QObject::tr( "Delete Auxiliary Field" );
2257  const QString errors = mLayer->auxiliaryLayer()->commitErrors().join( QLatin1String( "\n " ) );
2258  const QString msg = QObject::tr( "Unable to remove auxiliary field (%1)" ).arg( errors );
2259  mMessageBar->pushMessage( title, msg, Qgis::MessageLevel::Warning );
2260  }
2261 }
static QString defaultProjectScales()
A string with default project scales.
Definition: qgis.cpp:271
void clearActions()
Removes all actions.
QUuid addAction(QgsAction::ActionType type, const QString &name, const QString &command, bool capture=false)
Add an action with the given name and action details.
Utility class that encapsulates an action based on vector attributes.
Definition: qgsaction.h:35
static QString reportStyleSheet(QgsApplication::StyleSheetType styleSheetType=QgsApplication::StyleSheetType::Qt)
Returns a css style sheet for reports, the styleSheetType argument determines what type of stylesheet...
static QRegularExpression shortNameRegularExpression()
Returns the short name regular expression for line edit validator.
void init(const QgsActionManager &action, const QgsAttributeTableConfig &attributeTableConfig)
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.
QVector< QgsAttributeTableConfig::ColumnConfig > columns() const
Gets the list with all columns and their configuration.
void update(const QgsFields &fields)
Update the configuration with the given fields.
void setActionWidgetStyle(ActionWidgetStyle actionWidgetStyle)
Set the style of the action widget.
void setColumns(const QVector< QgsAttributeTableConfig::ColumnConfig > &columns)
Set the list of columns visible in the attribute table.
Class allowing to manage the auxiliary storage for a vector layer.
static QgsPropertyDefinition propertyDefinitionFromField(const QgsField &field)
Returns the property definition from an auxiliary field.
bool clear()
Deletes all features from the layer.
bool deleteAttribute(int attr) override
Removes attribute from the layer and commits changes.
QgsFields auxiliaryFields() const
Returns a list of all auxiliary fields currently managed by the layer.
int propertyFromIndex(int index) const
Returns the underlying property key for the field index.
QgsVectorLayerJoinInfo joinInfo() const
Returns information to use for joining with primary key and so on.
static QString nameFromProperty(const QgsPropertyDefinition &def, bool joined=false)
Returns the name of the auxiliary field for a property definition.
QgsPropertyDefinition propertyDefinitionFromIndex(int index) const
Returns the property definition for the underlying field index.
static bool deleteTable(const QgsDataSourceUri &uri)
Removes a table from the auxiliary storage.
This class represents a coordinate reference system (CRS).
virtual bool supportsSubsetString() const
Returns true if the provider supports setting of subset strings.
Class for storing the component parts of a RDBMS data source URI (e.g.
static bool run(const QgsCoordinateReferenceSystem &sourceCrs=QgsCoordinateReferenceSystem(), const QgsCoordinateReferenceSystem &destinationCrs=QgsCoordinateReferenceSystem(), QWidget *parent=nullptr, QgsMapCanvas *mapCanvas=nullptr, const QString &windowTitle=QString())
Runs the dialog (if required) prompting for the desired transform to use from sourceCrs to destinatio...
void syncToLayer()
Updates the widget to reflect the layer's current diagram settings.
static void setLayerVariables(QgsMapLayer *layer, const QVariantMap &variables)
Sets all layer context variables.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * atlasScope(const QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
bool forceRasterRender() const
Returns whether the renderer must render as a raster.
Definition: qgsrenderer.h:440
void setForceRasterRender(bool forceRaster)
Sets whether the renderer should be rendered to a raster destination.
Definition: qgsrenderer.h:450
double referenceScale() const
Returns the symbology reference scale.
Definition: qgsrenderer.h:466
void setReferenceScale(double scale)
Sets the symbology reference scale.
Definition: qgsrenderer.h:482
@ SpatialIndexPresent
A valid spatial index exists for the source.
virtual SpatialIndexPresence hasSpatialIndex() const
Returns an enum value representing the presence of a valid spatial index on the source,...
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:51
QString typeName() const
Gets the field type.
Definition: qgsfield.cpp:139
QString name
Definition: qgsfield.h:60
int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:202
int indexOf(const QString &fieldName) const
Gets the field index from the field name.
Definition: qgsfields.cpp:207
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
int size() const
Returns number of items.
Definition: qgsfields.cpp:138
static QgsProviderSourceWidgetProviderRegistry * sourceWidgetProviderRegistry()
Returns the registry of provider source widget providers.
Definition: qgsgui.cpp:110
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:75
static QgsSubsetStringEditorProviderRegistry * subsetStringEditorProviderRegistry()
Returns the registry of subset string editors of data providers.
Definition: qgsgui.cpp:105
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
Master widget for configuration of labeling of a vector layer.
void adaptToLayer()
reload the settings shown in the dialog from the current layer
QgsLabelingGui * labelingGui()
Returns the labeling gui widget or nullptr if none.
void auxiliaryFieldCreated()
Emitted when an auxiliary field is created.
void writeSettingsToLayer()
save config to layer
QgsLayerTreeFilterProxyModel is a sort filter proxy model to easily reproduce the legend/layer tree i...
QList< QgsMapLayer * > checkedLayers() const
Returns the checked layers.
void setLayerTreeModel(QgsLayerTreeModel *layerTreeModel)
Sets the layer tree model.
void setCheckedLayers(const QList< QgsMapLayer * > layers)
Initialize the list of checked layers.
The QgsLayerTreeModel class is model implementation for Qt item views framework.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:90
double scale() const
Returns the last reported scale of the canvas.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
Factory class for creating custom map layer property pages.
virtual bool supportsLayer(QgsMapLayer *layer) const
Check if the layer is supported for this widget.
virtual QIcon icon() const
The icon that will be shown in the UI for the panel.
virtual QgsMapLayerConfigWidget * createWidget(QgsMapLayer *layer, QgsMapCanvas *canvas, bool dockWidget=true, QWidget *parent=nullptr) const =0
Factory function to create the widget on demand as needed by the dock.
virtual QString title() const
The title of the panel.
virtual bool supportLayerPropertiesDialog() const
Flag if widget is supported for use in layer properties dialog.
virtual QString layerPropertiesPagePositionHint() const
Returns a tab name hinting at where this page should be inserted into the layer properties tab list.
A panel widget that can be shown in the map style dock.
This class models dependencies with or between map layers.
A reusable dialog which allows users to select stored layer styles and categories to load for a map l...
Manages QGIS Server properties for a map layer.
void addStyleManagerActions(QMenu *m, QgsMapLayer *layer)
adds actions to the menu in accordance to the layer
static QgsMapLayerStyleGuiUtils * instance()
returns a singleton instance of this class
QString currentStyle() const
Returns name of the current style.
QStringList styles() const
Returns list of all defined style names.
bool setCurrentStyle(const QString &name)
Set a different style as the current style - will apply it to the layer.
static bool isDefault(const QString &styleName)
Returns true if this is the default style.
QgsMapLayerStyle style(const QString &name) const
Returns data of a stored style - accessed by its unique name.
void currentStyleChanged(const QString &currentName)
Emitted when the current style has been changed.
QString xmlData() const
Returns XML content of the style.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
void setShortName(const QString &shortName)
Sets the short name of the layer used by QGIS Server to identify the layer.
Definition: qgsmaplayer.h:288
QString name
Definition: qgsmaplayer.h:76
QString legendUrlFormat() const
Returns the format for a URL based layer legend.
Definition: qgsmaplayer.h:1297
void setRefreshOnNotifyEnabled(bool enabled)
Set whether provider notification is connected to triggerRepaint.
virtual bool importNamedStyle(QDomDocument &doc, QString &errorMsg, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Import the properties of this layer from a QDomDocument.
void setAbstract(const QString &abstract)
Sets the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:318
virtual QString saveSldStyle(const QString &uri, bool &resultFlag) const
Saves the properties of this layer to an SLD format file.
QString source() const
Returns the source for the layer.
void setLegendUrl(const QString &legendUrl)
Sets the URL for the layer's legend.
Definition: qgsmaplayer.h:1282
QString providerType() const
Returns the provider type (provider key) for this layer.
void setMinimumScale(double scale)
Sets the minimum map scale (i.e.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
QString attribution() const
Returns the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:400
QString id() const
Returns the layer's unique ID, which is used to access this layer from QgsProject.
virtual QString loadNamedMetadata(const QString &uri, bool &resultFlag)
Retrieve a named metadata for this layer if one exists (either as a .qmd file on disk or as a record ...
bool hasAutoRefreshEnabled() const
Returns true if auto refresh is enabled for the layer.
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
void setAttributionUrl(const QString &attribUrl)
Sets the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:409
void setAutoRefreshEnabled(bool enabled)
Sets whether auto refresh is enabled for the layer.
void setMaximumScale(double scale)
Sets the maximum map scale (i.e.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:78
QString abstract() const
Returns the abstract of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:326
QString dataUrlFormat() const
Returns the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:380
QgsMapLayerServerProperties * serverProperties()
Returns QGIS Server Properties for the map layer.
Definition: qgsmaplayer.h:426
void setDataUrl(const QString &dataUrl)
Sets the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:353
void setKeywordList(const QString &keywords)
Sets the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:334
void setAttribution(const QString &attrib)
Sets the attribution of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:391
bool isRefreshOnNotifyEnabled() const
Returns true if the refresh on provider nofification is enabled.
Definition: qgsmaplayer.h:1459
QString shortName() const
Returns the short name of the layer used by QGIS Server to identify the layer.
virtual QString loadSldStyle(const QString &uri, bool &resultFlag)
Attempts to style the layer using the formatting from an SLD type file.
virtual QString saveDefaultMetadata(bool &resultFlag)
Save the current metadata of this layer as the default metadata (either as a .qmd file on disk or as ...
void setDataUrlFormat(const QString &dataUrlFormat)
Sets the DataUrl format of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:371
QString title() const
Returns the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:310
virtual QString styleURI() const
Retrieve the style URI for this layer (either as a .qml file on disk or as a record in the users styl...
void setScaleBasedVisibility(bool enabled)
Sets whether scale based visibility is enabled for the layer.
QString dataUrl() const
Returns the DataUrl of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:362
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
void setRefreshOnNofifyMessage(const QString &message)
Set the notification message that triggers repaint If refresh on notification is enabled,...
Definition: qgsmaplayer.h:1606
static QString extensionPropertyType(PropertyType type)
Returns the extension of a Property.
Definition: qgsmaplayer.cpp:68
void setName(const QString &name)
Set the display name of the layer.
void setAutoRefreshInterval(int interval)
Sets the auto refresh interval (in milliseconds) for the layer.
QString saveNamedMetadata(const QString &uri, bool &resultFlag)
Save the current metadata of this layer as a named metadata (either as a .qmd file on disk or as a re...
QString refreshOnNotifyMessage() const
Returns the message that should be notified by the provider to triggerRepaint.
Definition: qgsmaplayer.h:1452
QString attributionUrl() const
Returns the attribution URL of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:418
void setDataSource(const QString &dataSource, const QString &baseName, const QString &provider, bool loadDefaultStyleFlag=false)
Updates the data source of the layer.
double minimumScale() const
Returns the minimum map scale (i.e.
QgsMapLayerStyleManager * styleManager() const
Gets access to the layer's style manager.
QString legendUrl() const
Returns the URL for the layer's legend.
Definition: qgsmaplayer.h:1287
void setLegendUrlFormat(const QString &legendUrlFormat)
Sets the format for a URL based layer legend.
Definition: qgsmaplayer.h:1292
virtual QString saveNamedStyle(const QString &uri, bool &resultFlag, StyleCategories categories=AllStyleCategories)
Save the properties of this layer as a named style (either as a .qml file on disk or as a record in t...
virtual QString metadataUri() const
Retrieve the metadata URI for this layer (either as a .qmd file on disk or as a record in the users s...
int autoRefreshInterval
Definition: qgsmaplayer.h:77
virtual QString saveDefaultStyle(bool &resultFlag, StyleCategories categories)
Save the properties of this layer as the default style (either as a .qml file on disk or as a record ...
double maximumScale() const
Returns the maximum map scale (i.e.
QString keywordList() const
Returns the keyword list of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:342
void setTitle(const QString &title)
Sets the title of the layer used by QGIS Server in GetCapabilities request.
Definition: qgsmaplayer.h:302
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
void pushMessage(const QString &text, Qgis::MessageLevel level=Qgis::MessageLevel::Info, int duration=-1)
A convenience method for pushing a message with the specified text to the bar.
A wizard to edit metadata on a map layer.
void acceptMetadata()
Saves the metadata to the layer.
void crsChanged()
If the CRS is updated.
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas associated with the widget.
void setMetadata(const QgsAbstractMetadataBase *metadata)
Sets the metadata to display in the widget.
A dialog to create a new auxiliary field.
A dialog to create a new auxiliary layer.
A base dialog for options and properties dialogs that offers vertical tabs.
void resizeAlltabs(int index)
Resizes all tabs when the dialog is resized.
void addPage(const QString &title, const QString &tooltip, const QIcon &icon, QWidget *widget, const QStringList &path=QStringList())
Adds a new page to the dialog pages.
virtual void optionsStackedWidget_CurrentChanged(int index)
Select relevant tab on current page change.
void insertPage(const QString &title, const QString &tooltip, const QIcon &icon, QWidget *widget, const QString &before, const QStringList &path=QStringList())
Inserts a new page into the dialog pages.
void restoreOptionsBaseUi(const QString &title=QString())
Restore the base ui.
QStackedWidget * mOptStackedWidget
void initOptionsBase(bool restoreUi=true, const QString &title=QString())
Set up the base ui connections for vertical tabs.
Property
Data definable properties.
Base class for any widget that can be shown as a inline panel.
QString panelTitle()
The title of the panel.
void acceptPanel()
Accept the panel.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:479
Q_INVOKABLE QgsMapLayer * mapLayer(const QString &layerId) const
Retrieve a pointer to a registered layer by layer ID.
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:575
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
Definition for a property.
Definition: qgsproperty.h:47
QString comment() const
Returns the comment of the property.
Definition: qgsproperty.h:168
void setOrigin(const QString &origin)
Sets the origin of the property.
Definition: qgsproperty.h:158
QString name() const
Returns the name of the property.
Definition: qgsproperty.h:139
void setName(const QString &name)
Sets the name of the property.
Definition: qgsproperty.h:144
QString origin() const
Returns the origin of the property.
Definition: qgsproperty.h:151
void setComment(const QString &comment)
Sets comment of the property.
Definition: qgsproperty.h:173
static QgsProviderRegistry * instance(const QString &pluginPath=QString())
Means of accessing canonical single instance.
QgsProviderSourceWidget * createWidget(QgsMapLayer *layer, QWidget *parent=nullptr)
Creates a new widget to configure the source of the specified layer.
void validChanged(bool isValid)
Emitted whenever the validation status of the widget changes.
virtual QString sourceUri() const =0
Returns the source URI as currently defined by the widget.
virtual void setSourceUri(const QString &uri)=0
Sets the source uri to show in the widget.
void showPanel(QgsPanelWidget *panel)
Emit when you require a panel to be show in the interface.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the dialog is shown, e.g., the associated map canvas and expression context...
void apply()
Apply the changes from the dialog to the layer.
void layerVariablesChanged()
Emitted when expression context variables on the associated vector layers have been changed.
void widgetChanged()
Emitted when something on the widget has changed.
void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
void setMetadataUrls(const QList< QgsServerMetadataUrlProperties::MetadataUrl > &metaUrls)
Sets a the list of metadata URL for the layer.
QList< QgsServerMetadataUrlProperties::MetadataUrl > metadataUrls() const
Returns a list of metadataUrl resources associated for the layer.
static QMap< int, QString > wmsDimensionDefaultDisplayLabels()
Returns WMS Dimension default display labels.
bool addWmsDimension(const QgsServerWmsDimensionProperties::WmsDimensionInfo &wmsDimInfo)
Adds a QGIS Server WMS Dimension.
bool removeWmsDimension(const QString &wmsDimName)
Removes a QGIS Server WMS Dimension.
const QList< QgsServerWmsDimensionProperties::WmsDimensionInfo > wmsDimensions() const
Returns the QGIS Server WMS Dimension list.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
bool contains(const QString &key, QgsSettings::Section section=QgsSettings::NoSection) const
Returns true if there exists a setting called key; returns false otherwise.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:145
Interface for a dialog that can edit subset strings.
virtual QString subsetString() const =0
Returns the subset string entered in the dialog.
virtual void setSubsetString(const QString &subsetString)=0
Sets a subset string into the dialog.
QgsSubsetStringEditorInterface * createDialog(QgsVectorLayer *layer, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
Creates a new dialog to edit the subset string of the provided layer.
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
void setMessageBar(QgsMessageBar *bar)
Sets the message bar associated with the widget.
This is the base class for vector data providers.
static QStringList availableEncodings()
Returns a list of available encodings.
@ SimplifyGeometries
Supports simplification of geometries on provider side according to a distance tolerance.
@ SelectEncoding
Allows user to select encoding.
@ CreateSpatialIndex
Allows creation of spatial index.
virtual bool isSaveAndLoadStyleToDatabaseSupported() const
It returns false by default.
virtual bool createSpatialIndex()
Creates a spatial index on the datasource (if supported by the provider type).
virtual bool createAttributeIndex(int field)
Create an attribute index on the datasource.
QString encoding() const
Returns the encoding which is used for accessing data.
virtual Q_INVOKABLE QgsVectorDataProvider::Capabilities capabilities() const
Returns flags containing the supported capabilities.
Defines left outer join from our vector layer to some other vector layer.
bool hasCascadedDelete() const
Returns whether a feature deleted on the target layer has to impact the joined layer by deleting the ...
bool isDynamicFormEnabled() const
Returns whether the form has to be dynamically updated with joined fields when a feature is being cre...
bool hasUpsertOnEdit() const
Returns whether a feature created on the target layer has to impact the joined layer by creating a ne...
bool isEditable() const
Returns whether joined fields may be edited through the form of the target layer.
bool isUsingMemoryCache() const
Returns whether values from the joined layer should be cached in memory to speed up lookups.
QString prefix() const
Returns prefix of fields from the joined layer. If nullptr, joined layer's name will be used.
static QStringList joinFieldNamesSubset(const QgsVectorLayerJoinInfo &info, bool blocklisted=true)
Returns the list of field names to use for joining considering blocklisted fields and subset.
QString joinFieldName() const
Returns name of the field of joined layer that will be used for join.
QString targetFieldName() const
Returns name of the field of our layer that will be used for join.
QString joinLayerId() const
ID of the joined layer - may be used to resolve reference to the joined layer.
QgsVectorLayer * joinLayer() const
Returns joined layer (may be nullptr if the reference was set by layer ID and not resolved yet)
QgsVectorLayerProperties(QgsMapCanvas *canvas, QgsMessageBar *messageBar, QgsVectorLayer *lyr=nullptr, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
void optionsStackedWidget_CurrentChanged(int index) override
void addPropertiesPageFactory(const QgsMapLayerConfigWidgetFactory *factory)
Adds a properties page factory to the vector layer properties dialog.
void toggleEditing(QgsMapLayer *)
void exportAuxiliaryLayer(QgsAuxiliaryLayer *layer)
The QgsVectorLayerSaveStyleDialog class provides the UI to save the current style or multiple styles ...
A widget for configuring the temporal properties for a vector layer.
void syncToLayer()
Updates the widget state to match the current layer state.
void saveTemporalProperties()
Save widget temporal properties inputs.
Represents a vector layer which manages a vector based data sets.
void setAuxiliaryLayer(QgsAuxiliaryLayer *layer=nullptr)
Sets the current auxiliary layer.
virtual void saveStyleToDatabase(const QString &name, const QString &description, bool useAsDefault, const QString &uiFileContent, QString &msgError, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Saves named and sld style of the layer to the style table in the db.
Q_INVOKABLE QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
bool addJoin(const QgsVectorLayerJoinInfo &joinInfo)
Joins another vector layer to this layer.
QSet< QgsMapLayerDependency > dependencies() const FINAL
Gets the list of dependencies.
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
virtual int listStylesInDatabase(QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError)
Lists all the style in db split into related to the layer and not related to.
void updateFields()
Will regenerate the fields property of this layer by obtaining all fields from the dataProvider,...
bool isSpatial() const FINAL
Returns true if this is a geometry layer and false in case of NoGeometry (table only) or UnknownGeome...
virtual QString loadNamedStyle(const QString &theURI, bool &resultFlag, bool loadFromLocalDb, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Loads a named style from file/local db/datasource db.
QString mapTipTemplate
QString htmlMetadata() const FINAL
Obtain a formatted HTML string containing assorted metadata for this layer.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
void setSimplifyMethod(const QgsVectorSimplifyMethod &simplifyMethod)
Sets the simplification settings for fast rendering of features.
void setMapTipTemplate(const QString &mapTipTemplate)
The mapTip is a pretty, html representation for feature information.
virtual QString getStyleFromDatabase(const QString &styleId, QString &msgError)
Returns the named style corresponding to style id provided.
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
bool setDependencies(const QSet< QgsMapLayerDependency > &layers) FINAL
Sets the list of dependencies.
void setProviderEncoding(const QString &encoding)
Sets the text encoding of the data provider.
void setDisplayExpression(const QString &displayExpression)
Set the preview expression, used to create a human readable preview string.
bool removeJoin(const QString &joinLayerId)
Removes a vector layer join.
bool isEditable() const FINAL
Returns true if the provider is in editing mode.
QStringList commitErrors() const
Returns a list containing any error messages generated when attempting to commit changes to the layer...
virtual void updateExtents(bool force=false)
Update the extents for the layer.
QgsActionManager * actions()
Returns all layer actions defined on this layer.
QString subsetString
QString displayExpression
QgsVectorDataProvider * dataProvider() FINAL
Returns the layer's data provider, it may be nullptr.
QgsAttributeTableConfig attributeTableConfig() const
Returns the attribute table configuration object.
void setAttributeTableConfig(const QgsAttributeTableConfig &attributeTableConfig)
Sets the attribute table configuration object.
virtual bool setSubsetString(const QString &subset)
Sets the string (typically sql) used to define a subset of the layer.
const QList< QgsVectorLayerJoinInfo > vectorJoins() const
const QgsVectorSimplifyMethod & simplifyMethod() const
Returns the simplification settings for fast rendering of features.
QgsFeatureRenderer * renderer()
Returns the feature renderer used for rendering the features in the layer in 2D map views.
This class contains information how to simplify geometries fetched from a vector layer.
bool forceLocalOptimization() const
Gets where the simplification executes, after fetch the geometries from provider, or when supported,...
void setSimplifyHints(SimplifyHints simplifyHints)
Sets the simplification hints of the vector layer managed.
float maximumScale() const
Gets the maximum scale at which the layer should be simplified.
void setThreshold(float threshold)
Sets the simplification threshold of the vector layer managed.
void setSimplifyAlgorithm(SimplifyAlgorithm simplifyAlgorithm)
Sets the local simplification algorithm of the vector layer managed.
void setForceLocalOptimization(bool localOptimization)
Sets where the simplification executes, after fetch the geometries from provider, or when supported,...
SimplifyHints simplifyHints() const
Gets the simplification hints of the vector layer managed.
SimplifyAlgorithm simplifyAlgorithm() const
Gets the local simplification algorithm of the vector layer managed.
float threshold() const
Gets the simplification threshold of the vector layer managed.
@ GeometrySimplification
The geometries can be simplified using the current map2pixel context state.
@ AntialiasingSimplification
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'.
@ NoSimplification
No simplification can be applied.
SimplifyAlgorithm
Types of local simplification algorithms that can be used.
@ Distance
The simplification uses the distance between points to remove duplicate points.
@ SnapToGrid
The simplification uses a grid (similar to ST_SnapToGrid) to remove duplicate points.
@ Visvalingam
The simplification gives each point in a line an importance weighting, so that least important points...
void setMaximumScale(float maximumScale)
Sets the maximum scale at which the layer should be simplified.
The QgsWmsDimensionDialog class provides an interface for WMS/OAPIF (WFS3) dimensions configuration A...
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2815
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2814
const QgsField & field
Definition: qgsfield.h:463
const QgsCoordinateReferenceSystem & crs
Setting options for creating vector data providers.
QString format
Format specification of online resource.
Setting to define QGIS Server WMS Dimension.