From 0548f4267e017704b9ebbf257e9f18b018a69635 Mon Sep 17 00:00:00 2001 From: mj10777 Date: Mon, 5 Feb 2018 12:57:04 +0100 Subject: [PATCH] Added QgsLayerMetadata logic to QgsDataProvider. Added setMetadata in QgsVector/RasterLayer::setDataProvider. Corrections in QgsMetadataWidget with added get/setMetadata and hasChanged functions plus checking for set mLayer pointer before use. --- python/core/metadata/qgslayermetadata.sip.in | 1 + python/core/qgsdataprovider.sip.in | 21 ++++++ python/gui/qgsmetadatawidget.sip.in | 36 ++++++++++ src/core/metadata/qgslayermetadata.cpp | 23 ++++++ src/core/metadata/qgslayermetadata.h | 5 ++ src/core/qgsdataprovider.h | 19 +++++ src/core/qgsvectorlayer.cpp | 3 + src/core/raster/qgsrasterlayer.cpp | 3 + src/gui/qgsmetadatawidget.cpp | 74 +++++++++++++------- src/gui/qgsmetadatawidget.h | 27 +++++++ 10 files changed, 188 insertions(+), 24 deletions(-) diff --git a/python/core/metadata/qgslayermetadata.sip.in b/python/core/metadata/qgslayermetadata.sip.in index 7ea1d7ce971..db95ea090c8 100644 --- a/python/core/metadata/qgslayermetadata.sip.in +++ b/python/core/metadata/qgslayermetadata.sip.in @@ -618,6 +618,7 @@ Stores state in Dom node :return: true if successful %End + }; diff --git a/python/core/qgsdataprovider.sip.in b/python/core/qgsdataprovider.sip.in index 132e09edc1e..886c669bb20 100644 --- a/python/core/qgsdataprovider.sip.in +++ b/python/core/qgsdataprovider.sip.in @@ -362,6 +362,27 @@ The default implementation does nothing. %End + virtual QgsLayerMetadata layerMetadata() const; +%Docstring +Retrieve collected Metadata from the Provider source + A structured metadata store for a map layer. +\note + +.. seealso:: :py:func:`setLayerMetadata` + +.. versionadded:: 3.0 +%End + virtual bool setLayerMetadata( const QgsLayerMetadata &layerMetadata ); +%Docstring +Set collected Metadata from the Provider source + A structured metadata store for a map layer. +\note + +.. seealso:: :py:func:`layerMetadata` + +.. versionadded:: 3.0 +%End + signals: void fullExtentCalculated(); diff --git a/python/gui/qgsmetadatawidget.sip.in b/python/gui/qgsmetadatawidget.sip.in index 117d6edb441..0b735df5f94 100644 --- a/python/gui/qgsmetadatawidget.sip.in +++ b/python/gui/qgsmetadatawidget.sip.in @@ -26,16 +26,52 @@ class QgsMetadataWidget : QWidget QgsMetadataWidget( QWidget *parent, QgsMapLayer *layer = 0 ); %Docstring Constructor for the wizard. +\note +For use with a source \layer. This constructor automatically sets the widget's metadata() if the ``layer`` pointer is valid. +calls setMetadata, using mMetadata + +:param layer: to set the main QgsLayerMetadata with mLayer->metadata() when not None + +.. seealso:: :py:func:`setMetadata` +%End + + void setMetadata( const QgsLayerMetadata &layerMetadata ); +%Docstring +Sets the ``metadata`` to display in the widget +\note +Called from constructor and initializes child widget on first use +Can be called from outside to change the QgsLayerMetadata object. + +.. seealso:: :py:func:`metadata` +%End + + QgsLayerMetadata metadata(); +%Docstring +Retrieves a QgsLayerMetadata object representing the current state of the widget. +\note +saveMetdata is called before returning :py:class:`QgsLayerMetadata` + +.. seealso:: :py:func:`saveMetadata` %End void saveMetadata( QgsLayerMetadata &layerMetadata ); %Docstring Save all fields in a QgsLayerMetadata object. + +.. seealso:: :py:func:`getMetadata` + +.. seealso:: :py:func:`acceptMetadata` + +.. seealso:: :py:func:`checkMetadata` %End bool checkMetadata(); %Docstring Check if values in the wizard are correct. + +.. seealso:: :py:func:`updatePanel` + +.. seealso:: :py:func:`saveMetadata` %End void crsChanged(); diff --git a/src/core/metadata/qgslayermetadata.cpp b/src/core/metadata/qgslayermetadata.cpp index 8590bfa43d3..e0ac0e0d7a6 100644 --- a/src/core/metadata/qgslayermetadata.cpp +++ b/src/core/metadata/qgslayermetadata.cpp @@ -767,3 +767,26 @@ void QgsLayerMetadata::Extent::setTemporalExtents( const QList { mTemporalExtents = temporalExtents; } + +bool QgsLayerMetadata::operator==( const QgsLayerMetadata &metadataOther ) const +{ + return ( ( parentIdentifier() == metadataOther.parentIdentifier() ) && + ( identifier() == metadataOther.identifier() ) && + ( language() == metadataOther.language() ) && + ( type() == metadataOther.type() ) && + ( title() == metadataOther.title() ) && + ( abstract() == metadataOther.abstract() ) && + ( fees() == metadataOther.fees() ) && + ( rights() == metadataOther.rights() ) && + ( licenses() == metadataOther.licenses() ) && + ( history() == metadataOther.history() ) && + ( encoding() == metadataOther.encoding() ) && + ( crs() == metadataOther.crs() ) && + ( keywords() == metadataOther.keywords() ) && + ( categories() == metadataOther.categories() ) && + // QgsLayerMetadata::ConstraintList, LinkList, Extent, ContactList need to be delt with properly + ( constraints().count() == metadataOther.constraints().count() ) && + ( extent().spatialExtents().count() == metadataOther.extent().spatialExtents().count() ) && + ( contacts().count() == metadataOther.contacts().count() ) && + ( links().count() == metadataOther.links().count() ) ); +} diff --git a/src/core/metadata/qgslayermetadata.h b/src/core/metadata/qgslayermetadata.h index 3e8dabe6d19..322f631e01d 100644 --- a/src/core/metadata/qgslayermetadata.h +++ b/src/core/metadata/qgslayermetadata.h @@ -726,6 +726,11 @@ class CORE_EXPORT QgsLayerMetadata */ bool writeMetadataXml( QDomElement &metadataElement, QDomDocument &document ) const; + /** + * Compares two features + */ + bool operator==( const QgsLayerMetadata &metadataOther ) const SIP_SKIP; + private: /* diff --git a/src/core/qgsdataprovider.h b/src/core/qgsdataprovider.h index 62c914ce7eb..c725b505c90 100644 --- a/src/core/qgsdataprovider.h +++ b/src/core/qgsdataprovider.h @@ -24,6 +24,7 @@ //#include "qgsdataitem.h" #include "qgsdatasourceuri.h" +#include "qgslayermetadata.h" #include "qgserror.h" typedef int dataCapabilities_t(); // SIP_SKIP @@ -492,6 +493,24 @@ class CORE_EXPORT QgsDataProvider : public QObject */ virtual bool renderInPreview( const QgsDataProvider::PreviewContext &context ); // SIP_SKIP + /** + * Retrieve collected Metadata from the Provider source + * \brief A structured metadata store for a map layer. + * \note + * \see setLayerMetadata + * \since QGIS 3.0 + */ + virtual QgsLayerMetadata layerMetadata() const { return QgsLayerMetadata(); }; + + /** + * Set collected Metadata from the Provider source + * \brief A structured metadata store for a map layer. + * \note + * \see layerMetadata + * \since QGIS 3.0 + */ + virtual bool setLayerMetadata( const QgsLayerMetadata &layerMetadata ) { Q_UNUSED( layerMetadata ); return false; } + signals: /** diff --git a/src/core/qgsvectorlayer.cpp b/src/core/qgsvectorlayer.cpp index 866716c0452..ba7474b70b8 100644 --- a/src/core/qgsvectorlayer.cpp +++ b/src/core/qgsvectorlayer.cpp @@ -1526,6 +1526,9 @@ bool QgsVectorLayer::setDataProvider( QString const &provider ) return false; } + setMetadata( mDataProvider->layerMetadata() ); + QgsDebugMsgLevel( QString( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 ); + // TODO: Check if the provider has the capability to send fullExtentCalculated connect( mDataProvider, &QgsVectorDataProvider::fullExtentCalculated, this, [ = ] { updateExtents(); } ); diff --git a/src/core/raster/qgsrasterlayer.cpp b/src/core/raster/qgsrasterlayer.cpp index 569ec483f2c..c84e73cfc4a 100644 --- a/src/core/raster/qgsrasterlayer.cpp +++ b/src/core/raster/qgsrasterlayer.cpp @@ -625,6 +625,9 @@ void QgsRasterLayer::setDataProvider( QString const &provider ) return; } + setMetadata( mDataProvider->layerMetadata() ); + QgsDebugMsgLevel( QString( "Set Data provider QgsLayerMetadata identifier[%1]" ).arg( metadata().identifier() ), 4 ); + if ( provider == QLatin1String( "gdal" ) ) { // make sure that the /vsigzip or /vsizip is added to uri, if applicable diff --git a/src/gui/qgsmetadatawidget.cpp b/src/gui/qgsmetadatawidget.cpp index e822ce040cb..81270de1d42 100644 --- a/src/gui/qgsmetadatawidget.cpp +++ b/src/gui/qgsmetadatawidget.cpp @@ -35,7 +35,10 @@ QgsMetadataWidget::QgsMetadataWidget( QWidget *parent, QgsMapLayer *layer ) mLayer( layer ) { setupUi( this ); - mMetadata = layer->metadata(); + if ( mLayer ) + { + mMetadata = mLayer->metadata(); + } tabWidget->setCurrentIndex( 0 ); // Disable the encoding @@ -107,15 +110,36 @@ QgsMetadataWidget::QgsMetadataWidget( QWidget *parent, QgsMapLayer *layer ) connect( btnRemoveCategory, &QPushButton::clicked, this, &QgsMetadataWidget::removeSelectedCategories ); fillComboBox(); + if ( !mLayer ) + { + btnAutoSource->setEnabled( false ); + btnAutoEncoding->setEnabled( false ); + btnAutoCrs->setEnabled( false ); + } + setMetadata( mMetadata ); +} + +void QgsMetadataWidget::setMetadata( const QgsLayerMetadata &layerMetadata ) +{ + mMetadata = layerMetadata; setPropertiesFromLayer(); } -void QgsMetadataWidget::fillSourceFromLayer() +QgsLayerMetadata QgsMetadataWidget::metadata() { - lineEditIdentifier->setText( mLayer->publicSource() ); + saveMetadata( mMetadata ); + return mMetadata; } -void QgsMetadataWidget::addVocabulary() +void QgsMetadataWidget::fillSourceFromLayer() const +{ + if ( mLayer ) + { + lineEditIdentifier->setText( mLayer->publicSource() ); + } +} + +void QgsMetadataWidget::addVocabulary() const { int row = tabKeywords->rowCount(); tabKeywords->setRowCount( row + 1 ); @@ -130,7 +154,7 @@ void QgsMetadataWidget::addVocabulary() tabKeywords->setItem( row, 1, pCell ); } -void QgsMetadataWidget::removeSelectedVocabulary() +void QgsMetadataWidget::removeSelectedVocabulary() const { QItemSelectionModel *selectionModel = tabKeywords->selectionModel(); const QModelIndexList selectedRows = selectionModel->selectedRows(); @@ -152,7 +176,7 @@ void QgsMetadataWidget::addLicence() } } -void QgsMetadataWidget::removeSelectedLicence() +void QgsMetadataWidget::removeSelectedLicence() const { QItemSelectionModel *selectionModel = tabLicenses->selectionModel(); const QModelIndexList selectedRows = selectionModel->selectedRows(); @@ -173,7 +197,7 @@ void QgsMetadataWidget::addRight() } } -void QgsMetadataWidget::removeSelectedRight() +void QgsMetadataWidget::removeSelectedRight() const { QItemSelectionModel *selection = listRights->selectionModel(); if ( selection->hasSelection() ) @@ -187,22 +211,22 @@ void QgsMetadataWidget::removeSelectedRight() } } -void QgsMetadataWidget::addConstraint() +void QgsMetadataWidget::addConstraint() const { int row = mConstraintsModel->rowCount(); mConstraintsModel->setItem( row, 0, new QStandardItem( QString( tr( "undefined %1" ) ).arg( row + 1 ) ) ); mConstraintsModel->setItem( row, 1, new QStandardItem( QString( tr( "undefined %1" ) ).arg( row + 1 ) ) ); } -void QgsMetadataWidget::removeSelectedConstraint() +void QgsMetadataWidget::removeSelectedConstraint() const { const QModelIndexList selectedRows = tabConstraints->selectionModel()->selectedRows(); mConstraintsModel->removeRow( selectedRows[0].row() ); } -void QgsMetadataWidget::crsChanged() +void QgsMetadataWidget::crsChanged() const { - if ( mCrs.isValid() ) + if ( ( mCrs.isValid() ) && ( mLayer ) ) { lblCurrentCrs->setText( tr( "CRS: %1 - %2" ).arg( mCrs.authid(), mCrs.description() ) ); spatialExtentSelector->setEnabled( true ); @@ -233,7 +257,7 @@ void QgsMetadataWidget::crsChanged() } } -void QgsMetadataWidget::addAddress() +void QgsMetadataWidget::addAddress() const { int row = tabAddresses->rowCount(); tabAddresses->setRowCount( row + 1 ); @@ -259,7 +283,7 @@ void QgsMetadataWidget::addAddress() tabAddresses->setItem( row, 5, new QTableWidgetItem() ); } -void QgsMetadataWidget::removeSelectedAddress() +void QgsMetadataWidget::removeSelectedAddress() const { QItemSelectionModel *selectionModel = tabAddresses->selectionModel(); const QModelIndexList selectedRows = selectionModel->selectedRows(); @@ -281,7 +305,7 @@ void QgsMetadataWidget::fillCrsFromProvider() crsChanged(); } -void QgsMetadataWidget::addLink() +void QgsMetadataWidget::addLink() const { int row = mLinksModel->rowCount(); mLinksModel->setItem( row, 0, new QStandardItem( QString( tr( "undefined %1" ) ).arg( row + 1 ) ) ); @@ -293,7 +317,7 @@ void QgsMetadataWidget::addLink() mLinksModel->setItem( row, 6, new QStandardItem() ); } -void QgsMetadataWidget::removeSelectedLink() +void QgsMetadataWidget::removeSelectedLink() const { const QModelIndexList selectedRows = tabLinks->selectionModel()->selectedRows(); mLinksModel->removeRow( selectedRows[0].row() ); @@ -310,7 +334,7 @@ void QgsMetadataWidget::addHistory() } } -void QgsMetadataWidget::removeSelectedHistory() +void QgsMetadataWidget::removeSelectedHistory() const { QItemSelectionModel *selection = listHistory->selectionModel(); if ( selection->hasSelection() ) @@ -324,7 +348,7 @@ void QgsMetadataWidget::removeSelectedHistory() } } -void QgsMetadataWidget::fillComboBox() +void QgsMetadataWidget::fillComboBox() const { // Set default values in type combobox // It is advised to use the ISO 19115 MD_ScopeCode values. E.g. 'dataset' or 'series'. @@ -522,7 +546,7 @@ void QgsMetadataWidget::setPropertiesFromLayer() mHistoryModel->setStringList( mMetadata.history() ); } -void QgsMetadataWidget::saveMetadata( QgsLayerMetadata &layerMetadata ) +void QgsMetadataWidget::saveMetadata( QgsLayerMetadata &layerMetadata ) const { layerMetadata.setParentIdentifier( lineEditParentId->text() ); layerMetadata.setIdentifier( lineEditIdentifier->text() ); @@ -635,7 +659,7 @@ void QgsMetadataWidget::saveMetadata( QgsLayerMetadata &layerMetadata ) layerMetadata.setHistory( mHistoryModel->stringList() ); } -bool QgsMetadataWidget::checkMetadata() +bool QgsMetadataWidget::checkMetadata() const { QgsLayerMetadata metadata = QgsLayerMetadata(); saveMetadata( metadata ); @@ -815,9 +839,11 @@ void QgsMetadataWidget::setMapCanvas( QgsMapCanvas *canvas ) void QgsMetadataWidget::acceptMetadata() { saveMetadata( mMetadata ); - - // Save layer metadata properties - mLayer->setMetadata( mMetadata ); + if ( mLayer ) + { + // Save layer metadata properties + mLayer->setMetadata( mMetadata ); + } } void QgsMetadataWidget::setMetadata( const QgsLayerMetadata &metadata ) @@ -826,7 +852,7 @@ void QgsMetadataWidget::setMetadata( const QgsLayerMetadata &metadata ) setPropertiesFromLayer(); } -void QgsMetadataWidget::syncFromCategoriesTabToKeywordsTab() +void QgsMetadataWidget::syncFromCategoriesTabToKeywordsTab() const { if ( mCategoriesModel->rowCount() > 0 ) { @@ -847,7 +873,7 @@ void QgsMetadataWidget::syncFromCategoriesTabToKeywordsTab() } } -void QgsMetadataWidget::updatePanel() +void QgsMetadataWidget::updatePanel() const { int index = tabWidget->currentIndex(); QString currentTabText = tabWidget->widget( index )->objectName(); diff --git a/src/gui/qgsmetadatawidget.h b/src/gui/qgsmetadatawidget.h index d6cd000abc5..e4597608f8b 100644 --- a/src/gui/qgsmetadatawidget.h +++ b/src/gui/qgsmetadatawidget.h @@ -43,16 +43,43 @@ class GUI_EXPORT QgsMetadataWidget : public QWidget, private Ui::QgsMetadataWidg /** * Constructor for the wizard. + * \note + * For use with a source \layer. This constructor automatically sets the widget's metadata() if the \a layer pointer is valid. + * calls setMetadata, using mMetadata + * \param layer to set the main QgsLayerMetadata with mLayer->metadata() when not nullptr + * \see setMetadata */ QgsMetadataWidget( QWidget *parent, QgsMapLayer *layer = nullptr ); + /** + * Sets the \a metadata to display in the widget + * \note + * Called from constructor and initializes child widget on first use + * Can be called from outside to change the QgsLayerMetadata object. + * \see metadata() + */ + void setMetadata( const QgsLayerMetadata &layerMetadata ); + + /** + * Retrieves a QgsLayerMetadata object representing the current state of the widget. + * \note + * saveMetdata is called before returning QgsLayerMetadata + * \see saveMetadata + */ + QgsLayerMetadata metadata(); + /** * Save all fields in a QgsLayerMetadata object. + * \see getMetadata + * \see acceptMetadata + * \see checkMetadata */ void saveMetadata( QgsLayerMetadata &layerMetadata ); /** * Check if values in the wizard are correct. + * \see updatePanel + * \see saveMetadata */ bool checkMetadata();