QGIS API Documentation  3.25.0-Master (dec16ba68b)
qgsmetadatawidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  QgsAbstractMetadataBasewidget.h - description
3  -------------------
4  begin : 17/05/2017
5  copyright : (C) 2017 by Etienne Trimaille
6  email : etienne at kartoza.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 <QIcon>
19 #include <QPushButton>
20 #include <QComboBox>
21 #include <QString>
22 #include <QInputDialog>
23 #include <QStringListModel>
24 
25 #include "qgsbox3d.h"
26 #include "qgsmetadatawidget.h"
27 #include "qgslogger.h"
29 #include "qgsapplication.h"
30 #include "qgsmapcanvas.h"
31 #include "qgsprojectmetadata.h"
32 #include "qgsproject.h"
33 
35  : QWidget( parent ),
36  mLayer( layer )
37 {
38  setupUi( this );
39  tabWidget->setCurrentIndex( 0 );
40 
41  // Disable the encoding
42  encodingFrame->setHidden( true );
43 
44  // Default categories, we want them translated, so we are not using a CSV.
45  mDefaultCategories << tr( "Farming" ) << tr( "Climatology Meteorology Atmosphere" ) << tr( "Location" ) << tr( "Intelligence Military" ) << tr( "Transportation" ) << tr( "Structure" ) << tr( "Boundaries" );
46  mDefaultCategories << tr( "Inland Waters" ) << tr( "Planning Cadastre" ) << tr( "Geoscientific Information" ) << tr( "Elevation" ) << tr( "Health" ) << tr( "Biota" ) << tr( "Oceans" ) << tr( "Environment" );
47  mDefaultCategories << tr( "Utilities Communication" ) << tr( "Economy" ) << tr( "Society" ) << tr( "Imagery Base Maps Earth Cover" );
48  mDefaultCategoriesModel = new QStringListModel( mDefaultCategories, this );
49  mDefaultCategoriesModel->sort( 0 ); // Sorting using translations
50  listDefaultCategories->setModel( mDefaultCategoriesModel );
51 
52  // Categories
53  mCategoriesModel = new QStringListModel( listCategories );
54  listCategories->setModel( mCategoriesModel );
55 
56  // Rights
57  mRightsModel = new QStringListModel( listRights );
58  listRights->setModel( mRightsModel );
59 
60  // Setup the constraints view
61  mConstraintsModel = new QStandardItemModel( tabConstraints );
62  mConstraintsModel->setColumnCount( 2 );
63  QStringList constraintheaders;
64  constraintheaders << tr( "Type" ) << tr( "Constraint" );
65  mConstraintsModel->setHorizontalHeaderLabels( constraintheaders );
66  tabConstraints->setModel( mConstraintsModel );
67  tabConstraints->setItemDelegate( new ConstraintItemDelegate( this ) );
68 
69  // Extent
70  dateTimeFrom->setAllowNull( true );
71  dateTimeTo->setAllowNull( true );
72 
73  // Setup the link view
74  mLinksModel = new QStandardItemModel( tabLinks );
75  mLinksModel->setColumnCount( 7 );
76  QStringList headers = QStringList();
77  headers << tr( "Name" ) << tr( "Type" ) << tr( "URL" ) << tr( "Description" ) << tr( "Format" ) << tr( "MIME" ) << tr( "Size" );
78  mLinksModel->setHorizontalHeaderLabels( headers );
79  tabLinks->setModel( mLinksModel );
80  tabLinks->setItemDelegate( new LinkItemDelegate( this ) );
81 
82  // History
83  mHistoryModel = new QStringListModel( listHistory );
84  listHistory->setModel( mHistoryModel );
85 
86  // Connect signals and slots
87  connect( tabWidget, &QTabWidget::currentChanged, this, &QgsMetadataWidget::updatePanel );
88  connect( btnAutoSource, &QPushButton::clicked, this, &QgsMetadataWidget::fillSourceFromLayer );
89  connect( btnAddVocabulary, &QPushButton::clicked, this, &QgsMetadataWidget::addVocabulary );
90  connect( btnRemoveVocabulary, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedVocabulary );
91  connect( btnAddRight, &QPushButton::clicked, this, &QgsMetadataWidget::addRight );
92  connect( btnRemoveRight, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedRight );
93  connect( btnAddLicence, &QPushButton::clicked, this, &QgsMetadataWidget::addLicence );
94  connect( btnRemoveLicence, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedLicence );
95  connect( btnAddConstraint, &QPushButton::clicked, this, &QgsMetadataWidget::addConstraint );
96  connect( btnRemoveConstraint, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedConstraint );
97  connect( btnSetCrsFromLayer, &QPushButton::clicked, this, &QgsMetadataWidget::fillCrsFromLayer );
98  connect( btnSetCrsFromProvider, &QPushButton::clicked, this, &QgsMetadataWidget::fillCrsFromProvider );
99  connect( btnAddAddress, &QPushButton::clicked, this, &QgsMetadataWidget::addAddress );
100  connect( btnRemoveAddress, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedAddress );
101  connect( btnAddLink, &QPushButton::clicked, this, &QgsMetadataWidget::addLink );
102  connect( btnRemoveLink, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedLink );
103  connect( btnAddHistory, &QPushButton::clicked, this, &QgsMetadataWidget::addHistory );
104  connect( btnRemoveHistory, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedHistory );
105  connect( btnNewCategory, &QPushButton::clicked, this, &QgsMetadataWidget::addNewCategory );
106  connect( btnAddDefaultCategory, &QPushButton::clicked, this, &QgsMetadataWidget::addDefaultCategories );
107  connect( btnRemoveCategory, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedCategories );
108 
109  fillComboBox();
110  if ( !mLayer )
111  {
112  btnAutoSource->setEnabled( false );
113  btnAutoEncoding->setEnabled( false );
114  btnSetCrsFromLayer->setEnabled( false );
115  }
116 
117  if ( mLayer )
118  {
119  mMetadata.reset( mLayer->metadata().clone() );
121  setUiFromMetadata();
122  }
123 
124  connect( lineEditTitle, &QLineEdit::textChanged, this, &QgsMetadataWidget::titleChanged );
125 }
126 
128 {
129  QString type;
130  QString typeUpper;
131  mMode = mode;
132  switch ( mMode )
133  {
134  case LayerMetadata:
135  type = tr( "dataset" );
136  typeUpper = tr( "Dataset" );
137  mEncodingFrame->show();
138  mAuthorFrame->hide();
139  btnAutoSource->setEnabled( mLayer );
140  break;
141 
142  case ProjectMetadata:
143  type = tr( "project" );
144  typeUpper = tr( "Project" );
145  mEncodingFrame->hide();
146  mAuthorFrame->show();
147  tabWidget->removeTab( 4 );
148  tabWidget->removeTab( 3 );
149  btnAutoSource->setEnabled( true );
150  break;
151  }
152 
153  mIdLabel->setText( tr( "This page describes the basic attribution of the %1. Please use the tooltips for more information." ).arg( type ) );
154  mLabelCategories->setText( tr( "%1 categories." ).arg( typeUpper ) );
155  mLabelContact->setText( tr( "Contacts related to the %1." ).arg( type ) );
156  mLabelLinks->setText( tr( "Links describe ancillary resources and information related to this %1." ).arg( type ) );
157  mLabelHistory->setText( tr( "History about the %1." ).arg( type ) );
158  labelKeywords->setText( tr( "<html><head/><body><p>Keywords are optional, and provide a way to provide additional descriptive information about "
159  "the %1. Edits made in the categories tab will update the category entry below. For the concept, we suggest "
160  "to use a standard based vocabulary such as <a href=\"https://www.eionet.europa.eu/gemet/en/inspire-themes/\">"
161  "<span style=\" text-decoration: underline; color:#0000ff;\">GEMET.</span></a></p></body></html>" ).arg( type ) );
162  btnAutoSource->setText( tr( "Set from %1" ).arg( mMode == LayerMetadata ? tr( "layer" ) : tr( "project" ) ) );
163 }
164 
166 {
167  if ( !metadata )
168  return;
169 
170  if ( dynamic_cast< const QgsLayerMetadata * >( metadata ) && mMode != LayerMetadata )
172  else if ( dynamic_cast< const QgsProjectMetadata * >( metadata ) && mMode != ProjectMetadata )
174 
175  mMetadata.reset( metadata->clone() );
176  setUiFromMetadata();
177 }
178 
180 {
181  std::unique_ptr< QgsAbstractMetadataBase > md;
182  switch ( mMode )
183  {
184  case LayerMetadata:
185  md = std::make_unique< QgsLayerMetadata >();
186  break;
187 
188  case ProjectMetadata:
189  md = std::make_unique< QgsProjectMetadata >();
190  break;
191 
192  }
193  saveMetadata( md.get() );
194  return md.release();
195 }
196 
197 void QgsMetadataWidget::fillSourceFromLayer()
198 {
199  switch ( mMode )
200  {
201  case LayerMetadata:
202  if ( mLayer )
203  {
204  lineEditIdentifier->setText( mLayer->publicSource() );
205  }
206  break;
207 
208  case ProjectMetadata:
209  lineEditIdentifier->setText( QgsProject::instance()->fileName() );
210  break;
211  }
212 
213 }
214 
215 void QgsMetadataWidget::addVocabulary()
216 {
217  const int row = tabKeywords->rowCount();
218  tabKeywords->setRowCount( row + 1 );
219  QTableWidgetItem *pCell = nullptr;
220 
221  // Vocabulary
222  pCell = new QTableWidgetItem( tr( "undefined %1" ).arg( row + 1 ) );
223  tabKeywords->setItem( row, 0, pCell );
224 
225  // Keywords
226  pCell = new QTableWidgetItem();
227  tabKeywords->setItem( row, 1, pCell );
228 }
229 
230 void QgsMetadataWidget::removeSelectedVocabulary()
231 {
232  QItemSelectionModel *selectionModel = tabKeywords->selectionModel();
233  const QModelIndexList selectedRows = selectionModel->selectedRows();
234  for ( int i = 0; i < selectedRows.size() ; i++ )
235  {
236  tabKeywords->model()->removeRow( selectedRows[i].row() );
237  }
238 }
239 
240 void QgsMetadataWidget::addLicence()
241 {
242  QString newLicence = QInputDialog::getItem( this, tr( "New Licence" ), tr( "New Licence" ), parseLicenses(), 0, true );
243  if ( tabLicenses->findItems( newLicence, Qt::MatchExactly ).isEmpty() )
244  {
245  const int row = tabLicenses->rowCount();
246  tabLicenses->setRowCount( row + 1 );
247  QTableWidgetItem *pCell = new QTableWidgetItem( newLicence );
248  tabLicenses->setItem( row, 0, pCell );
249  }
250 }
251 
252 void QgsMetadataWidget::removeSelectedLicence()
253 {
254  QItemSelectionModel *selectionModel = tabLicenses->selectionModel();
255  const QModelIndexList selectedRows = selectionModel->selectedRows();
256  for ( int i = 0; i < selectedRows.size() ; i++ )
257  {
258  tabLicenses->model()->removeRow( selectedRows[i].row() );
259  }
260 }
261 
262 void QgsMetadataWidget::addRight()
263 {
264  QString newRight = QInputDialog::getText( this, tr( "New Right" ), tr( "New Right" ) );
265  QStringList existingRights = mRightsModel->stringList();
266  if ( ! existingRights.contains( newRight ) )
267  {
268  existingRights.append( newRight );
269  mRightsModel->setStringList( existingRights );
270  }
271 }
272 
273 void QgsMetadataWidget::removeSelectedRight()
274 {
275  QItemSelectionModel *selection = listRights->selectionModel();
276  if ( selection->hasSelection() )
277  {
278  QModelIndex indexElementSelectionne = selection->currentIndex();
279 
280  QVariant item = mRightsModel->data( indexElementSelectionne, Qt::DisplayRole );
281  QStringList list = mRightsModel->stringList();
282  list.removeOne( item.toString() );
283  mRightsModel->setStringList( list );
284  }
285 }
286 
287 void QgsMetadataWidget::addConstraint()
288 {
289  const int row = mConstraintsModel->rowCount();
290  mConstraintsModel->setItem( row, 0, new QStandardItem( tr( "undefined %1" ).arg( row + 1 ) ) );
291  mConstraintsModel->setItem( row, 1, new QStandardItem( tr( "undefined %1" ).arg( row + 1 ) ) );
292 }
293 
294 void QgsMetadataWidget::removeSelectedConstraint()
295 {
296  const QModelIndexList selectedRows = tabConstraints->selectionModel()->selectedRows();
297  if ( selectedRows.empty() )
298  return;
299  mConstraintsModel->removeRow( selectedRows[0].row() );
300 }
301 
303 {
304  if ( ( mCrs.isValid() ) && ( mLayer ) )
305  {
306  lblCurrentCrs->setText( tr( "CRS: %1" ).arg( mCrs.userFriendlyIdentifier() ) );
307  spatialExtentSelector->setEnabled( true );
308  spatialExtentSelector->setOutputCrs( mCrs );
309 
310  if ( mCrs == mLayer->crs() && mCrs == mLayer->dataProvider()->crs() )
311  {
312  lblCurrentCrsStatus->setText( tr( "Same as layer properties and provider." ) );
313  }
314  else if ( mCrs == mLayer->crs() && mCrs != mLayer->dataProvider()->crs() )
315  {
316  lblCurrentCrsStatus->setText( tr( "Same as layer properties but different than the provider." ) );
317  }
318  else if ( mCrs != mLayer->crs() && mCrs == mLayer->dataProvider()->crs() )
319  {
320  lblCurrentCrsStatus->setText( tr( "Same as the provider but different than the layer properties." ) );
321  }
322  else
323  {
324  lblCurrentCrsStatus->setText( tr( "Does not match either layer properties or the provider." ) );
325  }
326  }
327  else
328  {
329  lblCurrentCrs->setText( tr( "CRS: Not set." ) );
330  lblCurrentCrsStatus->setText( QString() );
331  spatialExtentSelector->setEnabled( false );
332  }
333 }
334 
335 void QgsMetadataWidget::addAddress()
336 {
337  const int row = tabAddresses->rowCount();
338  tabAddresses->setRowCount( row + 1 );
339  QTableWidgetItem *pCell = nullptr;
340 
341  // Type
342  pCell = new QTableWidgetItem( tr( "postal" ) );
343  tabAddresses->setItem( row, 0, pCell );
344 
345  // Address
346  tabAddresses->setItem( row, 1, new QTableWidgetItem() );
347 
348  // postal code
349  tabAddresses->setItem( row, 2, new QTableWidgetItem() );
350 
351  // City
352  tabAddresses->setItem( row, 3, new QTableWidgetItem() );
353 
354  // Admin area
355  tabAddresses->setItem( row, 4, new QTableWidgetItem() );
356 
357  // Country
358  tabAddresses->setItem( row, 5, new QTableWidgetItem() );
359 }
360 
361 void QgsMetadataWidget::removeSelectedAddress()
362 {
363  QItemSelectionModel *selectionModel = tabAddresses->selectionModel();
364  const QModelIndexList selectedRows = selectionModel->selectedRows();
365  for ( int i = 0; i < selectedRows.size() ; i++ )
366  {
367  tabAddresses->model()->removeRow( selectedRows[i].row() );
368  }
369 }
370 
371 void QgsMetadataWidget::fillCrsFromLayer()
372 {
373  mCrs = mLayer->crs();
374  crsChanged();
375 }
376 
377 void QgsMetadataWidget::fillCrsFromProvider()
378 {
379  mCrs = mLayer->dataProvider()->crs();
380  crsChanged();
381 }
382 
383 void QgsMetadataWidget::addLink()
384 {
385  const int row = mLinksModel->rowCount();
386  mLinksModel->setItem( row, 0, new QStandardItem( tr( "undefined %1" ).arg( row + 1 ) ) );
387  mLinksModel->setItem( row, 1, new QStandardItem() );
388  mLinksModel->setItem( row, 2, new QStandardItem() );
389  mLinksModel->setItem( row, 3, new QStandardItem() );
390  mLinksModel->setItem( row, 4, new QStandardItem() );
391  mLinksModel->setItem( row, 5, new QStandardItem() );
392  mLinksModel->setItem( row, 6, new QStandardItem() );
393 }
394 
395 void QgsMetadataWidget::removeSelectedLink()
396 {
397  const QModelIndexList selectedRows = tabLinks->selectionModel()->selectedRows();
398  if ( selectedRows.empty() )
399  return;
400 
401  mLinksModel->removeRow( selectedRows[0].row() );
402 }
403 
404 void QgsMetadataWidget::addHistory()
405 {
406  QString newHistory = QInputDialog::getText( this, tr( "New History" ), tr( "New History" ) );
407  QStringList existingHistory = mHistoryModel->stringList();
408  if ( ! existingHistory.contains( newHistory ) )
409  {
410  existingHistory.append( newHistory );
411  mHistoryModel->setStringList( existingHistory );
412  }
413 }
414 
415 void QgsMetadataWidget::removeSelectedHistory()
416 {
417  QItemSelectionModel *selection = listHistory->selectionModel();
418  if ( selection->hasSelection() )
419  {
420  QModelIndex indexElementSelectionne = selection->currentIndex();
421 
422  QVariant item = mHistoryModel->data( indexElementSelectionne, Qt::DisplayRole );
423  QStringList list = mHistoryModel->stringList();
424  list.removeOne( item.toString() );
425  mHistoryModel->setStringList( list );
426  }
427 }
428 
429 void QgsMetadataWidget::fillComboBox()
430 {
431  // Set default values in type combobox
432  // It is advised to use the ISO 19115 MD_ScopeCode values. E.g. 'dataset' or 'series'.
433  // http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml
434  comboType->setEditable( true );
435  comboType->clear();
436  QMap<QString, QString> types = parseTypes();
437  const QStringList &keys = types.keys();
438  int i = 0;
439  for ( const QString &type : keys )
440  {
441  comboType->insertItem( i, type );
442  comboType->setItemData( i, types.value( type ), Qt::ToolTipRole );
443  i++;
444  }
445 
446  // Set default values in language combobox
447  // It is advised to use the ISO 639.2 or ISO 3166 specifications, e.g. 'ENG' or 'SPA',
448  comboLanguage->setEditable( true );
449  comboLanguage->clear();
450  QMap<QString, QString> countries = parseLanguages();
451  const QStringList &k = countries.keys();
452  i = 0;
453  for ( const QString &countryCode : k )
454  {
455  comboLanguage->insertItem( i, countryCode );
456  comboLanguage->setItemData( i, countries.value( countryCode ), Qt::ToolTipRole );
457  i++;
458  }
459 }
460 
461 void QgsMetadataWidget::setUiFromMetadata()
462 {
463  // Parent ID
464  lineEditParentId->setText( mMetadata->parentIdentifier() );
465 
466  // Identifier
467  if ( ! mMetadata->identifier().isEmpty() )
468  {
469  lineEditIdentifier->setText( mMetadata->identifier() );
470  }
471 
472  // Title
473  if ( ! mMetadata->title().isEmpty() )
474  {
475  whileBlocking( lineEditTitle )->setText( mMetadata->title() );
476  }
477 
478  // Type
479  if ( ! mMetadata->type().isEmpty() )
480  {
481  if ( comboType->findText( mMetadata->type() ) == -1 )
482  {
483  comboType->addItem( mMetadata->type() );
484  }
485  comboType->setCurrentIndex( comboType->findText( mMetadata->type() ) );
486  }
487 
488  // Language
489  if ( ! mMetadata->language().isEmpty() )
490  {
491  if ( comboLanguage->findText( mMetadata->language() ) == -1 )
492  {
493  comboLanguage->addItem( mMetadata->language() );
494  }
495  comboLanguage->setCurrentIndex( comboLanguage->findText( mMetadata->language() ) );
496  }
497 
498  // Abstract
499  textEditAbstract->setPlainText( mMetadata->abstract() );
500 
501  // Categories
502  mCategoriesModel->setStringList( mMetadata->categories() );
503 
504  // Keywords
505  tabKeywords->setRowCount( 0 );
506  QMapIterator<QString, QStringList> i( mMetadata->keywords() );
507  while ( i.hasNext() )
508  {
509  i.next();
510  addVocabulary();
511  int currentRow = tabKeywords->rowCount() - 1;
512  tabKeywords->item( currentRow, 0 )->setText( i.key() );
513  tabKeywords->item( currentRow, 1 )->setText( i.value().join( QLatin1Char( ',' ) ) );
514  }
515 
516  if ( QgsLayerMetadata *layerMetadata = dynamic_cast< QgsLayerMetadata * >( mMetadata.get() ) )
517  {
518  // Encoding
519  comboEncoding->setCurrentText( layerMetadata->encoding() );
520 
521  // Fees
522  lineEditFees->setText( layerMetadata->fees() );
523 
524  // Licenses
525  tabLicenses->setRowCount( 0 );
526  const QStringList &licenses = layerMetadata->licenses();
527  for ( const QString &licence : licenses )
528  {
529  int currentRow = tabLicenses->rowCount();
530  tabLicenses->setRowCount( currentRow + 1 );
531  QTableWidgetItem *pCell = tabLicenses->item( currentRow, 0 );
532  if ( !pCell )
533  {
534  pCell = new QTableWidgetItem;
535  tabLicenses->setItem( currentRow, 0, pCell );
536  }
537  pCell->setText( licence );
538  }
539 
540  // Rights
541  mRightsModel->setStringList( layerMetadata->rights() );
542 
543  // Constraints
544  mConstraintsModel->clear();
545  const QList<QgsLayerMetadata::Constraint> &constraints = layerMetadata->constraints();
546  for ( const QgsLayerMetadata::Constraint &constraint : constraints )
547  {
548  const int row = mConstraintsModel->rowCount();
549  mConstraintsModel->setItem( row, 0, new QStandardItem( constraint.type ) );
550  mConstraintsModel->setItem( row, 1, new QStandardItem( constraint.constraint ) );
551  }
552 
553  // CRS
554  mCrs = layerMetadata->crs();
555  crsChanged();
556 
557  // Spatial extent
558  const QList<QgsLayerMetadata::SpatialExtent> &spatialExtents = layerMetadata->extent().spatialExtents();
559  if ( ! spatialExtents.isEmpty() )
560  {
561  // Even if it's a list, it's supposed to store the same extent in different CRS.
562  spatialExtentSelector->setOutputCrs( spatialExtents.at( 0 ).extentCrs );
563  spatialExtentSelector->setOriginalExtent( spatialExtents.at( 0 ).bounds.toRectangle(), spatialExtents.at( 0 ).extentCrs );
564  spatialExtentSelector->setOutputExtentFromOriginal();
565  spinBoxZMaximum->setValue( spatialExtents.at( 0 ).bounds.zMaximum() );
566  spinBoxZMinimum->setValue( spatialExtents.at( 0 ).bounds.zMinimum() );
567  }
568 
569  // Temporal extent
570  const QList<QgsDateTimeRange> &temporalExtents = layerMetadata->extent().temporalExtents();
571  if ( ! temporalExtents.isEmpty() )
572  {
573  // Even if it's a list, it seems we use only one for now (cf discussion with Tom)
574  dateTimeFrom->setDateTime( temporalExtents.at( 0 ).begin() );
575  dateTimeTo->setDateTime( temporalExtents.at( 0 ).end() );
576  }
577  else
578  {
579  dateTimeFrom->clear();
580  dateTimeTo->clear();
581  }
582  }
583  else if ( QgsProjectMetadata *projectMetadata = dynamic_cast< QgsProjectMetadata * >( mMetadata.get() ) )
584  {
585  mLineEditAuthor->setText( projectMetadata->author() );
586  mCreationDateTimeEdit->setDateTime( projectMetadata->creationDateTime() );
587  }
588 
589  // Contacts
590  const QList<QgsAbstractMetadataBase::Contact> &contacts = mMetadata->contacts();
591  if ( ! contacts.isEmpty() )
592  {
593  // Only one contact supported in the UI for now
594  const QgsAbstractMetadataBase::Contact &contact = contacts.at( 0 );
595  lineEditContactName->setText( contact.name );
596  lineEditContactEmail->setText( contact.email );
597  lineEditContactFax->setText( contact.fax );
598  lineEditContactOrganization->setText( contact.organization );
599  lineEditContactPosition->setText( contact.position );
600  lineEditContactVoice->setText( contact.voice );
601  if ( comboContactRole->findText( contact.role ) == -1 )
602  {
603  comboContactRole->addItem( contact.role );
604  }
605  comboContactRole->setCurrentIndex( comboContactRole->findText( contact.role ) );
606  tabAddresses->setRowCount( 0 );
607  const QList<QgsAbstractMetadataBase::Address> &addresses = contact.addresses;
608  for ( const QgsAbstractMetadataBase::Address &address : addresses )
609  {
610  int currentRow = tabAddresses->rowCount();
611  tabAddresses->setRowCount( currentRow + 1 );
612  tabAddresses->setItem( currentRow, 0, new QTableWidgetItem( address.type ) );
613  tabAddresses->setItem( currentRow, 1, new QTableWidgetItem( address.address ) );
614  tabAddresses->setItem( currentRow, 2, new QTableWidgetItem( address.postalCode ) );
615  tabAddresses->setItem( currentRow, 3, new QTableWidgetItem( address.city ) );
616  tabAddresses->setItem( currentRow, 4, new QTableWidgetItem( address.administrativeArea ) );
617  tabAddresses->setItem( currentRow, 5, new QTableWidgetItem( address.country ) );
618  }
619  }
620 
621  // Links
622  const QList<QgsAbstractMetadataBase::Link> &links = mMetadata->links();
623  mLinksModel->setRowCount( 0 );
624  for ( const QgsAbstractMetadataBase::Link &link : links )
625  {
626  const int row = mLinksModel->rowCount();
627  mLinksModel->setItem( row, 0, new QStandardItem( link.name ) );
628  mLinksModel->setItem( row, 1, new QStandardItem( link.type ) );
629  mLinksModel->setItem( row, 2, new QStandardItem( link.url ) );
630  mLinksModel->setItem( row, 3, new QStandardItem( link.description ) );
631  mLinksModel->setItem( row, 4, new QStandardItem( link.format ) );
632  mLinksModel->setItem( row, 5, new QStandardItem( link.mimeType ) );
633  mLinksModel->setItem( row, 6, new QStandardItem( link.size ) );
634  }
635 
636  // History
637  mHistoryModel->setStringList( mMetadata->history() );
638 }
639 
641 {
642  if ( !metadata )
643  return;
644 
645  metadata->setParentIdentifier( lineEditParentId->text() );
646  metadata->setIdentifier( lineEditIdentifier->text() );
647  metadata->setTitle( lineEditTitle->text() );
648  metadata->setType( comboType->currentText() );
649  metadata->setLanguage( comboLanguage->currentText() );
650  metadata->setAbstract( textEditAbstract->toPlainText() );
651 
652  // Keywords, it will save categories too.
653  syncFromCategoriesTabToKeywordsTab();
654  QMap<QString, QStringList> keywords;
655  for ( int i = 0; i < tabKeywords->rowCount() ; i++ )
656  {
657  keywords.insert( tabKeywords->item( i, 0 )->text(), tabKeywords->item( i, 1 )->text().split( ',' ) );
658  }
659  metadata->setKeywords( keywords );
660 
661  switch ( mMode )
662  {
663  case LayerMetadata:
664  {
665  QgsLayerMetadata *layerMetadata = static_cast< QgsLayerMetadata * >( metadata );
666  // Fees
667  layerMetadata->setFees( lineEditFees->text() );
668 
669  // Licenses
670  QStringList licenses;
671  for ( int i = 0; i < tabLicenses->rowCount() ; i++ )
672  {
673  licenses.append( tabLicenses->item( i, 0 )->text() );
674  }
675  layerMetadata->setLicenses( licenses );
676 
677  // Rights
678  layerMetadata->setRights( mRightsModel->stringList() );
679 
680  // Encoding
681  layerMetadata->setEncoding( comboEncoding->currentText() );
682 
683  // Constraints
684  QList<QgsLayerMetadata::Constraint> constraints;
685  for ( int row = 0; row < mConstraintsModel->rowCount() ; row++ )
686  {
687  QgsLayerMetadata::Constraint constraint;
688  constraint.type = mConstraintsModel->item( row, 0 )->text();
689  constraint.constraint = mConstraintsModel->item( row, 1 )->text();
690  constraints.append( constraint );
691  }
692  layerMetadata->setConstraints( constraints );
693 
694  // CRS
695  if ( mCrs.isValid() )
696  {
697  layerMetadata->setCrs( mCrs );
698  }
699 
700  // Extent
701  QgsLayerMetadata::SpatialExtent spatialExtent;
702  spatialExtent.bounds = QgsBox3d( spatialExtentSelector->outputExtent() );
703  spatialExtent.bounds.setZMinimum( spinBoxZMinimum->value() );
704  spatialExtent.bounds.setZMaximum( spinBoxZMaximum->value() );
705  spatialExtent.extentCrs = spatialExtentSelector->outputCrs();
706  QList<QgsLayerMetadata::SpatialExtent> spatialExtents;
707  spatialExtents.append( spatialExtent );
708  QList<QgsDateTimeRange> temporalExtents;
709  temporalExtents.append( QgsDateTimeRange( dateTimeFrom->dateTime(), dateTimeTo->dateTime() ) );
711  extent.setSpatialExtents( spatialExtents );
712  extent.setTemporalExtents( temporalExtents );
713  layerMetadata->setExtent( extent );
714  break;
715  }
716 
717  case ProjectMetadata:
718  {
719  QgsProjectMetadata *projectMetadata = static_cast< QgsProjectMetadata * >( metadata );
720  projectMetadata->setAuthor( mLineEditAuthor->text() );
721  projectMetadata->setCreationDateTime( mCreationDateTimeEdit->dateTime() );
722  break;
723  }
724  }
725 
726  // Contacts, only one contact supported in the UI for now.
727  // We don't want to lost data if more than one contact, so we update only the first one.
728  QList<QgsAbstractMetadataBase::Contact> contacts = mMetadata->contacts();
729  if ( contacts.size() > 0 )
730  contacts.removeFirst();
732  contact.email = lineEditContactEmail->text();
733  contact.position = lineEditContactPosition->text();
734  contact.fax = lineEditContactFax->text();
735  contact.voice = lineEditContactVoice->text();
736  contact.name = lineEditContactName->text();
737  contact.organization = lineEditContactOrganization->text();
738  contact.role = comboContactRole->currentText();
739  QList<QgsAbstractMetadataBase::Address> addresses;
740  for ( int i = 0; i < tabAddresses->rowCount() ; i++ )
741  {
743  address.type = tabAddresses->item( i, 0 )->text();
744  address.address = tabAddresses->item( i, 1 )->text();
745  address.postalCode = tabAddresses->item( i, 2 )->text();
746  address.city = tabAddresses->item( i, 3 )->text();
747  address.administrativeArea = tabAddresses->item( i, 4 )->text();
748  address.country = tabAddresses->item( i, 5 )->text();
749  addresses.append( address );
750  }
751  contact.addresses = addresses;
752  contacts.insert( 0, contact );
753  metadata->setContacts( contacts );
754 
755  // Links
756  QList<QgsAbstractMetadataBase::Link> links;
757  for ( int row = 0; row < mLinksModel->rowCount() ; row++ )
758  {
760  link.name = mLinksModel->item( row, 0 )->text();
761  link.type = mLinksModel->item( row, 1 )->text();
762  link.url = mLinksModel->item( row, 2 )->text();
763  link.description = mLinksModel->item( row, 3 )->text();
764  link.format = mLinksModel->item( row, 4 )->text();
765  link.mimeType = mLinksModel->item( row, 5 )->text();
766  link.size = mLinksModel->item( row, 6 )->text();
767  links.append( link );
768  }
769  metadata->setLinks( links );
770 
771  // History
772  metadata->setHistory( mHistoryModel->stringList() );
773 }
774 
776 {
777  std::unique_ptr< QgsAbstractMetadataBase > md( metadata() );
778 
779  std::unique_ptr< QgsNativeMetadataBaseValidator > validator;
780  switch ( mMode )
781  {
782  case LayerMetadata:
783  validator = std::make_unique< QgsNativeMetadataValidator>();
784  break;
785 
786  case ProjectMetadata:
787  validator = std::make_unique< QgsNativeProjectMetadataValidator>();
788  break;
789  }
790 
791  QList<QgsAbstractMetadataBaseValidator::ValidationResult> validationResults;
792  bool results = validator->validate( md.get(), validationResults );
793 
794  QString errors;
795  if ( !results )
796  {
797  for ( const QgsAbstractMetadataBaseValidator::ValidationResult &result : std::as_const( validationResults ) )
798  {
799  errors += QLatin1String( "<b>" ) % result.section;
800  if ( ! result._identifier().isNull() )
801  {
802  errors += QLatin1Char( ' ' ) % QVariant( result._identifier().toInt() + 1 ).toString();
803  }
804  errors += QLatin1String( "</b>: " ) % result.note % QLatin1String( "<br />" );
805  }
806  }
807  else
808  {
809  errors = tr( "Ok, it seems valid according to the QGIS Schema." );
810  }
811 
812  QString myStyle = QgsApplication::reportStyleSheet();
813  myStyle.append( QStringLiteral( "body { margin: 10px; }\n " ) );
814  resultsCheckMetadata->clear();
815  resultsCheckMetadata->document()->setDefaultStyleSheet( myStyle );
816  resultsCheckMetadata->setHtml( errors );
817 
818  return results;
819 }
820 
821 QMap<QString, QString> QgsMetadataWidget::parseLanguages()
822 {
823  QMap<QString, QString> countries;
824  countries.insert( QString(), QString() ); // We add an empty line, because it's not compulsory.
825 
826  QString path = QDir( QgsApplication::metadataPath() ).absoluteFilePath( QStringLiteral( "language_codes_ISO_639.csv" ) );
827  QFile file( path );
828  if ( !file.open( QIODevice::ReadOnly ) )
829  {
830  QgsDebugMsg( QStringLiteral( "Error while opening the CSV file: %1, %2 " ).arg( path, file.errorString() ) );
831  return countries;
832  }
833 
834  // Skip the first line of the CSV
835  file.readLine();
836  while ( !file.atEnd() )
837  {
838  QByteArray line = file.readLine();
839  QList<QByteArray> items = line.split( ',' );
840  countries.insert( QString( items.at( 0 ).constData() ).trimmed(), QString( items.at( 1 ).constData() ).trimmed() );
841  }
842  file.close();
843 
844  path = QDir( QgsApplication::metadataPath() ).absoluteFilePath( QStringLiteral( "country_code_ISO_3166.csv" ) );
845  QFile secondFile( path );
846  if ( !secondFile.open( QIODevice::ReadOnly ) )
847  {
848  QgsDebugMsg( QStringLiteral( "Error while opening the CSV file: %1, %2 " ).arg( path, file.errorString() ) );
849  return countries;
850  }
851 
852  // Skip the first line of the CSV
853  secondFile.readLine();
854  while ( !secondFile.atEnd() )
855  {
856  QByteArray line = secondFile.readLine();
857  QList<QByteArray> items = line.split( ',' );
858  countries.insert( QString( items.at( 2 ).constData() ).trimmed(), QString( items.at( 0 ).constData() ).trimmed() );
859  }
860  secondFile.close();
861  return countries;
862 }
863 
865 {
866  QStringList wordList;
867  wordList.append( QString() ); // We add an empty line, because it's not compulsory.
868 
869  QString path = QDir( QgsApplication::metadataPath() ).absoluteFilePath( QStringLiteral( "licenses.csv" ) );
870  QFile file( path );
871  if ( !file.open( QIODevice::ReadOnly ) )
872  {
873  QgsDebugMsg( QStringLiteral( "Error while opening the CSV file: %1, %2 " ).arg( path, file.errorString() ) );
874  return wordList;
875  }
876 
877  // Skip the first line of the CSV
878  file.readLine();
879  while ( !file.atEnd() )
880  {
881  QByteArray line = file.readLine();
882  wordList.append( line.split( ',' ).at( 0 ).trimmed() );
883  }
884  file.close();
885  return wordList;
886 }
887 
889 {
890  QStringList wordList;
891  wordList.append( QString() ); // We add an empty line, because it's not compulsory.
892 
893  QString path = QDir( QgsApplication::metadataPath() ).absoluteFilePath( QStringLiteral( "LinkPropertyLookupTable.csv" ) );
894  QFile file( path );
895  if ( !file.open( QIODevice::ReadOnly ) )
896  {
897  QgsDebugMsg( QStringLiteral( "Error while opening the CSV file: %1, %2 " ).arg( path, file.errorString() ) );
898  return wordList;
899  }
900 
901  // Skip the first line of the CSV
902  file.readLine();
903  while ( !file.atEnd() )
904  {
905  QByteArray line = file.readLine();
906  wordList.append( line.split( ',' ).at( 0 ).trimmed() );
907  }
908  file.close();
909  return wordList;
910 }
911 
913 {
914  QStringList wordList;
915  wordList.append( QString() ); // We add an empty line, because it's not compulsory.
916 
917  QString path = QDir( QgsApplication::metadataPath() ).absoluteFilePath( QStringLiteral( "mime.csv" ) );
918  QFile file( path );
919  if ( !file.open( QIODevice::ReadOnly ) )
920  {
921  QgsDebugMsg( QStringLiteral( "Error while opening the CSV file: %1, %2 " ).arg( path, file.errorString() ) );
922  return wordList;
923  }
924 
925  while ( !file.atEnd() )
926  {
927  QByteArray line = file.readLine();
928  wordList.append( line.split( ',' ).at( 0 ).trimmed() );
929  }
930  file.close();
931  return wordList;
932 }
933 
934 QMap<QString, QString> QgsMetadataWidget::parseTypes()
935 {
936  QMap<QString, QString> types;
937  types.insert( QString(), QString() ); // We add an empty line, because it's not compulsory.
938  QString path = QDir( QgsApplication::metadataPath() ).absoluteFilePath( QStringLiteral( "md_scope_codes.csv" ) );
939  QFile file( path );
940  if ( !file.open( QIODevice::ReadOnly ) )
941  {
942  QgsDebugMsg( QStringLiteral( "Error while opening the CSV file: %1, %2 " ).arg( path, file.errorString() ) );
943  return types;
944  }
945 
946  types.insert( QString(), QString() ); // We add an empty line, because it's not compulsory.
947  while ( !file.atEnd() )
948  {
949  QByteArray line = file.readLine();
950  QList<QByteArray> items = line.split( ';' );
951  types.insert( items.at( 0 ).constData(), items.at( 1 ).constData() );
952  }
953  file.close();
954  return types;
955 }
956 
958 {
959  if ( canvas )
960  spatialExtentSelector->setCurrentExtent( canvas->extent(), canvas->mapSettings().destinationCrs() );
961 }
962 
964 {
965  return lineEditTitle->text();
966 }
967 
968 void QgsMetadataWidget::setTitle( const QString &title )
969 {
970  if ( title != lineEditTitle->text() )
971  {
972  whileBlocking( lineEditTitle )->setText( title );
973  emit titleChanged( title );
974  }
975 }
976 
978 {
979  saveMetadata( mMetadata.get() );
980  switch ( mMode )
981  {
982  case LayerMetadata:
983  if ( mLayer )
984  {
985  // Save layer metadata properties
986  mLayer->setMetadata( *static_cast< QgsLayerMetadata * >( mMetadata.get() ) );
987  }
988  break;
989 
990  case ProjectMetadata:
991  QgsProject::instance()->setMetadata( *static_cast< QgsProjectMetadata * >( mMetadata.get() ) );
992  break;
993  }
994 }
995 
996 void QgsMetadataWidget::syncFromCategoriesTabToKeywordsTab()
997 {
998  if ( mCategoriesModel->rowCount() > 0 )
999  {
1000  QList<QTableWidgetItem *> categories = tabKeywords->findItems( QStringLiteral( "gmd:topicCategory" ), Qt::MatchExactly );
1001  int row;
1002  if ( !categories.isEmpty() )
1003  {
1004  row = categories.at( 0 )->row();
1005  }
1006  else
1007  {
1008  // Create a new line with 'gmd:topicCategory'
1009  addVocabulary();
1010  row = tabKeywords->rowCount() - 1;
1011  tabKeywords->item( row, 0 )->setText( QStringLiteral( "gmd:topicCategory" ) );
1012  }
1013  tabKeywords->item( row, 1 )->setText( mCategoriesModel->stringList().join( QLatin1Char( ',' ) ) );
1014  }
1015 }
1016 
1017 void QgsMetadataWidget::updatePanel()
1018 {
1019  int index = tabWidget->currentIndex();
1020  QString currentTabText = tabWidget->widget( index )->objectName();
1021  if ( currentTabText == QLatin1String( "tabCategoriesDialog" ) )
1022  {
1023  // Categories tab
1024  // We need to take keywords and insert them into the list
1025  QList<QTableWidgetItem *> categories = tabKeywords->findItems( QStringLiteral( "gmd:topicCategory" ), Qt::MatchExactly );
1026  if ( !categories.isEmpty() )
1027  {
1028  const int row = categories.at( 0 )->row();
1029  mCategoriesModel->setStringList( tabKeywords->item( row, 1 )->text().split( ',' ) );
1030  }
1031  else
1032  {
1033  mCategoriesModel->setStringList( QStringList() );
1034  }
1035  }
1036  else if ( currentTabText == QLatin1String( "tabKeywordsDialog" ) )
1037  {
1038  // Keywords tab
1039  // We need to take categories and insert them into the table
1040  syncFromCategoriesTabToKeywordsTab();
1041  }
1042  else if ( currentTabText == QLatin1String( "tabValidationDialog" ) )
1043  {
1044  checkMetadata();
1045  }
1046 }
1047 
1048 void QgsMetadataWidget::addNewCategory()
1049 {
1050  bool ok;
1051  QString text = QInputDialog::getText( this, tr( "New Category" ),
1052  tr( "New Category:" ), QLineEdit::Normal,
1053  QString(), &ok );
1054  if ( ok && !text.isEmpty() )
1055  {
1056  QStringList list = mCategoriesModel->stringList();
1057  if ( ! list.contains( text ) )
1058  {
1059  list.append( text );
1060  mCategoriesModel->setStringList( list );
1061  mCategoriesModel->sort( 0 );
1062  }
1063  }
1064 }
1065 
1066 void QgsMetadataWidget::addDefaultCategories()
1067 {
1068  const QModelIndexList selectedIndexes = listDefaultCategories->selectionModel()->selectedIndexes();
1069  QStringList defaultCategoriesList = mDefaultCategoriesModel->stringList();
1070  QStringList selectedCategories = mCategoriesModel->stringList();
1071 
1072  for ( const QModelIndex &selection : selectedIndexes )
1073  {
1074  QVariant item = mDefaultCategoriesModel->data( selection, Qt::DisplayRole );
1075  defaultCategoriesList.removeOne( item.toString() );
1076 
1077  selectedCategories.append( item.toString() );
1078  }
1079 
1080  mDefaultCategoriesModel->setStringList( defaultCategoriesList );
1081  mCategoriesModel->setStringList( selectedCategories );
1082  mCategoriesModel->sort( 0 );
1083 }
1084 
1085 void QgsMetadataWidget::removeSelectedCategories()
1086 {
1087  const QModelIndexList selectedIndexes = listCategories->selectionModel()->selectedIndexes();
1088  QStringList categories = mCategoriesModel->stringList();
1089  QStringList defaultList = mDefaultCategoriesModel->stringList();
1090 
1091  for ( const QModelIndex &selection : selectedIndexes )
1092  {
1093  QVariant item = mCategoriesModel->data( selection, Qt::DisplayRole );
1094  categories.removeOne( item.toString() );
1095 
1096  if ( mDefaultCategories.contains( item.toString() ) )
1097  {
1098  defaultList.append( item.toString() );
1099  }
1100  }
1101  mCategoriesModel->setStringList( categories );
1102 
1103  mDefaultCategoriesModel->setStringList( defaultList );
1104  mDefaultCategoriesModel->sort( 0 );
1105 }
1106 
1108 LinkItemDelegate::LinkItemDelegate( QObject *parent )
1109  : QStyledItemDelegate( parent )
1110 {
1111 
1112 }
1113 
1114 QWidget *LinkItemDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
1115 {
1116  if ( index.column() == 1 )
1117  {
1118  // Link type
1119  QComboBox *typeEditor = new QComboBox( parent );
1120  typeEditor->setEditable( true );
1121  QStringListModel *model = new QStringListModel( parent );
1122  model->setStringList( QgsMetadataWidget::parseLinkTypes() );
1123  typeEditor->setModel( model );
1124  return typeEditor;
1125  }
1126  else if ( index.column() == 5 )
1127  {
1128  // MIME
1129  QComboBox *mimeEditor = new QComboBox( parent );
1130  mimeEditor->setEditable( true );
1131  QStringListModel *model = new QStringListModel( parent );
1132  model->setStringList( QgsMetadataWidget::parseMimeTypes() );
1133  mimeEditor->setModel( model );
1134  return mimeEditor;
1135  }
1136 
1137  return QStyledItemDelegate::createEditor( parent, option, index );
1138 }
1139 
1140 ConstraintItemDelegate::ConstraintItemDelegate( QObject *parent )
1141  : QStyledItemDelegate( parent )
1142 {
1143 
1144 }
1145 
1146 QWidget *ConstraintItemDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
1147 {
1148  if ( index.column() == 0 )
1149  {
1150  // Constraint type
1151  QComboBox *typeEditor = new QComboBox( parent );
1152  typeEditor->setEditable( true );
1153  QStringList types;
1154  types << QStringLiteral( "access" ) << QStringLiteral( "use" ) << QStringLiteral( "other" );
1155  QStringListModel *model = new QStringListModel( parent );
1156  model->setStringList( types );
1157  typeEditor->setModel( model );
1158  return typeEditor;
1159  }
1160 
1161  return QStyledItemDelegate::createEditor( parent, option, index );
1162 }
Contains the parameters describing a metadata validation failure.
An abstract base class for metadata stores.
void setAbstract(const QString &abstract)
Sets a free-form abstract (description) of the resource.
void setType(const QString &type)
Sets the type (nature) of the resource.
void setParentIdentifier(const QString &parentIdentifier)
Sets a reference, URI, URL or some other mechanism to identify the parent resource that this resource...
void setTitle(const QString &title)
Sets the human readable title (name) of the resource, typically displayed in search results.
void setHistory(const QStringList &history)
Sets the freeform description of the history or lineage of the resource.
void setLinks(const QgsAbstractMetadataBase::LinkList &links)
Sets the list of online resources associated with the resource.
virtual QgsAbstractMetadataBase * clone() const =0
Clones the metadata object.
void setIdentifier(const QString &identifier)
Sets the reference, URI, URL or some other mechanism to identify the resource.
void setContacts(const QgsAbstractMetadataBase::ContactList &contacts)
Sets the list of contacts or entities associated with the resource.
void setKeywords(const QgsAbstractMetadataBase::KeywordMap &keywords)
Sets the keywords map, which is a set of descriptive keywords associated with the resource.
void setLanguage(const QString &language)
Sets the human language associated with the resource.
static QString reportStyleSheet(QgsApplication::StyleSheetType styleSheetType=QgsApplication::StyleSheetType::Qt)
Returns a css style sheet for reports, the styleSheetType argument determines what type of stylesheet...
static QString metadataPath()
Returns the path to the metadata directory.
A 3-dimensional box composed of x, y, z coordinates.
Definition: qgsbox3d.h:39
void setZMinimum(double z) SIP_HOLDGIL
Sets the minimum z value.
Definition: qgsbox3d.cpp:59
void setZMaximum(double z) SIP_HOLDGIL
Sets the maximum z value.
Definition: qgsbox3d.cpp:64
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
QString userFriendlyIdentifier(IdentifierType type=MediumString) const
Returns a user friendly identifier for the CRS.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
A structured metadata store for a map layer.
void setConstraints(const QgsLayerMetadata::ConstraintList &constraints)
Sets the list of constraints associated with using the resource.
void setFees(const QString &fees)
Sets the fees associated with using the resource.
void setLicenses(const QStringList &licenses)
Sets a list of licenses associated with the resource.
void setRights(const QStringList &rights)
Sets a list of rights (attribution or copyright strings) associated with the resource.
void setEncoding(const QString &encoding)
Sets the character encoding of the data in the resource.
QgsLayerMetadata * clone() const override
Clones the metadata object.
void setExtent(const QgsLayerMetadata::Extent &extent)
Sets the spatial and temporal extents associated with the resource.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the coordinate reference system for the layer's metadata.
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.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
Base class for all map layer types.
Definition: qgsmaplayer.h:73
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:78
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer's metadata store.
virtual Q_INVOKABLE QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
QgsCoordinateReferenceSystem destinationCrs() const
Returns the destination coordinate reference system for the map render.
void acceptMetadata()
Saves the metadata to the layer.
QgsMetadataWidget(QWidget *parent SIP_TRANSFERTHIS=nullptr, QgsMapLayer *layer=nullptr)
Constructor for the wizard.
static QMap< QString, QString > parseTypes()
Returns a list of types available by default in the wizard.
void crsChanged()
If the CRS is updated.
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas associated with the widget.
static QStringList parseLicenses()
Returns a list of licences available by default in the wizard.
void saveMetadata(QgsAbstractMetadataBase *metadata)
Save all fields in a metadata object.
static QMap< QString, QString > parseLanguages()
Returns a list of languages available by default in the wizard.
void setMetadata(const QgsAbstractMetadataBase *metadata)
Sets the metadata to display in the widget.
static QStringList parseLinkTypes()
Returns a list of link types available by default in the wizard.
bool checkMetadata()
Check if values in the wizard are correct.
@ LayerMetadata
Show layer metadata.
@ ProjectMetadata
Show project metadata.
Mode mode() const
Returns the widget's current mode.
static QStringList parseMimeTypes()
Returns a list of MIME types available by default in the wizard.
QgsAbstractMetadataBase * metadata() SIP_FACTORY
Returns a QgsAbstractMetadataBase object representing the current state of the widget.
void setMode(Mode mode)
Sets the widget's current mode.
void titleChanged(const QString &title)
Emitted when the title field is changed.
void setTitle(const QString &title)
Sets the title field for the metadata.
A structured metadata store for a map layer.
void setCreationDateTime(const QDateTime &creationDateTime)
Sets the project's creation date/timestamp.
void setAuthor(const QString &author)
Sets the project author string.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:474
void setMetadata(const QgsProjectMetadata &metadata)
Sets the project's metadata store.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:1929
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QString administrativeArea
Administrative area (state, province/territory, etc.).
QString address
Free-form physical address component, e.g.
QString city
City or locality name.
QString type
Type of address, e.g.
QString country
Free-form country string.
QString postalCode
Postal (or ZIP) code.
QString position
Position/title of contact.
QList< QgsAbstractMetadataBase::Address > addresses
List of addresses associated with this contact.
QString email
Electronic mail address.
QString organization
Organization contact belongs to/represents.
Metadata constraint structure.
QString constraint
Free-form constraint string.
QString type
Constraint type.
Metadata extent structure.
void setSpatialExtents(const QList< QgsLayerMetadata::SpatialExtent > &extents)
Sets the spatial extents of the resource.
void setTemporalExtents(const QList< QgsDateTimeRange > &extents)
Sets the temporal extents of the resource.
Metadata spatial extent structure.
QgsCoordinateReferenceSystem extentCrs
Coordinate reference system for spatial extent.
QgsBox3d bounds
Geospatial extent of the resource.