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