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