QGIS API Documentation  3.14.0-Pi (9f7028fd23)
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" ).arg( mCrs.userFriendlyIdentifier() ) );
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 }
QgsMetadataWidget::setMapCanvas
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas associated with the widget.
Definition: qgsmetadatawidget.cpp:957
QgsMetadataWidget::parseLinkTypes
static QStringList parseLinkTypes()
Returns a list of link types available by default in the wizard.
Definition: qgsmetadatawidget.cpp:888
QgsAbstractMetadataBase::Contact::name
QString name
Name of contact.
Definition: qgsabstractmetadatabase.h:151
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:88
LinkItemDelegate::LinkItemDelegate
LinkItemDelegate(QObject *parent=nullptr)
LinkItemDelegate constructor.
Definition: qgsmetadatawidget.cpp:1107
QgsLayerMetadata::setRights
void setRights(const QStringList &rights)
Sets a list of rights (attribution or copyright strings) associated with the resource.
Definition: qgslayermetadata.cpp:56
QgsMapCanvas::extent
QgsRectangle extent() const
Returns the current zoom extent of the map canvas.
Definition: qgsmapcanvas.cpp:1049
QgsLayerMetadata::SpatialExtent::extentCrs
QgsCoordinateReferenceSystem extentCrs
Coordinate reference system for spatial extent.
Definition: qgslayermetadata.h:72
QgsAbstractMetadataBaseValidator::ValidationResult
Contains the parameters describing a metadata validation failure.
Definition: qgslayermetadatavalidator.h:46
ConstraintItemDelegate::ConstraintItemDelegate
ConstraintItemDelegate(QObject *parent=nullptr)
ConstraintItemDelegate constructor.
Definition: qgsmetadatawidget.cpp:1139
QgsBox3d::setZMaximum
void setZMaximum(double z)
Sets the maximum z value.
Definition: qgsbox3d.cpp:65
QgsMetadataWidget::setMetadata
void setMetadata(const QgsAbstractMetadataBase *metadata)
Sets the metadata to display in the widget.
Definition: qgsmetadatawidget.cpp:166
qgslayermetadatavalidator.h
QgsProjectMetadata
A structured metadata store for a map layer.
Definition: qgsprojectmetadata.h:53
qgsmapcanvas.h
QgsAbstractMetadataBase::Contact::addresses
QList< QgsAbstractMetadataBase::Address > addresses
List of addresses associated with this contact.
Definition: qgsabstractmetadatabase.h:166
QgsLayerMetadata::setCrs
void setCrs(const QgsCoordinateReferenceSystem &crs)
Sets the coordinate reference system for the layer's metadata.
Definition: qgslayermetadata.cpp:86
QgsAbstractMetadataBase::Contact::fax
QString fax
Facsimile telephone.
Definition: qgsabstractmetadatabase.h:176
LinkItemDelegate::createEditor
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Create a special editor with a QCombobox in the link view.
Definition: qgsmetadatawidget.cpp:1113
QgsCoordinateReferenceSystem::userFriendlyIdentifier
QString userFriendlyIdentifier(IdentifierType type=MediumString) const
Returns a user friendly identifier for the CRS.
Definition: qgscoordinatereferencesystem.cpp:1316
QgsLayerMetadata::SpatialExtent
Metadata spatial extent structure.
Definition: qgslayermetadata.h:63
QgsAbstractMetadataBase::setLinks
void setLinks(const QgsAbstractMetadataBase::LinkList &links)
Sets the list of online resources associated with the resource.
Definition: qgsabstractmetadatabase.cpp:153
QgsMapCanvas::mapSettings
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
Definition: qgsmapcanvas.cpp:390
QgsAbstractMetadataBase::setHistory
void setHistory(const QStringList &history)
Sets the freeform description of the history or lineage of the resource.
Definition: qgsabstractmetadatabase.cpp:76
QgsAbstractMetadataBase::Address::city
QString city
City or locality name.
Definition: qgsabstractmetadatabase.h:113
QgsLayerMetadata
A structured metadata store for a map layer.
Definition: qgslayermetadata.h:56
QgsMapCanvas
Definition: qgsmapcanvas.h:83
QgsAbstractMetadataBase::setContacts
void setContacts(const QgsAbstractMetadataBase::ContactList &contacts)
Sets the list of contacts or entities associated with the resource.
Definition: qgsabstractmetadatabase.cpp:138
QgsAbstractMetadataBase::Address::country
QString country
Free-form country string.
Definition: qgsabstractmetadatabase.h:128
QgsProject::instance
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:458
QgsAbstractMetadataBase::Contact::voice
QString voice
Voice telephone.
Definition: qgsabstractmetadatabase.h:171
QgsAbstractMetadataBase::setTitle
void setTitle(const QString &title)
Sets the human readable title (name) of the resource, typically displayed in search results.
Definition: qgsabstractmetadatabase.cpp:56
QgsDebugMsg
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QgsLayerMetadata::clone
QgsLayerMetadata * clone() const override
Clones the metadata object.
Definition: qgslayermetadata.cpp:21
QgsMapLayer::setMetadata
virtual void setMetadata(const QgsLayerMetadata &metadata)
Sets the layer's metadata store.
Definition: qgsmaplayer.cpp:1827
QgsLayerMetadata::SpatialExtent::bounds
QgsBox3d bounds
Geospatial extent of the resource.
Definition: qgslayermetadata.h:82
qgsapplication.h
LinkItemDelegate
\@cond PRIVATE
Definition: qgsmetadatawidget.h:248
QgsLayerMetadata::setEncoding
void setEncoding(const QString &encoding)
Sets the character encoding of the data in the resource.
Definition: qgslayermetadata.cpp:76
QgsMapLayer::metadata
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:87
QgsMapLayer::dataProvider
virtual QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
Definition: qgsmaplayer.cpp:169
whileBlocking
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:262
QgsAbstractMetadataBase::setParentIdentifier
void setParentIdentifier(const QString &parentIdentifier)
Sets a reference, URI, URL or some other mechanism to identify the parent resource that this resource...
Definition: qgsabstractmetadatabase.cpp:36
QgsAbstractMetadataBase::Address::administrativeArea
QString administrativeArea
Administrative area (state, province/territory, etc.).
Definition: qgsabstractmetadatabase.h:118
QgsMetadataWidget::acceptMetadata
void acceptMetadata()
Saves the metadata to the layer.
Definition: qgsmetadatawidget.cpp:977
QgsApplication::metadataPath
static QString metadataPath()
Returns the path to the metadata directory.
Definition: qgsapplication.cpp:963
QgsMetadataWidget::setMode
void setMode(Mode mode)
Sets the widget's current mode.
Definition: qgsmetadatawidget.cpp:128
qgsmetadatawidget.h
QgsLayerMetadata::Constraint::type
QString type
Constraint type.
Definition: qgslayermetadata.h:151
QgsAbstractMetadataBase::setIdentifier
void setIdentifier(const QString &identifier)
Sets the reference, URI, URL or some other mechanism to identify the resource.
Definition: qgsabstractmetadatabase.cpp:26
QgsMetadataWidget::saveMetadata
void saveMetadata(QgsAbstractMetadataBase *metadata)
Save all fields in a metadata object.
Definition: qgsmetadatawidget.cpp:640
QgsMetadataWidget::LayerMetadata
@ LayerMetadata
Show layer metadata.
Definition: qgsmetadatawidget.h:54
QgsLayerMetadata::Constraint::constraint
QString constraint
Free-form constraint string.
Definition: qgslayermetadata.h:156
QgsAbstractMetadataBase::clone
virtual QgsAbstractMetadataBase * clone() const =0
Clones the metadata object.
QgsAbstractMetadataBase::Address::postalCode
QString postalCode
Postal (or ZIP) code.
Definition: qgsabstractmetadatabase.h:123
QgsProjectMetadata::setAuthor
void setAuthor(const QString &author)
Sets the project author string.
Definition: qgsprojectmetadata.cpp:75
QgsAbstractMetadataBase::Address
Metadata address structure.
Definition: qgsabstractmetadatabase.h:85
QgsMetadataWidget::parseLanguages
static QMap< QString, QString > parseLanguages()
Returns a list of languages available by default in the wizard.
Definition: qgsmetadatawidget.cpp:821
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:902
QgsMetadataWidget::title
QString title
Definition: qgsmetadatawidget.h:44
ConstraintItemDelegate
Special delegate for the constraint view in the metadata wizard.
Definition: qgsmetadatawidget.h:274
QgsMetadataWidget::parseTypes
static QMap< QString, QString > parseTypes()
Returns a list of types available by default in the wizard.
Definition: qgsmetadatawidget.cpp:934
QgsAbstractMetadataBase::Contact::role
QString role
Role of contact.
Definition: qgsabstractmetadatabase.h:189
QgsMetadataWidget::ProjectMetadata
@ ProjectMetadata
Show project metadata.
Definition: qgsmetadatawidget.h:55
QgsLayerMetadata::setLicenses
void setLicenses(const QStringList &licenses)
Sets a list of licenses associated with the resource.
Definition: qgslayermetadata.cpp:66
QgsAbstractMetadataBase::Address::type
QString type
Type of address, e.g.
Definition: qgsabstractmetadatabase.h:103
qgsbox3d.h
qgsprojectmetadata.h
QgsLayerMetadata::Extent
Metadata extent structure.
Definition: qgslayermetadata.h:90
QgsAbstractMetadataBase::setKeywords
void setKeywords(const QgsAbstractMetadataBase::KeywordMap &keywords)
Sets the keywords map, which is a set of descriptive keywords associated with the resource.
Definition: qgsabstractmetadatabase.cpp:91
QgsAbstractMetadataBase::Address::address
QString address
Free-form physical address component, e.g.
Definition: qgsabstractmetadatabase.h:108
QgsMetadataWidget::mode
Mode mode() const
Returns the widget's current mode.
Definition: qgsmetadatawidget.h:80
QgsMetadataWidget::parseMimeTypes
static QStringList parseMimeTypes()
Returns a list of MIME types available by default in the wizard.
Definition: qgsmetadatawidget.cpp:912
QgsMetadataWidget::QgsMetadataWidget
QgsMetadataWidget(QWidget *parent=nullptr, QgsMapLayer *layer=nullptr)
Constructor for the wizard.
Definition: qgsmetadatawidget.cpp:35
QgsMetadataWidget::crsChanged
void crsChanged()
If the CRS is updated.
Definition: qgsmetadatawidget.cpp:303
QgsMapSettings::destinationCrs
QgsCoordinateReferenceSystem destinationCrs() const
returns CRS of destination coordinate reference system
Definition: qgsmapsettings.cpp:317
QgsMapLayer::publicSource
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
Definition: qgsmaplayer.cpp:184
QgsBox3d::setZMinimum
void setZMinimum(double z)
Sets the minimum z value.
Definition: qgsbox3d.cpp:60
QgsMetadataWidget::setTitle
void setTitle(const QString &title)
Sets the title field for the metadata.
Definition: qgsmetadatawidget.cpp:968
QgsAbstractMetadataBase::setAbstract
void setAbstract(const QString &abstract)
Sets a free-form abstract (description) of the resource.
Definition: qgsabstractmetadatabase.cpp:66
QgsLayerMetadata::Extent::setTemporalExtents
void setTemporalExtents(const QList< QgsDateTimeRange > &extents)
Sets the temporal extents of the resource.
Definition: qgslayermetadata.cpp:374
QgsAbstractMetadataBase::setLanguage
void setLanguage(const QString &language)
Sets the human language associated with the resource.
Definition: qgsabstractmetadatabase.cpp:168
QgsAbstractMetadataBase::Contact::position
QString position
Position/title of contact.
Definition: qgsabstractmetadatabase.h:161
QgsMetadataWidget::parseLicenses
static QStringList parseLicenses()
Returns a list of licences available by default in the wizard.
Definition: qgsmetadatawidget.cpp:864
QgsMapLayer
Definition: qgsmaplayer.h:81
QgsAbstractMetadataBase::Contact::organization
QString organization
Organization contact belongs to/represents.
Definition: qgsabstractmetadatabase.h:156
QgsProject::setMetadata
void setMetadata(const QgsProjectMetadata &metadata)
Sets the project's metadata store.
Definition: qgsproject.cpp:3453
QgsLayerMetadata::Constraint
Metadata constraint structure.
Definition: qgslayermetadata.h:136
QgsLayerMetadata::setConstraints
void setConstraints(const QgsLayerMetadata::ConstraintList &constraints)
Sets the list of constraints associated with using the resource.
Definition: qgslayermetadata.cpp:46
QgsMetadataWidget::Mode
Mode
Widget modes.
Definition: qgsmetadatawidget.h:52
QgsMetadataWidget::checkMetadata
bool checkMetadata()
Check if values in the wizard are correct.
Definition: qgsmetadatawidget.cpp:775
QgsAbstractMetadataBase::Contact
Metadata contact structure.
Definition: qgsabstractmetadatabase.h:138
QgsBox3d
Definition: qgsbox3d.h:36
QgsAbstractMetadataBase::setType
void setType(const QString &type)
Sets the type (nature) of the resource.
Definition: qgsabstractmetadatabase.cpp:46
ConstraintItemDelegate::createEditor
QWidget * createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override
Create a special editor with a QCombobox in the constraint view.
Definition: qgsmetadatawidget.cpp:1145
qgslogger.h
QgsMetadataWidget::metadata
QgsAbstractMetadataBase * metadata()
Returns a QgsAbstractMetadataBase object representing the current state of the widget.
Definition: qgsmetadatawidget.cpp:180
QgsAbstractMetadataBase
An abstract base class for metadata stores.
Definition: qgsabstractmetadatabase.h:56
QgsApplication::reportStyleSheet
static QString reportStyleSheet(QgsApplication::StyleSheetType styleSheetType=QgsApplication::StyleSheetType::Qt)
Returns a css style sheet for reports, the styleSheetType argument determines what type of stylesheet...
Definition: qgsapplication.cpp:1344
QgsLayerMetadata::setExtent
void setExtent(const QgsLayerMetadata::Extent &extent)
Sets the spatial and temporal extents associated with the resource.
Definition: qgslayermetadata.cpp:354
qgsproject.h
QgsProjectMetadata::setCreationDateTime
void setCreationDateTime(const QDateTime &creationDateTime)
Sets the project's creation date/timestamp.
Definition: qgsprojectmetadata.cpp:85
QgsMetadataWidget::titleChanged
void titleChanged(const QString &title)
Emitted when the title field is changed.
QgsLayerMetadata::setFees
void setFees(const QString &fees)
Sets the fees associated with using the resource.
Definition: qgslayermetadata.cpp:31
QgsAbstractMetadataBase::Contact::email
QString email
Electronic mail address.
Definition: qgsabstractmetadatabase.h:182
QgsDataProvider::crs
virtual QgsCoordinateReferenceSystem crs() const =0
Returns the coordinate system for the data source.
QgsLayerMetadata::Extent::setSpatialExtents
void setSpatialExtents(const QList< QgsLayerMetadata::SpatialExtent > &extents)
Sets the spatial extents of the resource.
Definition: qgslayermetadata.cpp:364