QGIS API Documentation  3.24.2-Tisler (13c1a02865)
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  errorMsg = mLayer->saveDefaultStyle( defaultSavedFlag );
1095  if ( !defaultSavedFlag )
1096  {
1097  QMessageBox::warning( this, tr( "Default Style" ), errorMsg );
1098  }
1099 }
1100 
1101 void QgsVectorLayerProperties::loadMetadata()
1102 {
1103  QgsSettings myQSettings; // where we keep last used filter in persistent state
1104  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
1105 
1106  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load Layer Metadata from Metadata File" ), myLastUsedDir,
1107  tr( "QGIS Layer Metadata File" ) + " (*.qmd)" );
1108  if ( myFileName.isNull() )
1109  {
1110  return;
1111  }
1112 
1113  QString myMessage;
1114  bool defaultLoadedFlag = false;
1115  myMessage = mLayer->loadNamedMetadata( myFileName, defaultLoadedFlag );
1116 
1117  //reset if the default style was loaded OK only
1118  if ( defaultLoadedFlag )
1119  {
1120  mMetadataWidget->setMetadata( &mLayer->metadata() );
1121  }
1122  else
1123  {
1124  //let the user know what went wrong
1125  QMessageBox::warning( this, tr( "Load Metadata" ), myMessage );
1126  }
1127 
1128  QFileInfo myFI( myFileName );
1129  QString myPath = myFI.path();
1130  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), myPath );
1131 
1132  activateWindow(); // set focus back to properties dialog
1133 }
1134 
1135 void QgsVectorLayerProperties::saveMetadataAs()
1136 {
1137  QgsSettings myQSettings; // where we keep last used filter in persistent state
1138  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
1139 
1140  QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save Layer Metadata as QMD" ),
1141  myLastUsedDir, tr( "QMD File" ) + " (*.qmd)" );
1142  if ( myOutputFileName.isNull() ) //dialog canceled
1143  {
1144  return;
1145  }
1146 
1147  mMetadataWidget->acceptMetadata();
1148 
1149  //ensure the user never omitted the extension from the file name
1150  if ( !myOutputFileName.endsWith( QgsMapLayer::extensionPropertyType( QgsMapLayer::Metadata ), Qt::CaseInsensitive ) )
1151  {
1153  }
1154 
1155  QString myMessage;
1156  bool defaultLoadedFlag = false;
1157  myMessage = mLayer->saveNamedMetadata( myOutputFileName, defaultLoadedFlag );
1158 
1159  //reset if the default style was loaded OK only
1160  if ( defaultLoadedFlag )
1161  {
1162  syncToLayer();
1163  }
1164  else
1165  {
1166  //let the user know what went wrong
1167  QMessageBox::information( this, tr( "Save Metadata" ), myMessage );
1168  }
1169 
1170  QFileInfo myFI( myOutputFileName );
1171  QString myPath = myFI.path();
1172  // Persist last used dir
1173  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), myPath );
1174 }
1175 
1176 void QgsVectorLayerProperties::saveDefaultMetadata()
1177 {
1178  mMetadataWidget->acceptMetadata();
1179 
1180  bool defaultSavedFlag = false;
1181  QString errorMsg = mLayer->saveDefaultMetadata( defaultSavedFlag );
1182  if ( !defaultSavedFlag )
1183  {
1184  QMessageBox::warning( this, tr( "Default Metadata" ), errorMsg );
1185  }
1186 }
1187 
1188 void QgsVectorLayerProperties::loadDefaultMetadata()
1189 {
1190  bool defaultLoadedFlag = false;
1191  QString myMessage = mLayer->loadNamedMetadata( mLayer->metadataUri(), defaultLoadedFlag );
1192  //reset if the default metadata was loaded OK only
1193  if ( defaultLoadedFlag )
1194  {
1195  mMetadataWidget->setMetadata( &mLayer->metadata() );
1196  }
1197  else
1198  {
1199  QMessageBox::information( this, tr( "Default Metadata" ), myMessage );
1200  }
1201 }
1202 
1203 
1204 void QgsVectorLayerProperties::saveStyleAs()
1205 {
1206  if ( !mLayer->dataProvider() )
1207  return;
1208  QgsVectorLayerSaveStyleDialog dlg( mLayer );
1209  QgsSettings settings;
1210 
1211  if ( dlg.exec() )
1212  {
1213  apply();
1214 
1215  bool defaultLoadedFlag = false;
1216 
1217  StyleType type = dlg.currentStyleType();
1218  switch ( type )
1219  {
1220  case QML:
1221  case SLD:
1222  {
1223  QString message;
1224  QString filePath = dlg.outputFilePath();
1225  if ( type == QML )
1226  message = mLayer->saveNamedStyle( filePath, defaultLoadedFlag, dlg.styleCategories() );
1227  else
1228  message = mLayer->saveSldStyle( filePath, defaultLoadedFlag );
1229 
1230  //reset if the default style was loaded OK only
1231  if ( defaultLoadedFlag )
1232  {
1233  syncToLayer();
1234  }
1235  else
1236  {
1237  //let the user know what went wrong
1238  QMessageBox::information( this, tr( "Save Style" ), message );
1239  }
1240 
1241  break;
1242  }
1243  case DB:
1244  {
1245  QString infoWindowTitle = QObject::tr( "Save style to DB (%1)" ).arg( mLayer->providerType() );
1246  QString msgError;
1247 
1248  QgsVectorLayerSaveStyleDialog::SaveToDbSettings dbSettings = dlg.saveToDbSettings();
1249 
1250  QString errorMessage;
1251  if ( QgsProviderRegistry::instance()->styleExists( mLayer->providerType(), mLayer->source(), dbSettings.name, errorMessage ) )
1252  {
1253  if ( QMessageBox::question( nullptr, QObject::tr( "Save style in database" ),
1254  QObject::tr( "A matching style already exists in the database for this layer. Do you want to overwrite it?" ),
1255  QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
1256  {
1257  return;
1258  }
1259  }
1260  else if ( !errorMessage.isEmpty() )
1261  {
1262  mMessageBar->pushMessage( infoWindowTitle, errorMessage, Qgis::MessageLevel::Warning );
1263  return;
1264  }
1265 
1266  mLayer->saveStyleToDatabase( dbSettings.name, dbSettings.description, dbSettings.isDefault, dbSettings.uiFileContent, msgError );
1267 
1268  if ( !msgError.isNull() )
1269  {
1270  mMessageBar->pushMessage( infoWindowTitle, msgError, Qgis::MessageLevel::Warning );
1271  }
1272  else
1273  {
1274  mMessageBar->pushMessage( infoWindowTitle, tr( "Style saved" ), Qgis::MessageLevel::Success );
1275  }
1276  break;
1277  }
1278  }
1279  }
1280 }
1281 
1282 void QgsVectorLayerProperties::saveMultipleStylesAs()
1283 {
1284  QgsVectorLayerSaveStyleDialog dlg( mLayer );
1285  dlg.setSaveOnlyCurrentStyle( false );
1286  QgsSettings settings;
1287 
1288  if ( dlg.exec() )
1289  {
1290  apply();
1291 
1292  // Store the original style, that we can restore at the end
1293  const QString originalStyle { mLayer->styleManager()->currentStyle() };
1294  const QListWidget *stylesWidget { dlg.stylesWidget() };
1295 
1296  // Collect selected (checked) styles for export/save
1297  QStringList stylesSelected;
1298  for ( int i = 0; i < stylesWidget->count(); i++ )
1299  {
1300  if ( stylesWidget->item( i )->checkState() == Qt::CheckState::Checked )
1301  {
1302  stylesSelected.push_back( stylesWidget->item( i )->text() );
1303  }
1304  }
1305 
1306  if ( ! stylesSelected.isEmpty() )
1307  {
1308  int styleIndex = 0;
1309  for ( const QString &styleName : std::as_const( stylesSelected ) )
1310  {
1311  bool defaultLoadedFlag = false;
1312 
1313  StyleType type = dlg.currentStyleType();
1314  mLayer->styleManager()->setCurrentStyle( styleName );
1315  switch ( type )
1316  {
1317  case QML:
1318  case SLD:
1319  {
1320  QString message;
1321  const QString filePath { dlg.outputFilePath() };
1322  QString safePath { filePath };
1323  if ( styleIndex > 0 && stylesSelected.count( ) > 1 )
1324  {
1325  int i = 1;
1326  while ( QFile::exists( safePath ) )
1327  {
1328  const QFileInfo fi { filePath };
1329  safePath = QString( filePath ).replace( '.' + fi.completeSuffix(), QStringLiteral( "_%1.%2" )
1330  .arg( QString::number( i ) )
1331  .arg( fi.completeSuffix() ) );
1332  i++;
1333  }
1334  }
1335  if ( type == QML )
1336  message = mLayer->saveNamedStyle( safePath, defaultLoadedFlag, dlg.styleCategories() );
1337  else
1338  message = mLayer->saveSldStyle( safePath, defaultLoadedFlag );
1339 
1340  //reset if the default style was loaded OK only
1341  if ( defaultLoadedFlag )
1342  {
1343  syncToLayer();
1344  }
1345  else
1346  {
1347  //let the user know what went wrong
1348  QMessageBox::information( this, tr( "Save Style" ), message );
1349  }
1350 
1351  break;
1352  }
1353  case DB:
1354  {
1355  QString infoWindowTitle = QObject::tr( "Save style '%1' to DB (%2)" )
1356  .arg( styleName )
1357  .arg( mLayer->providerType() );
1358  QString msgError;
1359 
1360  QgsVectorLayerSaveStyleDialog::SaveToDbSettings dbSettings = dlg.saveToDbSettings();
1361 
1362  // If a name is defined, we add _1 etc. else we use the style name
1363  QString name { dbSettings.name };
1364  if ( name.isEmpty() )
1365  {
1366  name = styleName;
1367  }
1368  else
1369  {
1370  QStringList ids, names, descriptions;
1371  mLayer->listStylesInDatabase( ids, names, descriptions, msgError );
1372  int i = 1;
1373  while ( names.contains( name ) )
1374  {
1375  name = QStringLiteral( "%1 %2" ).arg( name ).arg( QString::number( i ) );
1376  i++;
1377  }
1378  }
1379 
1380  QString errorMessage;
1381  if ( QgsProviderRegistry::instance()->styleExists( mLayer->providerType(), mLayer->source(), dbSettings.name, errorMessage ) )
1382  {
1383  if ( QMessageBox::question( nullptr, QObject::tr( "Save style in database" ),
1384  QObject::tr( "A matching style already exists in the database for this layer. Do you want to overwrite it?" ),
1385  QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
1386  {
1387  return;
1388  }
1389  }
1390  else if ( !errorMessage.isEmpty() )
1391  {
1392  mMessageBar->pushMessage( infoWindowTitle, errorMessage, Qgis::MessageLevel::Warning );
1393  return;
1394  }
1395 
1396  mLayer->saveStyleToDatabase( name, dbSettings.description, dbSettings.isDefault, dbSettings.uiFileContent, msgError );
1397 
1398  if ( !msgError.isNull() )
1399  {
1400  mMessageBar->pushMessage( infoWindowTitle, msgError, Qgis::MessageLevel::Warning );
1401  }
1402  else
1403  {
1404  mMessageBar->pushMessage( infoWindowTitle, tr( "Style '%1' saved" ).arg( styleName ),
1405  Qgis::MessageLevel::Success );
1406  }
1407  break;
1408  }
1409  }
1410  styleIndex ++;
1411  }
1412  // Restore original style
1413  mLayer->styleManager()->setCurrentStyle( originalStyle );
1414  }
1415  } // Nothing selected!
1416 }
1417 
1418 void QgsVectorLayerProperties::aboutToShowStyleMenu()
1419 {
1420  // this should be unified with QgsRasterLayerProperties::aboutToShowStyleMenu()
1421  QMenu *m = qobject_cast<QMenu *>( sender() );
1422  m->clear();
1423 
1424  m->addAction( mActionLoadStyle );
1425  m->addAction( mActionSaveStyle );
1426 
1427  // If we have multiple styles, offer an option to save them at once
1428  if ( mLayer->styleManager()->styles().count() > 1 )
1429  {
1430  mActionSaveStyle->setText( tr( "Save Current Style…" ) );
1431  m->addAction( mActionSaveMultipleStyles );
1432  }
1433  else
1434  {
1435  mActionSaveStyle->setText( tr( "Save Style…" ) );
1436  }
1437 
1438  m->addSeparator();
1439  m->addAction( tr( "Save as Default" ), this, &QgsVectorLayerProperties::saveDefaultStyle_clicked );
1440  m->addAction( tr( "Restore Default" ), this, &QgsVectorLayerProperties::loadDefaultStyle_clicked );
1441 
1442  // re-add style manager actions!
1443  m->addSeparator();
1445 }
1446 
1447 void QgsVectorLayerProperties::loadStyle()
1448 {
1449  QgsSettings settings; // where we keep last used filter in persistent state
1450 
1451  QString errorMsg;
1452  QStringList ids, names, descriptions;
1453 
1454  //get the list of styles in the db
1455  int sectionLimit = mLayer->listStylesInDatabase( ids, names, descriptions, errorMsg );
1456  QgsMapLayerLoadStyleDialog dlg( mLayer );
1457  dlg.initializeLists( ids, names, descriptions, sectionLimit );
1458 
1459  if ( dlg.exec() )
1460  {
1461  mOldStyle = mLayer->styleManager()->style( mLayer->styleManager()->currentStyle() );
1462  QgsMapLayer::StyleCategories categories = dlg.styleCategories();
1463  StyleType type = dlg.currentStyleType();
1464  switch ( type )
1465  {
1466  case QML:
1467  case SLD:
1468  {
1469  QString message;
1470  bool defaultLoadedFlag = false;
1471  QString filePath = dlg.filePath();
1472  if ( type == SLD )
1473  {
1474  message = mLayer->loadSldStyle( filePath, defaultLoadedFlag );
1475  }
1476  else
1477  {
1478  message = mLayer->loadNamedStyle( filePath, defaultLoadedFlag, true, categories );
1479  }
1480  //reset if the default style was loaded OK only
1481  if ( defaultLoadedFlag )
1482  {
1483  syncToLayer();
1484  }
1485  else
1486  {
1487  //let the user know what went wrong
1488  QMessageBox::warning( this, tr( "Load Style" ), message );
1489  }
1490  break;
1491  }
1492  case DB:
1493  {
1494  QString selectedStyleId = dlg.selectedStyleId();
1495 
1496  QString qmlStyle = mLayer->getStyleFromDatabase( selectedStyleId, errorMsg );
1497  if ( !errorMsg.isNull() )
1498  {
1499  QMessageBox::warning( this, tr( "Load Styles from Database" ), errorMsg );
1500  return;
1501  }
1502 
1503  QDomDocument myDocument( QStringLiteral( "qgis" ) );
1504  myDocument.setContent( qmlStyle );
1505 
1506  if ( mLayer->importNamedStyle( myDocument, errorMsg, categories ) )
1507  {
1508  syncToLayer();
1509  }
1510  else
1511  {
1512  QMessageBox::warning( this, tr( "Load Styles from Database" ),
1513  tr( "The retrieved style is not a valid named style. Error message: %1" )
1514  .arg( errorMsg ) );
1515  }
1516  break;
1517  }
1518  }
1519  activateWindow(); // set focus back to properties dialog
1520  }
1521 }
1522 
1523 void QgsVectorLayerProperties::mButtonAddJoin_clicked()
1524 {
1525  if ( !mLayer )
1526  return;
1527 
1528  QList<QgsMapLayer *> joinedLayers;
1529  const QList< QgsVectorLayerJoinInfo > &joins = mLayer->vectorJoins();
1530  joinedLayers.reserve( joins.size() );
1531  for ( int i = 0; i < joins.size(); ++i )
1532  {
1533  joinedLayers.append( joins[i].joinLayer() );
1534  }
1535 
1536  QgsJoinDialog d( mLayer, joinedLayers );
1537  if ( d.exec() == QDialog::Accepted )
1538  {
1539  QgsVectorLayerJoinInfo info = d.joinInfo();
1540  //create attribute index if possible
1541  if ( d.createAttributeIndex() )
1542  {
1543  QgsVectorLayer *joinLayer = info.joinLayer();
1544  if ( joinLayer )
1545  {
1546  joinLayer->dataProvider()->createAttributeIndex( joinLayer->fields().indexFromName( info.joinFieldName() ) );
1547  }
1548  }
1549  mLayer->addJoin( info );
1550  addJoinToTreeWidget( info );
1551  setPbnQueryBuilderEnabled();
1552  mSourceFieldsPropertiesDialog->init();
1553  mAttributesFormPropertiesDialog->init();
1554  }
1555 }
1556 
1557 void QgsVectorLayerProperties::mButtonEditJoin_clicked()
1558 {
1559  QTreeWidgetItem *currentJoinItem = mJoinTreeWidget->currentItem();
1560  mJoinTreeWidget_itemDoubleClicked( currentJoinItem, 0 );
1561 }
1562 
1563 void QgsVectorLayerProperties::mJoinTreeWidget_itemDoubleClicked( QTreeWidgetItem *item, int )
1564 {
1565  if ( !mLayer || !item )
1566  {
1567  return;
1568  }
1569 
1570  QList<QgsMapLayer *> joinedLayers;
1571  QString joinLayerId = item->data( 0, Qt::UserRole ).toString();
1572  const QList< QgsVectorLayerJoinInfo > &joins = mLayer->vectorJoins();
1573  int j = -1;
1574  for ( int i = 0; i < joins.size(); ++i )
1575  {
1576  QgsVectorLayer *joinLayer = joins[i].joinLayer();
1577  if ( !joinLayer )
1578  continue; // invalid join (unresolved join layer)
1579 
1580  if ( joinLayer->id() == joinLayerId )
1581  {
1582  j = i;
1583  }
1584  else
1585  {
1586  // remove already joined layers from possible list to be displayed in dialog
1587  joinedLayers.append( joinLayer );
1588  }
1589  }
1590  if ( j == -1 )
1591  {
1592  return;
1593  }
1594 
1595  QgsJoinDialog d( mLayer, joinedLayers );
1596  d.setWindowTitle( tr( "Edit Vector Join" ) );
1597  d.setJoinInfo( joins[j] );
1598 
1599  if ( d.exec() == QDialog::Accepted )
1600  {
1601  QgsVectorLayerJoinInfo info = d.joinInfo();
1602 
1603  // remove old join
1604  mLayer->removeJoin( joinLayerId );
1605  int idx = mJoinTreeWidget->indexOfTopLevelItem( item );
1606  mJoinTreeWidget->takeTopLevelItem( idx );
1607 
1608  // add the new edited
1609 
1610  //create attribute index if possible
1611  if ( d.createAttributeIndex() )
1612  {
1613  QgsVectorLayer *joinLayer = info.joinLayer();
1614  if ( joinLayer )
1615  {
1616  joinLayer->dataProvider()->createAttributeIndex( joinLayer->fields().indexFromName( info.joinFieldName() ) );
1617  }
1618  }
1619  mLayer->addJoin( info );
1620  addJoinToTreeWidget( info, idx );
1621 
1622  setPbnQueryBuilderEnabled();
1623  mSourceFieldsPropertiesDialog->init();
1624  mAttributesFormPropertiesDialog->init();
1625  }
1626 }
1627 
1628 void QgsVectorLayerProperties::addJoinToTreeWidget( const QgsVectorLayerJoinInfo &join, const int insertIndex )
1629 {
1630  QTreeWidgetItem *joinItem = new QTreeWidgetItem();
1631  joinItem->setFlags( Qt::ItemIsEnabled );
1632 
1633  QgsVectorLayer *joinLayer = join.joinLayer();
1634  if ( !mLayer || !joinLayer )
1635  {
1636  return;
1637  }
1638 
1639  joinItem->setText( 0, tr( "Join layer" ) );
1640  if ( mLayer->auxiliaryLayer() && mLayer->auxiliaryLayer()->id() == join.joinLayerId() )
1641  {
1642  return;
1643  }
1644 
1645  joinItem->setText( 1, joinLayer->name() );
1646 
1647  QFont f = joinItem->font( 0 );
1648  f.setBold( true );
1649  joinItem->setFont( 0, f );
1650  joinItem->setFont( 1, f );
1651 
1652  joinItem->setData( 0, Qt::UserRole, join.joinLayerId() );
1653 
1654  QTreeWidgetItem *childJoinField = new QTreeWidgetItem();
1655  childJoinField->setText( 0, tr( "Join field" ) );
1656  childJoinField->setText( 1, join.joinFieldName() );
1657  childJoinField->setFlags( Qt::ItemIsEnabled );
1658  joinItem->addChild( childJoinField );
1659 
1660  QTreeWidgetItem *childTargetField = new QTreeWidgetItem();
1661  childTargetField->setText( 0, tr( "Target field" ) );
1662  childTargetField->setText( 1, join.targetFieldName() );
1663  joinItem->addChild( childTargetField );
1664 
1665  QTreeWidgetItem *childMemCache = new QTreeWidgetItem();
1666  childMemCache->setText( 0, tr( "Cache join layer in virtual memory" ) );
1667  if ( join.isUsingMemoryCache() )
1668  childMemCache->setText( 1, QChar( 0x2714 ) );
1669  joinItem->addChild( childMemCache );
1670 
1671  QTreeWidgetItem *childDynForm = new QTreeWidgetItem();
1672  childDynForm->setText( 0, tr( "Dynamic form" ) );
1673  if ( join.isDynamicFormEnabled() )
1674  childDynForm->setText( 1, QChar( 0x2714 ) );
1675  joinItem->addChild( childDynForm );
1676 
1677  QTreeWidgetItem *childEditable = new QTreeWidgetItem();
1678  childEditable->setText( 0, tr( "Editable join layer" ) );
1679  if ( join.isEditable() )
1680  childEditable->setText( 1, QChar( 0x2714 ) );
1681  joinItem->addChild( childEditable );
1682 
1683  QTreeWidgetItem *childUpsert = new QTreeWidgetItem();
1684  childUpsert->setText( 0, tr( "Upsert on edit" ) );
1685  if ( join.hasUpsertOnEdit() )
1686  childUpsert->setText( 1, QChar( 0x2714 ) );
1687  joinItem->addChild( childUpsert );
1688 
1689  QTreeWidgetItem *childCascade = new QTreeWidgetItem();
1690  childCascade->setText( 0, tr( "Delete cascade" ) );
1691  if ( join.hasCascadedDelete() )
1692  childCascade->setText( 1, QChar( 0x2714 ) );
1693  joinItem->addChild( childCascade );
1694 
1695  QTreeWidgetItem *childPrefix = new QTreeWidgetItem();
1696  childPrefix->setText( 0, tr( "Custom field name prefix" ) );
1697  childPrefix->setText( 1, join.prefix() );
1698  joinItem->addChild( childPrefix );
1699 
1700  QTreeWidgetItem *childFields = new QTreeWidgetItem();
1701  childFields->setText( 0, tr( "Joined fields" ) );
1702  const QStringList *list = join.joinFieldNamesSubset();
1703  if ( list )
1704  childFields->setText( 1, QLocale().toString( list->count() ) );
1705  else
1706  childFields->setText( 1, tr( "all" ) );
1707  joinItem->addChild( childFields );
1708 
1709  if ( insertIndex >= 0 )
1710  mJoinTreeWidget->insertTopLevelItem( insertIndex, joinItem );
1711  else
1712  mJoinTreeWidget->addTopLevelItem( joinItem );
1713 
1714  mJoinTreeWidget->setCurrentItem( joinItem );
1715  mJoinTreeWidget->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
1716 }
1717 
1718 QgsExpressionContext QgsVectorLayerProperties::createExpressionContext() const
1719 {
1720  return mContext;
1721 }
1722 
1723 void QgsVectorLayerProperties::openPanel( QgsPanelWidget *panel )
1724 {
1725  QDialog *dlg = new QDialog();
1726  QString key = QStringLiteral( "/UI/paneldialog/%1" ).arg( panel->panelTitle() );
1727  QgsSettings settings;
1728  dlg->restoreGeometry( settings.value( key ).toByteArray() );
1729  dlg->setWindowTitle( panel->panelTitle() );
1730  dlg->setLayout( new QVBoxLayout() );
1731  dlg->layout()->addWidget( panel );
1732  QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
1733  connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
1734  dlg->layout()->addWidget( buttonBox );
1735  dlg->exec();
1736  settings.setValue( key, dlg->saveGeometry() );
1737  panel->acceptPanel();
1738 }
1739 
1740 void QgsVectorLayerProperties::mButtonRemoveJoin_clicked()
1741 {
1742  QTreeWidgetItem *currentJoinItem = mJoinTreeWidget->currentItem();
1743  if ( !mLayer || !currentJoinItem )
1744  {
1745  return;
1746  }
1747 
1748  mLayer->removeJoin( currentJoinItem->data( 0, Qt::UserRole ).toString() );
1749  mJoinTreeWidget->takeTopLevelItem( mJoinTreeWidget->indexOfTopLevelItem( currentJoinItem ) );
1750  setPbnQueryBuilderEnabled();
1751  mSourceFieldsPropertiesDialog->init();
1752  mAttributesFormPropertiesDialog->init();
1753 }
1754 
1755 
1756 void QgsVectorLayerProperties::mButtonAddWmsDimension_clicked()
1757 {
1758  if ( !mLayer )
1759  return;
1760 
1761  // get wms dimensions name
1762  QStringList alreadyDefinedDimensions;
1763  QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
1764  const QList<QgsMapLayerServerProperties::WmsDimensionInfo> &dims = serverProperties->wmsDimensions();
1765  for ( const QgsMapLayerServerProperties::WmsDimensionInfo &dim : dims )
1766  {
1767  alreadyDefinedDimensions << dim.name;
1768  }
1769 
1770  QgsWmsDimensionDialog d( mLayer, alreadyDefinedDimensions );
1771  if ( d.exec() == QDialog::Accepted )
1772  {
1774  // save dimension
1775  serverProperties->addWmsDimension( info );
1776  addWmsDimensionInfoToTreeWidget( info );
1777  }
1778 }
1779 
1780 void QgsVectorLayerProperties::mButtonEditWmsDimension_clicked()
1781 {
1782  QTreeWidgetItem *currentWmsDimensionItem = mWmsDimensionsTreeWidget->currentItem();
1783  mWmsDimensionsTreeWidget_itemDoubleClicked( currentWmsDimensionItem, 0 );
1784 }
1785 
1786 void QgsVectorLayerProperties::mWmsDimensionsTreeWidget_itemDoubleClicked( QTreeWidgetItem *item, int )
1787 {
1788  if ( !mLayer || !item )
1789  {
1790  return;
1791  }
1792 
1793  QString wmsDimName = item->data( 0, Qt::UserRole ).toString();
1794  QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
1795  const QList<QgsMapLayerServerProperties::WmsDimensionInfo> &dims = serverProperties->wmsDimensions();
1796  QStringList alreadyDefinedDimensions;
1797  int j = -1;
1798  for ( int i = 0; i < dims.size(); ++i )
1799  {
1800  QString dimName = dims[i].name;
1801  if ( dimName == wmsDimName )
1802  {
1803  j = i;
1804  }
1805  else
1806  {
1807  alreadyDefinedDimensions << dimName;
1808  }
1809  }
1810  if ( j == -1 )
1811  {
1812  return;
1813  }
1814 
1815  QgsWmsDimensionDialog d( mLayer, alreadyDefinedDimensions );
1816  d.setWindowTitle( tr( "Edit WMS Dimension" ) );
1817  d.setInfo( dims[j] );
1818 
1819  if ( d.exec() == QDialog::Accepted )
1820  {
1822 
1823  // remove old
1824  QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
1825  serverProperties->removeWmsDimension( wmsDimName );
1826  int idx = mWmsDimensionsTreeWidget->indexOfTopLevelItem( item );
1827  mWmsDimensionsTreeWidget->takeTopLevelItem( idx );
1828 
1829  // save new
1830  serverProperties->addWmsDimension( info );
1831  addWmsDimensionInfoToTreeWidget( info, idx );
1832  }
1833 }
1834 
1835 void QgsVectorLayerProperties::addWmsDimensionInfoToTreeWidget( const QgsMapLayerServerProperties::WmsDimensionInfo &wmsDim, const int insertIndex )
1836 {
1837  QTreeWidgetItem *wmsDimensionItem = new QTreeWidgetItem();
1838  wmsDimensionItem->setFlags( Qt::ItemIsEnabled );
1839 
1840  wmsDimensionItem->setText( 0, tr( "Dimension" ) );
1841  wmsDimensionItem->setText( 1, wmsDim.name );
1842 
1843  QFont f = wmsDimensionItem->font( 0 );
1844  f.setBold( true );
1845  wmsDimensionItem->setFont( 0, f );
1846  wmsDimensionItem->setFont( 1, f );
1847 
1848  wmsDimensionItem->setData( 0, Qt::UserRole, wmsDim.name );
1849 
1850  QTreeWidgetItem *childWmsDimensionField = new QTreeWidgetItem();
1851  childWmsDimensionField->setText( 0, tr( "Field" ) );
1852  childWmsDimensionField->setText( 1, wmsDim.fieldName );
1853  childWmsDimensionField->setFlags( Qt::ItemIsEnabled );
1854  wmsDimensionItem->addChild( childWmsDimensionField );
1855 
1856  QTreeWidgetItem *childWmsDimensionEndField = new QTreeWidgetItem();
1857  childWmsDimensionEndField->setText( 0, tr( "End field" ) );
1858  childWmsDimensionEndField->setText( 1, wmsDim.endFieldName );
1859  childWmsDimensionEndField->setFlags( Qt::ItemIsEnabled );
1860  wmsDimensionItem->addChild( childWmsDimensionEndField );
1861 
1862  QTreeWidgetItem *childWmsDimensionUnits = new QTreeWidgetItem();
1863  childWmsDimensionUnits->setText( 0, tr( "Units" ) );
1864  childWmsDimensionUnits->setText( 1, wmsDim.units );
1865  childWmsDimensionUnits->setFlags( Qt::ItemIsEnabled );
1866  wmsDimensionItem->addChild( childWmsDimensionUnits );
1867 
1868  QTreeWidgetItem *childWmsDimensionUnitSymbol = new QTreeWidgetItem();
1869  childWmsDimensionUnitSymbol->setText( 0, tr( "Unit symbol" ) );
1870  childWmsDimensionUnitSymbol->setText( 1, wmsDim.unitSymbol );
1871  childWmsDimensionUnitSymbol->setFlags( Qt::ItemIsEnabled );
1872  wmsDimensionItem->addChild( childWmsDimensionUnitSymbol );
1873 
1874  QTreeWidgetItem *childWmsDimensionDefaultValue = new QTreeWidgetItem();
1875  childWmsDimensionDefaultValue->setText( 0, tr( "Default display" ) );
1876  childWmsDimensionDefaultValue->setText( 1, QgsMapLayerServerProperties::wmsDimensionDefaultDisplayLabels()[wmsDim.defaultDisplayType] );
1877  childWmsDimensionDefaultValue->setFlags( Qt::ItemIsEnabled );
1878  wmsDimensionItem->addChild( childWmsDimensionDefaultValue );
1879 
1880  QTreeWidgetItem *childWmsDimensionRefValue = new QTreeWidgetItem();
1881  childWmsDimensionRefValue->setText( 0, tr( "Reference value" ) );
1882  childWmsDimensionRefValue->setText( 1, wmsDim.referenceValue.toString() );
1883  childWmsDimensionRefValue->setFlags( Qt::ItemIsEnabled );
1884  wmsDimensionItem->addChild( childWmsDimensionRefValue );
1885 
1886  if ( insertIndex >= 0 )
1887  mWmsDimensionsTreeWidget->insertTopLevelItem( insertIndex, wmsDimensionItem );
1888  else
1889  mWmsDimensionsTreeWidget->addTopLevelItem( wmsDimensionItem );
1890 
1891  mWmsDimensionsTreeWidget->setCurrentItem( wmsDimensionItem );
1892  mWmsDimensionsTreeWidget->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
1893 }
1894 
1895 void QgsVectorLayerProperties::mButtonRemoveWmsDimension_clicked()
1896 {
1897  QTreeWidgetItem *currentWmsDimensionItem = mWmsDimensionsTreeWidget->currentItem();
1898  if ( !mLayer || !currentWmsDimensionItem )
1899  {
1900  return;
1901  }
1902 
1903  QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
1904  serverProperties->removeWmsDimension( currentWmsDimensionItem->data( 0, Qt::UserRole ).toString() );
1905  mWmsDimensionsTreeWidget->takeTopLevelItem( mWmsDimensionsTreeWidget->indexOfTopLevelItem( currentWmsDimensionItem ) );
1906 }
1907 
1908 
1909 void QgsVectorLayerProperties::updateSymbologyPage()
1910 {
1911 
1912  //find out the type of renderer in the vectorlayer, create a dialog with these settings and add it to the form
1913  delete mRendererDialog;
1914  mRendererDialog = nullptr;
1915 
1916  if ( mLayer->renderer() )
1917  {
1918  mRendererDialog = new QgsRendererPropertiesDialog( mLayer, QgsStyle::defaultStyle(), true, this );
1919  mRendererDialog->setDockMode( false );
1920  QgsSymbolWidgetContext context;
1921  context.setMapCanvas( mCanvas );
1922  context.setMessageBar( mMessageBar );
1923  mRendererDialog->setContext( context );
1924  connect( mRendererDialog, &QgsRendererPropertiesDialog::showPanel, this, &QgsVectorLayerProperties::openPanel );
1925  connect( mRendererDialog, &QgsRendererPropertiesDialog::layerVariablesChanged, this, &QgsVectorLayerProperties::updateVariableEditor );
1926  connect( mRendererDialog, &QgsRendererPropertiesDialog::widgetChanged, this, [ = ] { updateAuxiliaryStoragePage(); } );
1927  }
1928  else
1929  {
1930  mOptsPage_Style->setEnabled( false ); // hide symbology item
1931  }
1932 
1933  if ( mRendererDialog )
1934  {
1935  mRendererDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
1936  widgetStackRenderers->addWidget( mRendererDialog );
1937  widgetStackRenderers->setCurrentWidget( mRendererDialog );
1938  widgetStackRenderers->currentWidget()->layout()->setContentsMargins( 0, 0, 0, 0 );
1939  }
1940 }
1941 
1942 void QgsVectorLayerProperties::setPbnQueryBuilderEnabled()
1943 {
1944  pbnQueryBuilder->setEnabled( mLayer &&
1945  mLayer->dataProvider() &&
1946  mLayer->dataProvider()->supportsSubsetString() &&
1947  !mLayer->isEditable() );
1948 
1949  if ( mLayer && mLayer->isEditable() )
1950  {
1951  pbnQueryBuilder->setToolTip( tr( "Stop editing mode to enable this." ) );
1952  }
1953 
1954 }
1955 
1956 void QgsVectorLayerProperties::pbnUpdateExtents_clicked()
1957 {
1958  mLayer->updateExtents( true ); // force update whatever options activated
1959  mMetadataFilled = false;
1960 }
1961 
1963 {
1965 
1966  bool isMetadataPanel = ( index == mOptStackedWidget->indexOf( mOptsPage_Metadata ) );
1967  mBtnStyle->setVisible( ! isMetadataPanel );
1968  mBtnMetadata->setVisible( isMetadataPanel );
1969 
1970  if ( index == mOptStackedWidget->indexOf( mOptsPage_Information ) && ! mMetadataFilled )
1971  {
1972  //set the metadata contents (which can be expensive)
1973  teMetadataViewer->clear();
1974  teMetadataViewer->setHtml( htmlMetadata() );
1975  mMetadataFilled = true;
1976  }
1977 
1978  resizeAlltabs( index );
1979 }
1980 
1981 void QgsVectorLayerProperties::mSimplifyDrawingGroupBox_toggled( bool checked )
1982 {
1983  const QgsVectorDataProvider *provider = mLayer->dataProvider();
1984  if ( !( provider && ( provider->capabilities() & QgsVectorDataProvider::SimplifyGeometries ) != 0 ) )
1985  {
1986  mSimplifyDrawingAtProvider->setEnabled( false );
1987  }
1988  else
1989  {
1990  mSimplifyDrawingAtProvider->setEnabled( checked );
1991  }
1992 }
1993 
1994 void QgsVectorLayerProperties::updateVariableEditor()
1995 {
1996  QgsExpressionContext context;
1997  mVariableEditor->setContext( &context );
1998  mVariableEditor->context()->appendScope( QgsExpressionContextUtils::globalScope() );
1999  mVariableEditor->context()->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
2000  mVariableEditor->context()->appendScope( QgsExpressionContextUtils::layerScope( mLayer ) );
2001  mVariableEditor->reloadContext();
2002  mVariableEditor->setEditableScopeIndex( 2 );
2003 }
2004 
2005 void QgsVectorLayerProperties::showHelp()
2006 {
2007  const QVariant helpPage = mOptionsStackedWidget->currentWidget()->property( "helpPage" );
2008 
2009  if ( helpPage.isValid() )
2010  {
2011  QgsHelp::openHelp( helpPage.toString() );
2012  }
2013  else
2014  {
2015  QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html" ) );
2016  }
2017 }
2018 
2019 void QgsVectorLayerProperties::updateAuxiliaryStoragePage()
2020 {
2021  const QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2022 
2023  if ( alayer )
2024  {
2025  // set widgets to enable state
2026  mAuxiliaryStorageInformationGrpBox->setEnabled( true );
2027  mAuxiliaryStorageFieldsGrpBox->setEnabled( true );
2028 
2029  // update key
2030  mAuxiliaryStorageKeyLineEdit->setText( alayer->joinInfo().targetFieldName() );
2031 
2032  // update feature count
2033  const qlonglong features = alayer->featureCount();
2034  mAuxiliaryStorageFeaturesLineEdit->setText( QLocale().toString( features ) );
2035 
2036  // update actions
2037  mAuxiliaryLayerActionClear->setEnabled( true );
2038  mAuxiliaryLayerActionDelete->setEnabled( true );
2039  mAuxiliaryLayerActionExport->setEnabled( true );
2040  mAuxiliaryLayerActionNew->setEnabled( false );
2041 
2042  const QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2043  if ( alayer )
2044  {
2045  const int fields = alayer->auxiliaryFields().count();
2046  mAuxiliaryStorageFieldsLineEdit->setText( QLocale().toString( fields ) );
2047 
2048  // add fields
2049  mAuxiliaryStorageFieldsTree->clear();
2050  for ( const QgsField &field : alayer->auxiliaryFields() )
2051  {
2053  QTreeWidgetItem *item = new QTreeWidgetItem();
2054 
2055  item->setText( 0, prop.origin() );
2056  item->setText( 1, prop.name() );
2057  item->setText( 2, prop.comment() );
2058  item->setText( 3, field.typeName() );
2059  item->setText( 4, field.name() );
2060 
2061  mAuxiliaryStorageFieldsTree->addTopLevelItem( item );
2062  }
2063  }
2064  }
2065  else
2066  {
2067  mAuxiliaryStorageInformationGrpBox->setEnabled( false );
2068  mAuxiliaryStorageFieldsGrpBox->setEnabled( false );
2069 
2070  mAuxiliaryLayerActionClear->setEnabled( false );
2071  mAuxiliaryLayerActionDelete->setEnabled( false );
2072  mAuxiliaryLayerActionExport->setEnabled( false );
2073  mAuxiliaryLayerActionNew->setEnabled( true );
2074 
2075  mAuxiliaryStorageFieldsTree->clear();
2076  mAuxiliaryStorageKeyLineEdit->setText( QString() );
2077  mAuxiliaryStorageFieldsLineEdit->setText( QString() );
2078  mAuxiliaryStorageFeaturesLineEdit->setText( QString() );
2079  }
2080 }
2081 
2082 void QgsVectorLayerProperties::onAuxiliaryLayerNew()
2083 {
2084  QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2085 
2086  if ( alayer )
2087  return;
2088 
2089  QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
2090  if ( dlg.exec() == QDialog::Accepted )
2091  {
2092  updateAuxiliaryStoragePage();
2093  }
2094 }
2095 
2096 void QgsVectorLayerProperties::onAuxiliaryLayerClear()
2097 {
2098  QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2099 
2100  if ( !alayer )
2101  return;
2102 
2103  const QString msg = tr( "Are you sure you want to clear auxiliary data for %1?" ).arg( mLayer->name() );
2104  QMessageBox::StandardButton reply;
2105  reply = QMessageBox::question( this, "Clear Auxiliary Data", msg, QMessageBox::Yes | QMessageBox::No );
2106 
2107  if ( reply == QMessageBox::Yes )
2108  {
2109  QApplication::setOverrideCursor( Qt::WaitCursor );
2110  alayer->clear();
2111  QApplication::restoreOverrideCursor();
2112  updateAuxiliaryStoragePage();
2113  mLayer->triggerRepaint();
2114  }
2115 }
2116 
2117 void QgsVectorLayerProperties::onAuxiliaryLayerDelete()
2118 {
2119  QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2120  if ( !alayer )
2121  return;
2122 
2123  const QString msg = tr( "Are you sure you want to delete auxiliary storage for %1?" ).arg( mLayer->name() );
2124  QMessageBox::StandardButton reply;
2125  reply = QMessageBox::question( this, "Delete Auxiliary Storage", msg, QMessageBox::Yes | QMessageBox::No );
2126 
2127  if ( reply == QMessageBox::Yes )
2128  {
2129  QApplication::setOverrideCursor( Qt::WaitCursor );
2130  QgsDataSourceUri uri( alayer->source() );
2131 
2132  // delete each attribute to correctly update layer settings and data
2133  // defined buttons
2134  while ( alayer->auxiliaryFields().size() > 0 )
2135  {
2136  QgsField aField = alayer->auxiliaryFields()[0];
2137  deleteAuxiliaryField( alayer->fields().indexOf( aField.name() ) );
2138  }
2139 
2140  mLayer->setAuxiliaryLayer(); // remove auxiliary layer
2142  QApplication::restoreOverrideCursor();
2143  updateAuxiliaryStoragePage();
2144  mLayer->triggerRepaint();
2145  }
2146 }
2147 
2148 void QgsVectorLayerProperties::onAuxiliaryLayerDeleteField()
2149 {
2150  QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2151  if ( !alayer )
2152  return;
2153 
2154  QList<QTreeWidgetItem *> items = mAuxiliaryStorageFieldsTree->selectedItems();
2155  if ( items.count() < 1 )
2156  return;
2157 
2158  // get auxiliary field name and index from item
2159  const QTreeWidgetItem *item = items[0];
2161  def.setOrigin( item->text( 0 ) );
2162  def.setName( item->text( 1 ) );
2163  def.setComment( item->text( 2 ) );
2164 
2165  const QString fieldName = QgsAuxiliaryLayer::nameFromProperty( def );
2166 
2167  const int index = mLayer->auxiliaryLayer()->fields().indexOf( fieldName );
2168  if ( index < 0 )
2169  return;
2170 
2171  // should be only 1 field
2172  const QString msg = tr( "Are you sure you want to delete auxiliary field %1 for %2?" ).arg( item->text( 1 ), item->text( 0 ) );
2173 
2174  QMessageBox::StandardButton reply;
2175  const QString title = QObject::tr( "Delete Auxiliary Field" );
2176  reply = QMessageBox::question( this, title, msg, QMessageBox::Yes | QMessageBox::No );
2177 
2178  if ( reply == QMessageBox::Yes )
2179  {
2180  QApplication::setOverrideCursor( Qt::WaitCursor );
2181  deleteAuxiliaryField( index );
2182  mLayer->triggerRepaint();
2183  QApplication::restoreOverrideCursor();
2184  }
2185 }
2186 
2187 void QgsVectorLayerProperties::onAuxiliaryLayerAddField()
2188 {
2189  QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
2190  if ( !alayer )
2191  return;
2192 
2193  QgsNewAuxiliaryFieldDialog dlg( QgsPropertyDefinition(), mLayer, false );
2194  if ( dlg.exec() == QDialog::Accepted )
2195  {
2196  updateAuxiliaryStoragePage();
2197  }
2198 }
2199 
2200 void QgsVectorLayerProperties::deleteAuxiliaryField( int index )
2201 {
2202  if ( !mLayer->auxiliaryLayer() )
2203  return;
2204 
2205  int key = mLayer->auxiliaryLayer()->propertyFromIndex( index );
2207 
2208  if ( mLayer->auxiliaryLayer()->deleteAttribute( index ) )
2209  {
2210  mLayer->updateFields();
2211 
2212  // immediately deactivate data defined button
2213  if ( key >= 0 && def.origin().compare( "labeling", Qt::CaseInsensitive ) == 0
2214  && labelingDialog
2215  && labelingDialog->labelingGui() )
2216  {
2217  labelingDialog->labelingGui()->deactivateField( static_cast<QgsPalLayerSettings::Property>( key ) );
2218  }
2219 
2220  updateAuxiliaryStoragePage();
2221  mSourceFieldsPropertiesDialog->init();
2222  }
2223  else
2224  {
2225  const QString title = QObject::tr( "Delete Auxiliary Field" );
2226  const QString errors = mLayer->auxiliaryLayer()->commitErrors().join( QLatin1String( "\n " ) );
2227  const QString msg = QObject::tr( "Unable to remove auxiliary field (%1)" ).arg( errors );
2228  mMessageBar->pushMessage( title, msg, Qgis::MessageLevel::Warning );
2229  }
2230 }
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:426
void setForceRasterRender(bool forceRaster)
Sets whether the renderer should be rendered to a raster destination.
Definition: qgsrenderer.h:436
double referenceScale() const
Returns the symbology reference scale.
Definition: qgsrenderer.h:452
void setReferenceScale(double scale)
Sets the symbology reference scale.
Definition: qgsrenderer.h:468
@ 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:104
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:74
static QgsSubsetStringEditorProviderRegistry * subsetStringEditorProviderRegistry()
Returns the registry of subset string editors of data providers.
Definition: qgsgui.cpp:99
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.
bool isDefault(const QString &styleName) const
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:1284
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:1269
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
virtual QString saveDefaultStyle(bool &resultFlag)
Save the properties of this layer as the default style (either as a .qml file on disk or as a record ...
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:1446
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:1593
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:1439
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:1274
void setLegendUrlFormat(const QString &legendUrlFormat)
Sets the format for a URL based layer legend.
Definition: qgsmaplayer.h:1279
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
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:470
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:521
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:131
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.
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 saveStyleToDatabase(const QString &name, const QString &description, bool useAsDefault, const QString &uiFileContent, QString &msgError)
Saves named and sld style of the layer to the style table in the db.
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...
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.