QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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 <QtWidgets>
19 #include <QIcon>
20 #include <QPushButton>
21 #include <QComboBox>
22 #include <QString>
23 #include <QInputDialog>
24 #include <QStringListModel>
25 
26 #include "qgsbox3d.h"
27 #include "qgsmetadatawidget.h"
28 #include "qgslogger.h"
30 #include "qgsapplication.h"
31 #include "qgsmapcanvas.h"
32 #include "qgsprojectmetadata.h"
33 #include "qgsproject.h"
34 
36  : QWidget( parent ),
37  mLayer( layer )
38 {
39  setupUi( this );
40  tabWidget->setCurrentIndex( 0 );
41 
42  // Disable the encoding
43  encodingFrame->setHidden( true );
44 
45  // Default categories, we want them translated, so we are not using a CSV.
46  mDefaultCategories << tr( "Farming" ) << tr( "Climatology Meteorology Atmosphere" ) << tr( "Location" ) << tr( "Intelligence Military" ) << tr( "Transportation" ) << tr( "Structure" ) << tr( "Boundaries" );
47  mDefaultCategories << tr( "Inland Waters" ) << tr( "Planning Cadastre" ) << tr( "Geoscientific Information" ) << tr( "Elevation" ) << tr( "Health" ) << tr( "Biota" ) << tr( "Oceans" ) << tr( "Environment" );
48  mDefaultCategories << tr( "Utilities Communication" ) << tr( "Economy" ) << tr( "Society" ) << tr( "Imagery Base Maps Earth Cover" );
49  mDefaultCategoriesModel = new QStringListModel( mDefaultCategories, this );
50  mDefaultCategoriesModel->sort( 0 ); // Sorting using translations
51  listDefaultCategories->setModel( mDefaultCategoriesModel );
52 
53  // Categories
54  mCategoriesModel = new QStringListModel( listCategories );
55  listCategories->setModel( mCategoriesModel );
56 
57  // Rights
58  mRightsModel = new QStringListModel( listRights );
59  listRights->setModel( mRightsModel );
60 
61  // Setup the constraints view
62  mConstraintsModel = new QStandardItemModel( tabConstraints );
63  mConstraintsModel->setColumnCount( 2 );
64  QStringList constraintheaders;
65  constraintheaders << tr( "Type" ) << tr( "Constraint" );
66  mConstraintsModel->setHorizontalHeaderLabels( constraintheaders );
67  tabConstraints->setModel( mConstraintsModel );
68  tabConstraints->setItemDelegate( new ConstraintItemDelegate( this ) );
69 
70  // Extent
71  dateTimeFrom->setAllowNull( true );
72  dateTimeTo->setAllowNull( true );
73 
74  // Setup the link view
75  mLinksModel = new QStandardItemModel( tabLinks );
76  mLinksModel->setColumnCount( 7 );
77  QStringList headers = QStringList();
78  headers << tr( "Name" ) << tr( "Type" ) << tr( "URL" ) << tr( "Description" ) << tr( "Format" ) << tr( "MIME" ) << tr( "Size" );
79  mLinksModel->setHorizontalHeaderLabels( headers );
80  tabLinks->setModel( mLinksModel );
81  tabLinks->setItemDelegate( new LinkItemDelegate( this ) );
82 
83  // History
84  mHistoryModel = new QStringListModel( listHistory );
85  listHistory->setModel( mHistoryModel );
86 
87  // Connect signals and slots
88  connect( tabWidget, &QTabWidget::currentChanged, this, &QgsMetadataWidget::updatePanel );
89  connect( btnAutoSource, &QPushButton::clicked, this, &QgsMetadataWidget::fillSourceFromLayer );
90  connect( btnAddVocabulary, &QPushButton::clicked, this, &QgsMetadataWidget::addVocabulary );
91  connect( btnRemoveVocabulary, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedVocabulary );
92  connect( btnAddRight, &QPushButton::clicked, this, &QgsMetadataWidget::addRight );
93  connect( btnRemoveRight, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedRight );
94  connect( btnAddLicence, &QPushButton::clicked, this, &QgsMetadataWidget::addLicence );
95  connect( btnRemoveLicence, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedLicence );
96  connect( btnAddConstraint, &QPushButton::clicked, this, &QgsMetadataWidget::addConstraint );
97  connect( btnRemoveConstraint, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedConstraint );
98  connect( btnSetCrsFromLayer, &QPushButton::clicked, this, &QgsMetadataWidget::fillCrsFromLayer );
99  connect( btnSetCrsFromProvider, &QPushButton::clicked, this, &QgsMetadataWidget::fillCrsFromProvider );
100  connect( btnAddAddress, &QPushButton::clicked, this, &QgsMetadataWidget::addAddress );
101  connect( btnRemoveAddress, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedAddress );
102  connect( btnAddLink, &QPushButton::clicked, this, &QgsMetadataWidget::addLink );
103  connect( btnRemoveLink, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedLink );
104  connect( btnAddHistory, &QPushButton::clicked, this, &QgsMetadataWidget::addHistory );
105  connect( btnRemoveHistory, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedHistory );
106  connect( btnNewCategory, &QPushButton::clicked, this, &QgsMetadataWidget::addNewCategory );
107  connect( btnAddDefaultCategory, &QPushButton::clicked, this, &QgsMetadataWidget::addDefaultCategories );
108  connect( btnRemoveCategory, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedCategories );
109 
110  fillComboBox();
111  if ( !mLayer )
112  {
113  btnAutoSource->setEnabled( false );
114  btnAutoEncoding->setEnabled( false );
115  btnSetCrsFromLayer->setEnabled( false );
116  }
117 
118  if ( mLayer )
119  {
120  mMetadata.reset( mLayer->metadata().clone() );
122  setUiFromMetadata();
123  }
124 
125  connect( lineEditTitle, &QLineEdit::textChanged, this, &QgsMetadataWidget::titleChanged );
126 }
127 
129 {
130  QString type;
131  QString typeUpper;
132  mMode = mode;
133  switch ( mMode )
134  {
135  case LayerMetadata:
136  type = tr( "dataset" );
137  typeUpper = tr( "Dataset" );
138  mEncodingFrame->show();
139  mAuthorFrame->hide();
140  btnAutoSource->setEnabled( mLayer );
141  break;
142 
143  case ProjectMetadata:
144  type = tr( "project" );
145  typeUpper = tr( "Project" );
146  mEncodingFrame->hide();
147  mAuthorFrame->show();
148  tabWidget->removeTab( 4 );
149  tabWidget->removeTab( 3 );
150  btnAutoSource->setEnabled( true );
151  break;
152  }
153 
154  mIdLabel->setText( tr( "This page describes the basic attribution of the %1. Please use the tooltips for more information." ).arg( type ) );
155  mLabelCategories->setText( tr( "%1 categories." ).arg( typeUpper ) );
156  mLabelContact->setText( tr( "Contacts related to the %1." ).arg( type ) );
157  mLabelLinks->setText( tr( "Links describe ancillary resources and information related to this %1." ).arg( type ) );
158  mLabelHistory->setText( tr( "History about the %1." ).arg( type ) );
159  labelKeywords->setText( tr( "<html><head/><body><p>Keywords are optional, and provide a way to provide additional descriptive information about "
160  "the %1. Edits made in the categories tab will update the category entry below. For the concept, we suggest "
161  "to use a standard based vocabulary such as <a href=\"https://www.eionet.europa.eu/gemet/en/inspire-themes/\">"
162  "<span style=\" text-decoration: underline; color:#0000ff;\">GEMET.</span></a></p></body></html>" ).arg( type ) );
163  btnAutoSource->setText( tr( "Set from %1" ).arg( mMode == LayerMetadata ? tr( "layer" ) : tr( "project" ) ) );
164 }
165 
167 {
168  if ( !metadata )
169  return;
170 
171  if ( dynamic_cast< const QgsLayerMetadata * >( metadata ) && mMode != LayerMetadata )
173  else if ( dynamic_cast< const QgsProjectMetadata * >( metadata ) && mMode != ProjectMetadata )
175 
176  mMetadata.reset( metadata->clone() );
177  setUiFromMetadata();
178 }
179 
181 {
182  std::unique_ptr< QgsAbstractMetadataBase > md;
183  switch ( mMode )
184  {
185  case LayerMetadata:
186  md = qgis::make_unique< QgsLayerMetadata >();
187  break;
188 
189  case ProjectMetadata:
190  md = qgis::make_unique< QgsProjectMetadata >();
191  break;
192 
193  }
194  saveMetadata( md.get() );
195  return md.release();
196 }
197 
198 void QgsMetadataWidget::fillSourceFromLayer()
199 {
200  switch ( mMode )
201  {
202  case LayerMetadata:
203  if ( mLayer )
204  {
205  lineEditIdentifier->setText( mLayer->publicSource() );
206  }
207  break;
208 
209  case ProjectMetadata:
210  lineEditIdentifier->setText( QgsProject::instance()->fileName() );
211  break;
212  }
213 
214 }
215 
216 void QgsMetadataWidget::addVocabulary()
217 {
218  int row = tabKeywords->rowCount();
219  tabKeywords->setRowCount( row + 1 );
220  QTableWidgetItem *pCell = nullptr;
221 
222  // Vocabulary
223  pCell = new QTableWidgetItem( QString( tr( "undefined %1" ) ).arg( row + 1 ) );
224  tabKeywords->setItem( row, 0, pCell );
225 
226  // Keywords
227  pCell = new QTableWidgetItem();
228  tabKeywords->setItem( row, 1, pCell );
229 }
230 
231 void QgsMetadataWidget::removeSelectedVocabulary()
232 {
233  QItemSelectionModel *selectionModel = tabKeywords->selectionModel();
234  const QModelIndexList selectedRows = selectionModel->selectedRows();
235  for ( int i = 0; i < selectedRows.size() ; i++ )
236  {
237  tabKeywords->model()->removeRow( selectedRows[i].row() );
238  }
239 }
240 
241 void QgsMetadataWidget::addLicence()
242 {
243  QString newLicence = QInputDialog::getItem( this, tr( "New Licence" ), tr( "New Licence" ), parseLicenses(), 0, true );
244  if ( tabLicenses->findItems( newLicence, Qt::MatchExactly ).isEmpty() )
245  {
246  int row = tabLicenses->rowCount();
247  tabLicenses->setRowCount( row + 1 );
248  QTableWidgetItem *pCell = new QTableWidgetItem( newLicence );
249  tabLicenses->setItem( row, 0, pCell );
250  }
251 }
252 
253 void QgsMetadataWidget::removeSelectedLicence()
254 {
255  QItemSelectionModel *selectionModel = tabLicenses->selectionModel();
256  const QModelIndexList selectedRows = selectionModel->selectedRows();
257  for ( int i = 0; i < selectedRows.size() ; i++ )
258  {
259  tabLicenses->model()->removeRow( selectedRows[i].row() );
260  }
261 }
262 
263 void QgsMetadataWidget::addRight()
264 {
265  QString newRight = QInputDialog::getText( this, tr( "New Right" ), tr( "New Right" ) );
266  QStringList existingRights = mRightsModel->stringList();
267  if ( ! existingRights.contains( newRight ) )
268  {
269  existingRights.append( newRight );
270  mRightsModel->setStringList( existingRights );
271  }
272 }
273 
274 void QgsMetadataWidget::removeSelectedRight()
275 {
276  QItemSelectionModel *selection = listRights->selectionModel();
277  if ( selection->hasSelection() )
278  {
279  QModelIndex indexElementSelectionne = selection->currentIndex();
280 
281  QVariant item = mRightsModel->data( indexElementSelectionne, Qt::DisplayRole );
282  QStringList list = mRightsModel->stringList();
283  list.removeOne( item.toString() );
284  mRightsModel->setStringList( list );
285  }
286 }
287 
288 void QgsMetadataWidget::addConstraint()
289 {
290  int row = mConstraintsModel->rowCount();
291  mConstraintsModel->setItem( row, 0, new QStandardItem( QString( tr( "undefined %1" ) ).arg( row + 1 ) ) );
292  mConstraintsModel->setItem( row, 1, new QStandardItem( QString( tr( "undefined %1" ) ).arg( row + 1 ) ) );
293 }
294 
295 void QgsMetadataWidget::removeSelectedConstraint()
296 {
297  const QModelIndexList selectedRows = tabConstraints->selectionModel()->selectedRows();
298  if ( selectedRows.empty() )
299  return;
300  mConstraintsModel->removeRow( selectedRows[0].row() );
301 }
302 
304 {
305  if ( ( mCrs.isValid() ) && ( mLayer ) )
306  {
307  lblCurrentCrs->setText( tr( "CRS: %1 - %2" ).arg( mCrs.authid(), mCrs.description() ) );
308  spatialExtentSelector->setEnabled( true );
309  spatialExtentSelector->setOutputCrs( mCrs );
310 
311  if ( mCrs == mLayer->crs() && mCrs == mLayer->dataProvider()->crs() )
312  {
313  lblCurrentCrsStatus->setText( tr( "Same as layer properties and provider." ) );
314  }
315  else if ( mCrs == mLayer->crs() && mCrs != mLayer->dataProvider()->crs() )
316  {
317  lblCurrentCrsStatus->setText( tr( "Same as layer properties but different than the provider." ) );
318  }
319  else if ( mCrs != mLayer->crs() && mCrs == mLayer->dataProvider()->crs() )
320  {
321  lblCurrentCrsStatus->setText( tr( "Same as the provider but different than the layer properties." ) );
322  }
323  else
324  {
325  lblCurrentCrsStatus->setText( tr( "Does not match either layer properties or the provider." ) );
326  }
327  }
328  else
329  {
330  lblCurrentCrs->setText( tr( "CRS: Not set." ) );
331  lblCurrentCrsStatus->setText( QString() );
332  spatialExtentSelector->setEnabled( false );
333  }
334 }
335 
336 void QgsMetadataWidget::addAddress()
337 {
338  int row = tabAddresses->rowCount();
339  tabAddresses->setRowCount( row + 1 );
340  QTableWidgetItem *pCell = nullptr;
341 
342  // Type
343  pCell = new QTableWidgetItem( QString( tr( "postal" ) ) );
344  tabAddresses->setItem( row, 0, pCell );
345 
346  // Address
347  tabAddresses->setItem( row, 1, new QTableWidgetItem() );
348 
349  // postal code
350  tabAddresses->setItem( row, 2, new QTableWidgetItem() );
351 
352  // City
353  tabAddresses->setItem( row, 3, new QTableWidgetItem() );
354 
355  // Admin area
356  tabAddresses->setItem( row, 4, new QTableWidgetItem() );
357 
358  // Country
359  tabAddresses->setItem( row, 5, new QTableWidgetItem() );
360 }
361 
362 void QgsMetadataWidget::removeSelectedAddress()
363 {
364  QItemSelectionModel *selectionModel = tabAddresses->selectionModel();
365  const QModelIndexList selectedRows = selectionModel->selectedRows();
366  for ( int i = 0; i < selectedRows.size() ; i++ )
367  {
368  tabAddresses->model()->removeRow( selectedRows[i].row() );
369  }
370 }
371 
372 void QgsMetadataWidget::fillCrsFromLayer()
373 {
374  mCrs = mLayer->crs();
375  crsChanged();
376 }
377 
378 void QgsMetadataWidget::fillCrsFromProvider()
379 {
380  mCrs = mLayer->dataProvider()->crs();
381  crsChanged();
382 }
383 
384 void QgsMetadataWidget::addLink()
385 {
386  int row = mLinksModel->rowCount();
387  mLinksModel->setItem( row, 0, new QStandardItem( QString( tr( "undefined %1" ) ).arg( row + 1 ) ) );
388  mLinksModel->setItem( row, 1, new QStandardItem() );
389  mLinksModel->setItem( row, 2, new QStandardItem() );
390  mLinksModel->setItem( row, 3, new QStandardItem() );
391  mLinksModel->setItem( row, 4, new QStandardItem() );
392  mLinksModel->setItem( row, 5, new QStandardItem() );
393  mLinksModel->setItem( row, 6, new QStandardItem() );
394 }
395 
396 void QgsMetadataWidget::removeSelectedLink()
397 {
398  const QModelIndexList selectedRows = tabLinks->selectionModel()->selectedRows();
399  if ( selectedRows.empty() )
400  return;
401 
402  mLinksModel->removeRow( selectedRows[0].row() );
403 }
404 
405 void QgsMetadataWidget::addHistory()
406 {
407  QString newHistory = QInputDialog::getText( this, tr( "New History" ), tr( "New History" ) );
408  QStringList existingHistory = mHistoryModel->stringList();
409  if ( ! existingHistory.contains( newHistory ) )
410  {
411  existingHistory.append( newHistory );
412  mHistoryModel->setStringList( existingHistory );
413  }
414 }
415 
416 void QgsMetadataWidget::removeSelectedHistory()
417 {
418  QItemSelectionModel *selection = listHistory->selectionModel();
419  if ( selection->hasSelection() )
420  {
421  QModelIndex indexElementSelectionne = selection->currentIndex();
422 
423  QVariant item = mHistoryModel->data( indexElementSelectionne, Qt::DisplayRole );
424  QStringList list = mHistoryModel->stringList();
425  list.removeOne( item.toString() );
426  mHistoryModel->setStringList( list );
427  }
428 }
429 
430 void QgsMetadataWidget::fillComboBox()
431 {
432  // Set default values in type combobox
433  // It is advised to use the ISO 19115 MD_ScopeCode values. E.g. 'dataset' or 'series'.
434  // http://www.isotc211.org/2005/resources/Codelist/gmxCodelists.xml
435  comboType->setEditable( true );
436  comboType->clear();
437  QMap<QString, QString> types = parseTypes();
438  const QStringList &keys = types.keys();
439  int i = 0;
440  for ( const QString &type : keys )
441  {
442  comboType->insertItem( i, type );
443  comboType->setItemData( i, types.value( type ), Qt::ToolTipRole );
444  i++;
445  }
446 
447  // Set default values in language combobox
448  // It is advised to use the ISO 639.2 or ISO 3166 specifications, e.g. 'ENG' or 'SPA',
449  comboLanguage->setEditable( true );
450  comboLanguage->clear();
451  QMap<QString, QString> countries = parseLanguages();
452  const QStringList &k = countries.keys();
453  i = 0;
454  for ( const QString &countryCode : k )
455  {
456  comboLanguage->insertItem( i, countryCode );
457  comboLanguage->setItemData( i, countries.value( countryCode ), Qt::ToolTipRole );
458  i++;
459  }
460 }
461 
462 void QgsMetadataWidget::setUiFromMetadata()
463 {
464  // Parent ID
465  lineEditParentId->setText( mMetadata->parentIdentifier() );
466 
467  // Identifier
468  if ( ! mMetadata->identifier().isEmpty() )
469  {
470  lineEditIdentifier->setText( mMetadata->identifier() );
471  }
472 
473  // Title
474  if ( ! mMetadata->title().isEmpty() )
475  {
476  whileBlocking( lineEditTitle )->setText( mMetadata->title() );
477  }
478 
479  // Type
480  if ( ! mMetadata->type().isEmpty() )
481  {
482  if ( comboType->findText( mMetadata->type() ) == -1 )
483  {
484  comboType->addItem( mMetadata->type() );
485  }
486  comboType->setCurrentIndex( comboType->findText( mMetadata->type() ) );
487  }
488 
489  // Language
490  if ( ! mMetadata->language().isEmpty() )
491  {
492  if ( comboLanguage->findText( mMetadata->language() ) == -1 )
493  {
494  comboLanguage->addItem( mMetadata->language() );
495  }
496  comboLanguage->setCurrentIndex( comboLanguage->findText( mMetadata->language() ) );
497  }
498 
499  // Abstract
500  textEditAbstract->setPlainText( mMetadata->abstract() );
501 
502  // Categories
503  mCategoriesModel->setStringList( mMetadata->categories() );
504 
505  // Keywords
506  tabKeywords->setRowCount( 0 );
507  QMapIterator<QString, QStringList> i( mMetadata->keywords() );
508  while ( i.hasNext() )
509  {
510  i.next();
511  addVocabulary();
512  int currentRow = tabKeywords->rowCount() - 1;
513  tabKeywords->item( currentRow, 0 )->setText( i.key() );
514  tabKeywords->item( currentRow, 1 )->setText( i.value().join( QStringLiteral( "," ) ) );
515  }
516 
517  if ( QgsLayerMetadata *layerMetadata = dynamic_cast< QgsLayerMetadata * >( mMetadata.get() ) )
518  {
519  // Encoding
520  comboEncoding->setCurrentText( layerMetadata->encoding() );
521 
522  // Fees
523  lineEditFees->setText( layerMetadata->fees() );
524 
525  // Licenses
526  tabLicenses->setRowCount( 0 );
527  const QStringList &licenses = layerMetadata->licenses();
528  for ( const QString &licence : licenses )
529  {
530  int currentRow = tabLicenses->rowCount();
531  tabLicenses->setRowCount( currentRow + 1 );
532  QTableWidgetItem *pCell = tabLicenses->item( currentRow, 0 );
533  if ( !pCell )
534  {
535  pCell = new QTableWidgetItem;
536  tabLicenses->setItem( currentRow, 0, pCell );
537  }
538  pCell->setText( licence );
539  }
540 
541  // Rights
542  mRightsModel->setStringList( layerMetadata->rights() );
543 
544  // Constraints
545  const QList<QgsLayerMetadata::Constraint> &constraints = layerMetadata->constraints();
546  for ( const QgsLayerMetadata::Constraint &constraint : constraints )
547  {
548  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  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 = qgis::make_unique< QgsNativeMetadataValidator>();
784  break;
785 
786  case ProjectMetadata:
787  validator = qgis::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 : qgis::as_const( validationResults ) )
798  {
799  errors += QLatin1String( "<b>" ) % result.section;
800  if ( ! result.identifier.isNull() )
801  {
802  errors += QLatin1String( " " ) % QVariant( result.identifier.toInt() + 1 ).toString();
803  }
804  errors += QLatin1String( "</b>: " ) % result.note % QLatin1String( "<br />" );
805  }
806  }
807  else
808  {
809  errors = QString( 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 
963 QString QgsMetadataWidget::title() const
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( QStringLiteral( "," ) ) );
1014  }
1015 }
1016 
1017 void QgsMetadataWidget::updatePanel()
1018 {
1019  int index = tabWidget->currentIndex();
1020  QString currentTabText = tabWidget->widget( index )->objectName();
1021  if ( currentTabText == QStringLiteral( "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  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 == QStringLiteral( "tabKeywordsDialog" ) )
1037  {
1038  // Keywords tab
1039  // We need to take categories and insert them into the table
1040  syncFromCategoriesTabToKeywordsTab();
1041  }
1042  else if ( currentTabText == QStringLiteral( "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  : QStyledItemDelegate( parent )
1109 {
1110 
1111 }
1112 
1113 QWidget *LinkItemDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
1114 {
1115  if ( index.column() == 1 )
1116  {
1117  // Link type
1118  QComboBox *typeEditor = new QComboBox( parent );
1119  typeEditor->setEditable( true );
1120  QStringListModel *model = new QStringListModel( parent );
1121  model->setStringList( QgsMetadataWidget::parseLinkTypes() );
1122  typeEditor->setModel( model );
1123  return typeEditor;
1124  }
1125  else if ( index.column() == 5 )
1126  {
1127  // MIME
1128  QComboBox *mimeEditor = new QComboBox( parent );
1129  mimeEditor->setEditable( true );
1130  QStringListModel *model = new QStringListModel( parent );
1131  model->setStringList( QgsMetadataWidget::parseMimeTypes() );
1132  mimeEditor->setModel( model );
1133  return mimeEditor;
1134  }
1135 
1136  return QStyledItemDelegate::createEditor( parent, option, index );
1137 }
1138 
1140  : QStyledItemDelegate( parent )
1141 {
1142 
1143 }
1144 
1145 QWidget *ConstraintItemDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
1146 {
1147  if ( index.column() == 0 )
1148  {
1149  // Constraint type
1150  QComboBox *typeEditor = new QComboBox( parent );
1151  typeEditor->setEditable( true );
1152  QStringList types;
1153  types << QStringLiteral( "access" ) << QStringLiteral( "use" ) << QStringLiteral( "other" );
1154  QStringListModel *model = new QStringListModel( parent );
1155  model->setStringList( types );
1156  typeEditor->setModel( model );
1157  return typeEditor;
1158  }
1159 
1160  return QStyledItemDelegate::createEditor( parent, option, index );
1161 }
void titleChanged(const QString &title)
Emitted when the title field is changed.
QList< QgsAbstractMetadataBase::Address > addresses
List of addresses associated with this contact.
Base class for all map layer types.
Definition: qgsmaplayer.h:78
QString fax
Facsimile telephone.
QString city
City or locality name.
virtual QgsDataProvider * dataProvider()
Returns the layer&#39;s data provider, it may be nullptr.
void setMetadata(const QgsAbstractMetadataBase *metadata)
Sets the metadata to display in the widget.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QString country
Free-form country string.
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas associated with the widget.
void setLinks(const QgsAbstractMetadataBase::LinkList &links)
Sets the list of online resources associated with the resource.
void setCreationDateTime(const QDateTime &creationDateTime)
Sets the project&#39;s creation date/timestamp.
void setLicenses(const QStringList &licenses)
Sets a list of licenses associated with the resource.
void setContacts(const QgsAbstractMetadataBase::ContactList &contacts)
Sets the list of contacts or entities associated with the resource.
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:84
static QString reportStyleSheet()
Returns a standard css style sheet for reports.
A 3-dimensional box composed of x, y, z coordinates.
Definition: qgsbox3d.h:36
\@cond PRIVATE
void setExtent(const QgsLayerMetadata::Extent &extent)
Sets the spatial and temporal extents associated with the resource.
Metadata address structure.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:73
void setTitle(const QString &title)
Sets the human readable title (name) of the resource, typically displayed in search results...
void setMode(Mode mode)
Sets the widget&#39;s current mode.
void setHistory(const QStringList &history)
Sets the freeform description of the history or lineage of the resource.
QgsCoordinateReferenceSystem extentCrs
Coordinate reference system for spatial extent.
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
QString type
Constraint type.
void setAuthor(const QString &author)
Sets the project author string.
Metadata constraint structure.
static QMap< QString, QString > parseTypes()
Returns a list of types available by default in the wizard.
void setIdentifier(const QString &identifier)
Sets the reference, URI, URL or some other mechanism to identify the resource.
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer&#39;s metadata store.
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
void setConstraints(const QgsLayerMetadata::ConstraintList &constraints)
Sets the list of constraints associated with using the resource.
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
void setParentIdentifier(const QString &parentIdentifier)
Sets a reference, URI, URL or some other mechanism to identify the parent resource that this resource...
QgsMetadataWidget(QWidget *parent=nullptr, QgsMapLayer *layer=nullptr)
Constructor for the wizard.
QString administrativeArea
Administrative area (state, province/territory, etc.).
QString description() const
Returns the descriptive name of the CRS, e.g., "WGS 84" or "GDA 94 / Vicgrid94".
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Create a special editor with a QCombobox in the constraint view.
LinkItemDelegate(QObject *parent=nullptr)
LinkItemDelegate constructor.
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example...
void setFees(const QString &fees)
Sets the fees associated with using the resource.
Metadata extent structure.
void saveMetadata(QgsAbstractMetadataBase *metadata)
Save all fields in a metadata object.
Contains the parameters describing a metadata validation failure.
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the coordinate reference system for the layer&#39;s metadata.
void setKeywords(const QgsAbstractMetadataBase::KeywordMap &keywords)
Sets the keywords map, which is a set of descriptive keywords associated with the resource...
QString postalCode
Postal (or ZIP) code.
void setLanguage(const QString &language)
Sets the human language associated with the resource.
static QStringList parseLicenses()
Returns a list of licences available by default in the wizard.
void acceptMetadata()
Saves the metadata to the layer.
void setRights(const QStringList &rights)
Sets a list of rights (attribution or copyright strings) associated with the resource.
void setZMinimum(double z)
Sets the minimum z value.
Definition: qgsbox3d.cpp:60
void setMetadata(const QgsProjectMetadata &metadata)
Sets the project&#39;s metadata store.
QString type
Type of address, e.g.
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Create a special editor with a QCombobox in the link view.
virtual QgsAbstractMetadataBase * clone() const =0
Clones the metadata object.
A structured metadata store for a map layer.
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
void setSpatialExtents(const QList< QgsLayerMetadata::SpatialExtent > &extents)
Sets the spatial extents of the resource.
QString position
Position/title of contact.
static QMap< QString, QString > parseLanguages()
Returns a list of languages available by default in the wizard.
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:212
QString address
Free-form physical address component, e.g.
static QStringList parseMimeTypes()
Returns a list of MIME types available by default in the wizard.
void crsChanged()
If the CRS is updated.
QgsLayerMetadata * clone() const override
Clones the metadata object.
void setTitle(const QString &title)
Sets the title field for the metadata.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:438
QgsBox3d bounds
Geospatial extent of the resource.
Mode mode() const
Returns the widget&#39;s current mode.
An abstract base class for metadata stores.
QString organization
Organization contact belongs to/represents.
QgsAbstractMetadataBase * metadata()
Returns a QgsAbstractMetadataBase object representing the current state of the widget.
Special delegate for the constraint view in the metadata wizard.
void setAbstract(const QString &abstract)
Sets a free-form abstract (description) of the resource.
void setEncoding(const QString &encoding)
Sets the character encoding of the data in the resource.
void setType(const QString &type)
Sets the type (nature) of the resource.
QString constraint
Free-form constraint string.
Metadata spatial extent structure.
static QString metadataPath()
Returns the path to the metadata directory.
QString email
Electronic mail address.
ConstraintItemDelegate(QObject *parent=nullptr)
ConstraintItemDelegate constructor.
static QStringList parseLinkTypes()
Returns a list of link types available by default in the wizard.
QString title() const
Returns the current title field for the metadata.
QString authid() const
Returns the authority identifier for the CRS.
Mode
Widget modes.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:85
bool checkMetadata()
Check if values in the wizard are correct.
void setTemporalExtents(const QList< QgsDateTimeRange > &extents)
Sets the temporal extents of the resource.
A structured metadata store for a map layer.
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
void setZMaximum(double z)
Sets the maximum z value.
Definition: qgsbox3d.cpp:65