QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
qgsmeshlayerproperties.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmeshlayerproperties.cpp
3  --------------------------
4  begin : Jun 2018
5  copyright : (C) 2018 by Peter Petrik
6  email : zilolv at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include <limits>
19 #include <typeinfo>
20 
21 #include "qgsapplication.h"
22 #include "qgscoordinatetransform.h"
23 #include "qgsfileutils.h"
24 #include "qgshelp.h"
25 #include "qgslogger.h"
26 #include "qgsmapcanvas.h"
29 #include "qgsmeshlayer.h"
30 #include "qgsmeshlayerproperties.h"
32 #include "qgsproject.h"
36 #include "qgssettings.h"
37 #include "qgsprojecttimesettings.h"
38 #include "qgsproviderregistry.h"
41 #include "qgsgui.h"
42 #include "qgsnative.h"
43 #include "qgsmetadatawidget.h"
44 
45 #include <QDesktopServices>
46 #include <QFileDialog>
47 #include <QMessageBox>
48 
49 QgsMeshLayerProperties::QgsMeshLayerProperties( QgsMapLayer *lyr, QgsMapCanvas *canvas, QWidget *parent, Qt::WindowFlags fl )
50  : QgsOptionsDialogBase( QStringLiteral( "MeshLayerProperties" ), parent, fl )
51  , mMeshLayer( qobject_cast<QgsMeshLayer *>( lyr ) )
52  , mCanvas( canvas )
53 {
54  Q_ASSERT( mMeshLayer );
55 
56  setupUi( this );
57  mRendererMeshPropertiesWidget = new QgsRendererMeshPropertiesWidget( mMeshLayer, canvas, this );
58  mConfigWidgets << mRendererMeshPropertiesWidget;
59  mOptsPage_StyleContent->layout()->addWidget( mRendererMeshPropertiesWidget );
60 
61  mSimplifyReductionFactorSpinBox->setClearValue( 10.0 );
62  mSimplifyMeshResolutionSpinBox->setClearValue( 5 );
63 
64  mStaticDatasetWidget->setLayer( mMeshLayer );
65  mIsMapSettingsTemporal = mMeshLayer && canvas && canvas->mapSettings().isTemporal();
66 
67  mTemporalProviderTimeUnitComboBox->addItem( tr( "Seconds" ), QgsUnitTypes::TemporalSeconds );
68  mTemporalProviderTimeUnitComboBox->addItem( tr( "Minutes" ), QgsUnitTypes::TemporalMinutes );
69  mTemporalProviderTimeUnitComboBox->addItem( tr( "Hours" ), QgsUnitTypes::TemporalHours );
70  mTemporalProviderTimeUnitComboBox->addItem( tr( "Days" ), QgsUnitTypes::TemporalDays );
71 
72  connect( mCrsSelector, &QgsProjectionSelectionWidget::crsChanged, this, &QgsMeshLayerProperties::changeCrs );
73  connect( mDatasetGroupTreeWidget, &QgsMeshDatasetGroupTreeWidget::datasetGroupAdded, this, &QgsMeshLayerProperties::syncToLayer );
74 
75  // QgsOptionsDialogBase handles saving/restoring of geometry, splitter and current tab states,
76  // switching vertical tabs between icon/text to icon-only modes (splitter collapsed to left),
77  // and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
78  initOptionsBase( false );
79 
80  connect( lyr->styleManager(), &QgsMapLayerStyleManager::currentStyleChanged, this, &QgsMeshLayerProperties::syncAndRepaint );
81 
82  connect( this, &QDialog::accepted, this, &QgsMeshLayerProperties::apply );
83  connect( this, &QDialog::rejected, this, &QgsMeshLayerProperties::onCancel );
84  connect( buttonBox->button( QDialogButtonBox::Apply ), &QAbstractButton::clicked, this, &QgsMeshLayerProperties::apply );
85 
86  connect( mMeshLayer, &QgsMeshLayer::dataChanged, this, &QgsMeshLayerProperties::syncAndRepaint );
87  connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsMeshLayerProperties::showHelp );
88 
89  connect( mTemporalReloadButton, &QPushButton::clicked, this, &QgsMeshLayerProperties::reloadTemporalProperties );
90  connect( mTemporalDateTimeReference, &QDateTimeEdit::dateTimeChanged, this, &QgsMeshLayerProperties::onTimeReferenceChange );
93 
94  mComboBoxTemporalDatasetMatchingMethod->addItem( tr( "Find Closest Dataset Before Requested Time" ),
96  mComboBoxTemporalDatasetMatchingMethod->addItem( tr( "Find Closest Dataset From Requested Time (After or Before)" ),
98 
99  QVBoxLayout *layout = new QVBoxLayout( metadataFrame );
100  layout->setContentsMargins( 0, 0, 0, 0 );
101  metadataFrame->setContentsMargins( 0, 0, 0, 0 );
102  mMetadataWidget = new QgsMetadataWidget( this, mMeshLayer );
103  mMetadataWidget->layout()->setContentsMargins( 0, 0, 0, 0 );
104  mMetadataWidget->setMapCanvas( mCanvas );
105  layout->addWidget( mMetadataWidget );
106  metadataFrame->setLayout( layout );
107  mOptsPage_Metadata->setContentsMargins( 0, 0, 0, 0 );
108  mBackupCrs = mMeshLayer->crs();
109 
110  mTemporalDateTimeStart->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
111  mTemporalDateTimeEnd->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
112  mTemporalDateTimeReference->setDisplayFormat( "yyyy-MM-dd HH:mm:ss" );
113 
114  // update based on lyr's current state
115  syncToLayer();
116 
117  QgsSettings settings;
118  // if dialog hasn't been opened/closed yet, default to Styles tab, which is used most often
119  // this will be read by restoreOptionsBaseUi()
120  if ( !settings.contains( QStringLiteral( "/Windows/MeshLayerProperties/tab" ) ) )
121  {
122  settings.setValue( QStringLiteral( "Windows/MeshLayerProperties/tab" ),
123  mOptStackedWidget->indexOf( mOptsPage_Style ) );
124  }
125 
126  //Add help page references
127  mOptsPage_Information->setProperty( "helpPage", QStringLiteral( "working_with_mesh/mesh_properties.html#information-properties" ) );
128  mOptsPage_Source->setProperty( "helpPage", QStringLiteral( "working_with_mesh/mesh_properties.html#source-properties" ) );
129  mOptsPage_Style->setProperty( "helpPage", QStringLiteral( "working_with_mesh/mesh_properties.html#symbology-properties" ) );
130  mOptsPage_Rendering->setProperty( "helpPage", QStringLiteral( "working_with_mesh/mesh_properties.html#rendering-properties" ) );
131 
132  mBtnStyle = new QPushButton( tr( "Style" ) );
133  QMenu *menuStyle = new QMenu( this );
134  menuStyle->addAction( tr( "Load Style…" ), this, &QgsMeshLayerProperties::loadStyle );
135  menuStyle->addAction( tr( "Save Style…" ), this, &QgsMeshLayerProperties::saveStyleAs );
136  menuStyle->addSeparator();
137  menuStyle->addAction( tr( "Save as Default" ), this, &QgsMeshLayerProperties::saveDefaultStyle );
138  menuStyle->addAction( tr( "Restore Default" ), this, &QgsMeshLayerProperties::loadDefaultStyle );
139  mBtnStyle->setMenu( menuStyle );
140  connect( menuStyle, &QMenu::aboutToShow, this, &QgsMeshLayerProperties::aboutToShowStyleMenu );
141 
142  buttonBox->addButton( mBtnStyle, QDialogButtonBox::ResetRole );
143 
144  mBtnMetadata = new QPushButton( tr( "Metadata" ), this );
145  QMenu *menuMetadata = new QMenu( this );
146  mActionLoadMetadata = menuMetadata->addAction( tr( "Load Metadata…" ), this, &QgsMeshLayerProperties::loadMetadata );
147  mActionSaveMetadataAs = menuMetadata->addAction( tr( "Save Metadata…" ), this, &QgsMeshLayerProperties::saveMetadataAs );
148  mBtnMetadata->setMenu( menuMetadata );
149  buttonBox->addButton( mBtnMetadata, QDialogButtonBox::ResetRole );
150 
151  QString title = tr( "Layer Properties — %1" ).arg( lyr->name() );
152 
153  if ( !mMeshLayer->styleManager()->isDefault( mMeshLayer->styleManager()->currentStyle() ) )
154  title += QStringLiteral( " (%1)" ).arg( mMeshLayer->styleManager()->currentStyle() );
155  restoreOptionsBaseUi( title );
156 }
157 
159 {
160  if ( !factory->supportsLayer( mMeshLayer ) || !factory->supportLayerPropertiesDialog() )
161  {
162  return;
163  }
164 
165  QgsMapLayerConfigWidget *page = factory->createWidget( mMeshLayer, mCanvas, false, this );
166  mConfigWidgets << page;
167 
168  page->setProperty( "helpPage", QStringLiteral( "working_with_mesh/mesh_properties.html#d-view-properties" ) );
169 
170  const QString beforePage = factory->layerPropertiesPagePositionHint();
171  if ( beforePage.isEmpty() )
172  addPage( factory->title(), factory->title(), factory->icon(), page );
173  else
174  insertPage( factory->title(), factory->title(), factory->icon(), page, beforePage );
175 
176  page->syncToLayer( mMeshLayer );
177 
178 }
179 
181 {
183 
184  bool isMetadataPanel = ( index == mOptStackedWidget->indexOf( mOptsPage_Metadata ) );
185  mBtnStyle->setVisible( ! isMetadataPanel );
186  mBtnMetadata->setVisible( isMetadataPanel );
187 }
188 
189 void QgsMeshLayerProperties::syncToLayer()
190 {
191  Q_ASSERT( mRendererMeshPropertiesWidget );
192 
193  QgsDebugMsgLevel( QStringLiteral( "populate general information tab" ), 4 );
194  /*
195  * Information Tab
196  */
197  QString myStyle = QgsApplication::reportStyleSheet();
198  myStyle.append( QStringLiteral( "body { margin: 10px; }\n " ) );
199  mInformationTextBrowser->clear();
200  mInformationTextBrowser->document()->setDefaultStyleSheet( myStyle );
201  mInformationTextBrowser->setHtml( mMeshLayer->htmlMetadata() );
202  mInformationTextBrowser->setOpenLinks( false );
203  connect( mInformationTextBrowser, &QTextBrowser::anchorClicked, this, &QgsMeshLayerProperties::urlClicked );
204 
205  QgsDebugMsgLevel( QStringLiteral( "populate source tab" ), 4 );
206  /*
207  * Source Tab
208  */
209  mLayerOrigNameLineEd->setText( mMeshLayer->name() );
210  whileBlocking( mCrsSelector )->setCrs( mMeshLayer->crs() );
211 
212  if ( mMeshLayer )
213  mDatasetGroupTreeWidget->syncToLayer( mMeshLayer );
214 
215  QgsDebugMsgLevel( QStringLiteral( "populate config tab" ), 4 );
216  for ( QgsMapLayerConfigWidget *w : std::as_const( mConfigWidgets ) )
217  w->syncToLayer( mMeshLayer );
218 
219  QgsDebugMsgLevel( QStringLiteral( "populate rendering tab" ), 4 );
220  if ( mMeshLayer->isEditable() )
221  mSimplifyMeshGroupBox->setEnabled( false );
222 
223  QgsMeshSimplificationSettings simplifySettings = mMeshLayer->meshSimplificationSettings();
224  mSimplifyMeshGroupBox->setChecked( simplifySettings.isEnabled() );
225  mSimplifyReductionFactorSpinBox->setValue( simplifySettings.reductionFactor() );
226  mSimplifyMeshResolutionSpinBox->setValue( simplifySettings.meshResolution() );
227 
228  QgsDebugMsgLevel( QStringLiteral( "populate temporal tab" ), 4 );
229  const QgsMeshLayerTemporalProperties *temporalProperties = qobject_cast< const QgsMeshLayerTemporalProperties * >( mMeshLayer->temporalProperties() );
230  whileBlocking( mTemporalDateTimeReference )->setDateTime( temporalProperties->referenceTime() );
231  const QgsDateTimeRange timeRange = temporalProperties->timeExtent();
232  mTemporalDateTimeStart->setDateTime( timeRange.begin() );
233  mTemporalDateTimeEnd->setDateTime( timeRange.end() );
234  if ( mMeshLayer->dataProvider() )
235  {
236  mTemporalProviderTimeUnitComboBox->setCurrentIndex(
237  mTemporalProviderTimeUnitComboBox->findData( mMeshLayer->dataProvider()->temporalCapabilities()->temporalUnit() ) );
238  }
239  mComboBoxTemporalDatasetMatchingMethod->setCurrentIndex(
240  mComboBoxTemporalDatasetMatchingMethod->findData( temporalProperties->matchingMethod() ) );
241 
242  mStaticDatasetWidget->syncToLayer();
243  mStaticDatasetGroupBox->setChecked( !mMeshLayer->temporalProperties()->isActive() );
244 }
245 
246 void QgsMeshLayerProperties::loadDefaultStyle()
247 {
248  bool defaultLoadedFlag = false;
249  QString myMessage = mMeshLayer->loadDefaultStyle( defaultLoadedFlag );
250  // reset if the default style was loaded OK only
251  if ( defaultLoadedFlag )
252  {
253  syncToLayer();
254  }
255  else
256  {
257  // otherwise let the user know what went wrong
258  QMessageBox::information( this,
259  tr( "Default Style" ),
260  myMessage
261  );
262  }
263 }
264 
265 void QgsMeshLayerProperties::saveDefaultStyle()
266 {
267  apply(); // make sure the style to save is up-to-date
268 
269  // a flag passed by reference
270  bool defaultSavedFlag = false;
271  // after calling this the above flag will be set true for success
272  // or false if the save operation failed
273  QString myMessage = mMeshLayer->saveDefaultStyle( defaultSavedFlag );
274  if ( !defaultSavedFlag )
275  {
276  // let the user know what went wrong
277  QMessageBox::information( this,
278  tr( "Default Style" ),
279  myMessage
280  );
281  }
282 }
283 
284 void QgsMeshLayerProperties::loadStyle()
285 {
286  QgsSettings settings;
287  QString lastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
288 
289  QString fileName = QFileDialog::getOpenFileName(
290  this,
291  tr( "Load rendering setting from style file" ),
292  lastUsedDir,
293  tr( "QGIS Layer Style File" ) + " (*.qml)" );
294  if ( fileName.isEmpty() )
295  return;
296 
297  // ensure the user never omits the extension from the file name
298  if ( !fileName.endsWith( QLatin1String( ".qml" ), Qt::CaseInsensitive ) )
299  fileName += QLatin1String( ".qml" );
300 
301  mOldStyle = mMeshLayer->styleManager()->style( mMeshLayer->styleManager()->currentStyle() );
302 
303  bool defaultLoadedFlag = false;
304  QString message = mMeshLayer->loadNamedStyle( fileName, defaultLoadedFlag );
305  if ( defaultLoadedFlag )
306  {
307  settings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( fileName ).absolutePath() );
308  syncToLayer();
309  }
310  else
311  {
312  QMessageBox::information( this, tr( "Load Style" ), message );
313  }
314 }
315 
316 void QgsMeshLayerProperties::saveStyleAs()
317 {
318  QgsSettings settings;
319  QString lastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
320 
321  QString outputFileName = QFileDialog::getSaveFileName(
322  this,
323  tr( "Save layer properties as style file" ),
324  lastUsedDir,
325  tr( "QGIS Layer Style File" ) + " (*.qml)" );
326  if ( outputFileName.isEmpty() )
327  return;
328 
329  // ensure the user never omits the extension from the file name
330  outputFileName = QgsFileUtils::ensureFileNameHasExtension( outputFileName, QStringList() << QStringLiteral( "qml" ) );
331 
332  apply(); // make sure the style to save is up-to-date
333 
334  // then export style
335  bool defaultLoadedFlag = false;
336  QString message;
337  message = mMeshLayer->saveNamedStyle( outputFileName, defaultLoadedFlag );
338 
339  if ( defaultLoadedFlag )
340  {
341  settings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( outputFileName ).absolutePath() );
342  }
343  else
344  QMessageBox::information( this, tr( "Save Style" ), message );
345 }
346 
347 void QgsMeshLayerProperties::apply()
348 {
349  Q_ASSERT( mRendererMeshPropertiesWidget );
350 
351  QgsDebugMsgLevel( QStringLiteral( "processing general tab" ), 4 );
352  /*
353  * General Tab
354  */
355  mMeshLayer->setName( mLayerOrigNameLineEd->text() );
356 
357  QgsDebugMsgLevel( QStringLiteral( "processing source tab" ), 4 );
358  /*
359  * Source Tab
360  */
361  mDatasetGroupTreeWidget->apply();
362 
363  QgsDebugMsgLevel( QStringLiteral( "processing config tabs" ), 4 );
364 
365  for ( QgsMapLayerConfigWidget *w : std::as_const( mConfigWidgets ) )
366  w->apply();
367 
368  QgsDebugMsgLevel( QStringLiteral( "processing rendering tab" ), 4 );
369  /*
370  * Rendering Tab
371  */
372  QgsMeshSimplificationSettings simplifySettings;
373  simplifySettings.setEnabled( mSimplifyMeshGroupBox->isChecked() );
374  simplifySettings.setReductionFactor( mSimplifyReductionFactorSpinBox->value() );
375  simplifySettings.setMeshResolution( mSimplifyMeshResolutionSpinBox->value() );
376  bool needMeshUpdating = ( ( simplifySettings.isEnabled() != mMeshLayer->meshSimplificationSettings().isEnabled() ) ||
377  ( simplifySettings.reductionFactor() != mMeshLayer->meshSimplificationSettings().reductionFactor() ) );
378 
379  mMeshLayer->setMeshSimplificationSettings( simplifySettings );
380 
381  QgsDebugMsgLevel( QStringLiteral( "processing temporal tab" ), 4 );
382  /*
383  * Temporal Tab
384  */
385 
386  mMeshLayer->setReferenceTime( mTemporalDateTimeReference->dateTime() );
387  if ( mMeshLayer->dataProvider() )
388  mMeshLayer->dataProvider()->setTemporalUnit(
389  static_cast<QgsUnitTypes::TemporalUnit>( mTemporalProviderTimeUnitComboBox->currentData().toInt() ) );
390 
391  mStaticDatasetWidget->apply();
392  bool needEmitRendererChanged = mMeshLayer->temporalProperties()->isActive() == mStaticDatasetGroupBox->isChecked();
393  mMeshLayer->temporalProperties()->setIsActive( !mStaticDatasetGroupBox->isChecked() );
395  mComboBoxTemporalDatasetMatchingMethod->currentData().toInt() ) );
396 
397  mMetadataWidget->acceptMetadata();
398 
399  mBackupCrs = mMeshLayer->crs();
400 
401  if ( needMeshUpdating )
402  mMeshLayer->reload();
403 
404  if ( needEmitRendererChanged )
405  emit mMeshLayer->rendererChanged();
406 
407  //make sure the layer is redrawn
408  mMeshLayer->triggerRepaint();
409 
410  // notify the project we've made a change
411  QgsProject::instance()->setDirty( true );
412 
413  // Resync what have to be resync (widget that can be changed by other properties part)
414  mStaticDatasetWidget->syncToLayer();
415  for ( QgsMapLayerConfigWidget *w : std::as_const( mConfigWidgets ) )
416  w->syncToLayer( mMeshLayer );
417 }
418 
419 void QgsMeshLayerProperties::changeCrs( const QgsCoordinateReferenceSystem &crs )
420 {
421  QgsDatumTransformDialog::run( crs, QgsProject::instance()->crs(), this, mCanvas, tr( "Select Transformation" ) );
422  mMeshLayer->setCrs( crs );
423 }
424 
425 void QgsMeshLayerProperties::syncAndRepaint()
426 {
427  syncToLayer();
428  mMeshLayer->triggerRepaint();
429 }
430 
431 void QgsMeshLayerProperties::showHelp()
432 {
433  const QVariant helpPage = mOptionsStackedWidget->currentWidget()->property( "helpPage" );
434 
435  if ( helpPage.isValid() )
436  {
437  QgsHelp::openHelp( helpPage.toString() );
438  }
439  else
440  {
441  QgsHelp::openHelp( QStringLiteral( "working_with_mesh/mesh_properties.html" ) );
442  }
443 }
444 
445 void QgsMeshLayerProperties::aboutToShowStyleMenu()
446 {
447  QMenu *m = qobject_cast<QMenu *>( sender() );
448 
450  // re-add style manager actions!
451  m->addSeparator();
453 }
454 
455 void QgsMeshLayerProperties::reloadTemporalProperties()
456 {
457  if ( !mMeshLayer->dataProvider() )
458  return;
459  QgsMeshDataProviderTemporalCapabilities *temporalCapabalities = mMeshLayer->dataProvider()->temporalCapabilities();
460  QgsDateTimeRange timeExtent;
461  QDateTime referenceTime = temporalCapabalities->referenceTime();
462  if ( referenceTime.isValid() )
463  {
464  timeExtent = temporalCapabalities->timeExtent();
465  whileBlocking( mTemporalDateTimeReference )->setDateTime( referenceTime );
466  }
467  else
468  // The reference time already here is used again to define the time extent
469  timeExtent = temporalCapabalities->timeExtent( mTemporalDateTimeReference->dateTime() );
470 
471  mTemporalDateTimeStart->setDateTime( timeExtent.begin() );
472  mTemporalDateTimeEnd->setDateTime( timeExtent.end() );
473 }
474 
475 void QgsMeshLayerProperties::onTimeReferenceChange()
476 {
477  if ( !mMeshLayer->dataProvider() )
478  return;
479  const QgsDateTimeRange &timeExtent = mMeshLayer->dataProvider()->temporalCapabilities()->timeExtent( mTemporalDateTimeReference->dateTime() );
480  mTemporalDateTimeStart->setDateTime( timeExtent.begin() );
481  mTemporalDateTimeEnd->setDateTime( timeExtent.end() );
482 }
483 
484 void QgsMeshLayerProperties::urlClicked( const QUrl &url )
485 {
486  QFileInfo file( url.toLocalFile() );
487  if ( file.exists() && !file.isDir() )
488  QgsGui::instance()->nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
489  else
490  QDesktopServices::openUrl( url );
491 }
492 
493 void QgsMeshLayerProperties::loadMetadata()
494 {
495  QgsSettings myQSettings; // where we keep last used filter in persistent state
496  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
497 
498  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load layer metadata from metadata file" ), myLastUsedDir,
499  tr( "QGIS Layer Metadata File" ) + " (*.qmd)" );
500  if ( myFileName.isNull() )
501  {
502  return;
503  }
504 
505  QString myMessage;
506  bool defaultLoadedFlag = false;
507  myMessage = mMeshLayer->loadNamedMetadata( myFileName, defaultLoadedFlag );
508 
509  //reset if the default style was loaded OK only
510  if ( defaultLoadedFlag )
511  {
512  mMetadataWidget->setMetadata( &mMeshLayer->metadata() );
513  }
514  else
515  {
516  //let the user know what went wrong
517  QMessageBox::warning( this, tr( "Load Metadata" ), myMessage );
518  }
519 
520  QFileInfo myFI( myFileName );
521  QString myPath = myFI.path();
522  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), myPath );
523 
524  activateWindow(); // set focus back to properties dialog
525 }
526 
527 void QgsMeshLayerProperties::saveMetadataAs()
528 {
529  QgsSettings myQSettings; // where we keep last used filter in persistent state
530  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
531 
532  QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save Layer Metadata as QMD" ),
533  myLastUsedDir, tr( "QMD File" ) + " (*.qmd)" );
534  if ( myOutputFileName.isNull() ) //dialog canceled
535  {
536  return;
537  }
538 
539  mMetadataWidget->acceptMetadata();
540 
541  //ensure the user never omitted the extension from the file name
542  if ( !myOutputFileName.endsWith( QgsMapLayer::extensionPropertyType( QgsMapLayer::Metadata ), Qt::CaseInsensitive ) )
543  {
545  }
546 
547  bool defaultLoadedFlag = false;
548  QString message = mMeshLayer->saveNamedMetadata( myOutputFileName, defaultLoadedFlag );
549  if ( defaultLoadedFlag )
550  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( myOutputFileName ).absolutePath() );
551  else
552  QMessageBox::information( this, tr( "Save Metadata" ), message );
553 }
554 
555 void QgsMeshLayerProperties::onCancel()
556 {
557  if ( mBackupCrs != mMeshLayer->crs() )
558  mMeshLayer->setCrs( mBackupCrs );
559 }
static QString reportStyleSheet(QgsApplication::StyleSheetType styleSheetType=QgsApplication::StyleSheetType::Qt)
Returns a css style sheet for reports, the styleSheetType argument determines what type of stylesheet...
This class 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...
static QString ensureFileNameHasExtension(const QString &fileName, const QStringList &extensions)
Ensures that a fileName ends with an extension from the provided list of extensions.
static QgsGui * instance()
Returns a pointer to the singleton instance.
Definition: qgsgui.cpp:67
static QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:73
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:36
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:89
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
Factory class for creating custom map layer property pages.
virtual bool supportsLayer(QgsMapLayer *layer) const
Check if the layer is supported for this widget.
virtual QIcon icon() const
The icon that will be shown in the UI for the panel.
virtual QgsMapLayerConfigWidget * createWidget(QgsMapLayer *layer, QgsMapCanvas *canvas, bool dockWidget=true, QWidget *parent=nullptr) const =0
Factory function to create the widget on demand as needed by the dock.
virtual QString title() const
The title of the panel.
virtual bool supportLayerPropertiesDialog() const
Flag if widget is supported for use in layer properties dialog.
virtual QString layerPropertiesPagePositionHint() const
Returns a tab name hinting at where this page should be inserted into the layer properties tab list.
A panel widget that can be shown in the map style dock.
virtual void syncToLayer(QgsMapLayer *layer)
Reset to original (vector layer) values.
void removesExtraMenuSeparators(QMenu *m)
removes extra separators from the menu
void addStyleManagerActions(QMenu *m, QgsMapLayer *layer)
adds actions to the menu in accordance to the layer
static QgsMapLayerStyleGuiUtils * instance()
returns a singleton instance of this class
QString currentStyle() const
Returns name of the current style.
bool isDefault(const QString &styleName) const
Returns true if this is the default style.
QgsMapLayerStyle style(const QString &name) const
Returns data of a stored style - accessed by its unique name.
void currentStyleChanged(const QString &currentName)
Emitted when the current style has been changed.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString name
Definition: qgsmaplayer.h:76
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
virtual QString loadNamedMetadata(const QString &uri, bool &resultFlag)
Retrieve a named metadata for this layer if one exists (either as a .qmd file on disk or as a record ...
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:78
virtual QString saveDefaultStyle(bool &resultFlag)
Save the properties of this layer as the default style (either as a .qml file on disk or as a record ...
void rendererChanged()
Signal emitted when renderer is changed.
virtual QString loadNamedStyle(const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Retrieve a named style for this layer if one exists (either as a .qml file on disk or as a record in ...
void dataChanged()
Data of layer changed.
static QString extensionPropertyType(PropertyType type)
Returns the extension of a Property.
Definition: qgsmaplayer.cpp:68
void setName(const QString &name)
Set the display name of the layer.
QString saveNamedMetadata(const QString &uri, bool &resultFlag)
Save the current metadata of this layer as a named metadata (either as a .qmd file on disk or as a re...
QgsMapLayerStyleManager * styleManager() const
Gets access to the layer's style manager.
virtual QString saveNamedStyle(const QString &uri, bool &resultFlag, StyleCategories categories=AllStyleCategories)
Save the properties of this layer as a named style (either as a .qml file on disk or as a record in t...
void setCrs(const QgsCoordinateReferenceSystem &srs, bool emitSignal=true)
Sets layer's spatial reference system.
Class for handling properties relating to a mesh data provider's temporal capabilities.
QgsUnitTypes::TemporalUnit temporalUnit() const
Returns the temporal unit used to read data by the data provider.
QDateTime referenceTime() const
Returns the reference time.
QgsDateTimeRange timeExtent() const
Returns the time extent using the internal reference time and the first and last times available from...
MatchingTemporalDatasetMethod
Method for selection of temporal mesh dataset from a range time.
@ FindClosestDatasetFromStartRangeTime
Finds the closest dataset which have its time before the requested start range time.
QgsMeshDataProviderTemporalCapabilities * temporalCapabilities() override
Returns the provider's temporal capabilities.
void setTemporalUnit(QgsUnitTypes::TemporalUnit unit)
Sets the temporal unit of the provider and reload data if it changes.
void optionsStackedWidget_CurrentChanged(int index) override
QgsMeshLayerProperties(QgsMapLayer *lyr, QgsMapCanvas *canvas, QWidget *parent=nullptr, Qt::WindowFlags=QgsGuiUtils::ModalDialogFlags)
Constructor.
void addPropertiesPageFactory(const QgsMapLayerConfigWidgetFactory *factory)
Adds properties page from a factory.
Implementation of map layer temporal properties for mesh layers.
QDateTime referenceTime() const
Returns the reference time.
QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod matchingMethod() const
Returns the method used to match dataset from temporal capabilities.
QgsDateTimeRange timeExtent() const
Returns the time extent.
Represents a mesh layer supporting display of data on structured or unstructured meshes.
Definition: qgsmeshlayer.h:97
void setMeshSimplificationSettings(const QgsMeshSimplificationSettings &meshSimplificationSettings)
Sets mesh simplification settings.
void activeScalarDatasetGroupChanged(int index)
Emitted when active scalar group dataset is changed.
void activeVectorDatasetGroupChanged(int index)
Emitted when active vector group dataset is changed.
void reload() override
Synchronises with changes in the datasource.
QString loadDefaultStyle(bool &resultFlag) FINAL
Retrieve the default style for this layer if one exists (either as a .qml file on disk or as a record...
QString htmlMetadata() const override
Obtain a formatted HTML string containing assorted metadata for this layer.
QgsMeshSimplificationSettings meshSimplificationSettings() const
Returns mesh simplification settings.
bool isEditable() const override
Returns true if the layer can be edited.
QgsMeshDataProvider * dataProvider() override
Returns the layer's data provider, it may be nullptr.
QgsMapLayerTemporalProperties * temporalProperties() override
Returns the layer's temporal properties.
void setReferenceTime(const QDateTime &referenceTime)
Sets the reference time of the layer.
void setTemporalMatchingMethod(const QgsMeshDataProviderTemporalCapabilities::MatchingTemporalDatasetMethod &matchingMethod)
Sets the method used to match the temporal dataset from a requested time, see activeVectorDatasetAtTi...
Represents an overview renderer settings.
void setMeshResolution(int meshResolution)
Sets the mesh resolution i.e., the minimum size (average) of triangles in pixels This value is used d...
void setEnabled(bool isEnabled)
Sets if the overview is active.
double reductionFactor() const
Returns the reduction factor used to build simplified mesh.
bool isEnabled() const
Returns if the overview is active.
int meshResolution() const
Returns the mesh resolution i.e., the minimum size (average) of triangles in pixels.
void setReductionFactor(double value)
Sets the reduction factor used to build simplified mesh.
void setScalarDatasetGroup(int index)
Sets the scalar dataset group.
void setVectorDatasetGroup(int index)
Sets the vector dataset group.
A wizard to edit metadata on a map layer.
void acceptMetadata()
Saves the metadata to the layer.
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas associated with the widget.
void setMetadata(const QgsAbstractMetadataBase *metadata)
Sets the metadata to display in the widget.
A base dialog for options and properties dialogs that offers vertical tabs.
void addPage(const QString &title, const QString &tooltip, const QIcon &icon, QWidget *widget, const QStringList &path=QStringList())
Adds a new page to the dialog pages.
virtual void optionsStackedWidget_CurrentChanged(int index)
Select relevant tab on current page change.
void insertPage(const QString &title, const QString &tooltip, const QIcon &icon, QWidget *widget, const QString &before, const QStringList &path=QStringList())
Inserts a new page into the dialog pages.
void restoreOptionsBaseUi(const QString &title=QString())
Restore the base ui.
QStackedWidget * mOptStackedWidget
void initOptionsBase(bool restoreUi=true, const QString &title=QString())
Set up the base ui connections for vertical tabs.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:467
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:518
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
Widget for renderer properties of the mesh, contours (scalars) and vectors data associated with the m...
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
bool contains(const QString &key, QgsSettings::Section section=QgsSettings::NoSection) const
Returns true if there exists a setting called key; returns false otherwise.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
bool isActive() const
Returns true if the temporal property is active.
void setIsActive(bool active)
Sets whether the temporal property is active.
bool isTemporal() const
Returns true if the object's temporal range is enabled, and the object will be filtered when renderin...
TemporalUnit
Temporal units.
Definition: qgsunittypes.h:150
@ TemporalDays
Days.
Definition: qgsunittypes.h:155
@ TemporalSeconds
Seconds.
Definition: qgsunittypes.h:152
@ TemporalMinutes
Minutes.
Definition: qgsunittypes.h:153
@ TemporalHours
Hours.
Definition: qgsunittypes.h:154
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:1185
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
const QgsCoordinateReferenceSystem & crs