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