QGIS API Documentation  3.16.0-Hannover (43b64b13f3)
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( 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( tr( "undefined %1" ).arg( row + 1 ) ) );
292  mConstraintsModel->setItem( row, 1, new QStandardItem( 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( 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( 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( QLatin1Char( ',' ) ) );
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  mConstraintsModel->clear();
546  const QList<QgsLayerMetadata::Constraint> &constraints = layerMetadata->constraints();
547  for ( const QgsLayerMetadata::Constraint &constraint : constraints )
548  {
549  int row = mConstraintsModel->rowCount();
550  mConstraintsModel->setItem( row, 0, new QStandardItem( constraint.type ) );
551  mConstraintsModel->setItem( row, 1, new QStandardItem( constraint.constraint ) );
552  }
553 
554  // CRS
555  mCrs = layerMetadata->crs();
556  crsChanged();
557 
558  // Spatial extent
559  const QList<QgsLayerMetadata::SpatialExtent> &spatialExtents = layerMetadata->extent().spatialExtents();
560  if ( ! spatialExtents.isEmpty() )
561  {
562  // Even if it's a list, it's supposed to store the same extent in different CRS.
563  spatialExtentSelector->setOutputCrs( spatialExtents.at( 0 ).extentCrs );
564  spatialExtentSelector->setOriginalExtent( spatialExtents.at( 0 ).bounds.toRectangle(), spatialExtents.at( 0 ).extentCrs );
565  spatialExtentSelector->setOutputExtentFromOriginal();
566  spinBoxZMaximum->setValue( spatialExtents.at( 0 ).bounds.zMaximum() );
567  spinBoxZMinimum->setValue( spatialExtents.at( 0 ).bounds.zMinimum() );
568  }
569 
570  // Temporal extent
571  const QList<QgsDateTimeRange> &temporalExtents = layerMetadata->extent().temporalExtents();
572  if ( ! temporalExtents.isEmpty() )
573  {
574  // Even if it's a list, it seems we use only one for now (cf discussion with Tom)
575  dateTimeFrom->setDateTime( temporalExtents.at( 0 ).begin() );
576  dateTimeTo->setDateTime( temporalExtents.at( 0 ).end() );
577  }
578  else
579  {
580  dateTimeFrom->clear();
581  dateTimeTo->clear();
582  }
583  }
584  else if ( QgsProjectMetadata *projectMetadata = dynamic_cast< QgsProjectMetadata * >( mMetadata.get() ) )
585  {
586  mLineEditAuthor->setText( projectMetadata->author() );
587  mCreationDateTimeEdit->setDateTime( projectMetadata->creationDateTime() );
588  }
589 
590  // Contacts
591  const QList<QgsAbstractMetadataBase::Contact> &contacts = mMetadata->contacts();
592  if ( ! contacts.isEmpty() )
593  {
594  // Only one contact supported in the UI for now
595  const QgsAbstractMetadataBase::Contact &contact = contacts.at( 0 );
596  lineEditContactName->setText( contact.name );
597  lineEditContactEmail->setText( contact.email );
598  lineEditContactFax->setText( contact.fax );
599  lineEditContactOrganization->setText( contact.organization );
600  lineEditContactPosition->setText( contact.position );
601  lineEditContactVoice->setText( contact.voice );
602  if ( comboContactRole->findText( contact.role ) == -1 )
603  {
604  comboContactRole->addItem( contact.role );
605  }
606  comboContactRole->setCurrentIndex( comboContactRole->findText( contact.role ) );
607  tabAddresses->setRowCount( 0 );
608  const QList<QgsAbstractMetadataBase::Address> &addresses = contact.addresses;
609  for ( const QgsAbstractMetadataBase::Address &address : addresses )
610  {
611  int currentRow = tabAddresses->rowCount();
612  tabAddresses->setRowCount( currentRow + 1 );
613  tabAddresses->setItem( currentRow, 0, new QTableWidgetItem( address.type ) );
614  tabAddresses->setItem( currentRow, 1, new QTableWidgetItem( address.address ) );
615  tabAddresses->setItem( currentRow, 2, new QTableWidgetItem( address.postalCode ) );
616  tabAddresses->setItem( currentRow, 3, new QTableWidgetItem( address.city ) );
617  tabAddresses->setItem( currentRow, 4, new QTableWidgetItem( address.administrativeArea ) );
618  tabAddresses->setItem( currentRow, 5, new QTableWidgetItem( address.country ) );
619  }
620  }
621 
622  // Links
623  const QList<QgsAbstractMetadataBase::Link> &links = mMetadata->links();
624  mLinksModel->setRowCount( 0 );
625  for ( const QgsAbstractMetadataBase::Link &link : links )
626  {
627  int row = mLinksModel->rowCount();
628  mLinksModel->setItem( row, 0, new QStandardItem( link.name ) );
629  mLinksModel->setItem( row, 1, new QStandardItem( link.type ) );
630  mLinksModel->setItem( row, 2, new QStandardItem( link.url ) );
631  mLinksModel->setItem( row, 3, new QStandardItem( link.description ) );
632  mLinksModel->setItem( row, 4, new QStandardItem( link.format ) );
633  mLinksModel->setItem( row, 5, new QStandardItem( link.mimeType ) );
634  mLinksModel->setItem( row, 6, new QStandardItem( link.size ) );
635  }
636 
637  // History
638  mHistoryModel->setStringList( mMetadata->history() );
639 }
640 
642 {
643  if ( !metadata )
644  return;
645 
646  metadata->setParentIdentifier( lineEditParentId->text() );
647  metadata->setIdentifier( lineEditIdentifier->text() );
648  metadata->setTitle( lineEditTitle->text() );
649  metadata->setType( comboType->currentText() );
650  metadata->setLanguage( comboLanguage->currentText() );
651  metadata->setAbstract( textEditAbstract->toPlainText() );
652 
653  // Keywords, it will save categories too.
654  syncFromCategoriesTabToKeywordsTab();
655  QMap<QString, QStringList> keywords;
656  for ( int i = 0; i < tabKeywords->rowCount() ; i++ )
657  {
658  keywords.insert( tabKeywords->item( i, 0 )->text(), tabKeywords->item( i, 1 )->text().split( ',' ) );
659  }
660  metadata->setKeywords( keywords );
661 
662  switch ( mMode )
663  {
664  case LayerMetadata:
665  {
666  QgsLayerMetadata *layerMetadata = static_cast< QgsLayerMetadata * >( metadata );
667  // Fees
668  layerMetadata->setFees( lineEditFees->text() );
669 
670  // Licenses
671  QStringList licenses;
672  for ( int i = 0; i < tabLicenses->rowCount() ; i++ )
673  {
674  licenses.append( tabLicenses->item( i, 0 )->text() );
675  }
676  layerMetadata->setLicenses( licenses );
677 
678  // Rights
679  layerMetadata->setRights( mRightsModel->stringList() );
680 
681  // Encoding
682  layerMetadata->setEncoding( comboEncoding->currentText() );
683 
684  // Constraints
685  QList<QgsLayerMetadata::Constraint> constraints;
686  for ( int row = 0; row < mConstraintsModel->rowCount() ; row++ )
687  {
688  QgsLayerMetadata::Constraint constraint;
689  constraint.type = mConstraintsModel->item( row, 0 )->text();
690  constraint.constraint = mConstraintsModel->item( row, 1 )->text();
691  constraints.append( constraint );
692  }
693  layerMetadata->setConstraints( constraints );
694 
695  // CRS
696  if ( mCrs.isValid() )
697  {
698  layerMetadata->setCrs( mCrs );
699  }
700 
701  // Extent
702  QgsLayerMetadata::SpatialExtent spatialExtent;
703  spatialExtent.bounds = QgsBox3d( spatialExtentSelector->outputExtent() );
704  spatialExtent.bounds.setZMinimum( spinBoxZMinimum->value() );
705  spatialExtent.bounds.setZMaximum( spinBoxZMaximum->value() );
706  spatialExtent.extentCrs = spatialExtentSelector->outputCrs();
707  QList<QgsLayerMetadata::SpatialExtent> spatialExtents;
708  spatialExtents.append( spatialExtent );
709  QList<QgsDateTimeRange> temporalExtents;
710  temporalExtents.append( QgsDateTimeRange( dateTimeFrom->dateTime(), dateTimeTo->dateTime() ) );
712  extent.setSpatialExtents( spatialExtents );
713  extent.setTemporalExtents( temporalExtents );
714  layerMetadata->setExtent( extent );
715  break;
716  }
717 
718  case ProjectMetadata:
719  {
720  QgsProjectMetadata *projectMetadata = static_cast< QgsProjectMetadata * >( metadata );
721  projectMetadata->setAuthor( mLineEditAuthor->text() );
722  projectMetadata->setCreationDateTime( mCreationDateTimeEdit->dateTime() );
723  break;
724  }
725  }
726 
727  // Contacts, only one contact supported in the UI for now.
728  // We don't want to lost data if more than one contact, so we update only the first one.
729  QList<QgsAbstractMetadataBase::Contact> contacts = mMetadata->contacts();
730  if ( contacts.size() > 0 )
731  contacts.removeFirst();
733  contact.email = lineEditContactEmail->text();
734  contact.position = lineEditContactPosition->text();
735  contact.fax = lineEditContactFax->text();
736  contact.voice = lineEditContactVoice->text();
737  contact.name = lineEditContactName->text();
738  contact.organization = lineEditContactOrganization->text();
739  contact.role = comboContactRole->currentText();
740  QList<QgsAbstractMetadataBase::Address> addresses;
741  for ( int i = 0; i < tabAddresses->rowCount() ; i++ )
742  {
744  address.type = tabAddresses->item( i, 0 )->text();
745  address.address = tabAddresses->item( i, 1 )->text();
746  address.postalCode = tabAddresses->item( i, 2 )->text();
747  address.city = tabAddresses->item( i, 3 )->text();
748  address.administrativeArea = tabAddresses->item( i, 4 )->text();
749  address.country = tabAddresses->item( i, 5 )->text();
750  addresses.append( address );
751  }
752  contact.addresses = addresses;
753  contacts.insert( 0, contact );
754  metadata->setContacts( contacts );
755 
756  // Links
757  QList<QgsAbstractMetadataBase::Link> links;
758  for ( int row = 0; row < mLinksModel->rowCount() ; row++ )
759  {
761  link.name = mLinksModel->item( row, 0 )->text();
762  link.type = mLinksModel->item( row, 1 )->text();
763  link.url = mLinksModel->item( row, 2 )->text();
764  link.description = mLinksModel->item( row, 3 )->text();
765  link.format = mLinksModel->item( row, 4 )->text();
766  link.mimeType = mLinksModel->item( row, 5 )->text();
767  link.size = mLinksModel->item( row, 6 )->text();
768  links.append( link );
769  }
770  metadata->setLinks( links );
771 
772  // History
773  metadata->setHistory( mHistoryModel->stringList() );
774 }
775 
777 {
778  std::unique_ptr< QgsAbstractMetadataBase > md( metadata() );
779 
780  std::unique_ptr< QgsNativeMetadataBaseValidator > validator;
781  switch ( mMode )
782  {
783  case LayerMetadata:
784  validator = qgis::make_unique< QgsNativeMetadataValidator>();
785  break;
786 
787  case ProjectMetadata:
788  validator = qgis::make_unique< QgsNativeProjectMetadataValidator>();
789  break;
790  }
791 
792  QList<QgsAbstractMetadataBaseValidator::ValidationResult> validationResults;
793  bool results = validator->validate( md.get(), validationResults );
794 
795  QString errors;
796  if ( !results )
797  {
798  for ( const QgsAbstractMetadataBaseValidator::ValidationResult &result : qgis::as_const( validationResults ) )
799  {
800  errors += QLatin1String( "<b>" ) % result.section;
801  if ( ! result._identifier().isNull() )
802  {
803  errors += QLatin1Char( ' ' ) % QVariant( result._identifier().toInt() + 1 ).toString();
804  }
805  errors += QLatin1String( "</b>: " ) % result.note % QLatin1String( "<br />" );
806  }
807  }
808  else
809  {
810  errors = tr( "Ok, it seems valid according to the QGIS Schema." );
811  }
812 
813  QString myStyle = QgsApplication::reportStyleSheet();
814  myStyle.append( QStringLiteral( "body { margin: 10px; }\n " ) );
815  resultsCheckMetadata->clear();
816  resultsCheckMetadata->document()->setDefaultStyleSheet( myStyle );
817  resultsCheckMetadata->setHtml( errors );
818 
819  return results;
820 }
821 
822 QMap<QString, QString> QgsMetadataWidget::parseLanguages()
823 {
824  QMap<QString, QString> countries;
825  countries.insert( QString(), QString() ); // We add an empty line, because it's not compulsory.
826 
827  QString path = QDir( QgsApplication::metadataPath() ).absoluteFilePath( QStringLiteral( "language_codes_ISO_639.csv" ) );
828  QFile file( path );
829  if ( !file.open( QIODevice::ReadOnly ) )
830  {
831  QgsDebugMsg( QStringLiteral( "Error while opening the CSV file: %1, %2 " ).arg( path, file.errorString() ) );
832  return countries;
833  }
834 
835  // Skip the first line of the CSV
836  file.readLine();
837  while ( !file.atEnd() )
838  {
839  QByteArray line = file.readLine();
840  QList<QByteArray> items = line.split( ',' );
841  countries.insert( QString( items.at( 0 ).constData() ).trimmed(), QString( items.at( 1 ).constData() ).trimmed() );
842  }
843  file.close();
844 
845  path = QDir( QgsApplication::metadataPath() ).absoluteFilePath( QStringLiteral( "country_code_ISO_3166.csv" ) );
846  QFile secondFile( path );
847  if ( !secondFile.open( QIODevice::ReadOnly ) )
848  {
849  QgsDebugMsg( QStringLiteral( "Error while opening the CSV file: %1, %2 " ).arg( path, file.errorString() ) );
850  return countries;
851  }
852 
853  // Skip the first line of the CSV
854  secondFile.readLine();
855  while ( !secondFile.atEnd() )
856  {
857  QByteArray line = secondFile.readLine();
858  QList<QByteArray> items = line.split( ',' );
859  countries.insert( QString( items.at( 2 ).constData() ).trimmed(), QString( items.at( 0 ).constData() ).trimmed() );
860  }
861  secondFile.close();
862  return countries;
863 }
864 
866 {
867  QStringList wordList;
868  wordList.append( QString() ); // We add an empty line, because it's not compulsory.
869 
870  QString path = QDir( QgsApplication::metadataPath() ).absoluteFilePath( QStringLiteral( "licenses.csv" ) );
871  QFile file( path );
872  if ( !file.open( QIODevice::ReadOnly ) )
873  {
874  QgsDebugMsg( QStringLiteral( "Error while opening the CSV file: %1, %2 " ).arg( path, file.errorString() ) );
875  return wordList;
876  }
877 
878  // Skip the first line of the CSV
879  file.readLine();
880  while ( !file.atEnd() )
881  {
882  QByteArray line = file.readLine();
883  wordList.append( line.split( ',' ).at( 0 ).trimmed() );
884  }
885  file.close();
886  return wordList;
887 }
888 
890 {
891  QStringList wordList;
892  wordList.append( QString() ); // We add an empty line, because it's not compulsory.
893 
894  QString path = QDir( QgsApplication::metadataPath() ).absoluteFilePath( QStringLiteral( "LinkPropertyLookupTable.csv" ) );
895  QFile file( path );
896  if ( !file.open( QIODevice::ReadOnly ) )
897  {
898  QgsDebugMsg( QStringLiteral( "Error while opening the CSV file: %1, %2 " ).arg( path, file.errorString() ) );
899  return wordList;
900  }
901 
902  // Skip the first line of the CSV
903  file.readLine();
904  while ( !file.atEnd() )
905  {
906  QByteArray line = file.readLine();
907  wordList.append( line.split( ',' ).at( 0 ).trimmed() );
908  }
909  file.close();
910  return wordList;
911 }
912 
914 {
915  QStringList wordList;
916  wordList.append( QString() ); // We add an empty line, because it's not compulsory.
917 
918  QString path = QDir( QgsApplication::metadataPath() ).absoluteFilePath( QStringLiteral( "mime.csv" ) );
919  QFile file( path );
920  if ( !file.open( QIODevice::ReadOnly ) )
921  {
922  QgsDebugMsg( QStringLiteral( "Error while opening the CSV file: %1, %2 " ).arg( path, file.errorString() ) );
923  return wordList;
924  }
925 
926  while ( !file.atEnd() )
927  {
928  QByteArray line = file.readLine();
929  wordList.append( line.split( ',' ).at( 0 ).trimmed() );
930  }
931  file.close();
932  return wordList;
933 }
934 
935 QMap<QString, QString> QgsMetadataWidget::parseTypes()
936 {
937  QMap<QString, QString> types;
938  types.insert( QString(), QString() ); // We add an empty line, because it's not compulsory.
939  QString path = QDir( QgsApplication::metadataPath() ).absoluteFilePath( QStringLiteral( "md_scope_codes.csv" ) );
940  QFile file( path );
941  if ( !file.open( QIODevice::ReadOnly ) )
942  {
943  QgsDebugMsg( QStringLiteral( "Error while opening the CSV file: %1, %2 " ).arg( path, file.errorString() ) );
944  return types;
945  }
946 
947  types.insert( QString(), QString() ); // We add an empty line, because it's not compulsory.
948  while ( !file.atEnd() )
949  {
950  QByteArray line = file.readLine();
951  QList<QByteArray> items = line.split( ';' );
952  types.insert( items.at( 0 ).constData(), items.at( 1 ).constData() );
953  }
954  file.close();
955  return types;
956 }
957 
959 {
960  if ( canvas )
961  spatialExtentSelector->setCurrentExtent( canvas->extent(), canvas->mapSettings().destinationCrs() );
962 }
963 
965 {
966  return lineEditTitle->text();
967 }
968 
969 void QgsMetadataWidget::setTitle( const QString &title )
970 {
971  if ( title != lineEditTitle->text() )
972  {
973  whileBlocking( lineEditTitle )->setText( title );
974  emit titleChanged( title );
975  }
976 }
977 
979 {
980  saveMetadata( mMetadata.get() );
981  switch ( mMode )
982  {
983  case LayerMetadata:
984  if ( mLayer )
985  {
986  // Save layer metadata properties
987  mLayer->setMetadata( *static_cast< QgsLayerMetadata * >( mMetadata.get() ) );
988  }
989  break;
990 
991  case ProjectMetadata:
992  QgsProject::instance()->setMetadata( *static_cast< QgsProjectMetadata * >( mMetadata.get() ) );
993  break;
994  }
995 }
996 
997 void QgsMetadataWidget::syncFromCategoriesTabToKeywordsTab()
998 {
999  if ( mCategoriesModel->rowCount() > 0 )
1000  {
1001  QList<QTableWidgetItem *> categories = tabKeywords->findItems( QStringLiteral( "gmd:topicCategory" ), Qt::MatchExactly );
1002  int row;
1003  if ( !categories.isEmpty() )
1004  {
1005  row = categories.at( 0 )->row();
1006  }
1007  else
1008  {
1009  // Create a new line with 'gmd:topicCategory'
1010  addVocabulary();
1011  row = tabKeywords->rowCount() - 1;
1012  tabKeywords->item( row, 0 )->setText( QStringLiteral( "gmd:topicCategory" ) );
1013  }
1014  tabKeywords->item( row, 1 )->setText( mCategoriesModel->stringList().join( QLatin1Char( ',' ) ) );
1015  }
1016 }
1017 
1018 void QgsMetadataWidget::updatePanel()
1019 {
1020  int index = tabWidget->currentIndex();
1021  QString currentTabText = tabWidget->widget( index )->objectName();
1022  if ( currentTabText == QLatin1String( "tabCategoriesDialog" ) )
1023  {
1024  // Categories tab
1025  // We need to take keywords and insert them into the list
1026  QList<QTableWidgetItem *> categories = tabKeywords->findItems( QStringLiteral( "gmd:topicCategory" ), Qt::MatchExactly );
1027  if ( !categories.isEmpty() )
1028  {
1029  int row = categories.at( 0 )->row();
1030  mCategoriesModel->setStringList( tabKeywords->item( row, 1 )->text().split( ',' ) );
1031  }
1032  else
1033  {
1034  mCategoriesModel->setStringList( QStringList() );
1035  }
1036  }
1037  else if ( currentTabText == QLatin1String( "tabKeywordsDialog" ) )
1038  {
1039  // Keywords tab
1040  // We need to take categories and insert them into the table
1041  syncFromCategoriesTabToKeywordsTab();
1042  }
1043  else if ( currentTabText == QLatin1String( "tabValidationDialog" ) )
1044  {
1045  checkMetadata();
1046  }
1047 }
1048 
1049 void QgsMetadataWidget::addNewCategory()
1050 {
1051  bool ok;
1052  QString text = QInputDialog::getText( this, tr( "New Category" ),
1053  tr( "New Category:" ), QLineEdit::Normal,
1054  QString(), &ok );
1055  if ( ok && !text.isEmpty() )
1056  {
1057  QStringList list = mCategoriesModel->stringList();
1058  if ( ! list.contains( text ) )
1059  {
1060  list.append( text );
1061  mCategoriesModel->setStringList( list );
1062  mCategoriesModel->sort( 0 );
1063  }
1064  }
1065 }
1066 
1067 void QgsMetadataWidget::addDefaultCategories()
1068 {
1069  const QModelIndexList selectedIndexes = listDefaultCategories->selectionModel()->selectedIndexes();
1070  QStringList defaultCategoriesList = mDefaultCategoriesModel->stringList();
1071  QStringList selectedCategories = mCategoriesModel->stringList();
1072 
1073  for ( const QModelIndex &selection : selectedIndexes )
1074  {
1075  QVariant item = mDefaultCategoriesModel->data( selection, Qt::DisplayRole );
1076  defaultCategoriesList.removeOne( item.toString() );
1077 
1078  selectedCategories.append( item.toString() );
1079  }
1080 
1081  mDefaultCategoriesModel->setStringList( defaultCategoriesList );
1082  mCategoriesModel->setStringList( selectedCategories );
1083  mCategoriesModel->sort( 0 );
1084 }
1085 
1086 void QgsMetadataWidget::removeSelectedCategories()
1087 {
1088  const QModelIndexList selectedIndexes = listCategories->selectionModel()->selectedIndexes();
1089  QStringList categories = mCategoriesModel->stringList();
1090  QStringList defaultList = mDefaultCategoriesModel->stringList();
1091 
1092  for ( const QModelIndex &selection : selectedIndexes )
1093  {
1094  QVariant item = mCategoriesModel->data( selection, Qt::DisplayRole );
1095  categories.removeOne( item.toString() );
1096 
1097  if ( mDefaultCategories.contains( item.toString() ) )
1098  {
1099  defaultList.append( item.toString() );
1100  }
1101  }
1102  mCategoriesModel->setStringList( categories );
1103 
1104  mDefaultCategoriesModel->setStringList( defaultList );
1105  mDefaultCategoriesModel->sort( 0 );
1106 }
1107 
1109  : QStyledItemDelegate( parent )
1110 {
1111 
1112 }
1113 
1114 QWidget *LinkItemDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
1115 {
1116  if ( index.column() == 1 )
1117  {
1118  // Link type
1119  QComboBox *typeEditor = new QComboBox( parent );
1120  typeEditor->setEditable( true );
1121  QStringListModel *model = new QStringListModel( parent );
1122  model->setStringList( QgsMetadataWidget::parseLinkTypes() );
1123  typeEditor->setModel( model );
1124  return typeEditor;
1125  }
1126  else if ( index.column() == 5 )
1127  {
1128  // MIME
1129  QComboBox *mimeEditor = new QComboBox( parent );
1130  mimeEditor->setEditable( true );
1131  QStringListModel *model = new QStringListModel( parent );
1132  model->setStringList( QgsMetadataWidget::parseMimeTypes() );
1133  mimeEditor->setModel( model );
1134  return mimeEditor;
1135  }
1136 
1137  return QStyledItemDelegate::createEditor( parent, option, index );
1138 }
1139 
1141  : QStyledItemDelegate( parent )
1142 {
1143 
1144 }
1145 
1146 QWidget *ConstraintItemDelegate::createEditor( QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index ) const
1147 {
1148  if ( index.column() == 0 )
1149  {
1150  // Constraint type
1151  QComboBox *typeEditor = new QComboBox( parent );
1152  typeEditor->setEditable( true );
1153  QStringList types;
1154  types << QStringLiteral( "access" ) << QStringLiteral( "use" ) << QStringLiteral( "other" );
1155  QStringListModel *model = new QStringListModel( parent );
1156  model->setStringList( types );
1157  typeEditor->setModel( model );
1158  return typeEditor;
1159  }
1160 
1161  return QStyledItemDelegate::createEditor( parent, option, index );
1162 }
QgsMetadataWidget::setMapCanvas
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas associated with the widget.
Definition: qgsmetadatawidget.cpp:958
QgsMetadataWidget::parseLinkTypes
static QStringList parseLinkTypes()
Returns a list of link types available by default in the wizard.
Definition: qgsmetadatawidget.cpp:889
QgsAbstractMetadataBase::Contact::name
QString name
Name of contact.
Definition: qgsabstractmetadatabase.h:151
QgsMapLayer::crs
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:89
LinkItemDelegate::LinkItemDelegate
LinkItemDelegate(QObject *parent=nullptr)
LinkItemDelegate constructor.
Definition: qgsmetadatawidget.cpp:1108
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:1056
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:47
ConstraintItemDelegate::ConstraintItemDelegate
ConstraintItemDelegate(QObject *parent=nullptr)
ConstraintItemDelegate constructor.
Definition: qgsmetadatawidget.cpp:1140
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:54
qgsmapcanvas.h
QgsAbstractMetadataBase::Contact::addresses
QList< QgsAbstractMetadataBase::Address > addresses
List of addresses associated with this contact.
Definition: qgsabstractmetadatabase.h:166
QgsBox3d::setZMaximum
void setZMaximum(double z) SIP_HOLDGIL
Sets the maximum z value.
Definition: qgsbox3d.cpp:65
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:1114
QgsCoordinateReferenceSystem::userFriendlyIdentifier
QString userFriendlyIdentifier(IdentifierType type=MediumString) const
Returns a user friendly identifier for the CRS.
Definition: qgscoordinatereferencesystem.cpp:1338
QgsLayerMetadata::SpatialExtent
Metadata spatial extent structure.
Definition: qgslayermetadata.h:64
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:391
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
QgsBox3d::setZMinimum
void setZMinimum(double z) SIP_HOLDGIL
Sets the minimum z value.
Definition: qgsbox3d.cpp:60
QgsLayerMetadata
A structured metadata store for a map layer.
Definition: qgslayermetadata.h:57
QgsMapCanvas
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:85
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:468
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:1836
QgsLayerMetadata::SpatialExtent::bounds
QgsBox3d bounds
Geospatial extent of the resource.
Definition: qgslayermetadata.h:82
qgsapplication.h
LinkItemDelegate
\@cond PRIVATE
Definition: qgsmetadatawidget.h:249
QgsLayerMetadata::setEncoding
void setEncoding(const QString &encoding)
Sets the character encoding of the data in the resource.
Definition: qgslayermetadata.cpp:76
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:978
QgsApplication::metadataPath
static QString metadataPath()
Returns the path to the metadata directory.
Definition: qgsapplication.cpp:983
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:641
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:86
QgsMetadataWidget::parseLanguages
static QMap< QString, QString > parseLanguages()
Returns a list of languages available by default in the wizard.
Definition: qgsmetadatawidget.cpp:822
QgsCoordinateReferenceSystem::isValid
bool isValid() const
Returns whether this CRS is correctly initialized and usable.
Definition: qgscoordinatereferencesystem.cpp:924
QgsMetadataWidget::title
QString title
Definition: qgsmetadatawidget.h:44
ConstraintItemDelegate
Special delegate for the constraint view in the metadata wizard.
Definition: qgsmetadatawidget.h:275
QgsMetadataWidget::parseTypes
static QMap< QString, QString > parseTypes()
Returns a list of types available by default in the wizard.
Definition: qgsmetadatawidget.cpp:935
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:91
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:913
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:318
QgsMapLayer::publicSource
QString publicSource() const
Gets a version of the internal layer definition that has sensitive bits removed (for example,...
Definition: qgsmaplayer.cpp:184
QgsMetadataWidget::setTitle
void setTitle(const QString &title)
Sets the title field for the metadata.
Definition: qgsmetadatawidget.cpp:969
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:865
QgsMapLayer
Base class for all map layer types.
Definition: qgsmaplayer.h:83
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:3542
QgsLayerMetadata::Constraint
Metadata constraint structure.
Definition: qgslayermetadata.h:137
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:53
QgsMetadataWidget::checkMetadata
bool checkMetadata()
Check if values in the wizard are correct.
Definition: qgsmetadatawidget.cpp:776
QgsAbstractMetadataBase::Contact
Metadata contact structure.
Definition: qgsabstractmetadatabase.h:139
QgsBox3d
A 3-dimensional box composed of x, y, z coordinates.
Definition: qgsbox3d.h:37
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:1146
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:57
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:1363
QgsLayerMetadata::setExtent
void setExtent(const QgsLayerMetadata::Extent &extent)
Sets the spatial and temporal extents associated with the resource.
Definition: qgslayermetadata.cpp:354
qgsproject.h
QgsMapLayer::metadata
QgsLayerMetadata metadata
Definition: qgsmaplayer.h:88
QgsMapLayer::dataProvider
virtual QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
Definition: qgsmaplayer.cpp:169
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