QGIS API Documentation 3.99.0-Master (26c88405ac0)
Loading...
Searching...
No Matches
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
20
21#include <limits>
22#include <memory>
23
24#include "qgsactionmanager.h"
25#include "qgsapplication.h"
29#include "qgsauxiliarystorage.h"
30#include "qgsdatasourceuri.h"
32#include "qgsdiagramwidget.h"
35#include "qgsexpressionfinder.h"
36#include "qgsfileutils.h"
37#include "qgsgui.h"
38#include "qgsjoindialog.h"
39#include "qgslabelinggui.h"
40#include "qgslabelingwidget.h"
41#include "qgslayertreemodel.h"
42#include "qgsmapcanvas.h"
47#include "qgsmaptip.h"
48#include "qgsmaskingwidget.h"
49#include "qgsmessagebar.h"
50#include "qgsmetadatawidget.h"
51#include "qgsnative.h"
54#include "qgsproject.h"
55#include "qgsproviderregistry.h"
58#include "qgsrenderer.h"
60#include "qgssettings.h"
62#include "qgsstyle.h"
67#include "qgsvectorlayer.h"
71#include "qgswebframe.h"
72#include "qgswebview.h"
74
75#include "moc_qgsvectorlayerproperties.cpp"
76
77#if WITH_QTWEBKIT
78#include <QWebElement>
79#endif
80
81#include <QDesktopServices>
82#include <QMessageBox>
83#include <QDir>
84#include <QFile>
85#include <QFileDialog>
86#include <QFileInfo>
87#include <QFontDialog>
88#include <QComboBox>
89#include <QCheckBox>
90#include <QHeaderView>
91#include <QColorDialog>
92#include <QMenu>
93#include <QUrl>
94#include <QRegularExpressionValidator>
95
96
98 QgsMapCanvas *canvas,
99 QgsMessageBar *messageBar,
100 QgsVectorLayer *lyr,
101 QWidget *parent,
102 Qt::WindowFlags fl
103)
104 : QgsLayerPropertiesDialog( lyr, canvas, QStringLiteral( "VectorLayerProperties" ), parent, fl )
105 , mMessageBar( messageBar )
106 , mLayer( lyr )
107 , mOriginalSubsetSQL( lyr->subsetString() )
108{
109 setupUi( this );
110 connect( pbnQueryBuilder, &QPushButton::clicked, this, &QgsVectorLayerProperties::pbnQueryBuilder_clicked );
111 connect( pbnIndex, &QPushButton::clicked, this, &QgsVectorLayerProperties::pbnIndex_clicked );
112 connect( mCrsSelector, &QgsProjectionSelectionWidget::crsChanged, this, &QgsVectorLayerProperties::mCrsSelector_crsChanged );
113 connect( pbnUpdateExtents, &QPushButton::clicked, this, &QgsVectorLayerProperties::pbnUpdateExtents_clicked );
114 connect( mButtonAddJoin, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonAddJoin_clicked );
115 connect( mButtonEditJoin, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonEditJoin_clicked );
116 connect( mJoinTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QgsVectorLayerProperties::mJoinTreeWidget_itemDoubleClicked );
117 connect( mButtonRemoveJoin, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonRemoveJoin_clicked );
118 connect( mButtonAddWmsDimension, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonAddWmsDimension_clicked );
119 connect( mButtonEditWmsDimension, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonEditWmsDimension_clicked );
120 connect( mWmsDimensionsTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QgsVectorLayerProperties::mWmsDimensionsTreeWidget_itemDoubleClicked );
121 connect( mButtonRemoveWmsDimension, &QPushButton::clicked, this, &QgsVectorLayerProperties::mButtonRemoveWmsDimension_clicked );
122 connect( mSimplifyDrawingGroupBox, &QGroupBox::toggled, this, &QgsVectorLayerProperties::mSimplifyDrawingGroupBox_toggled );
123 connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsVectorLayerProperties::showHelp );
124
125 mProjectDirtyBlocker = std::make_unique<QgsProjectDirtyBlocker>( QgsProject::instance() );
126
127 // QgsOptionsDialogBase handles saving/restoring of geometry, splitter and current tab states,
128 // switching vertical tabs between icon/text to icon-only modes (splitter collapsed to left),
129 // and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
130 initOptionsBase( false );
131
132 mBtnStyle = new QPushButton( tr( "Style" ), this );
133 QMenu *menuStyle = new QMenu( this );
134 mActionLoadStyle = new QAction( tr( "Load Style…" ), this );
135 connect( mActionLoadStyle, &QAction::triggered, this, &QgsVectorLayerProperties::loadStyle );
136
137 mActionSaveStyle = new QAction( tr( "Save Current Style…" ), this );
138 connect( mActionSaveStyle, &QAction::triggered, this, &QgsVectorLayerProperties::saveStyleAs );
139
140 mActionSaveMultipleStyles = new QAction( tr( "Save Multiple Styles…" ), this );
141 connect( mActionSaveMultipleStyles, &QAction::triggered, this, &QgsVectorLayerProperties::saveMultipleStylesAs );
142
143 mSourceGroupBox->hide();
144
145 mBtnStyle->setMenu( menuStyle );
146 connect( menuStyle, &QMenu::aboutToShow, this, &QgsVectorLayerProperties::aboutToShowStyleMenu );
147 buttonBox->addButton( mBtnStyle, QDialogButtonBox::ResetRole );
148
150
151 connect( buttonBox->button( QDialogButtonBox::Apply ), &QAbstractButton::clicked, this, &QgsVectorLayerProperties::apply );
152 connect( this, &QDialog::accepted, this, &QgsVectorLayerProperties::apply );
153 connect( this, &QDialog::rejected, this, &QgsVectorLayerProperties::rollback );
154
155 if ( mCanvas )
156 {
157 mContext = mCanvas->createExpressionContext();
158 }
159 else
160 {
165 }
166 mContext << QgsExpressionContextUtils::layerScope( mLayer );
167
168 mMapTipFieldComboBox->setLayer( lyr );
169 mDisplayExpressionWidget->setLayer( lyr );
170 mDisplayExpressionWidget->registerExpressionContextGenerator( this );
171 initMapTipPreview();
172
173 mFeaturesSortOrderExpressionWidget->setLayer( lyr );
174 mFeaturesSortOrderExpressionWidget->registerExpressionContextGenerator( this );
175 connect( mFeaturesSortOrderDirectionButton, &QAbstractButton::clicked, this, [this]() {
176 mFeaturesSortOrderDirectionButton->setArrowType( mFeaturesSortOrderDirectionButton->arrowType() == Qt::UpArrow ? Qt::DownArrow : Qt::UpArrow );
177 } );
178
179 connect( mMapTipInsertFieldButton, &QAbstractButton::clicked, this, &QgsVectorLayerProperties::insertField );
180 connect( mMapTipInsertExpressionButton, &QAbstractButton::clicked, this, &QgsVectorLayerProperties::insertOrEditExpression );
181
182 if ( !mLayer )
183 return;
184
185 mEnableMapTips->setChecked( mLayer->mapTipsEnabled() );
186
187 QVBoxLayout *layout = nullptr;
188
189 if ( mLayer->isSpatial() )
190 {
191 // Create the Labeling dialog tab
192 layout = new QVBoxLayout( labelingFrame );
193 layout->setContentsMargins( 0, 0, 0, 0 );
194 labelingDialog = new QgsLabelingWidget( mLayer, mCanvas, labelingFrame );
195 labelingDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
196 connect( labelingDialog, &QgsLabelingWidget::auxiliaryFieldCreated, this, [this] { updateAuxiliaryStoragePage(); } );
197 layout->addWidget( labelingDialog );
198 labelingFrame->setLayout( layout );
199
200 // Create the masking dialog tab
201 layout = new QVBoxLayout( mMaskingFrame );
202 layout->setContentsMargins( 0, 0, 0, 0 );
203 mMaskingWidget = new QgsMaskingWidget( mMaskingFrame );
204 mMaskingWidget->setLayer( mLayer );
205 mMaskingWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
206 layout->addWidget( mMaskingWidget );
207 mMaskingFrame->setLayout( layout );
208 }
209 else
210 {
211 labelingDialog = nullptr;
212 mOptsPage_Labels->setEnabled( false ); // disable labeling item
213 mOptsPage_Masks->setEnabled( false ); // disable masking item
214 mGeomGroupBox->setEnabled( false );
215 mGeomGroupBox->setVisible( false );
216 mCrsGroupBox->setEnabled( false );
217 mCrsGroupBox->setVisible( false );
218 }
219
220 // Create the Actions dialog tab
221 QVBoxLayout *actionLayout = new QVBoxLayout( actionOptionsFrame );
222 actionLayout->setContentsMargins( 0, 0, 0, 0 );
223 mActionDialog = new QgsAttributeActionDialog( *mLayer->actions(), actionOptionsFrame );
224 mActionDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
225 actionLayout->addWidget( mActionDialog );
226
227 mSourceFieldsPropertiesDialog = new QgsSourceFieldsProperties( mLayer, mSourceFieldsFrame );
228 mSourceFieldsPropertiesDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
229 mSourceFieldsFrame->setLayout( new QVBoxLayout( mSourceFieldsFrame ) );
230 mSourceFieldsFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
231 mSourceFieldsFrame->layout()->addWidget( mSourceFieldsPropertiesDialog );
232
233 connect( mSourceFieldsPropertiesDialog, &QgsSourceFieldsProperties::toggleEditing, this, static_cast<void ( QgsVectorLayerProperties::* )()>( &QgsVectorLayerProperties::toggleEditing ) );
234
235 mAttributesFormPropertiesDialog = new QgsAttributesFormProperties( mLayer, mAttributesFormFrame );
236 mAttributesFormPropertiesDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
237 mAttributesFormFrame->setLayout( new QVBoxLayout( mAttributesFormFrame ) );
238 mAttributesFormFrame->layout()->setContentsMargins( 0, 0, 0, 0 );
239 mAttributesFormFrame->layout()->addWidget( mAttributesFormPropertiesDialog );
240
241 // Metadata tab, before the syncToLayer
242 QVBoxLayout *metadataLayout = new QVBoxLayout( metadataFrame );
243 metadataLayout->setContentsMargins( 0, 0, 0, 0 );
244 mMetadataWidget = new QgsMetadataWidget( this, mLayer );
245 mMetadataWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
246 mMetadataWidget->setMapCanvas( mCanvas );
247 metadataLayout->addWidget( mMetadataWidget );
248 metadataFrame->setLayout( metadataLayout );
249
250 QVBoxLayout *temporalLayout = new QVBoxLayout( temporalFrame );
251 temporalLayout->setContentsMargins( 0, 0, 0, 0 );
252 mTemporalWidget = new QgsVectorLayerTemporalPropertiesWidget( this, mLayer );
253 temporalLayout->addWidget( mTemporalWidget );
254
255 setMetadataWidget( mMetadataWidget, mOptsPage_Metadata );
256
257 mBtnMetadata = new QPushButton( tr( "Metadata" ), this );
258 QMenu *menuMetadata = new QMenu( this );
259 mActionLoadMetadata = menuMetadata->addAction( tr( "Load Metadata from File…" ), this, &QgsVectorLayerProperties::loadMetadataFromFile );
260 mActionSaveMetadataAs = menuMetadata->addAction( tr( "Save Metadata to File…" ), this, &QgsVectorLayerProperties::saveMetadataToFile );
261 menuMetadata->addSeparator();
262 menuMetadata->addAction( tr( "Save to Default Location" ), this, &QgsVectorLayerProperties::saveMetadataAsDefault );
263 menuMetadata->addAction( tr( "Restore from Default Location" ), this, &QgsVectorLayerProperties::loadDefaultMetadata );
264 mBtnMetadata->setMenu( menuMetadata );
265 buttonBox->addButton( mBtnMetadata, QDialogButtonBox::ResetRole );
266
267 mSelectionColorButton->setAllowOpacity( true );
268 mSelectionColorButton->setColorDialogTitle( tr( "Override Selection Color" ) );
269 if ( mCanvas )
270 {
271 mSelectionColorButton->setColor( mCanvas->selectionColor() );
272 mSelectionColorButton->setDefaultColor( mCanvas->selectionColor() );
273 }
274 connect( mRadioOverrideSelectionColor, &QRadioButton::toggled, mSelectionColorButton, &QWidget::setEnabled );
275 mSelectionColorButton->setEnabled( false );
276 connect( mRadioOverrideSelectionSymbol, &QRadioButton::toggled, mSelectionSymbolButton, &QWidget::setEnabled );
277 switch ( mLayer->geometryType() )
278 {
280 mSelectionSymbolButton->setSymbolType( Qgis::SymbolType::Marker );
281 break;
283 mSelectionSymbolButton->setSymbolType( Qgis::SymbolType::Line );
284 break;
286 mSelectionSymbolButton->setSymbolType( Qgis::SymbolType::Fill );
287 break;
288
291 break;
292 }
293 mSelectionSymbolButton->setEnabled( false );
294 mRadioDefaultSelectionColor->setChecked( true );
295
296 // Diagram tab, before the syncToLayer
297 QVBoxLayout *diagLayout = new QVBoxLayout( mDiagramFrame );
298 diagLayout->setContentsMargins( 0, 0, 0, 0 );
299 diagramPropertiesDialog = new QgsDiagramWidget( mLayer, mCanvas, mDiagramFrame );
300 diagramPropertiesDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
301 connect( diagramPropertiesDialog, &QgsDiagramWidget::auxiliaryFieldCreated, this, [this] { updateAuxiliaryStoragePage(); } );
302 diagLayout->addWidget( diagramPropertiesDialog );
303 mDiagramFrame->setLayout( diagLayout );
304
305 syncToLayer();
306
307 if ( mLayer->dataProvider() )
308 {
309 //enable spatial index button group if supported by provider, or if one already exists
310 Qgis::VectorProviderCapabilities capabilities = mLayer->dataProvider()->capabilities();
312 {
313 pbnIndex->setEnabled( false );
314 }
315 if ( mLayer->dataProvider()->hasSpatialIndex() == Qgis::SpatialIndexPresence::Present )
316 {
317 pbnIndex->setEnabled( false );
318 pbnIndex->setText( tr( "Spatial Index Exists" ) );
319 }
320
322 {
323 cboProviderEncoding->addItems( QgsVectorDataProvider::availableEncodings() );
324 QString enc = mLayer->dataProvider()->encoding();
325 int encindex = cboProviderEncoding->findText( enc );
326 if ( encindex < 0 )
327 {
328 cboProviderEncoding->insertItem( 0, enc );
329 encindex = 0;
330 }
331 cboProviderEncoding->setCurrentIndex( encindex );
332 }
333 else if ( mLayer->providerType() == QLatin1String( "ogr" ) )
334 {
335 // if OGR_L_TestCapability(OLCStringsAsUTF8) returns true, OGR provider encoding can be set to only UTF-8
336 // so make encoding box grayed out
337 cboProviderEncoding->addItem( mLayer->dataProvider()->encoding() );
338 cboProviderEncoding->setEnabled( false );
339 }
340 else
341 {
342 // other providers do not use mEncoding, so hide the group completely
343 mDataSourceEncodingFrame->hide();
344 }
345 }
346
347 mCrsSelector->setCrs( mLayer->crs() );
348
349 //insert existing join info
350 const QList<QgsVectorLayerJoinInfo> &joins = mLayer->vectorJoins();
351 for ( const QgsVectorLayerJoinInfo &join : joins )
352 {
353 addJoinToTreeWidget( join );
354 }
355
356 mOldJoins = mLayer->vectorJoins();
357
358 // Legend tab
359 mLegendWidget->setMapCanvas( mCanvas );
360 mLegendWidget->setLayer( mLayer );
361 mLegendConfigEmbeddedWidget->setLayer( mLayer );
362
363 //insert existing dimension info
364 QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
365 const QList<QgsMapLayerServerProperties::WmsDimensionInfo> &wmsDims = serverProperties->wmsDimensions();
366 for ( const QgsMapLayerServerProperties::WmsDimensionInfo &dim : wmsDims )
367 {
368 addWmsDimensionInfoToTreeWidget( dim );
369 }
370
371 QString myStyle = QgsApplication::reportStyleSheet();
372 myStyle.append( QStringLiteral( "body { margin: 10px; }\n " ) );
373 teMetadataViewer->clear();
374 teMetadataViewer->document()->setDefaultStyleSheet( myStyle );
375 teMetadataViewer->setOpenLinks( false );
376 connect( teMetadataViewer, &QTextBrowser::anchorClicked, this, &QgsVectorLayerProperties::openUrl );
377
378 QgsSettings settings;
379 // if dialog hasn't been opened/closed yet, default to Styles tab, which is used most often
380 // this will be read by restoreOptionsBaseUi()
381 if ( !settings.contains( QStringLiteral( "/Windows/VectorLayerProperties/tab" ) ) )
382 {
383 settings.setValue( QStringLiteral( "Windows/VectorLayerProperties/tab" ), mOptStackedWidget->indexOf( mOptsPage_Style ) );
384 }
385
386 QList<QgsMapLayer *> dependencySources;
387 const QSet<QgsMapLayerDependency> constDependencies = mLayer->dependencies();
388 for ( const QgsMapLayerDependency &dep : constDependencies )
389 {
390 QgsMapLayer *layer = QgsProject::instance()->mapLayer( dep.layerId() );
391 if ( layer )
392 dependencySources << layer;
393 }
394
395 mLayersDependenciesTreeModel = new QgsLayerTreeFilterProxyModel( this );
396 mLayersDependenciesTreeModel->setLayerTreeModel( new QgsLayerTreeModel( QgsProject::instance()->layerTreeRoot(), mLayersDependenciesTreeModel ) );
397 mLayersDependenciesTreeModel->setCheckedLayers( dependencySources );
398 connect( QgsProject::instance(), &QObject::destroyed, this, [this] { mLayersDependenciesTreeView->setModel( nullptr ); } );
399 mLayersDependenciesTreeView->setModel( mLayersDependenciesTreeModel );
400
401 mRefreshSettingsWidget->setLayer( mLayer );
402 mMapLayerServerPropertiesWidget->setHasWfsTitle( true );
403 mMapLayerServerPropertiesWidget->setServerProperties( mLayer->serverProperties() );
404
405 // auxiliary layer
406 QMenu *menu = new QMenu( this );
407
408 mAuxiliaryLayerActionNew = new QAction( tr( "Create" ), this );
409 menu->addAction( mAuxiliaryLayerActionNew );
410 connect( mAuxiliaryLayerActionNew, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerNew );
411
412 mAuxiliaryLayerActionClear = new QAction( tr( "Clear" ), this );
413 menu->addAction( mAuxiliaryLayerActionClear );
414 connect( mAuxiliaryLayerActionClear, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerClear );
415
416 mAuxiliaryLayerActionDelete = new QAction( tr( "Delete" ), this );
417 menu->addAction( mAuxiliaryLayerActionDelete );
418 connect( mAuxiliaryLayerActionDelete, &QAction::triggered, this, &QgsVectorLayerProperties::onAuxiliaryLayerDelete );
419
420 mAuxiliaryLayerActionExport = new QAction( tr( "Export" ), this );
421 menu->addAction( mAuxiliaryLayerActionExport );
422 connect( mAuxiliaryLayerActionExport, &QAction::triggered, this, [this] { emit exportAuxiliaryLayer( mLayer->auxiliaryLayer() ); } );
423
424 mAuxiliaryStorageActions->setMenu( menu );
425
426 connect( mAuxiliaryStorageFieldsDeleteBtn, &QPushButton::clicked, this, &QgsVectorLayerProperties::onAuxiliaryLayerDeleteField );
427 connect( mAuxiliaryStorageFieldsAddBtn, &QPushButton::clicked, this, &QgsVectorLayerProperties::onAuxiliaryLayerAddField );
428
429 updateAuxiliaryStoragePage();
430
431 mOptsPage_Information->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#information-properties" ) );
432 mOptsPage_Source->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#source-properties" ) );
433 mOptsPage_Style->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#symbology-properties" ) );
434 mOptsPage_Labels->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#labels-properties" ) );
435 mOptsPage_Masks->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#masks-properties" ) );
436 mOptsPage_Diagrams->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#diagrams-properties" ) );
437 mOptsPage_SourceFields->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#fields-properties" ) );
438 mOptsPage_AttributesForm->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#attributes-form-properties" ) );
439 mOptsPage_Joins->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#joins-properties" ) );
440 mOptsPage_AuxiliaryStorage->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#auxiliary-storage-properties" ) );
441 mOptsPage_Actions->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#actions-properties" ) );
442 mOptsPage_Display->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#display-properties" ) );
443 mOptsPage_Rendering->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#rendering-properties" ) );
444 mOptsPage_Temporal->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#temporal-properties" ) );
445 mOptsPage_Variables->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#variables-properties" ) );
446 mOptsPage_Metadata->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#metadata-properties" ) );
447 mOptsPage_DataDependencies->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#dependencies-properties" ) );
448 mOptsPage_Legend->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#legend-properties" ) );
449 mOptsPage_Server->setProperty( "helpPage", QStringLiteral( "working_with_vector/vector_properties.html#qgis-server-properties" ) );
450
451
453
454 initialize();
455}
456
458{
459 if ( !mLayer )
460 return;
461
462 emit toggleEditing( mLayer );
463
464 setPbnQueryBuilderEnabled();
465}
466
467void QgsVectorLayerProperties::insertField()
468{
469 // Convert the selected field to an expression and
470 // insert it into the action at the cursor position
471 if ( mMapTipFieldComboBox->currentField().isEmpty() )
472 return;
473 QString expression = QStringLiteral( "[%\"" );
474 expression += mMapTipFieldComboBox->currentField();
475 expression += QLatin1String( "\"%]" );
476
477 mMapTipWidget->insertText( expression );
478}
479
480void QgsVectorLayerProperties::insertOrEditExpression()
481{
482 // Get the linear indexes if the start and end of the selection
483 int selectionStart = mMapTipWidget->selectionStart();
484 int selectionEnd = mMapTipWidget->selectionEnd();
485 QString expression = QgsExpressionFinder::findAndSelectActiveExpression( mMapTipWidget );
486
487 QgsExpressionContext context = createExpressionContext();
488 QgsExpressionBuilderDialog exprDlg( mLayer, expression, this, QStringLiteral( "generic" ), context );
489
490 exprDlg.setWindowTitle( tr( "Insert Expression" ) );
491 if ( exprDlg.exec() == QDialog::Accepted && !exprDlg.expressionText().trimmed().isEmpty() )
492 mMapTipWidget->insertText( "[%" + exprDlg.expressionText().trimmed() + "%]" );
493 else // Restore the selection
494 mMapTipWidget->setLinearSelection( selectionStart, selectionEnd );
495}
496
498{
499 if ( !mSourceWidget )
500 {
501 mSourceWidget = QgsGui::sourceWidgetProviderRegistry()->createWidget( mLayer );
502 if ( mSourceWidget )
503 {
504 QHBoxLayout *layout = new QHBoxLayout();
505 layout->addWidget( mSourceWidget );
506 mSourceGroupBox->setLayout( layout );
507 if ( !mSourceWidget->groupTitle().isEmpty() )
508 mSourceGroupBox->setTitle( mSourceWidget->groupTitle() );
509
510 mSourceGroupBox->show();
511
512 connect( mSourceWidget, &QgsProviderSourceWidget::validChanged, this, [this]( bool isValid ) {
513 buttonBox->button( QDialogButtonBox::Apply )->setEnabled( isValid );
514 buttonBox->button( QDialogButtonBox::Ok )->setEnabled( isValid );
515 } );
516 }
517 }
518
519 if ( mSourceWidget )
520 {
521 mSourceWidget->setMapCanvas( mCanvas );
522 mSourceWidget->setSourceUri( mLayer->source() );
523 }
524
525 // populate the general information
526 mLayerOrigNameLineEdit->setText( mLayer->name() );
527 mBackupCrs = mLayer->crs();
528
529 //see if we are dealing with a pg layer here
530 mSubsetGroupBox->setEnabled( true );
531 txtSubsetSQL->setText( mLayer->subsetString() );
532 // if the user is allowed to type an adhoc query, the app will crash if the query
533 // is bad. For this reason, the sql box is disabled and the query must be built
534 // using the query builder, either by typing it in by hand or using the buttons, etc
535 // on the builder. If the ability to enter a query directly into the box is required,
536 // a mechanism to check it must be implemented.
537 txtSubsetSQL->setReadOnly( true );
538 txtSubsetSQL->setCaretWidth( 0 );
539 txtSubsetSQL->setCaretLineVisible( false );
540 setPbnQueryBuilderEnabled();
541 if ( mLayer->dataProvider() && !mLayer->dataProvider()->supportsSubsetString() )
542 {
543 // hide subset box entirely if not supported by data provider
544 mSubsetGroupBox->hide();
545 }
546
547 mDisplayExpressionWidget->setField( mLayer->displayExpression() );
548 mEnableMapTips->setChecked( mLayer->mapTipsEnabled() );
549 mMapTipWidget->setText( mLayer->mapTipTemplate() );
550
551 mFeaturesSortOrderExpressionWidget->setField( mLayer->attributeTableConfig().sortExpression() );
552 mFeaturesSortOrderDirectionButton->setArrowType( mLayer->attributeTableConfig().sortOrder() == Qt::AscendingOrder ? Qt::UpArrow : Qt::DownArrow );
553
554 // set up the scale based layer visibility stuff....
555 mScaleRangeWidget->setScaleRange( mLayer->minimumScale(), mLayer->maximumScale() );
556 mScaleVisibilityGroupBox->setChecked( mLayer->hasScaleBasedVisibility() );
557 mScaleRangeWidget->setMapCanvas( mCanvas );
558
559 mUseReferenceScaleGroupBox->setChecked( mLayer->renderer() && mLayer->renderer()->referenceScale() > 0 );
560 mReferenceScaleWidget->setShowCurrentScaleButton( true );
561 mReferenceScaleWidget->setMapCanvas( mCanvas );
562 if ( mUseReferenceScaleGroupBox->isChecked() )
563 mReferenceScaleWidget->setScale( mLayer->renderer()->referenceScale() );
564 else if ( mCanvas )
565 mReferenceScaleWidget->setScale( mCanvas->scale() );
566
567 // get simplify drawing configuration
568 const QgsVectorSimplifyMethod &simplifyMethod = mLayer->simplifyMethod();
570 mSimplifyDrawingSpinBox->setValue( simplifyMethod.threshold() );
571 mSimplifyDrawingSpinBox->setClearValue( 1.0 );
572
573 QgsVectorLayerSelectionProperties *selectionProperties = qobject_cast<QgsVectorLayerSelectionProperties *>( mLayer->selectionProperties() );
574 if ( selectionProperties->selectionColor().isValid() )
575 {
576 mSelectionColorButton->setColor( selectionProperties->selectionColor() );
577 }
578 if ( QgsSymbol *symbol = selectionProperties->selectionSymbol() )
579 {
580 mSelectionSymbolButton->setSymbol( symbol->clone() );
581 }
582 switch ( selectionProperties->selectionRenderingMode() )
583 {
585 mRadioDefaultSelectionColor->setChecked( true );
586 break;
587
589 {
590 if ( selectionProperties->selectionColor().isValid() )
591 {
592 mRadioOverrideSelectionColor->setChecked( true );
593 }
594 else
595 {
596 mRadioDefaultSelectionColor->setChecked( true );
597 }
598 break;
599 }
600
602 if ( selectionProperties->selectionSymbol() )
603 {
604 mRadioOverrideSelectionSymbol->setChecked( true );
605 }
606 else
607 {
608 mRadioDefaultSelectionColor->setChecked( true );
609 }
610 break;
611 }
612
613 QString remark = QStringLiteral( " (%1)" ).arg( tr( "Not supported" ) );
614 const QgsVectorDataProvider *provider = mLayer->dataProvider();
615 if ( !( provider && ( provider->capabilities() & Qgis::VectorProviderCapability::SimplifyGeometries ) ) )
616 {
617 mSimplifyDrawingAtProvider->setChecked( false );
618 mSimplifyDrawingAtProvider->setEnabled( false );
619 if ( !mSimplifyDrawingAtProvider->text().endsWith( remark ) )
620 mSimplifyDrawingAtProvider->setText( mSimplifyDrawingAtProvider->text().append( remark ) );
621 }
622 else
623 {
624 mSimplifyDrawingAtProvider->setChecked( !simplifyMethod.forceLocalOptimization() );
625 mSimplifyDrawingAtProvider->setEnabled( mSimplifyDrawingGroupBox->isChecked() );
626 if ( mSimplifyDrawingAtProvider->text().endsWith( remark ) )
627 {
628 QString newText = mSimplifyDrawingAtProvider->text();
629 newText.chop( remark.size() );
630 mSimplifyDrawingAtProvider->setText( newText );
631 }
632 }
633
634 // disable simplification for point layers, now it is not implemented
635 if ( mLayer->geometryType() == Qgis::GeometryType::Point )
636 {
637 mSimplifyDrawingGroupBox->setChecked( false );
638 mSimplifyDrawingGroupBox->setEnabled( false );
639 }
640
641 // Default local simplification algorithm
642 mSimplifyAlgorithmComboBox->addItem( tr( "Distance" ), QVariant::fromValue( Qgis::VectorSimplificationAlgorithm::Distance ) );
643 mSimplifyAlgorithmComboBox->addItem( tr( "SnapToGrid" ), QVariant::fromValue( Qgis::VectorSimplificationAlgorithm::SnapToGrid ) );
644 mSimplifyAlgorithmComboBox->addItem( tr( "Visvalingam" ), QVariant::fromValue( Qgis::VectorSimplificationAlgorithm::Visvalingam ) );
645 mSimplifyAlgorithmComboBox->setCurrentIndex( mSimplifyAlgorithmComboBox->findData( QVariant::fromValue( simplifyMethod.simplifyAlgorithm() ) ) );
646
647 QStringList myScalesList = Qgis::defaultProjectScales().split( ',' );
648 myScalesList.append( QStringLiteral( "1:1" ) );
649 mSimplifyMaximumScaleComboBox->updateScales( myScalesList );
650 mSimplifyMaximumScaleComboBox->setScale( simplifyMethod.maximumScale() );
651
652 mForceRasterCheckBox->setChecked( mLayer->renderer() && mLayer->renderer()->forceRasterRender() );
653
654 mRefreshSettingsWidget->syncToLayer();
655 mMapLayerServerPropertiesWidget->sync();
656
657 mRefreshLayerNotificationCheckBox->setChecked( mLayer->isRefreshOnNotifyEnabled() );
658 mNotificationMessageCheckBox->setChecked( !mLayer->refreshOnNotifyMessage().isEmpty() );
659 mNotifyMessageValueLineEdit->setText( mLayer->refreshOnNotifyMessage() );
660
661
662 // load appropriate symbology page (V1 or V2)
663 updateSymbologyPage();
664
665 mActionDialog->init( *mLayer->actions(), mLayer->attributeTableConfig() );
666
667 if ( labelingDialog )
668 labelingDialog->adaptToLayer();
669
670 mSourceFieldsPropertiesDialog->init();
671 mAttributesFormPropertiesDialog->init();
672
673 // set initial state for variable editor
674 updateVariableEditor();
675
676 if ( diagramPropertiesDialog )
677 diagramPropertiesDialog->syncToOwnLayer();
678
679 // sync all plugin dialogs
680 for ( QgsMapLayerConfigWidget *page : std::as_const( mConfigWidgets ) )
681 {
682 page->syncToLayer( mLayer );
683 }
684
685 mMetadataWidget->setMetadata( &mLayer->metadata() );
686
687 mTemporalWidget->syncToLayer();
688
689 mLegendWidget->setLayer( mLayer );
690}
691
693{
694 if ( labelingDialog )
695 {
696 labelingDialog->writeSettingsToLayer();
697 }
698 mBackupCrs = mLayer->crs();
699 // apply legend settings
700 mLegendWidget->applyToLayer();
701 mLegendConfigEmbeddedWidget->applyToLayer();
702
703 // save metadata
704 mMetadataWidget->acceptMetadata();
705 mMetadataFilled = false;
706
707 // save masking settings
708 if ( mMaskingWidget )
709 mMaskingWidget->apply();
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 {
719 if ( mLayer->dataProvider()->capabilities() & Qgis::VectorProviderCapability::SelectEncoding )
720 {
721 mLayer->setProviderEncoding( cboProviderEncoding->currentText() );
722 }
723 }
724
725 mLayer->setDisplayExpression( mDisplayExpressionWidget->asExpression() );
726 mLayer->setMapTipsEnabled( mEnableMapTips->isChecked() );
727 mLayer->setMapTipTemplate( mMapTipWidget->text() );
728
729 QgsAttributeTableConfig config = mLayer->attributeTableConfig();
730 config.setSortExpression( mFeaturesSortOrderExpressionWidget->asExpression() );
731 config.setSortOrder( mFeaturesSortOrderDirectionButton->arrowType() == Qt::UpArrow ? Qt::AscendingOrder : Qt::DescendingOrder );
732 mLayer->setAttributeTableConfig( config );
733
734 mLayer->actions()->clearActions();
735 const auto constActions = mActionDialog->actions();
736 for ( const QgsAction &action : constActions )
737 {
738 mLayer->actions()->addAction( action );
739 }
740 QgsAttributeTableConfig attributeTableConfig = mLayer->attributeTableConfig();
741 attributeTableConfig.update( mLayer->fields() );
742 attributeTableConfig.setActionWidgetStyle( mActionDialog->attributeTableWidgetStyle() );
743 QVector<QgsAttributeTableConfig::ColumnConfig> columns = attributeTableConfig.columns();
744
745 for ( int i = 0; i < columns.size(); ++i )
746 {
747 if ( columns.at( i ).type == QgsAttributeTableConfig::Action )
748 {
749 columns[i].hidden = !mActionDialog->showWidgetInAttributeTable();
750 }
751 }
752
753 attributeTableConfig.setColumns( columns );
754
755 mLayer->setAttributeTableConfig( attributeTableConfig );
756
757 mLayer->setName( mLayerOrigNameLineEdit->text() );
758
759 mAttributesFormPropertiesDialog->apply();
760 mSourceFieldsPropertiesDialog->apply();
761
762 // Update temporal properties
763 mTemporalWidget->saveTemporalProperties();
764
765 if ( mLayer->renderer() )
766 {
767 QgsRendererPropertiesDialog *dlg = static_cast<QgsRendererPropertiesDialog *>( widgetStackRenderers->currentWidget() );
768 dlg->apply();
769 }
770
771 //apply diagram settings
772 diagramPropertiesDialog->apply();
773
774 // apply all plugin dialogs
775 for ( QgsMapLayerConfigWidget *page : std::as_const( mConfigWidgets ) )
776 {
777 page->apply();
778 }
779
780 if ( mMapLayerServerPropertiesWidget->save() )
781 mMetadataFilled = false;
782
783 //layer simplify drawing configuration
785 if ( mSimplifyDrawingGroupBox->isChecked() )
786 {
788 if ( mSimplifyDrawingSpinBox->value() > 1 )
790 }
791 QgsVectorSimplifyMethod simplifyMethod = mLayer->simplifyMethod();
792 simplifyMethod.setSimplifyHints( simplifyHints );
793 simplifyMethod.setSimplifyAlgorithm( mSimplifyAlgorithmComboBox->currentData().value<Qgis::VectorSimplificationAlgorithm>() );
794 simplifyMethod.setThreshold( mSimplifyDrawingSpinBox->value() );
795 simplifyMethod.setForceLocalOptimization( !mSimplifyDrawingAtProvider->isChecked() );
796 simplifyMethod.setMaximumScale( mSimplifyMaximumScaleComboBox->scale() );
797 mLayer->setSimplifyMethod( simplifyMethod );
798
799 if ( mLayer->renderer() )
800 {
801 mLayer->renderer()->setForceRasterRender( mForceRasterCheckBox->isChecked() );
802 mLayer->renderer()->setReferenceScale( mUseReferenceScaleGroupBox->isChecked() ? mReferenceScaleWidget->scale() : -1 );
803 }
804
805 QgsVectorLayerSelectionProperties *selectionProperties = qobject_cast<QgsVectorLayerSelectionProperties *>( mLayer->selectionProperties() );
806 if ( mSelectionColorButton->color() != mSelectionColorButton->defaultColor() )
807 selectionProperties->setSelectionColor( mSelectionColorButton->color() );
808 else
809 selectionProperties->setSelectionColor( QColor() );
810 if ( QgsSymbol *symbol = mSelectionSymbolButton->symbol() )
811 selectionProperties->setSelectionSymbol( symbol->clone() );
812
813 if ( mRadioOverrideSelectionSymbol->isChecked() )
814 {
816 }
817 else if ( mRadioOverrideSelectionColor->isChecked() )
818 {
820 }
821 else
822 {
824 }
825
826 mRefreshSettingsWidget->saveToLayer();
827
828 mLayer->setRefreshOnNotifyEnabled( mRefreshLayerNotificationCheckBox->isChecked() );
829 mLayer->setRefreshOnNofifyMessage( mNotificationMessageCheckBox->isChecked() ? mNotifyMessageValueLineEdit->text() : QString() );
830
831 mOldJoins = mLayer->vectorJoins();
832
833 //save variables
834 QgsExpressionContextUtils::setLayerVariables( mLayer, mVariableEditor->variablesInActiveScope() );
835 updateVariableEditor();
836
837 // save dependencies
838 QSet<QgsMapLayerDependency> deps;
839 const auto checkedLayers = mLayersDependenciesTreeModel->checkedLayers();
840 for ( const QgsMapLayer *layer : checkedLayers )
841 deps << QgsMapLayerDependency( layer->id() );
842 if ( !mLayer->setDependencies( deps ) )
843 {
844 QMessageBox::warning( nullptr, tr( "Save Dependency" ), tr( "This configuration introduces a cycle in data dependencies and will be ignored." ) );
845 }
846
847 // Why is this here? Well, we if we're making changes to the layer's source then potentially
848 // we are changing the geometry type of the layer, or even going from spatial <-> non spatial types.
849 // So we need to ensure that anything from the dialog which sets things like renderer properties
850 // happens BEFORE we change the source, otherwise we might end up with a renderer which is not
851 // compatible with the new geometry type of the layer. (And likewise for other properties like
852 // fields!)
853 bool dialogNeedsResync = false;
854 if ( mSourceWidget )
855 {
856 const QString newSource = mSourceWidget->sourceUri();
857 if ( newSource != mLayer->source() )
858 {
859 mLayer->setDataSource( newSource, mLayer->name(), mLayer->providerType(), QgsDataProvider::ProviderOptions(), Qgis::DataProviderReadFlags() );
860
861 // resync dialog to layer's new state -- this allows any changed layer properties
862 // (such as a forced creation of a new renderer compatible with the new layer, new field configuration, etc)
863 // to show in the dialog correctly
864 dialogNeedsResync = true;
865 }
866 }
867 // now apply the subset string AFTER setting the layer's source. It's messy, but the subset string
868 // can form part of the layer's source, but it WON'T be present in the URI returned by the source widget!
869 // If we don't apply the subset string AFTER changing the source, then the subset string will be lost.
870 mSubsetGroupBox->setEnabled( true );
871 if ( txtSubsetSQL->text() != mLayer->subsetString() )
872 {
873 // set the subset sql for the layer
874 mLayer->setSubsetString( txtSubsetSQL->text() );
875 mMetadataFilled = false;
876 // need to resync the dialog, the subset string may have changed the layer's geometry type!
877 dialogNeedsResync = true;
878 }
879 mOriginalSubsetSQL = mLayer->subsetString();
880
881 if ( dialogNeedsResync )
882 syncToLayer();
883
884 mLayer->triggerRepaint();
885 // notify the project we've made a change
886 mProjectDirtyBlocker.reset();
888 mProjectDirtyBlocker = std::make_unique<QgsProjectDirtyBlocker>( QgsProject::instance() );
889}
890
892{
893 if ( mOldJoins != mLayer->vectorJoins() )
894 {
895 // need to undo changes in vector layer joins - they are applied directly to the layer (not in apply())
896 // so other parts of the properties dialog can use the fields from the joined layers
897
898 const auto constVectorJoins = mLayer->vectorJoins();
899 for ( const QgsVectorLayerJoinInfo &info : constVectorJoins )
900 mLayer->removeJoin( info.joinLayerId() );
901
902 for ( const QgsVectorLayerJoinInfo &info : std::as_const( mOldJoins ) )
903 mLayer->addJoin( info );
904 }
905
906 if ( mOriginalSubsetSQL != mLayer->subsetString() )
907 {
908 // need to undo changes in subset string - they are applied directly to the layer (not in apply())
909 // by QgsQueryBuilder::accept()
910
911 mLayer->setSubsetString( mOriginalSubsetSQL );
912 }
913
914 // Store it because QgsLayerPropertiesDialog::rollback() calls syncToLayer() which
915 // resets the backupCrs
916 const QgsCoordinateReferenceSystem backupCrs { mBackupCrs };
917
919
920 if ( backupCrs != mLayer->crs() )
921 mLayer->setCrs( backupCrs );
922}
923
924void QgsVectorLayerProperties::pbnQueryBuilder_clicked()
925{
926 // launch the query builder
928
929 // Set the sql in the query builder to the same in the prop dialog
930 // (in case the user has already changed it)
931 dialog->setSubsetString( txtSubsetSQL->text() );
932 // Open the query builder
933 if ( dialog->exec() )
934 {
935 // if the sql is changed, update it in the prop subset text box
936 txtSubsetSQL->setText( dialog->subsetString() );
937 //TODO If the sql is changed in the prop dialog, the layer extent should be recalculated
938
939 // The datasource for the layer needs to be updated with the new sql since this gets
940 // saved to the project file. This should happen at the map layer level...
941 }
942 // delete the query builder object
943 delete dialog;
944}
945
946void QgsVectorLayerProperties::pbnIndex_clicked()
947{
948 QgsVectorDataProvider *pr = mLayer->dataProvider();
949 if ( pr )
950 {
951 setCursor( Qt::WaitCursor );
952 bool errval = pr->createSpatialIndex();
953 setCursor( Qt::ArrowCursor );
954 if ( errval )
955 {
956 pbnIndex->setEnabled( false );
957 pbnIndex->setText( tr( "Spatial Index Exists" ) );
958 QMessageBox::information( this, tr( "Spatial Index" ), tr( "Creation of spatial index successful" ) );
959 }
960 else
961 {
962 QMessageBox::warning( this, tr( "Spatial Index" ), tr( "Creation of spatial index failed" ) );
963 }
964 }
965}
966
967QString QgsVectorLayerProperties::htmlMetadata()
968{
969 return mLayer->htmlMetadata();
970}
971
972void QgsVectorLayerProperties::mCrsSelector_crsChanged( const QgsCoordinateReferenceSystem &crs )
973{
974 QgsDatumTransformDialog::run( crs, QgsProject::instance()->crs(), this, mCanvas, tr( "Select Transformation for the vector layer" ) );
975 mLayer->setCrs( crs );
976 mMetadataFilled = false;
977 mMetadataWidget->crsChanged();
978}
979
980void QgsVectorLayerProperties::saveMultipleStylesAs()
981{
982 QgsMapLayerSaveStyleDialog dlg( mLayer );
983 dlg.setSaveOnlyCurrentStyle( false );
984 QgsSettings settings;
985
986 if ( dlg.exec() )
987 {
988 apply();
989
990 // Store the original style, that we can restore at the end
991 const QString originalStyle { mLayer->styleManager()->currentStyle() };
992 const QListWidget *stylesWidget { dlg.stylesWidget() };
993
994 // Collect selected (checked) styles for export/save
995 QStringList stylesSelected;
996 for ( int i = 0; i < stylesWidget->count(); i++ )
997 {
998 if ( stylesWidget->item( i )->checkState() == Qt::CheckState::Checked )
999 {
1000 stylesSelected.push_back( stylesWidget->item( i )->text() );
1001 }
1002 }
1003
1004 if ( !stylesSelected.isEmpty() )
1005 {
1006 int styleIndex = 0;
1007 for ( const QString &styleName : std::as_const( stylesSelected ) )
1008 {
1009 bool defaultLoadedFlag = false;
1010
1011 StyleType type = dlg.currentStyleType();
1012 mLayer->styleManager()->setCurrentStyle( styleName );
1013 switch ( type )
1014 {
1015 case QML:
1016 case SLD:
1017 {
1018 QString message;
1019 const QString filePath { dlg.outputFilePath() };
1020 const QFileInfo fi { filePath };
1021 QString safePath { QString( filePath ).replace( fi.baseName(), QStringLiteral( "%1_%2" ).arg( fi.baseName(), QgsFileUtils::stringToSafeFilename( styleName ) ) ) };
1022 if ( styleIndex > 0 && stylesSelected.count() > 1 )
1023 {
1024 int i = 1;
1025 while ( QFile::exists( safePath ) )
1026 {
1027 const QFileInfo fi { safePath };
1028 safePath = QString( safePath ).replace( '.' + fi.completeSuffix(), QStringLiteral( "_%1.%2" ).arg( QString::number( i ), fi.completeSuffix() ) );
1029 i++;
1030 }
1031 }
1032 if ( type == QML )
1033 message = mLayer->saveNamedStyle( safePath, defaultLoadedFlag, dlg.styleCategories() );
1034 else
1035 message = mLayer->saveSldStyle( safePath, defaultLoadedFlag );
1036
1037 //reset if the default style was loaded OK only
1038 if ( defaultLoadedFlag )
1039 {
1040 syncToLayer();
1041 }
1042 else
1043 {
1044 //let the user know what went wrong
1045 QMessageBox::information( this, tr( "Save Style" ), message );
1046 }
1047
1048 break;
1049 }
1050 case DatasourceDatabase:
1051 {
1052 QString infoWindowTitle = QObject::tr( "Save style '%1' to DB (%2)" )
1053 .arg( styleName, mLayer->providerType() );
1054 QString msgError;
1055
1056 QgsMapLayerSaveStyleDialog::SaveToDbSettings dbSettings = dlg.saveToDbSettings();
1057
1058 // If a name is defined, we add _1 etc. else we use the style name
1059 QString name { dbSettings.name };
1060 if ( name.isEmpty() )
1061 {
1062 name = styleName;
1063 }
1064 else
1065 {
1066 name += QStringLiteral( "_%1" ).arg( styleName );
1067 QStringList ids, names, descriptions;
1068 mLayer->listStylesInDatabase( ids, names, descriptions, msgError );
1069 int i = 1;
1070 while ( names.contains( name ) )
1071 {
1072 name = QStringLiteral( "%1 %2" ).arg( name, QString::number( i ) );
1073 i++;
1074 }
1075 }
1076
1077 QString errorMessage;
1078 if ( QgsProviderRegistry::instance()->styleExists( mLayer->providerType(), mLayer->source(), dbSettings.name, errorMessage ) )
1079 {
1080 if ( QMessageBox::question( nullptr, QObject::tr( "Save style in database" ), QObject::tr( "A matching style already exists in the database for this layer. Do you want to overwrite it?" ), QMessageBox::Yes | QMessageBox::No ) == QMessageBox::No )
1081 {
1082 return;
1083 }
1084 }
1085 else if ( !errorMessage.isEmpty() )
1086 {
1087 QMessageBox::warning( this, infoWindowTitle, errorMessage );
1088 return;
1089 }
1090
1091 mLayer->saveStyleToDatabaseV2( name, dbSettings.description, dbSettings.isDefault, dbSettings.uiFileContent, msgError, dlg.styleCategories() );
1092
1093 if ( !msgError.isNull() )
1094 {
1095 QMessageBox::warning( this, infoWindowTitle, msgError );
1096 }
1097 else
1098 {
1099 QMessageBox::information( this, infoWindowTitle, tr( "Style '%1' saved" ).arg( styleName ) );
1100 }
1101 break;
1102 }
1103 case UserDatabase:
1104 break;
1105 }
1106 styleIndex++;
1107 }
1108 // Restore original style
1109 mLayer->styleManager()->setCurrentStyle( originalStyle );
1110 }
1111 } // Nothing selected!
1112}
1113
1114void QgsVectorLayerProperties::aboutToShowStyleMenu()
1115{
1116 // this should be unified with QgsRasterLayerProperties::aboutToShowStyleMenu()
1117 QMenu *m = qobject_cast<QMenu *>( sender() );
1118 m->clear();
1119
1120 m->addAction( mActionLoadStyle );
1121 m->addAction( mActionSaveStyle );
1122
1123 // If we have multiple styles, offer an option to save them at once
1124 if ( mLayer->styleManager()->styles().count() > 1 )
1125 {
1126 mActionSaveStyle->setText( tr( "Save Current Style…" ) );
1127 m->addAction( mActionSaveMultipleStyles );
1128 }
1129 else
1130 {
1131 mActionSaveStyle->setText( tr( "Save Style…" ) );
1132 }
1133
1134 m->addSeparator();
1135 m->addAction( tr( "Save as Default" ), this, &QgsVectorLayerProperties::saveDefaultStyle );
1136 m->addAction( tr( "Restore Default" ), this, &QgsVectorLayerProperties::loadDefaultStyle );
1137
1138 // re-add style manager actions!
1139 m->addSeparator();
1141}
1142
1143void QgsVectorLayerProperties::mButtonAddJoin_clicked()
1144{
1145 if ( !mLayer )
1146 return;
1147
1148 QList<QgsMapLayer *> joinedLayers;
1149 const QList<QgsVectorLayerJoinInfo> &joins = mLayer->vectorJoins();
1150 joinedLayers.reserve( joins.size() );
1151 for ( int i = 0; i < joins.size(); ++i )
1152 {
1153 joinedLayers.append( joins[i].joinLayer() );
1154 }
1155
1156 QgsJoinDialog d( mLayer, joinedLayers );
1157 if ( d.exec() == QDialog::Accepted )
1158 {
1159 QgsVectorLayerJoinInfo info = d.joinInfo();
1160 //create attribute index if possible
1161 if ( d.createAttributeIndex() )
1162 {
1163 QgsVectorLayer *joinLayer = info.joinLayer();
1164 if ( joinLayer )
1165 {
1166 joinLayer->dataProvider()->createAttributeIndex( joinLayer->fields().indexFromName( info.joinFieldName() ) );
1167 }
1168 }
1169 mLayer->addJoin( info );
1170 addJoinToTreeWidget( info );
1171 setPbnQueryBuilderEnabled();
1172 mSourceFieldsPropertiesDialog->init();
1173 mAttributesFormPropertiesDialog->init();
1174 }
1175}
1176
1177void QgsVectorLayerProperties::mButtonEditJoin_clicked()
1178{
1179 QTreeWidgetItem *currentJoinItem = mJoinTreeWidget->currentItem();
1180 mJoinTreeWidget_itemDoubleClicked( currentJoinItem, 0 );
1181}
1182
1183void QgsVectorLayerProperties::mJoinTreeWidget_itemDoubleClicked( QTreeWidgetItem *item, int )
1184{
1185 if ( !mLayer || !item )
1186 {
1187 return;
1188 }
1189
1190 // if current item is a child item, we should use its parent to be able to edit join
1191 QTreeWidgetItem *currentJoinItem = item;
1192 if ( item->parent() )
1193 {
1194 currentJoinItem = item->parent();
1195 }
1196
1197
1198 QList<QgsMapLayer *> joinedLayers;
1199 QString joinLayerId = currentJoinItem->data( 0, Qt::UserRole ).toString();
1200 const QList<QgsVectorLayerJoinInfo> &joins = mLayer->vectorJoins();
1201 int j = -1;
1202 for ( int i = 0; i < joins.size(); ++i )
1203 {
1204 QgsVectorLayer *joinLayer = joins[i].joinLayer();
1205 if ( !joinLayer )
1206 continue; // invalid join (unresolved join layer)
1207
1208 if ( joinLayer->id() == joinLayerId )
1209 {
1210 j = i;
1211 }
1212 else
1213 {
1214 // remove already joined layers from possible list to be displayed in dialog
1215 joinedLayers.append( joinLayer );
1216 }
1217 }
1218 if ( j == -1 )
1219 {
1220 return;
1221 }
1222
1223 QgsJoinDialog d( mLayer, joinedLayers );
1224 d.setWindowTitle( tr( "Edit Vector Join" ) );
1225 d.setJoinInfo( joins[j] );
1226
1227 if ( d.exec() == QDialog::Accepted )
1228 {
1229 QgsVectorLayerJoinInfo info = d.joinInfo();
1230
1231 // remove old join
1232 mLayer->removeJoin( joinLayerId );
1233 int idx = mJoinTreeWidget->indexOfTopLevelItem( item );
1234 mJoinTreeWidget->takeTopLevelItem( idx );
1235
1236 // add the new edited
1237
1238 //create attribute index if possible
1239 if ( d.createAttributeIndex() )
1240 {
1241 QgsVectorLayer *joinLayer = info.joinLayer();
1242 if ( joinLayer )
1243 {
1244 joinLayer->dataProvider()->createAttributeIndex( joinLayer->fields().indexFromName( info.joinFieldName() ) );
1245 }
1246 }
1247 mLayer->addJoin( info );
1248 addJoinToTreeWidget( info, idx );
1249
1250 setPbnQueryBuilderEnabled();
1251 mSourceFieldsPropertiesDialog->init();
1252 mAttributesFormPropertiesDialog->init();
1253 }
1254}
1255
1256void QgsVectorLayerProperties::addJoinToTreeWidget( const QgsVectorLayerJoinInfo &join, const int insertIndex )
1257{
1258 QTreeWidgetItem *joinItem = new QTreeWidgetItem();
1259 joinItem->setFlags( Qt::ItemIsEnabled );
1260
1261 QgsVectorLayer *joinLayer = join.joinLayer();
1262 if ( !mLayer || !joinLayer )
1263 {
1264 return;
1265 }
1266
1267 joinItem->setText( 0, tr( "Join layer" ) );
1268 if ( mLayer->auxiliaryLayer() && mLayer->auxiliaryLayer()->id() == join.joinLayerId() )
1269 {
1270 return;
1271 }
1272
1273 joinItem->setText( 1, joinLayer->name() );
1274
1275 QFont f = joinItem->font( 0 );
1276 f.setBold( true );
1277 joinItem->setFont( 0, f );
1278 joinItem->setFont( 1, f );
1279
1280 joinItem->setData( 0, Qt::UserRole, join.joinLayerId() );
1281
1282 QTreeWidgetItem *childJoinField = new QTreeWidgetItem();
1283 childJoinField->setText( 0, tr( "Join field" ) );
1284 childJoinField->setText( 1, join.joinFieldName() );
1285 childJoinField->setFlags( Qt::ItemIsEnabled );
1286 joinItem->addChild( childJoinField );
1287
1288 QTreeWidgetItem *childTargetField = new QTreeWidgetItem();
1289 childTargetField->setText( 0, tr( "Target field" ) );
1290 childTargetField->setText( 1, join.targetFieldName() );
1291 joinItem->addChild( childTargetField );
1292
1293 QTreeWidgetItem *childMemCache = new QTreeWidgetItem();
1294 childMemCache->setText( 0, tr( "Cache join layer in virtual memory" ) );
1295 if ( join.isUsingMemoryCache() )
1296 childMemCache->setText( 1, QChar( 0x2714 ) );
1297 joinItem->addChild( childMemCache );
1298
1299 QTreeWidgetItem *childDynForm = new QTreeWidgetItem();
1300 childDynForm->setText( 0, tr( "Dynamic form" ) );
1301 if ( join.isDynamicFormEnabled() )
1302 childDynForm->setText( 1, QChar( 0x2714 ) );
1303 joinItem->addChild( childDynForm );
1304
1305 QTreeWidgetItem *childEditable = new QTreeWidgetItem();
1306 childEditable->setText( 0, tr( "Editable join layer" ) );
1307 if ( join.isEditable() )
1308 childEditable->setText( 1, QChar( 0x2714 ) );
1309 joinItem->addChild( childEditable );
1310
1311 QTreeWidgetItem *childUpsert = new QTreeWidgetItem();
1312 childUpsert->setText( 0, tr( "Upsert on edit" ) );
1313 if ( join.hasUpsertOnEdit() )
1314 childUpsert->setText( 1, QChar( 0x2714 ) );
1315 joinItem->addChild( childUpsert );
1316
1317 QTreeWidgetItem *childCascade = new QTreeWidgetItem();
1318 childCascade->setText( 0, tr( "Delete cascade" ) );
1319 if ( join.hasCascadedDelete() )
1320 childCascade->setText( 1, QChar( 0x2714 ) );
1321 joinItem->addChild( childCascade );
1322
1323 QTreeWidgetItem *childPrefix = new QTreeWidgetItem();
1324 childPrefix->setText( 0, tr( "Custom field name prefix" ) );
1325 childPrefix->setText( 1, join.prefix() );
1326 joinItem->addChild( childPrefix );
1327
1328 QTreeWidgetItem *childFields = new QTreeWidgetItem();
1329 childFields->setText( 0, tr( "Joined fields" ) );
1330 const QStringList *list = join.joinFieldNamesSubset();
1331 if ( list )
1332 childFields->setText( 1, QLocale().toString( list->count() ) );
1333 else
1334 childFields->setText( 1, tr( "all" ) );
1335 joinItem->addChild( childFields );
1336
1337 if ( insertIndex >= 0 )
1338 mJoinTreeWidget->insertTopLevelItem( insertIndex, joinItem );
1339 else
1340 mJoinTreeWidget->addTopLevelItem( joinItem );
1341
1342 mJoinTreeWidget->setCurrentItem( joinItem );
1343 mJoinTreeWidget->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
1344}
1345
1347{
1348 return mContext;
1349}
1350
1351void QgsVectorLayerProperties::openPanel( QgsPanelWidget *panel )
1352{
1353 QDialog *dlg = new QDialog();
1354 QString key = QStringLiteral( "/UI/paneldialog/%1" ).arg( panel->panelTitle() );
1355 QgsSettings settings;
1356 dlg->restoreGeometry( settings.value( key ).toByteArray() );
1357 dlg->setWindowTitle( panel->panelTitle() );
1358 dlg->setLayout( new QVBoxLayout() );
1359 dlg->layout()->addWidget( panel );
1360 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Ok );
1361 connect( buttonBox, &QDialogButtonBox::accepted, dlg, &QDialog::accept );
1362 dlg->layout()->addWidget( buttonBox );
1363 dlg->exec();
1364 settings.setValue( key, dlg->saveGeometry() );
1365 panel->acceptPanel();
1366}
1367
1368void QgsVectorLayerProperties::mButtonRemoveJoin_clicked()
1369{
1370 QTreeWidgetItem *currentJoinItem = mJoinTreeWidget->currentItem();
1371 // if current item is a child item, we should use its parent to be able to remove join
1372 if ( currentJoinItem && currentJoinItem->parent() )
1373 {
1374 currentJoinItem = currentJoinItem->parent();
1375 }
1376
1377 if ( !mLayer || !currentJoinItem )
1378 {
1379 return;
1380 }
1381
1382 mLayer->removeJoin( currentJoinItem->data( 0, Qt::UserRole ).toString() );
1383 mJoinTreeWidget->takeTopLevelItem( mJoinTreeWidget->indexOfTopLevelItem( currentJoinItem ) );
1384 setPbnQueryBuilderEnabled();
1385 mSourceFieldsPropertiesDialog->init();
1386 mAttributesFormPropertiesDialog->init();
1387}
1388
1389
1390void QgsVectorLayerProperties::mButtonAddWmsDimension_clicked()
1391{
1392 if ( !mLayer )
1393 return;
1394
1395 // get wms dimensions name
1396 QStringList alreadyDefinedDimensions;
1397 QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
1398 const QList<QgsMapLayerServerProperties::WmsDimensionInfo> &dims = serverProperties->wmsDimensions();
1399 for ( const QgsMapLayerServerProperties::WmsDimensionInfo &dim : dims )
1400 {
1401 alreadyDefinedDimensions << dim.name;
1402 }
1403
1404 QgsWmsDimensionDialog d( mLayer, alreadyDefinedDimensions );
1405 if ( d.exec() == QDialog::Accepted )
1406 {
1407 QgsMapLayerServerProperties::WmsDimensionInfo info = d.info();
1408 // save dimension
1409 serverProperties->addWmsDimension( info );
1410 addWmsDimensionInfoToTreeWidget( info );
1411 }
1412}
1413
1414void QgsVectorLayerProperties::mButtonEditWmsDimension_clicked()
1415{
1416 QTreeWidgetItem *currentWmsDimensionItem = mWmsDimensionsTreeWidget->currentItem();
1417 mWmsDimensionsTreeWidget_itemDoubleClicked( currentWmsDimensionItem, 0 );
1418}
1419
1420void QgsVectorLayerProperties::mWmsDimensionsTreeWidget_itemDoubleClicked( QTreeWidgetItem *item, int )
1421{
1422 if ( !mLayer || !item )
1423 {
1424 return;
1425 }
1426
1427 QString wmsDimName = item->data( 0, Qt::UserRole ).toString();
1428 QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
1429 const QList<QgsMapLayerServerProperties::WmsDimensionInfo> &dims = serverProperties->wmsDimensions();
1430 QStringList alreadyDefinedDimensions;
1431 int j = -1;
1432 for ( int i = 0; i < dims.size(); ++i )
1433 {
1434 QString dimName = dims[i].name;
1435 if ( dimName == wmsDimName )
1436 {
1437 j = i;
1438 }
1439 else
1440 {
1441 alreadyDefinedDimensions << dimName;
1442 }
1443 }
1444 if ( j == -1 )
1445 {
1446 return;
1447 }
1448
1449 QgsWmsDimensionDialog d( mLayer, alreadyDefinedDimensions );
1450 d.setWindowTitle( tr( "Edit WMS Dimension" ) );
1451 d.setInfo( dims[j] );
1452
1453 if ( d.exec() == QDialog::Accepted )
1454 {
1455 QgsMapLayerServerProperties::WmsDimensionInfo info = d.info();
1456
1457 // remove old
1458 QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
1459 serverProperties->removeWmsDimension( wmsDimName );
1460 int idx = mWmsDimensionsTreeWidget->indexOfTopLevelItem( item );
1461 mWmsDimensionsTreeWidget->takeTopLevelItem( idx );
1462
1463 // save new
1464 serverProperties->addWmsDimension( info );
1465 addWmsDimensionInfoToTreeWidget( info, idx );
1466 }
1467}
1468
1469void QgsVectorLayerProperties::addWmsDimensionInfoToTreeWidget( const QgsMapLayerServerProperties::WmsDimensionInfo &wmsDim, const int insertIndex )
1470{
1471 QTreeWidgetItem *wmsDimensionItem = new QTreeWidgetItem();
1472 wmsDimensionItem->setFlags( Qt::ItemIsEnabled );
1473
1474 wmsDimensionItem->setText( 0, tr( "Dimension" ) );
1475 wmsDimensionItem->setText( 1, wmsDim.name );
1476
1477 QFont f = wmsDimensionItem->font( 0 );
1478 f.setBold( true );
1479 wmsDimensionItem->setFont( 0, f );
1480 wmsDimensionItem->setFont( 1, f );
1481
1482 wmsDimensionItem->setData( 0, Qt::UserRole, wmsDim.name );
1483
1484 QTreeWidgetItem *childWmsDimensionField = new QTreeWidgetItem();
1485 childWmsDimensionField->setText( 0, tr( "Field" ) );
1486 childWmsDimensionField->setText( 1, wmsDim.fieldName );
1487 childWmsDimensionField->setFlags( Qt::ItemIsEnabled );
1488 wmsDimensionItem->addChild( childWmsDimensionField );
1489
1490 QTreeWidgetItem *childWmsDimensionEndField = new QTreeWidgetItem();
1491 childWmsDimensionEndField->setText( 0, tr( "End field" ) );
1492 childWmsDimensionEndField->setText( 1, wmsDim.endFieldName );
1493 childWmsDimensionEndField->setFlags( Qt::ItemIsEnabled );
1494 wmsDimensionItem->addChild( childWmsDimensionEndField );
1495
1496 QTreeWidgetItem *childWmsDimensionUnits = new QTreeWidgetItem();
1497 childWmsDimensionUnits->setText( 0, tr( "Units" ) );
1498 childWmsDimensionUnits->setText( 1, wmsDim.units );
1499 childWmsDimensionUnits->setFlags( Qt::ItemIsEnabled );
1500 wmsDimensionItem->addChild( childWmsDimensionUnits );
1501
1502 QTreeWidgetItem *childWmsDimensionUnitSymbol = new QTreeWidgetItem();
1503 childWmsDimensionUnitSymbol->setText( 0, tr( "Unit symbol" ) );
1504 childWmsDimensionUnitSymbol->setText( 1, wmsDim.unitSymbol );
1505 childWmsDimensionUnitSymbol->setFlags( Qt::ItemIsEnabled );
1506 wmsDimensionItem->addChild( childWmsDimensionUnitSymbol );
1507
1508 QTreeWidgetItem *childWmsDimensionDefaultValue = new QTreeWidgetItem();
1509 childWmsDimensionDefaultValue->setText( 0, tr( "Default display" ) );
1510 childWmsDimensionDefaultValue->setText( 1, QgsMapLayerServerProperties::wmsDimensionDefaultDisplayLabels().value( wmsDim.defaultDisplayType ) );
1511 childWmsDimensionDefaultValue->setFlags( Qt::ItemIsEnabled );
1512 wmsDimensionItem->addChild( childWmsDimensionDefaultValue );
1513
1514 QTreeWidgetItem *childWmsDimensionRefValue = new QTreeWidgetItem();
1515 childWmsDimensionRefValue->setText( 0, tr( "Reference value" ) );
1516 childWmsDimensionRefValue->setText( 1, wmsDim.referenceValue.toString() );
1517 childWmsDimensionRefValue->setFlags( Qt::ItemIsEnabled );
1518 wmsDimensionItem->addChild( childWmsDimensionRefValue );
1519
1520 if ( insertIndex >= 0 )
1521 mWmsDimensionsTreeWidget->insertTopLevelItem( insertIndex, wmsDimensionItem );
1522 else
1523 mWmsDimensionsTreeWidget->addTopLevelItem( wmsDimensionItem );
1524
1525 mWmsDimensionsTreeWidget->setCurrentItem( wmsDimensionItem );
1526 mWmsDimensionsTreeWidget->header()->setSectionResizeMode( QHeaderView::ResizeToContents );
1527}
1528
1529void QgsVectorLayerProperties::mButtonRemoveWmsDimension_clicked()
1530{
1531 QTreeWidgetItem *currentWmsDimensionItem = mWmsDimensionsTreeWidget->currentItem();
1532 if ( !mLayer || !currentWmsDimensionItem )
1533 {
1534 return;
1535 }
1536
1537 QgsMapLayerServerProperties *serverProperties = static_cast<QgsMapLayerServerProperties *>( mLayer->serverProperties() );
1538 serverProperties->removeWmsDimension( currentWmsDimensionItem->data( 0, Qt::UserRole ).toString() );
1539 mWmsDimensionsTreeWidget->takeTopLevelItem( mWmsDimensionsTreeWidget->indexOfTopLevelItem( currentWmsDimensionItem ) );
1540}
1541
1542
1543void QgsVectorLayerProperties::updateSymbologyPage()
1544{
1545 //find out the type of renderer in the vectorlayer, create a dialog with these settings and add it to the form
1546 delete mRendererDialog;
1547 mRendererDialog = nullptr;
1548
1549 if ( mLayer->renderer() )
1550 {
1551 mRendererDialog = new QgsRendererPropertiesDialog( mLayer, QgsStyle::defaultStyle(), true, this );
1552 mRendererDialog->setDockMode( false );
1553 QgsSymbolWidgetContext context;
1554 context.setMapCanvas( mCanvas );
1555 context.setMessageBar( mMessageBar );
1556 mRendererDialog->setContext( context );
1557 connect( mRendererDialog, &QgsRendererPropertiesDialog::showPanel, this, &QgsVectorLayerProperties::openPanel );
1558 connect( mRendererDialog, &QgsRendererPropertiesDialog::layerVariablesChanged, this, &QgsVectorLayerProperties::updateVariableEditor );
1559 connect( mRendererDialog, &QgsRendererPropertiesDialog::widgetChanged, this, [this] { updateAuxiliaryStoragePage(); } );
1560 }
1561 else
1562 {
1563 mOptsPage_Style->setEnabled( false ); // hide symbology item
1564 }
1565
1566 if ( mRendererDialog )
1567 {
1568 mRendererDialog->layout()->setContentsMargins( 0, 0, 0, 0 );
1569 widgetStackRenderers->addWidget( mRendererDialog );
1570 widgetStackRenderers->setCurrentWidget( mRendererDialog );
1571 widgetStackRenderers->currentWidget()->layout()->setContentsMargins( 0, 0, 0, 0 );
1572 }
1573}
1574
1575void QgsVectorLayerProperties::setPbnQueryBuilderEnabled()
1576{
1577 pbnQueryBuilder->setEnabled( mLayer && mLayer->dataProvider() && mLayer->dataProvider()->supportsSubsetString() && !mLayer->isEditable() );
1578
1579 if ( mLayer && mLayer->isEditable() )
1580 {
1581 pbnQueryBuilder->setToolTip( tr( "Stop editing mode to enable this." ) );
1582 }
1583}
1584
1585void QgsVectorLayerProperties::pbnUpdateExtents_clicked()
1586{
1587 mLayer->updateExtents( true ); // force update whatever options activated
1588 mMetadataFilled = false;
1589}
1590
1592{
1594
1595 if ( index == mOptStackedWidget->indexOf( mOptsPage_Information ) && !mMetadataFilled )
1596 {
1597 // set the metadata contents (which can be expensive)
1598 teMetadataViewer->clear();
1599 teMetadataViewer->setHtml( htmlMetadata() );
1600 mMetadataFilled = true;
1601 }
1602 else if ( index == mOptStackedWidget->indexOf( mOptsPage_SourceFields ) || index == mOptStackedWidget->indexOf( mOptsPage_Joins ) )
1603 {
1604 // store any edited attribute form field configuration to prevent loss of edits when adding/removing fields and/or joins
1605 mAttributesFormPropertiesDialog->store();
1606 }
1607 else if ( index == mOptStackedWidget->indexOf( mOptsPage_AttributesForm ) )
1608 {
1609 // Refresh actions in Available Widgets panel
1610 if ( mActionDialog )
1611 {
1612 mAttributesFormPropertiesDialog->initAvailableWidgetsActions( mActionDialog->actions() );
1613 }
1614 }
1615
1616 resizeAlltabs( index );
1617}
1618
1619void QgsVectorLayerProperties::mSimplifyDrawingGroupBox_toggled( bool checked )
1620{
1621 const QgsVectorDataProvider *provider = mLayer->dataProvider();
1622 if ( !( provider && ( provider->capabilities() & Qgis::VectorProviderCapability::SimplifyGeometries ) != 0 ) )
1623 {
1624 mSimplifyDrawingAtProvider->setEnabled( false );
1625 }
1626 else
1627 {
1628 mSimplifyDrawingAtProvider->setEnabled( checked );
1629 }
1630}
1631
1632void QgsVectorLayerProperties::updateVariableEditor()
1633{
1634 QgsExpressionContext context;
1635 mVariableEditor->setContext( &context );
1636 mVariableEditor->context()->appendScope( QgsExpressionContextUtils::globalScope() );
1637 mVariableEditor->context()->appendScope( QgsExpressionContextUtils::projectScope( QgsProject::instance() ) );
1638 mVariableEditor->context()->appendScope( QgsExpressionContextUtils::layerScope( mLayer ) );
1639 mVariableEditor->reloadContext();
1640 mVariableEditor->setEditableScopeIndex( 2 );
1641}
1642
1643void QgsVectorLayerProperties::showHelp()
1644{
1645 const QVariant helpPage = mOptionsStackedWidget->currentWidget()->property( "helpPage" );
1646
1647 if ( helpPage.isValid() )
1648 {
1649 QgsHelp::openHelp( helpPage.toString() );
1650 }
1651 else
1652 {
1653 QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html" ) );
1654 }
1655}
1656
1657void QgsVectorLayerProperties::updateAuxiliaryStoragePage()
1658{
1659 const QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
1660
1661 if ( alayer )
1662 {
1663 // set widgets to enable state
1664 mAuxiliaryStorageInformationGrpBox->setEnabled( true );
1665 mAuxiliaryStorageFieldsGrpBox->setEnabled( true );
1666
1667 // update key
1668 mAuxiliaryStorageKeyLineEdit->setText( alayer->joinInfo().targetFieldName() );
1669
1670 // update feature count
1671 const qlonglong features = alayer->featureCount();
1672 mAuxiliaryStorageFeaturesLineEdit->setText( QLocale().toString( features ) );
1673
1674 // update actions
1675 mAuxiliaryLayerActionClear->setEnabled( true );
1676 mAuxiliaryLayerActionDelete->setEnabled( true );
1677 mAuxiliaryLayerActionExport->setEnabled( true );
1678 mAuxiliaryLayerActionNew->setEnabled( false );
1679
1680 const QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
1681 if ( alayer )
1682 {
1683 const int fields = alayer->auxiliaryFields().count();
1684 mAuxiliaryStorageFieldsLineEdit->setText( QLocale().toString( fields ) );
1685
1686 // add fields
1687 mAuxiliaryStorageFieldsTree->clear();
1688 for ( const QgsField &field : alayer->auxiliaryFields() )
1689 {
1690 const QgsPropertyDefinition prop = QgsAuxiliaryLayer::propertyDefinitionFromField( field );
1691 QTreeWidgetItem *item = new QTreeWidgetItem();
1692
1693 item->setText( 0, prop.origin() );
1694 item->setText( 1, prop.name() );
1695 item->setText( 2, prop.comment() );
1696 item->setText( 3, field.typeName() );
1697 item->setText( 4, field.name() );
1698
1699 mAuxiliaryStorageFieldsTree->addTopLevelItem( item );
1700 }
1701 }
1702 }
1703 else
1704 {
1705 mAuxiliaryStorageInformationGrpBox->setEnabled( false );
1706 mAuxiliaryStorageFieldsGrpBox->setEnabled( false );
1707
1708 mAuxiliaryLayerActionClear->setEnabled( false );
1709 mAuxiliaryLayerActionDelete->setEnabled( false );
1710 mAuxiliaryLayerActionExport->setEnabled( false );
1711 mAuxiliaryLayerActionNew->setEnabled( true );
1712
1713 mAuxiliaryStorageFieldsTree->clear();
1714 mAuxiliaryStorageKeyLineEdit->setText( QString() );
1715 mAuxiliaryStorageFieldsLineEdit->setText( QString() );
1716 mAuxiliaryStorageFeaturesLineEdit->setText( QString() );
1717 }
1718}
1719
1720void QgsVectorLayerProperties::onAuxiliaryLayerNew()
1721{
1722 QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
1723
1724 if ( alayer )
1725 return;
1726
1727 QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
1728 if ( dlg.exec() == QDialog::Accepted )
1729 {
1730 updateAuxiliaryStoragePage();
1731 }
1732}
1733
1734void QgsVectorLayerProperties::onAuxiliaryLayerClear()
1735{
1736 QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
1737
1738 if ( !alayer )
1739 return;
1740
1741 const QString msg = tr( "Are you sure you want to clear auxiliary data for %1?" ).arg( mLayer->name() );
1742 QMessageBox::StandardButton reply;
1743 reply = QMessageBox::question( this, "Clear Auxiliary Data", msg, QMessageBox::Yes | QMessageBox::No );
1744
1745 if ( reply == QMessageBox::Yes )
1746 {
1747 QApplication::setOverrideCursor( Qt::WaitCursor );
1748 alayer->clear();
1749 QApplication::restoreOverrideCursor();
1750 updateAuxiliaryStoragePage();
1751 mLayer->triggerRepaint();
1752 }
1753}
1754
1755void QgsVectorLayerProperties::onAuxiliaryLayerDelete()
1756{
1757 QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
1758 if ( !alayer )
1759 return;
1760
1761 const QString msg = tr( "Are you sure you want to delete auxiliary storage for %1?" ).arg( mLayer->name() );
1762 QMessageBox::StandardButton reply;
1763 reply = QMessageBox::question( this, "Delete Auxiliary Storage", msg, QMessageBox::Yes | QMessageBox::No );
1764
1765 if ( reply == QMessageBox::Yes )
1766 {
1767 QApplication::setOverrideCursor( Qt::WaitCursor );
1768 QgsDataSourceUri uri( alayer->source() );
1769
1770 // delete each attribute to correctly update layer settings and data
1771 // defined buttons
1772 while ( alayer->auxiliaryFields().size() > 0 )
1773 {
1774 QgsField aField = alayer->auxiliaryFields()[0];
1775 deleteAuxiliaryField( alayer->fields().indexOf( aField.name() ) );
1776 }
1777
1778 mLayer->setAuxiliaryLayer(); // remove auxiliary layer
1780 QApplication::restoreOverrideCursor();
1781 updateAuxiliaryStoragePage();
1782 mLayer->triggerRepaint();
1783 }
1784}
1785
1786void QgsVectorLayerProperties::onAuxiliaryLayerDeleteField()
1787{
1788 QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
1789 if ( !alayer )
1790 return;
1791
1792 QList<QTreeWidgetItem *> items = mAuxiliaryStorageFieldsTree->selectedItems();
1793 if ( items.count() < 1 )
1794 return;
1795
1796 // get auxiliary field name and index from item
1797 const QTreeWidgetItem *item = items[0];
1798 QgsPropertyDefinition def;
1799 def.setOrigin( item->text( 0 ) );
1800 def.setName( item->text( 1 ) );
1801 def.setComment( item->text( 2 ) );
1802
1803 const QString fieldName = QgsAuxiliaryLayer::nameFromProperty( def );
1804
1805 const int index = mLayer->auxiliaryLayer()->fields().indexOf( fieldName );
1806 if ( index < 0 )
1807 return;
1808
1809 // should be only 1 field
1810 const QString msg = tr( "Are you sure you want to delete auxiliary field %1 for %2?" ).arg( item->text( 1 ), item->text( 0 ) );
1811
1812 QMessageBox::StandardButton reply;
1813 const QString title = QObject::tr( "Delete Auxiliary Field" );
1814 reply = QMessageBox::question( this, title, msg, QMessageBox::Yes | QMessageBox::No );
1815
1816 if ( reply == QMessageBox::Yes )
1817 {
1818 QApplication::setOverrideCursor( Qt::WaitCursor );
1819 deleteAuxiliaryField( index );
1820 mLayer->triggerRepaint();
1821 QApplication::restoreOverrideCursor();
1822 }
1823}
1824
1825void QgsVectorLayerProperties::onAuxiliaryLayerAddField()
1826{
1827 QgsAuxiliaryLayer *alayer = mLayer->auxiliaryLayer();
1828 if ( !alayer )
1829 return;
1830
1831 QgsNewAuxiliaryFieldDialog dlg( QgsPropertyDefinition(), mLayer, false );
1832 if ( dlg.exec() == QDialog::Accepted )
1833 {
1834 updateAuxiliaryStoragePage();
1835 }
1836}
1837
1838void QgsVectorLayerProperties::deleteAuxiliaryField( int index )
1839{
1840 if ( !mLayer->auxiliaryLayer() )
1841 return;
1842
1843 int key = mLayer->auxiliaryLayer()->propertyFromIndex( index );
1844 QgsPropertyDefinition def = mLayer->auxiliaryLayer()->propertyDefinitionFromIndex( index );
1845
1846 if ( mLayer->auxiliaryLayer()->deleteAttribute( index ) )
1847 {
1848 mLayer->updateFields();
1849
1850 // immediately deactivate data defined button
1851 if ( key >= 0 && def.origin().compare( "labeling", Qt::CaseInsensitive ) == 0
1852 && labelingDialog
1853 && labelingDialog->labelingGui() )
1854 {
1855 labelingDialog->labelingGui()->deactivateField( static_cast<QgsPalLayerSettings::Property>( key ) );
1856 }
1857
1858 updateAuxiliaryStoragePage();
1859 mSourceFieldsPropertiesDialog->init();
1860 }
1861 else
1862 {
1863 const QString title = QObject::tr( "Delete Auxiliary Field" );
1864 const QString errors = mLayer->auxiliaryLayer()->commitErrors().join( QLatin1String( "\n " ) );
1865 const QString msg = QObject::tr( "Unable to remove auxiliary field (%1)" ).arg( errors );
1866 mMessageBar->pushMessage( title, msg, Qgis::MessageLevel::Warning );
1867 }
1868}
1869
1870bool QgsVectorLayerProperties::eventFilter( QObject *obj, QEvent *ev )
1871{
1872 // If the map tip preview container is resized, resize the map tip
1873 if ( obj == mMapTipPreviewContainer && ev->type() == QEvent::Resize )
1874 {
1875 resizeMapTip();
1876 }
1877 return QgsOptionsDialogBase::eventFilter( obj, ev );
1878}
1879
1880void QgsVectorLayerProperties::initMapTipPreview()
1881{
1882 // HTML editor and preview are in a splitter. By default, the editor takes 2/3 of the space
1883 mMapTipSplitter->setSizes( { 400, 200 } );
1884 // Event filter is used to resize the map tip when the container is resized
1885 mMapTipPreviewContainer->installEventFilter( this );
1886
1887 // Note: there's quite a bit of overlap between this and the code in QgsMapTip::showMapTip
1888 // Create the WebView
1889 mMapTipPreview = new QgsWebView( mMapTipPreviewContainer );
1890 mMapTipPreviewLayout->addWidget( mMapTipPreview );
1891
1892#if WITH_QTWEBKIT
1893 mMapTipPreview->page()->setLinkDelegationPolicy( QWebPage::DelegateAllLinks ); //Handle link clicks by yourself
1894 mMapTipPreview->setContextMenuPolicy( Qt::NoContextMenu ); //No context menu is allowed if you don't need it
1895 connect( mMapTipPreview, &QWebView::loadFinished, this, &QgsVectorLayerProperties::resizeMapTip );
1896#endif
1897
1898 mMapTipPreview->page()->settings()->setAttribute( QWebSettings::DeveloperExtrasEnabled, true );
1899 mMapTipPreview->page()->settings()->setAttribute( QWebSettings::JavascriptEnabled, true );
1900 mMapTipPreview->page()->settings()->setAttribute( QWebSettings::LocalStorageEnabled, true );
1901
1902 // Disable scrollbars, avoid random resizing issues
1903 mMapTipPreview->page()->mainFrame()->setScrollBarPolicy( Qt::Horizontal, Qt::ScrollBarAlwaysOff );
1904 mMapTipPreview->page()->mainFrame()->setScrollBarPolicy( Qt::Vertical, Qt::ScrollBarAlwaysOff );
1905
1906 // Update the map tip preview when the expression or the map tip template changes
1907 connect( mMapTipWidget, &QgsCodeEditorHTML::textChanged, this, &QgsVectorLayerProperties::updateMapTipPreview );
1908 connect( mDisplayExpressionWidget, qOverload<const QString &>( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsVectorLayerProperties::updateMapTipPreview );
1909}
1910
1911void QgsVectorLayerProperties::updateMapTipPreview()
1912{
1913 mMapTipPreview->setMaximumSize( mMapTipPreviewContainer->width(), mMapTipPreviewContainer->height() );
1914 const QString htmlContent = QgsMapTip::vectorMapTipPreviewText( mLayer, mCanvas, mMapTipWidget->text(), mDisplayExpressionWidget->asExpression() );
1915 mMapTipPreview->setHtml( htmlContent );
1916}
1917
1918void QgsVectorLayerProperties::resizeMapTip()
1919{
1920 // Ensure the map tip is not bigger than the container
1921 mMapTipPreview->setMaximumSize( mMapTipPreviewContainer->width(), mMapTipPreviewContainer->height() );
1922#if WITH_QTWEBKIT
1923 // Get the content size
1924 const QWebElement container = mMapTipPreview->page()->mainFrame()->findFirstElement(
1925 QStringLiteral( "#QgsWebViewContainer" )
1926 );
1927 const int width = container.geometry().width();
1928 const int height = container.geometry().height();
1929 mMapTipPreview->resize( width, height );
1930
1931 // Move the map tip to the center of the container
1932 mMapTipPreview->move( ( mMapTipPreviewContainer->width() - mMapTipPreview->width() ) / 2, ( mMapTipPreviewContainer->height() - mMapTipPreview->height() ) / 2 );
1933
1934#else
1935 mMapTipPreview->adjustSize();
1936#endif
1937}
@ SimplifyGeometries
Supports simplification of geometries on provider side according to a distance tolerance.
Definition qgis.h:511
@ SelectEncoding
Allows user to select encoding.
Definition qgis.h:509
@ CreateSpatialIndex
Allows creation of spatial index.
Definition qgis.h:506
QFlags< VectorRenderingSimplificationFlag > VectorRenderingSimplificationFlags
Simplification flags for vector feature rendering.
Definition qgis.h:3044
@ Present
A valid spatial index exists for the source.
Definition qgis.h:561
@ AntialiasingSimplification
The geometries can be rendered with 'AntiAliasing' disabled because of it is '1-pixel size'.
Definition qgis.h:3032
@ NoSimplification
No simplification can be applied.
Definition qgis.h:3030
@ GeometrySimplification
The geometries can be simplified using the current map2pixel context state.
Definition qgis.h:3031
VectorSimplificationAlgorithm
Simplification algorithms for vector features.
Definition qgis.h:3013
@ Distance
The simplification uses the distance between points to remove duplicate points.
Definition qgis.h:3014
@ SnapToGrid
The simplification uses a grid (similar to ST_SnapToGrid) to remove duplicate points.
Definition qgis.h:3015
@ Visvalingam
The simplification gives each point in a line an importance weighting, so that least important points...
Definition qgis.h:3016
@ Warning
Warning message.
Definition qgis.h:158
static QString defaultProjectScales()
A string with default project scales.
Definition qgis.cpp:671
@ Point
Points.
Definition qgis.h:359
@ Line
Lines.
Definition qgis.h:360
@ Polygon
Polygons.
Definition qgis.h:361
@ Unknown
Unknown types.
Definition qgis.h:362
@ Null
No geometry.
Definition qgis.h:363
QFlags< DataProviderReadFlag > DataProviderReadFlags
Flags which control data provider construction.
Definition qgis.h:486
QFlags< VectorProviderCapability > VectorProviderCapabilities
Vector data provider capabilities.
Definition qgis.h:536
@ Marker
Marker symbol.
Definition qgis.h:611
@ Line
Line symbol.
Definition qgis.h:612
@ Fill
Fill symbol.
Definition qgis.h:613
@ CustomColor
Use default symbol with a custom selection color.
Definition qgis.h:1760
@ CustomSymbol
Use a custom symbol.
Definition qgis.h:1761
@ Default
Use default symbol and selection colors.
Definition qgis.h:1759
Utility class that encapsulates an action based on vector attributes.
Definition qgsaction.h:37
static QString reportStyleSheet(QgsApplication::StyleSheetType styleSheetType=QgsApplication::StyleSheetType::Qt)
Returns a css style sheet for reports, the styleSheetType argument determines what type of stylesheet...
A dialog for configuring vector layer actions.
A container for configuration of the attribute table.
void setSortExpression(const QString &sortExpression)
Set the sort expression used for sorting.
@ 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 setSortOrder(Qt::SortOrder sortOrder)
Set the sort order.
void setColumns(const QVector< QgsAttributeTableConfig::ColumnConfig > &columns)
Set the list of columns visible in the attribute table.
Creates panels to configure attributes forms.
static QString nameFromProperty(const QgsPropertyDefinition &def, bool joined=false)
Returns the name of the auxiliary field for a property definition.
static QgsPropertyDefinition propertyDefinitionFromField(const QgsField &field)
Returns the property definition from an auxiliary field.
bool clear()
Deletes all features from the layer.
QgsFields auxiliaryFields() const
Returns a list of all auxiliary fields currently managed by the layer.
QgsVectorLayerJoinInfo joinInfo() const
Returns information to use for joining with primary key and so on.
static bool deleteTable(const QgsDataSourceUri &uri)
Removes a table from the auxiliary storage.
Represents a coordinate reference system (CRS).
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...
A widget for configuring layer diagrams.
void auxiliaryFieldCreated()
Emitted when an auxiliary field is created.
virtual QgsExpressionContext createExpressionContext() const =0
This method needs to be reimplemented in all classes which implement this interface and return an exp...
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...
static QString findAndSelectActiveExpression(QgsCodeEditor *editor, const QString &pattern=QString())
Find the expression under the cursor in the given editor and select it.
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
QString name
Definition qgsfield.h:63
int count
Definition qgsfields.h:50
Q_INVOKABLE int indexFromName(const QString &fieldName) const
Gets the field index from the field name.
Q_INVOKABLE int indexOf(const QString &fieldName) const
Gets the field index from the field name.
int size() const
Returns number of items.
static QString stringToSafeFilename(const QString &string)
Converts a string to a safe filename, replacing characters which are not safe for filenames with an '...
static QgsProviderSourceWidgetProviderRegistry * sourceWidgetProviderRegistry()
Returns the registry of provider source widget providers.
Definition qgsgui.cpp:131
static QgsSubsetStringEditorProviderRegistry * subsetStringEditorProviderRegistry()
Returns the registry of subset string editors of data providers.
Definition qgsgui.cpp:126
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:38
Master widget for configuration of labeling of a vector layer.
void auxiliaryFieldCreated()
Emitted when an auxiliary field is created.
QPushButton * mBtnStyle
Style button.
void saveMetadataToFile()
Allows the user to save the layer's metadata as a file.
virtual void rollback()
Rolls back changes made to the layer.
void optionsStackedWidget_CurrentChanged(int index) override
QList< QgsMapLayerConfigWidget * > mConfigWidgets
Layer config widgets.
void setMetadataWidget(QgsMetadataWidget *widget, QWidget *page)
Sets the metadata widget and page associated with the dialog.
void loadDefaultStyle()
Reloads the default style for the layer.
void saveStyleAs()
Saves a style when appriate button is pressed.
void loadStyle()
Triggers a dialog to load a saved style.
QgsMapCanvas * mCanvas
Associated map canvas.
void loadDefaultMetadata()
Reloads the default layer metadata for the layer.
QgsLayerPropertiesDialog(QgsMapLayer *layer, QgsMapCanvas *canvas, const QString &settingsKey, QWidget *parent=nullptr, Qt::WindowFlags fl=Qt::WindowFlags(), QgsSettings *settings=nullptr)
Constructor for QgsLayerPropertiesDialog.
void loadMetadataFromFile()
Allows the user to load layer metadata from a file.
void saveDefaultStyle()
Saves the default style when appropriate button is pressed.
QPushButton * mBtnMetadata
Metadata button.
void initialize()
Initialize the dialog.
void saveMetadataAsDefault()
Saves the current layer metadata as the default for the layer.
void openUrl(const QUrl &url)
Handles opening a url from the dialog.
A sort filter proxy model to easily reproduce the legend/layer tree in a tree view.
A model representing the layer tree, including layers and groups of layers.
Map canvas is a class for displaying all GIS data types on a canvas.
A panel widget that can be shown in the map style dock.
Models dependencies with or between map layers.
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
void currentStyleChanged(const QString &currentName)
Emitted when the current style has been changed.
Base class for all map layer types.
Definition qgsmaplayer.h:80
QString name
Definition qgsmaplayer.h:84
QString source() const
Returns the source for the layer.
QString id
Definition qgsmaplayer.h:83
QgsMapLayerStyleManager * styleManager() const
Gets access to the layer's style manager.
Contains configuration for rendering maps.
static QString vectorMapTipPreviewText(QgsMapLayer *layer, QgsMapCanvas *mapCanvas, const QString &mapTemplate, const QString &displayExpression)
Returns the html that would be displayed in a maptip for a given layer.
A bar for displaying non-blocking messages to the user.
A wizard to edit metadata on a map layer.
void resizeAlltabs(int index)
Resizes all tabs when the dialog is resized.
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 an inline panel.
QString panelTitle() const
The title of the panel.
void acceptPanel()
Accept the panel.
static QgsProject * instance()
Returns the QgsProject singleton instance.
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).
void crsChanged(const QgsCoordinateReferenceSystem &crs)
Emitted when the selected CRS is changed.
QString comment() const
Returns the comment of the property.
void setOrigin(const QString &origin)
Sets the origin of the property.
QString name() const
Returns the name of the property.
void setName(const QString &name)
Sets the name of the property.
QString origin() const
Returns the origin of the property.
void setComment(const QString &comment)
Sets comment of the property.
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.
A dialog for configuring vector layer renderers.
void showPanel(QgsPanelWidget *panel)
Emit when you require a panel to be show in the interface.
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.
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.
Stores settings for use within QGIS.
Definition qgssettings.h:65
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.
A widget which displays information about vector layer fields, and allows some configuration of them.
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:147
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.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
void setMessageBar(QgsMessageBar *bar)
Sets the message bar associated with the widget.
Abstract base class for all rendered symbols.
Definition qgssymbol.h:231
Base class for vector data providers.
static QStringList availableEncodings()
Returns a list of available encodings.
virtual bool createSpatialIndex()
Creates a spatial index on the datasource (if supported by the provider type).
virtual Q_INVOKABLE Qgis::VectorProviderCapabilities capabilities() const
Returns flags containing the supported capabilities.
virtual bool createAttributeIndex(int field)
Create an attribute index on the datasource.
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).
bool eventFilter(QObject *obj, QEvent *ev) override
QgsVectorLayerProperties(QgsMapCanvas *canvas, QgsMessageBar *messageBar, QgsVectorLayer *lyr=nullptr, QWidget *parent=nullptr, Qt::WindowFlags fl=QgsGuiUtils::ModalDialogFlags)
void optionsStackedWidget_CurrentChanged(int index) final
void toggleEditing(QgsMapLayer *)
void exportAuxiliaryLayer(QgsAuxiliaryLayer *layer)
Implementation of layer selection properties for vector layers.
void setSelectionSymbol(QgsSymbol *symbol)
Sets the symbol used to render selected features in the layer.
QgsSymbol * selectionSymbol() const
Returns the symbol used to render selected features in the layer.
void setSelectionColor(const QColor &color)
Sets the color to use for rendering selected features in the layer.
void setSelectionRenderingMode(Qgis::SelectionRenderingMode mode)
Sets the selection rendering mode to use for selected features in the layer.
A widget for configuring the temporal properties for a vector layer.
Represents a vector layer which manages a vector based dataset.
long long featureCount(const QString &legendKey) const
Number of features rendered with specified legend key.
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
QgsVectorDataProvider * dataProvider() final
Returns the layer's data provider, it may be nullptr.
Contains settings for simplifying geometries fetched from a vector layer.
bool forceLocalOptimization() const
Gets where the simplification executes, after fetch the geometries from provider, or when supported,...
Qgis::VectorRenderingSimplificationFlags simplifyHints() const
Gets the simplification hints of the vector layer managed.
float maximumScale() const
Gets the maximum scale at which the layer should be simplified.
Qgis::VectorSimplificationAlgorithm simplifyAlgorithm() const
Gets the local simplification algorithm of the vector layer managed.
void setThreshold(float threshold)
Sets the simplification threshold of the vector layer managed.
void setForceLocalOptimization(bool localOptimization)
Sets where the simplification executes, after fetch the geometries from provider, or when supported,...
void setSimplifyHints(Qgis::VectorRenderingSimplificationFlags simplifyHints)
Sets the simplification hints of the vector layer managed.
float threshold() const
Gets the simplification threshold of the vector layer managed.
void setMaximumScale(float maximumScale)
Sets the maximum scale at which the layer should be simplified.
void setSimplifyAlgorithm(Qgis::VectorSimplificationAlgorithm simplifyAlgorithm)
Sets the local simplification algorithm of the vector layer managed.
Setting options for creating vector data providers.
Setting to define QGIS Server WMS Dimension.