QGIS API Documentation  3.27.0-Master (0e23467727)
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  // TODO Once the deprecated `saveDefaultStyle()` method is gone, just
272  // remove the NOWARN_DEPRECATED tags
274  // after calling this the above flag will be set true for success
275  // or false if the save operation failed
276  QString myMessage = mMeshLayer->saveDefaultStyle( defaultSavedFlag );
278  if ( !defaultSavedFlag )
279  {
280  // let the user know what went wrong
281  QMessageBox::information( this,
282  tr( "Default Style" ),
283  myMessage
284  );
285  }
286 }
287 
288 void QgsMeshLayerProperties::loadStyle()
289 {
290  QgsSettings settings;
291  QString lastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
292 
293  QString fileName = QFileDialog::getOpenFileName(
294  this,
295  tr( "Load rendering setting from style file" ),
296  lastUsedDir,
297  tr( "QGIS Layer Style File" ) + " (*.qml)" );
298  if ( fileName.isEmpty() )
299  return;
300 
301  // ensure the user never omits the extension from the file name
302  if ( !fileName.endsWith( QLatin1String( ".qml" ), Qt::CaseInsensitive ) )
303  fileName += QLatin1String( ".qml" );
304 
305  mOldStyle = mMeshLayer->styleManager()->style( mMeshLayer->styleManager()->currentStyle() );
306 
307  bool defaultLoadedFlag = false;
308  QString message = mMeshLayer->loadNamedStyle( fileName, defaultLoadedFlag );
309  if ( defaultLoadedFlag )
310  {
311  settings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( fileName ).absolutePath() );
312  syncToLayer();
313  }
314  else
315  {
316  QMessageBox::information( this, tr( "Load Style" ), message );
317  }
318 }
319 
320 void QgsMeshLayerProperties::saveStyleAs()
321 {
322  QgsSettings settings;
323  QString lastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
324 
325  QString outputFileName = QFileDialog::getSaveFileName(
326  this,
327  tr( "Save layer properties as style file" ),
328  lastUsedDir,
329  tr( "QGIS Layer Style File" ) + " (*.qml)" );
330  if ( outputFileName.isEmpty() )
331  return;
332 
333  // ensure the user never omits the extension from the file name
334  outputFileName = QgsFileUtils::ensureFileNameHasExtension( outputFileName, QStringList() << QStringLiteral( "qml" ) );
335 
336  apply(); // make sure the style to save is up-to-date
337 
338  // then export style
339  bool defaultLoadedFlag = false;
340  QString message;
341  message = mMeshLayer->saveNamedStyle( outputFileName, defaultLoadedFlag );
342 
343  if ( defaultLoadedFlag )
344  {
345  settings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( outputFileName ).absolutePath() );
346  }
347  else
348  QMessageBox::information( this, tr( "Save Style" ), message );
349 }
350 
351 void QgsMeshLayerProperties::apply()
352 {
353  Q_ASSERT( mRendererMeshPropertiesWidget );
354 
355  QgsDebugMsgLevel( QStringLiteral( "processing general tab" ), 4 );
356  /*
357  * General Tab
358  */
359  mMeshLayer->setName( mLayerOrigNameLineEd->text() );
360 
361  QgsDebugMsgLevel( QStringLiteral( "processing source tab" ), 4 );
362  /*
363  * Source Tab
364  */
365  mDatasetGroupTreeWidget->apply();
366 
367  QgsDebugMsgLevel( QStringLiteral( "processing config tabs" ), 4 );
368 
369  for ( QgsMapLayerConfigWidget *w : std::as_const( mConfigWidgets ) )
370  w->apply();
371 
372  QgsDebugMsgLevel( QStringLiteral( "processing rendering tab" ), 4 );
373  /*
374  * Rendering Tab
375  */
376  QgsMeshSimplificationSettings simplifySettings;
377  simplifySettings.setEnabled( mSimplifyMeshGroupBox->isChecked() );
378  simplifySettings.setReductionFactor( mSimplifyReductionFactorSpinBox->value() );
379  simplifySettings.setMeshResolution( mSimplifyMeshResolutionSpinBox->value() );
380  bool needMeshUpdating = ( ( simplifySettings.isEnabled() != mMeshLayer->meshSimplificationSettings().isEnabled() ) ||
381  ( simplifySettings.reductionFactor() != mMeshLayer->meshSimplificationSettings().reductionFactor() ) );
382 
383  mMeshLayer->setMeshSimplificationSettings( simplifySettings );
384 
385  QgsDebugMsgLevel( QStringLiteral( "processing temporal tab" ), 4 );
386  /*
387  * Temporal Tab
388  */
389 
390  mMeshLayer->setReferenceTime( mTemporalDateTimeReference->dateTime() );
391  if ( mMeshLayer->dataProvider() )
392  mMeshLayer->dataProvider()->setTemporalUnit(
393  static_cast<QgsUnitTypes::TemporalUnit>( mTemporalProviderTimeUnitComboBox->currentData().toInt() ) );
394 
395  mStaticDatasetWidget->apply();
396  bool needEmitRendererChanged = mMeshLayer->temporalProperties()->isActive() == mStaticDatasetGroupBox->isChecked();
397  mMeshLayer->temporalProperties()->setIsActive( !mStaticDatasetGroupBox->isChecked() );
399  mComboBoxTemporalDatasetMatchingMethod->currentData().toInt() ) );
400 
401  mMetadataWidget->acceptMetadata();
402 
403  mBackupCrs = mMeshLayer->crs();
404 
405  if ( needMeshUpdating )
406  mMeshLayer->reload();
407 
408  if ( needEmitRendererChanged )
409  emit mMeshLayer->rendererChanged();
410 
411  //make sure the layer is redrawn
412  mMeshLayer->triggerRepaint();
413 
414  // notify the project we've made a change
415  QgsProject::instance()->setDirty( true );
416 
417  // Resync what have to be resync (widget that can be changed by other properties part)
418  mStaticDatasetWidget->syncToLayer();
419  for ( QgsMapLayerConfigWidget *w : std::as_const( mConfigWidgets ) )
420  w->syncToLayer( mMeshLayer );
421 }
422 
423 void QgsMeshLayerProperties::changeCrs( const QgsCoordinateReferenceSystem &crs )
424 {
425  QgsDatumTransformDialog::run( crs, QgsProject::instance()->crs(), this, mCanvas, tr( "Select Transformation" ) );
426  mMeshLayer->setCrs( crs );
427 }
428 
429 void QgsMeshLayerProperties::syncAndRepaint()
430 {
431  syncToLayer();
432  mMeshLayer->triggerRepaint();
433 }
434 
435 void QgsMeshLayerProperties::showHelp()
436 {
437  const QVariant helpPage = mOptionsStackedWidget->currentWidget()->property( "helpPage" );
438 
439  if ( helpPage.isValid() )
440  {
441  QgsHelp::openHelp( helpPage.toString() );
442  }
443  else
444  {
445  QgsHelp::openHelp( QStringLiteral( "working_with_mesh/mesh_properties.html" ) );
446  }
447 }
448 
449 void QgsMeshLayerProperties::aboutToShowStyleMenu()
450 {
451  QMenu *m = qobject_cast<QMenu *>( sender() );
452 
454  // re-add style manager actions!
455  m->addSeparator();
457 }
458 
459 void QgsMeshLayerProperties::reloadTemporalProperties()
460 {
461  if ( !mMeshLayer->dataProvider() )
462  return;
463  QgsMeshDataProviderTemporalCapabilities *temporalCapabalities = mMeshLayer->dataProvider()->temporalCapabilities();
464  QgsDateTimeRange timeExtent;
465  QDateTime referenceTime = temporalCapabalities->referenceTime();
466  if ( referenceTime.isValid() )
467  {
468  timeExtent = temporalCapabalities->timeExtent();
469  whileBlocking( mTemporalDateTimeReference )->setDateTime( referenceTime );
470  }
471  else
472  // The reference time already here is used again to define the time extent
473  timeExtent = temporalCapabalities->timeExtent( mTemporalDateTimeReference->dateTime() );
474 
475  mTemporalDateTimeStart->setDateTime( timeExtent.begin() );
476  mTemporalDateTimeEnd->setDateTime( timeExtent.end() );
477 }
478 
479 void QgsMeshLayerProperties::onTimeReferenceChange()
480 {
481  if ( !mMeshLayer->dataProvider() )
482  return;
483  const QgsDateTimeRange &timeExtent = mMeshLayer->dataProvider()->temporalCapabilities()->timeExtent( mTemporalDateTimeReference->dateTime() );
484  mTemporalDateTimeStart->setDateTime( timeExtent.begin() );
485  mTemporalDateTimeEnd->setDateTime( timeExtent.end() );
486 }
487 
488 void QgsMeshLayerProperties::urlClicked( const QUrl &url )
489 {
490  QFileInfo file( url.toLocalFile() );
491  if ( file.exists() && !file.isDir() )
492  QgsGui::nativePlatformInterface()->openFileExplorerAndSelectFile( url.toLocalFile() );
493  else
494  QDesktopServices::openUrl( url );
495 }
496 
497 void QgsMeshLayerProperties::loadMetadata()
498 {
499  QgsSettings myQSettings; // where we keep last used filter in persistent state
500  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
501 
502  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load layer metadata from metadata file" ), myLastUsedDir,
503  tr( "QGIS Layer Metadata File" ) + " (*.qmd)" );
504  if ( myFileName.isNull() )
505  {
506  return;
507  }
508 
509  QString myMessage;
510  bool defaultLoadedFlag = false;
511  myMessage = mMeshLayer->loadNamedMetadata( myFileName, defaultLoadedFlag );
512 
513  //reset if the default style was loaded OK only
514  if ( defaultLoadedFlag )
515  {
516  mMetadataWidget->setMetadata( &mMeshLayer->metadata() );
517  }
518  else
519  {
520  //let the user know what went wrong
521  QMessageBox::warning( this, tr( "Load Metadata" ), myMessage );
522  }
523 
524  QFileInfo myFI( myFileName );
525  QString myPath = myFI.path();
526  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), myPath );
527 
528  activateWindow(); // set focus back to properties dialog
529 }
530 
531 void QgsMeshLayerProperties::saveMetadataAs()
532 {
533  QgsSettings myQSettings; // where we keep last used filter in persistent state
534  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
535 
536  QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save Layer Metadata as QMD" ),
537  myLastUsedDir, tr( "QMD File" ) + " (*.qmd)" );
538  if ( myOutputFileName.isNull() ) //dialog canceled
539  {
540  return;
541  }
542 
543  mMetadataWidget->acceptMetadata();
544 
545  //ensure the user never omitted the extension from the file name
546  if ( !myOutputFileName.endsWith( QgsMapLayer::extensionPropertyType( QgsMapLayer::Metadata ), Qt::CaseInsensitive ) )
547  {
549  }
550 
551  bool defaultLoadedFlag = false;
552  QString message = mMeshLayer->saveNamedMetadata( myOutputFileName, defaultLoadedFlag );
553  if ( defaultLoadedFlag )
554  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( myOutputFileName ).absolutePath() );
555  else
556  QMessageBox::information( this, tr( "Save Metadata" ), message );
557 }
558 
559 void QgsMeshLayerProperties::onCancel()
560 {
561  if ( mBackupCrs != mMeshLayer->crs() )
562  mMeshLayer->setCrs( mBackupCrs );
563 }
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 QgsNative * nativePlatformInterface()
Returns the global native interface, which offers abstraction to the host OS's underlying public inte...
Definition: qgsgui.cpp:75
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:90
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.
static bool isDefault(const QString &styleName)
Returns true if this is the default style.
QgsMapLayerStyle style(const QString &name) const
Returns data of a stored style - accessed by its unique name.
void currentStyleChanged(const QString &currentName)
Emitted when the current style has been changed.
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
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...
virtual QString saveDefaultStyle(bool &resultFlag, StyleCategories categories)
Save the properties of this layer as the default style (either as a .qml file on disk or as a record ...
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:99
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:479
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:575
void crsChanged(const QgsCoordinateReferenceSystem &)
Emitted when the selected CRS is changed.
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
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:2815
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:2814
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:2186
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
const QgsCoordinateReferenceSystem & crs