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