mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-13 00:03:09 -04:00
load and save metadata to a QMD file
This commit is contained in:
parent
a343570eab
commit
3432bf8f3b
@ -55,6 +55,12 @@ This is the base class for all map layer types (vector, raster).
|
||||
PluginLayer
|
||||
};
|
||||
|
||||
enum PropertyType
|
||||
{
|
||||
Style,
|
||||
Metadata,
|
||||
};
|
||||
|
||||
QgsMapLayer( QgsMapLayer::LayerType type = VectorLayer, const QString &name = QString(), const QString &source = QString() );
|
||||
%Docstring
|
||||
Constructor for QgsMapLayer
|
||||
@ -80,6 +86,15 @@ is still unique.
|
||||
QgsMapLayer::LayerType type() const;
|
||||
%Docstring
|
||||
Returns the type of the layer.
|
||||
%End
|
||||
|
||||
static QString extensionPropertyType( PropertyType type );
|
||||
%Docstring
|
||||
Returns the extension of a Property.
|
||||
|
||||
:return: The extension
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
QString id() const;
|
||||
@ -545,6 +560,118 @@ Sets layer's spatial reference system
|
||||
%Docstring
|
||||
A convenience function to capitalize and format a layer ``name``.
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
virtual QString metadataUri() const;
|
||||
%Docstring
|
||||
Retrieve the metadata URI for this layer
|
||||
(either as a .qmd file on disk or as a
|
||||
record in the users style table in their personal qgis.db)
|
||||
|
||||
:return: a QString with the metadata file name
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
void exportNamedMetadata( QDomDocument &doc, QString &errorMsg ) const;
|
||||
%Docstring
|
||||
Export the current metadata of this layer as named metadata in a QDomDocument
|
||||
|
||||
:param doc: the target QDomDocument
|
||||
:param errorMsg: this QString will be initialized on error
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
virtual QString saveDefaultMetadata( bool &resultFlag /Out/ );
|
||||
%Docstring
|
||||
Save the current metadata of this layer as the default metadata
|
||||
(either as a .qmd file on disk or as a
|
||||
record in the users style table in their personal qgis.db)
|
||||
|
||||
:param resultFlag: a reference to a flag that will be set to false if
|
||||
we did not manage to save the default metadata.
|
||||
|
||||
:return: a QString with any status messages
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
QString saveNamedMetadata( const QString &uri, bool &resultFlag );
|
||||
%Docstring
|
||||
Save the current metadata of this layer as a named metadata
|
||||
(either as a .qmd file on disk or as a
|
||||
record in the users style table in their personal qgis.db)
|
||||
|
||||
:param uri: the file name or other URI for the
|
||||
metadata file. First an attempt will be made to see if this
|
||||
is a file and save to that, if that fails the qgis.db metadata
|
||||
table will be used to create a metadata entry who's
|
||||
key matches the URI.
|
||||
:param resultFlag: a reference to a flag that will be set to false if
|
||||
we did not manage to save the default metadata.
|
||||
|
||||
:return: a QString with any status messages
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
virtual QString loadNamedMetadata( const QString &uri, bool &resultFlag /Out/ );
|
||||
%Docstring
|
||||
Retrieve a named metadata for this layer if one
|
||||
exists (either as a .qmd file on disk or as a
|
||||
record in the users style table in their personal qgis.db)
|
||||
|
||||
:param uri: - the file name or other URI for the
|
||||
metadata file. First an attempt will be made to see if this
|
||||
is a file and load that, if that fails the qgis.db metadata
|
||||
table will be consulted to see if there is a metadata who's
|
||||
key matches the URI.
|
||||
:param resultFlag: a reference to a flag that will be set to false if
|
||||
we did not manage to load the default metadata.
|
||||
|
||||
:return: a QString with any status messages
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
QString loadDefaultMetadata( bool &resultFlag );
|
||||
%Docstring
|
||||
Retrieve the default metadata for this layer if one
|
||||
exists (either as a .qmd file on disk or as a
|
||||
record in the users metadata table in their personal qgis.db)
|
||||
|
||||
:param resultFlag: a reference to a flag that will be set to false if
|
||||
we did not manage to load the default metadata.
|
||||
|
||||
:return: a QString with any status messages
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
bool loadNamedMetadataFromDatabase( const QString &db, const QString &uri, QString &qmd );
|
||||
%Docstring
|
||||
Retrieve a named metadata for this layer from a sqlite database.
|
||||
|
||||
:param db: path to sqlite database
|
||||
:param uri: uri for table
|
||||
:param qmd: will be set to QMD xml metadata content from database
|
||||
|
||||
:return: true if style was successfully loaded
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
bool importNamedMetadata( QDomDocument &document, QString &errorMessage );
|
||||
%Docstring
|
||||
Import the metadata of this layer from a QDomDocument
|
||||
|
||||
:param document: source QDomDocument
|
||||
:param errorMessage: this QString will be initialized on error
|
||||
|
||||
:return: true on success
|
||||
|
||||
.. versionadded:: 3.0
|
||||
%End
|
||||
|
||||
|
@ -46,6 +46,11 @@ If the CRS is updated.
|
||||
void acceptMetadata();
|
||||
%Docstring
|
||||
Saves the metadata to the layer.
|
||||
%End
|
||||
|
||||
virtual void setMetadata( const QgsLayerMetadata &metadata );
|
||||
%Docstring
|
||||
Sets the layer's ``metadata`` store.
|
||||
%End
|
||||
|
||||
static QMap<QString, QString> parseLanguages();
|
||||
|
@ -4321,6 +4321,7 @@ bool QgisApp::addVectorLayers( const QStringList &layerQStringList, const QStrin
|
||||
{
|
||||
bool ok;
|
||||
l->loadDefaultStyle( ok );
|
||||
l->loadDefaultMetadata( ok );
|
||||
}
|
||||
activateDeactivateLayerRelatedActions( activeLayer() );
|
||||
|
||||
@ -4747,6 +4748,7 @@ void QgisApp::askUserForOGRSublayers( QgsVectorLayer *layer )
|
||||
{
|
||||
bool ok;
|
||||
l->loadDefaultStyle( ok );
|
||||
l->loadDefaultMetadata( ok );
|
||||
if ( addToGroup )
|
||||
group->addLayer( l );
|
||||
}
|
||||
@ -4839,6 +4841,7 @@ void QgisApp::addDatabaseLayers( QStringList const &layerPathList, QString const
|
||||
{
|
||||
bool ok;
|
||||
l->loadDefaultStyle( ok );
|
||||
l->loadDefaultMetadata( ok );
|
||||
}
|
||||
|
||||
// draw the map
|
||||
@ -10249,6 +10252,7 @@ QgsVectorLayer *QgisApp::addVectorLayer( const QString &vectorLayerPath, const Q
|
||||
QgsProject::instance()->addMapLayers( myList );
|
||||
bool ok;
|
||||
layer->loadDefaultStyle( ok );
|
||||
layer->loadDefaultMetadata( ok );
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -104,16 +104,26 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer *lyr, QgsMapCanv
|
||||
|
||||
connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsRasterLayerProperties::showHelp );
|
||||
|
||||
QPushButton *b = new QPushButton( tr( "Style" ) );
|
||||
QMenu *m = new QMenu( this );
|
||||
m->addAction( tr( "Load Style..." ), this, SLOT( loadStyle_clicked() ) );
|
||||
m->addAction( tr( "Save Style..." ), this, SLOT( saveStyleAs_clicked() ) );
|
||||
m->addSeparator();
|
||||
m->addAction( tr( "Save as Default" ), this, SLOT( saveDefaultStyle_clicked() ) );
|
||||
m->addAction( tr( "Restore Default" ), this, SLOT( loadDefaultStyle_clicked() ) );
|
||||
b->setMenu( m );
|
||||
connect( m, &QMenu::aboutToShow, this, &QgsRasterLayerProperties::aboutToShowStyleMenu );
|
||||
buttonBox->addButton( b, QDialogButtonBox::ResetRole );
|
||||
mBtnStyle = new QPushButton( tr( "Style" ) );
|
||||
QMenu *menuStyle = new QMenu( this );
|
||||
menuStyle->addAction( tr( "Load Style..." ), this, SLOT( loadStyle_clicked() ) );
|
||||
menuStyle->addAction( tr( "Save Style..." ), this, SLOT( saveStyleAs_clicked() ) );
|
||||
menuStyle->addSeparator();
|
||||
menuStyle->addAction( tr( "Save as Default" ), this, SLOT( saveDefaultStyle_clicked() ) );
|
||||
menuStyle->addAction( tr( "Restore Default" ), this, SLOT( loadDefaultStyle_clicked() ) );
|
||||
mBtnStyle->setMenu( menuStyle );
|
||||
connect( menuStyle, &QMenu::aboutToShow, this, &QgsRasterLayerProperties::aboutToShowStyleMenu );
|
||||
buttonBox->addButton( mBtnStyle, QDialogButtonBox::ResetRole );
|
||||
|
||||
mBtnMetadata = new QPushButton( tr( "Metadata" ), this );
|
||||
QMenu *menuMetadata = new QMenu( this );
|
||||
mActionLoadMetadata = menuMetadata->addAction( tr( "Load Metadata" ), this, SLOT( loadMetadata() ) );
|
||||
mActionSaveMetadataAs = menuMetadata->addAction( tr( "Save Metadata" ), this, SLOT( saveMetadataAs() ) );
|
||||
menuMetadata->addSeparator();
|
||||
menuMetadata->addAction( tr( "Save as Default" ), this, SLOT( saveDefaultMetadata() ) );
|
||||
menuMetadata->addAction( tr( "Restore Default" ), this, SLOT( loadDefaultMetadata() ) );
|
||||
mBtnMetadata->setMenu( menuMetadata );
|
||||
buttonBox->addButton( mBtnMetadata, QDialogButtonBox::ResetRole );
|
||||
|
||||
connect( lyr->styleManager(), &QgsMapLayerStyleManager::currentStyleChanged, this, &QgsRasterLayerProperties::syncToLayer );
|
||||
|
||||
@ -436,6 +446,7 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer *lyr, QgsMapCanv
|
||||
|
||||
QString title = QString( tr( "Layer Properties - %1" ) ).arg( lyr->name() );
|
||||
restoreOptionsBaseUi( title );
|
||||
optionsStackedWidget_CurrentChanged( mOptionsStackedWidget->currentIndex() );
|
||||
} // QgsRasterLayerProperties ctor
|
||||
|
||||
|
||||
@ -1488,6 +1499,10 @@ void QgsRasterLayerProperties::optionsStackedWidget_CurrentChanged( int index )
|
||||
{
|
||||
QgsOptionsDialogBase::optionsStackedWidget_CurrentChanged( index );
|
||||
|
||||
bool isMetadataPanel = ( index == mOptStackedWidget->indexOf( mOptsPage_Metadata ) );
|
||||
mBtnStyle->setVisible( ! isMetadataPanel );
|
||||
mBtnMetadata->setVisible( isMetadataPanel );
|
||||
|
||||
if ( !mHistogramWidget )
|
||||
return;
|
||||
|
||||
@ -1856,6 +1871,102 @@ void QgsRasterLayerProperties::saveStyleAs_clicked()
|
||||
QMessageBox::information( this, tr( "Saved Style" ), message );
|
||||
}
|
||||
|
||||
//
|
||||
//
|
||||
// Next four methods for saving and restoring QMD metadata
|
||||
//
|
||||
//
|
||||
|
||||
void QgsRasterLayerProperties::loadMetadata()
|
||||
{
|
||||
QgsSettings myQSettings; // where we keep last used filter in persistent state
|
||||
QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
|
||||
|
||||
QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load layer metadata from metadata file" ), myLastUsedDir,
|
||||
tr( "QGIS Layer Metadata File" ) + " (*.qmd)" );
|
||||
if ( myFileName.isNull() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QString myMessage;
|
||||
bool defaultLoadedFlag = false;
|
||||
myMessage = mRasterLayer->loadNamedMetadata( myFileName, defaultLoadedFlag );
|
||||
|
||||
//reset if the default style was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
mMetadataWidget->setMetadata( mRasterLayer->metadata() );
|
||||
}
|
||||
else
|
||||
{
|
||||
//let the user know what went wrong
|
||||
QMessageBox::warning( this, tr( "Load Metadata" ), myMessage );
|
||||
}
|
||||
|
||||
QFileInfo myFI( myFileName );
|
||||
QString myPath = myFI.path();
|
||||
myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), myPath );
|
||||
|
||||
activateWindow(); // set focus back to properties dialog
|
||||
}
|
||||
|
||||
void QgsRasterLayerProperties::saveMetadataAs()
|
||||
{
|
||||
QgsSettings myQSettings; // where we keep last used filter in persistent state
|
||||
QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
|
||||
|
||||
QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save layer metadata as QMD" ),
|
||||
myLastUsedDir, tr( "QMD File" ) + " (*.qmd)" );
|
||||
if ( myOutputFileName.isNull() ) //dialog canceled
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mMetadataWidget->acceptMetadata();
|
||||
|
||||
//ensure the user never omitted the extension from the file name
|
||||
if ( !myOutputFileName.endsWith( QgsMapLayer::extensionPropertyType( QgsMapLayer::Metadata ), Qt::CaseInsensitive ) )
|
||||
{
|
||||
myOutputFileName += QgsMapLayer::extensionPropertyType( QgsMapLayer::Metadata );
|
||||
}
|
||||
|
||||
bool defaultLoadedFlag = false;
|
||||
QString message = mRasterLayer->saveNamedMetadata( myOutputFileName, defaultLoadedFlag );
|
||||
if ( defaultLoadedFlag )
|
||||
myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), QFileInfo( myOutputFileName ).absolutePath() );
|
||||
else
|
||||
QMessageBox::information( this, tr( "Saved Metadata" ), message );
|
||||
}
|
||||
|
||||
void QgsRasterLayerProperties::saveDefaultMetadata()
|
||||
{
|
||||
mMetadataWidget->acceptMetadata();
|
||||
|
||||
bool defaultSavedFlag = false;
|
||||
QString errorMsg = mRasterLayer->saveDefaultMetadata( defaultSavedFlag );
|
||||
if ( !defaultSavedFlag )
|
||||
{
|
||||
QMessageBox::warning( this, tr( "Default Metadata" ), errorMsg );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsRasterLayerProperties::loadDefaultMetadata()
|
||||
{
|
||||
bool defaultLoadedFlag = false;
|
||||
QString myMessage = mRasterLayer->loadNamedMetadata( mRasterLayer->metadataUri(), defaultLoadedFlag );
|
||||
//reset if the default metadata was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
mMetadataWidget->setMetadata( mRasterLayer->metadata() );
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::information( this, tr( "Default Metadata" ), myMessage );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void QgsRasterLayerProperties::toggleBuildPyramidsButton()
|
||||
{
|
||||
if ( lbxPyramidResolutions->selectedItems().empty() )
|
||||
|
@ -103,6 +103,16 @@ class APP_EXPORT QgsRasterLayerProperties : public QgsOptionsDialogBase, private
|
||||
void loadStyle_clicked();
|
||||
//! Save a style when appriate button is pressed.
|
||||
void saveStyleAs_clicked();
|
||||
|
||||
//! Load a saved metadata file.
|
||||
void loadMetadata();
|
||||
//! Save a metadata.
|
||||
void saveMetadataAs();
|
||||
//! Save the default metadata.
|
||||
void saveDefaultMetadata();
|
||||
//! Load the default metadata.
|
||||
void loadDefaultMetadata();
|
||||
|
||||
//! Help button
|
||||
void showHelp();
|
||||
|
||||
@ -131,6 +141,11 @@ class APP_EXPORT QgsRasterLayerProperties : public QgsOptionsDialogBase, private
|
||||
void refreshLegend( const QString &layerID, bool expandItem );
|
||||
|
||||
private:
|
||||
QPushButton *mBtnStyle = nullptr;
|
||||
QPushButton *mBtnMetadata = nullptr;
|
||||
QAction *mActionLoadMetadata = nullptr;
|
||||
QAction *mActionSaveMetadataAs = nullptr;
|
||||
|
||||
//! \brief A constant that signals property not used
|
||||
const QString TRSTRING_NOT_SET;
|
||||
|
||||
|
@ -111,16 +111,26 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
|
||||
// and connecting QDialogButtonBox's accepted/rejected signals to dialog's accept/reject slots
|
||||
initOptionsBase( false );
|
||||
|
||||
QPushButton *b = new QPushButton( tr( "Style" ) );
|
||||
QMenu *m = new QMenu( this );
|
||||
mActionLoadStyle = m->addAction( tr( "Load Style" ), this, SLOT( loadStyle_clicked() ) );
|
||||
mActionSaveStyleAs = m->addAction( tr( "Save Style" ), this, SLOT( saveStyleAs_clicked() ) );
|
||||
m->addSeparator();
|
||||
m->addAction( tr( "Save as Default" ), this, SLOT( saveDefaultStyle_clicked() ) );
|
||||
m->addAction( tr( "Restore Default" ), this, SLOT( loadDefaultStyle_clicked() ) );
|
||||
b->setMenu( m );
|
||||
connect( m, &QMenu::aboutToShow, this, &QgsVectorLayerProperties::aboutToShowStyleMenu );
|
||||
buttonBox->addButton( b, QDialogButtonBox::ResetRole );
|
||||
mBtnStyle = new QPushButton( tr( "Style" ), this );
|
||||
QMenu *menuStyle = new QMenu( this );
|
||||
mActionLoadStyle = menuStyle->addAction( tr( "Load Style" ), this, SLOT( loadStyle_clicked() ) );
|
||||
mActionSaveStyleAs = menuStyle->addAction( tr( "Save Style" ), this, SLOT( saveStyleAs_clicked() ) );
|
||||
menuStyle->addSeparator();
|
||||
menuStyle->addAction( tr( "Save as Default" ), this, SLOT( saveDefaultStyle_clicked() ) );
|
||||
menuStyle->addAction( tr( "Restore Default" ), this, SLOT( loadDefaultStyle_clicked() ) );
|
||||
mBtnStyle->setMenu( menuStyle );
|
||||
connect( menuStyle, &QMenu::aboutToShow, this, &QgsVectorLayerProperties::aboutToShowStyleMenu );
|
||||
buttonBox->addButton( mBtnStyle, QDialogButtonBox::ResetRole );
|
||||
|
||||
mBtnMetadata = new QPushButton( tr( "Metadata" ), this );
|
||||
QMenu *menuMetadata = new QMenu( this );
|
||||
mActionLoadMetadata = menuMetadata->addAction( tr( "Load Metadata" ), this, SLOT( loadMetadata() ) );
|
||||
mActionSaveMetadataAs = menuMetadata->addAction( tr( "Save Metadata" ), this, SLOT( saveMetadataAs() ) );
|
||||
menuMetadata->addSeparator();
|
||||
menuMetadata->addAction( tr( "Save as Default" ), this, SLOT( saveDefaultMetadata() ) );
|
||||
menuMetadata->addAction( tr( "Restore Default" ), this, SLOT( loadDefaultMetadata() ) );
|
||||
mBtnMetadata->setMenu( menuMetadata );
|
||||
buttonBox->addButton( mBtnMetadata, QDialogButtonBox::ResetRole );
|
||||
|
||||
connect( lyr->styleManager(), &QgsMapLayerStyleManager::currentStyleChanged, this, &QgsVectorLayerProperties::syncToLayer );
|
||||
|
||||
@ -227,6 +237,15 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
|
||||
delete mOptsPage_3DView; // removes both the "3d view" list item and its page
|
||||
#endif
|
||||
|
||||
// Metadata tab, before the syncToLayer
|
||||
QVBoxLayout *metadataLayout = new QVBoxLayout( metadataFrame );
|
||||
metadataLayout->setMargin( 0 );
|
||||
mMetadataWidget = new QgsMetadataWidget( this, mLayer );
|
||||
mMetadataWidget->layout()->setContentsMargins( -1, 0, -1, 0 );
|
||||
mMetadataWidget->setMapCanvas( QgisApp::instance()->mapCanvas() );
|
||||
metadataLayout->addWidget( mMetadataWidget );
|
||||
metadataFrame->setLayout( metadataLayout );
|
||||
|
||||
syncToLayer();
|
||||
|
||||
if ( mLayer->dataProvider() )//enable spatial index button group if supported by provider
|
||||
@ -282,15 +301,6 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
|
||||
diagLayout->addWidget( diagramPropertiesDialog );
|
||||
mDiagramFrame->setLayout( diagLayout );
|
||||
|
||||
// Metadata tab
|
||||
QVBoxLayout *metadataLayout = new QVBoxLayout( metadataFrame );
|
||||
metadataLayout->setMargin( 0 );
|
||||
mMetadataWidget = new QgsMetadataWidget( this, mLayer );
|
||||
mMetadataWidget->layout()->setContentsMargins( -1, 0, -1, 0 );
|
||||
mMetadataWidget->setMapCanvas( QgisApp::instance()->mapCanvas() );
|
||||
metadataLayout->addWidget( mMetadataWidget );
|
||||
metadataFrame->setLayout( metadataLayout );
|
||||
|
||||
// Legend tab
|
||||
mLegendConfigEmbeddedWidget->setLayer( mLayer );
|
||||
|
||||
@ -401,6 +411,8 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
|
||||
connect( mAuxiliaryStorageFieldsAddBtn, &QPushButton::clicked, this, &QgsVectorLayerProperties::onAuxiliaryLayerAddField );
|
||||
|
||||
updateAuxiliaryStoragePage();
|
||||
|
||||
optionsStackedWidget_CurrentChanged( mOptStackedWidget->currentIndex() );
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::toggleEditing()
|
||||
@ -546,6 +558,8 @@ void QgsVectorLayerProperties::syncToLayer()
|
||||
mVector3DWidget->setLayer( mLayer );
|
||||
#endif
|
||||
|
||||
mMetadataWidget->setMetadata( mLayer->metadata() );
|
||||
|
||||
} // syncToLayer()
|
||||
|
||||
void QgsVectorLayerProperties::apply()
|
||||
@ -982,6 +996,108 @@ void QgsVectorLayerProperties::saveStyleAs_clicked()
|
||||
saveStyleAs( QML );
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::loadMetadata()
|
||||
{
|
||||
QgsSettings myQSettings; // where we keep last used filter in persistent state
|
||||
QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
|
||||
|
||||
QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load layer metadata from metadata file" ), myLastUsedDir,
|
||||
tr( "QGIS Layer Metadata File" ) + " (*.qmd)" );
|
||||
if ( myFileName.isNull() )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QString myMessage;
|
||||
bool defaultLoadedFlag = false;
|
||||
myMessage = mLayer->loadNamedMetadata( myFileName, defaultLoadedFlag );
|
||||
|
||||
//reset if the default style was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
mMetadataWidget->setMetadata( mLayer->metadata() );
|
||||
}
|
||||
else
|
||||
{
|
||||
//let the user know what went wrong
|
||||
QMessageBox::warning( this, tr( "Load Metadata" ), myMessage );
|
||||
}
|
||||
|
||||
QFileInfo myFI( myFileName );
|
||||
QString myPath = myFI.path();
|
||||
myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), myPath );
|
||||
|
||||
activateWindow(); // set focus back to properties dialog
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::saveMetadataAs()
|
||||
{
|
||||
QgsSettings myQSettings; // where we keep last used filter in persistent state
|
||||
QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
|
||||
|
||||
QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save layer metadata as QMD" ),
|
||||
myLastUsedDir, tr( "QMD File" ) + " (*.qmd)" );
|
||||
if ( myOutputFileName.isNull() ) //dialog canceled
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
mMetadataWidget->acceptMetadata();
|
||||
|
||||
//ensure the user never omitted the extension from the file name
|
||||
if ( !myOutputFileName.endsWith( QgsMapLayer::extensionPropertyType( QgsMapLayer::Metadata ), Qt::CaseInsensitive ) )
|
||||
{
|
||||
myOutputFileName += QgsMapLayer::extensionPropertyType( QgsMapLayer::Metadata );
|
||||
}
|
||||
|
||||
QString myMessage;
|
||||
bool defaultLoadedFlag = false;
|
||||
myMessage = mLayer->saveNamedMetadata( myOutputFileName, defaultLoadedFlag );
|
||||
|
||||
//reset if the default style was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
syncToLayer();
|
||||
}
|
||||
else
|
||||
{
|
||||
//let the user know what went wrong
|
||||
QMessageBox::information( this, tr( "Saved Metadata" ), myMessage );
|
||||
}
|
||||
|
||||
QFileInfo myFI( myOutputFileName );
|
||||
QString myPath = myFI.path();
|
||||
// Persist last used dir
|
||||
myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), myPath );
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::saveDefaultMetadata()
|
||||
{
|
||||
mMetadataWidget->acceptMetadata();
|
||||
|
||||
bool defaultSavedFlag = false;
|
||||
QString errorMsg = mLayer->saveDefaultMetadata( defaultSavedFlag );
|
||||
if ( !defaultSavedFlag )
|
||||
{
|
||||
QMessageBox::warning( this, tr( "Default Metadata" ), errorMsg );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::loadDefaultMetadata()
|
||||
{
|
||||
bool defaultLoadedFlag = false;
|
||||
QString myMessage = mLayer->loadNamedMetadata( mLayer->metadataUri(), defaultLoadedFlag );
|
||||
//reset if the default metadata was loaded OK only
|
||||
if ( defaultLoadedFlag )
|
||||
{
|
||||
mMetadataWidget->setMetadata( mLayer->metadata() );
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::information( this, tr( "Default Metadata" ), myMessage );
|
||||
}
|
||||
}
|
||||
|
||||
void QgsVectorLayerProperties::saveStyleAsMenuTriggered( QAction *action )
|
||||
{
|
||||
QMenu *menu = qobject_cast<QMenu *>( sender() );
|
||||
@ -1045,7 +1161,7 @@ void QgsVectorLayerProperties::saveStyleAs( StyleType styleType )
|
||||
else
|
||||
{
|
||||
format = tr( "QGIS Layer Style File" ) + " (*.qml)";
|
||||
extension = QStringLiteral( ".qml" );
|
||||
extension = QgsMapLayer::extensionPropertyType( QgsMapLayer::Style );
|
||||
}
|
||||
|
||||
QString myOutputFileName = QFileDialog::getSaveFileName( this, tr( "Save layer properties as style file" ),
|
||||
@ -1480,6 +1596,10 @@ void QgsVectorLayerProperties::optionsStackedWidget_CurrentChanged( int index )
|
||||
{
|
||||
QgsOptionsDialogBase::optionsStackedWidget_CurrentChanged( index );
|
||||
|
||||
bool isMetadataPanel = ( index == mOptStackedWidget->indexOf( mOptsPage_Metadata ) );
|
||||
mBtnStyle->setVisible( ! isMetadataPanel );
|
||||
mBtnMetadata->setVisible( isMetadataPanel );
|
||||
|
||||
if ( index != mOptStackedWidget->indexOf( mOptsPage_Information ) || mMetadataFilled )
|
||||
return;
|
||||
|
||||
|
@ -118,6 +118,10 @@ class APP_EXPORT QgsVectorLayerProperties : public QgsOptionsDialogBase, private
|
||||
void saveDefaultStyle_clicked();
|
||||
void loadStyle_clicked();
|
||||
void saveStyleAs_clicked();
|
||||
void loadMetadata();
|
||||
void saveMetadataAs();
|
||||
void saveDefaultMetadata();
|
||||
void loadDefaultMetadata();
|
||||
void optionsStackedWidget_CurrentChanged( int index ) override;
|
||||
void pbnUpdateExtents_clicked();
|
||||
|
||||
@ -167,6 +171,12 @@ class APP_EXPORT QgsVectorLayerProperties : public QgsOptionsDialogBase, private
|
||||
|
||||
private:
|
||||
|
||||
enum PropertyType
|
||||
{
|
||||
Style = 0,
|
||||
Metadata,
|
||||
};
|
||||
|
||||
void saveStyleAs( StyleType styleType );
|
||||
|
||||
//! When provider supports, it will list all the styles relative the layer in a dialog
|
||||
@ -182,6 +192,11 @@ class APP_EXPORT QgsVectorLayerProperties : public QgsOptionsDialogBase, private
|
||||
|
||||
QString mOriginalSubsetSQL;
|
||||
|
||||
QPushButton *mBtnStyle = nullptr;
|
||||
QPushButton *mBtnMetadata = nullptr;
|
||||
QAction *mActionLoadMetadata = nullptr;
|
||||
QAction *mActionSaveMetadataAs = nullptr;
|
||||
|
||||
QMenu *mSaveAsMenu = nullptr;
|
||||
QMenu *mLoadStyleMenu = nullptr;
|
||||
|
||||
|
@ -54,6 +54,19 @@
|
||||
#include "qgssettings.h" // TODO: get rid of it [MD]
|
||||
#include "qgsstringutils.h"
|
||||
|
||||
QString QgsMapLayer::extensionPropertyType( QgsMapLayer::PropertyType type )
|
||||
{
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
return QStringLiteral( ".qmd" );
|
||||
|
||||
case Style:
|
||||
return QStringLiteral( ".qml" );
|
||||
}
|
||||
return QStringLiteral();
|
||||
}
|
||||
|
||||
QgsMapLayer::QgsMapLayer( QgsMapLayer::LayerType type,
|
||||
const QString &lyrname,
|
||||
const QString &source )
|
||||
@ -1009,7 +1022,7 @@ QString QgsMapLayer::formatLayerName( const QString &name )
|
||||
return layerName;
|
||||
}
|
||||
|
||||
QString QgsMapLayer::styleURI() const
|
||||
QString QgsMapLayer::baseURI( PropertyType type ) const
|
||||
{
|
||||
QString myURI = publicSource();
|
||||
|
||||
@ -1051,7 +1064,7 @@ QString QgsMapLayer::styleURI() const
|
||||
myURI.chop( 4 );
|
||||
myFileInfo.setFile( myURI );
|
||||
// get the file name for our .qml style file
|
||||
key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
|
||||
key = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1061,12 +1074,42 @@ QString QgsMapLayer::styleURI() const
|
||||
return key;
|
||||
}
|
||||
|
||||
QString QgsMapLayer::metadataUri() const
|
||||
{
|
||||
return baseURI( PropertyType::Metadata );
|
||||
}
|
||||
|
||||
QString QgsMapLayer::saveDefaultMetadata( bool &resultFlag )
|
||||
{
|
||||
return saveNamedMetadata( metadataUri(), resultFlag );
|
||||
}
|
||||
|
||||
QString QgsMapLayer::loadDefaultMetadata( bool &resultFlag )
|
||||
{
|
||||
return loadNamedMetadata( metadataUri(), resultFlag );
|
||||
}
|
||||
|
||||
QString QgsMapLayer::styleURI() const
|
||||
{
|
||||
return baseURI( PropertyType::Style );
|
||||
}
|
||||
|
||||
QString QgsMapLayer::loadDefaultStyle( bool &resultFlag )
|
||||
{
|
||||
return loadNamedStyle( styleURI(), resultFlag );
|
||||
}
|
||||
|
||||
bool QgsMapLayer::loadNamedMetadataFromDatabase( const QString &db, const QString &uri, QString &qmd )
|
||||
{
|
||||
return loadNamedPropertyFromDatabase( db, uri, qmd, PropertyType::Metadata );
|
||||
}
|
||||
|
||||
bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &uri, QString &qml )
|
||||
{
|
||||
return loadNamedPropertyFromDatabase( db, uri, qml, PropertyType::Style );
|
||||
}
|
||||
|
||||
bool QgsMapLayer::loadNamedPropertyFromDatabase( const QString &db, const QString &uri, QString &xml, QgsMapLayer::PropertyType type )
|
||||
{
|
||||
QgsDebugMsgLevel( QString( "db = %1 uri = %2" ).arg( db, uri ), 4 );
|
||||
|
||||
@ -1078,7 +1121,7 @@ bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &
|
||||
|
||||
int myResult;
|
||||
|
||||
QgsDebugMsgLevel( QString( "Trying to load style for \"%1\" from \"%2\"" ).arg( uri, db ), 4 );
|
||||
QgsDebugMsgLevel( QString( "Trying to load style or metadata for \"%1\" from \"%2\"" ).arg( uri, db ), 4 );
|
||||
|
||||
if ( db.isEmpty() || !QFile( db ).exists() )
|
||||
return false;
|
||||
@ -1089,7 +1132,18 @@ bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &
|
||||
return false;
|
||||
}
|
||||
|
||||
QString mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
|
||||
QString mySql;
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
mySql = QStringLiteral( "select qmd from tbl_metadata where metadata=?" );
|
||||
break;
|
||||
|
||||
case Style:
|
||||
mySql = QStringLiteral( "select qml from tbl_styles where style=?" );
|
||||
break;
|
||||
}
|
||||
|
||||
statement = database.prepare( mySql, myResult );
|
||||
if ( myResult == SQLITE_OK )
|
||||
{
|
||||
@ -1098,7 +1152,7 @@ bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &
|
||||
if ( sqlite3_bind_text( statement.get(), 1, param.data(), param.length(), SQLITE_STATIC ) == SQLITE_OK &&
|
||||
sqlite3_step( statement.get() ) == SQLITE_ROW )
|
||||
{
|
||||
qml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement.get(), 0 ) ) );
|
||||
xml = QString::fromUtf8( reinterpret_cast< const char * >( sqlite3_column_text( statement.get(), 0 ) ) );
|
||||
resultFlag = true;
|
||||
}
|
||||
}
|
||||
@ -1107,9 +1161,15 @@ bool QgsMapLayer::loadNamedStyleFromDatabase( const QString &db, const QString &
|
||||
|
||||
|
||||
QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag )
|
||||
{
|
||||
return loadNamedProperty( uri, PropertyType::Style, resultFlag );
|
||||
}
|
||||
|
||||
QString QgsMapLayer::loadNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag )
|
||||
{
|
||||
QgsDebugMsgLevel( QString( "uri = %1 myURI = %2" ).arg( uri, publicSource() ), 4 );
|
||||
|
||||
QgsDebugMsg( "loadNamedProperty" );
|
||||
resultFlag = false;
|
||||
|
||||
QDomDocument myDocument( QStringLiteral( "qgis" ) );
|
||||
@ -1121,6 +1181,7 @@ QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag )
|
||||
QFile myFile( uri );
|
||||
if ( myFile.open( QFile::ReadOnly ) )
|
||||
{
|
||||
QgsDebugMsg( QString( "file found %1" ).arg( uri ) );
|
||||
// read file
|
||||
resultFlag = myDocument.setContent( &myFile, &myErrorMessage, &line, &column );
|
||||
if ( !resultFlag )
|
||||
@ -1132,20 +1193,47 @@ QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag )
|
||||
QFileInfo project( QgsProject::instance()->fileName() );
|
||||
QgsDebugMsgLevel( QString( "project fileName: %1" ).arg( project.absoluteFilePath() ), 4 );
|
||||
|
||||
QString qml;
|
||||
if ( loadNamedStyleFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, qml ) ||
|
||||
( project.exists() && loadNamedStyleFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, qml ) ) ||
|
||||
loadNamedStyleFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, qml ) )
|
||||
QString xml;
|
||||
switch ( type )
|
||||
{
|
||||
resultFlag = myDocument.setContent( qml, &myErrorMessage, &line, &column );
|
||||
if ( !resultFlag )
|
||||
case QgsMapLayer::Style:
|
||||
{
|
||||
myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
|
||||
if ( loadNamedStyleFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
|
||||
( project.exists() && loadNamedStyleFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
|
||||
loadNamedStyleFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
|
||||
{
|
||||
resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
|
||||
if ( !resultFlag )
|
||||
{
|
||||
myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
myErrorMessage = tr( "Style not found in database" );
|
||||
resultFlag = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case QgsMapLayer::Metadata:
|
||||
{
|
||||
if ( loadNamedMetadataFromDatabase( QDir( QgsApplication::qgisSettingsDirPath() ).absoluteFilePath( QStringLiteral( "qgis.qmldb" ) ), uri, xml ) ||
|
||||
( project.exists() && loadNamedMetadataFromDatabase( project.absoluteDir().absoluteFilePath( project.baseName() + ".qmldb" ), uri, xml ) ) ||
|
||||
loadNamedMetadataFromDatabase( QDir( QgsApplication::pkgDataPath() ).absoluteFilePath( QStringLiteral( "resources/qgis.qmldb" ) ), uri, xml ) )
|
||||
{
|
||||
resultFlag = myDocument.setContent( xml, &myErrorMessage, &line, &column );
|
||||
if ( !resultFlag )
|
||||
{
|
||||
myErrorMessage = tr( "%1 at line %2 column %3" ).arg( myErrorMessage ).arg( line ).arg( column );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
myErrorMessage = tr( "Metadata not found in database" );
|
||||
resultFlag = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
myErrorMessage = tr( "Style not found in database" );
|
||||
}
|
||||
}
|
||||
|
||||
@ -1154,13 +1242,33 @@ QString QgsMapLayer::loadNamedStyle( const QString &uri, bool &resultFlag )
|
||||
return myErrorMessage;
|
||||
}
|
||||
|
||||
resultFlag = importNamedStyle( myDocument, myErrorMessage );
|
||||
if ( !resultFlag )
|
||||
myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
|
||||
|
||||
switch ( type )
|
||||
{
|
||||
case QgsMapLayer::Style:
|
||||
resultFlag = importNamedStyle( myDocument, myErrorMessage );
|
||||
if ( !resultFlag )
|
||||
myErrorMessage = tr( "Loading style file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
|
||||
break;
|
||||
case QgsMapLayer::Metadata:
|
||||
resultFlag = importNamedMetadata( myDocument, myErrorMessage );
|
||||
if ( !resultFlag )
|
||||
myErrorMessage = tr( "Loading metadata file %1 failed because:\n%2" ).arg( uri, myErrorMessage );
|
||||
break;
|
||||
}
|
||||
return myErrorMessage;
|
||||
}
|
||||
|
||||
bool QgsMapLayer::importNamedMetadata( QDomDocument &document, QString &errorMessage )
|
||||
{
|
||||
QDomElement myRoot = document.firstChildElement( QStringLiteral( "qgis" ) );
|
||||
if ( myRoot.isNull() )
|
||||
{
|
||||
errorMessage = tr( "Root <qgis> element could not be found" );
|
||||
return false;
|
||||
}
|
||||
|
||||
return mMetadata.readMetadataXml( myRoot );
|
||||
}
|
||||
|
||||
bool QgsMapLayer::importNamedStyle( QDomDocument &myDocument, QString &myErrorMessage )
|
||||
{
|
||||
@ -1210,6 +1318,25 @@ bool QgsMapLayer::importNamedStyle( QDomDocument &myDocument, QString &myErrorMe
|
||||
return readSymbology( myRoot, myErrorMessage, QgsReadWriteContext() ); // TODO: support relative paths in QML?
|
||||
}
|
||||
|
||||
void QgsMapLayer::exportNamedMetadata( QDomDocument &doc, QString &errorMsg ) const
|
||||
{
|
||||
QDomImplementation DomImplementation;
|
||||
QDomDocumentType documentType = DomImplementation.createDocumentType( QStringLiteral( "qgis" ), QStringLiteral( "http://mrcc.com/qgis.dtd" ), QStringLiteral( "SYSTEM" ) );
|
||||
QDomDocument myDocument( documentType );
|
||||
|
||||
QDomElement myRootNode = myDocument.createElement( QStringLiteral( "qgis" ) );
|
||||
myRootNode.setAttribute( QStringLiteral( "version" ), Qgis::QGIS_VERSION );
|
||||
myDocument.appendChild( myRootNode );
|
||||
|
||||
if ( !mMetadata.writeMetadataXml( myRootNode, myDocument ) )
|
||||
{
|
||||
errorMsg = QObject::tr( "Could not save metadata" );
|
||||
return;
|
||||
}
|
||||
|
||||
doc = myDocument;
|
||||
}
|
||||
|
||||
void QgsMapLayer::exportNamedStyle( QDomDocument &doc, QString &errorMsg ) const
|
||||
{
|
||||
QDomImplementation DomImplementation;
|
||||
@ -1256,13 +1383,19 @@ QString QgsMapLayer::saveDefaultStyle( bool &resultFlag )
|
||||
return saveNamedStyle( styleURI(), resultFlag );
|
||||
}
|
||||
|
||||
QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag )
|
||||
QString QgsMapLayer::saveNamedMetadata( const QString &uri, bool &resultFlag )
|
||||
{
|
||||
QString myErrorMessage;
|
||||
QDomDocument myDocument;
|
||||
exportNamedStyle( myDocument, myErrorMessage );
|
||||
return saveNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
|
||||
}
|
||||
|
||||
// check if the uri is a file or ends with .qml,
|
||||
QString QgsMapLayer::loadNamedMetadata( const QString &uri, bool &resultFlag )
|
||||
{
|
||||
return loadNamedProperty( uri, QgsMapLayer::Metadata, resultFlag );
|
||||
}
|
||||
|
||||
QString QgsMapLayer::saveNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag )
|
||||
{
|
||||
// check if the uri is a file or ends with .qml/.qmd,
|
||||
// which indicates that it should become one
|
||||
// everything else goes to the database
|
||||
QString filename;
|
||||
@ -1290,8 +1423,21 @@ QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag )
|
||||
filename = uri;
|
||||
}
|
||||
|
||||
QString myErrorMessage;
|
||||
QDomDocument myDocument;
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
exportNamedMetadata( myDocument, myErrorMessage );
|
||||
break;
|
||||
|
||||
case Style:
|
||||
exportNamedStyle( myDocument, myErrorMessage );
|
||||
break;
|
||||
}
|
||||
|
||||
QFileInfo myFileInfo( filename );
|
||||
if ( myFileInfo.exists() || filename.endsWith( QLatin1String( ".qml" ), Qt::CaseInsensitive ) )
|
||||
if ( myFileInfo.exists() || filename.endsWith( QgsMapLayer::extensionPropertyType( type ), Qt::CaseInsensitive ) )
|
||||
{
|
||||
QFileInfo myDirInfo( myFileInfo.path() ); //excludes file name
|
||||
if ( !myDirInfo.isWritable() )
|
||||
@ -1299,8 +1445,8 @@ QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag )
|
||||
return tr( "The directory containing your dataset needs to be writable!" );
|
||||
}
|
||||
|
||||
// now construct the file name for our .qml style file
|
||||
QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + ".qml";
|
||||
// now construct the file name for our .qml or .qmd file
|
||||
QString myFileName = myFileInfo.path() + QDir::separator() + myFileInfo.completeBaseName() + QgsMapLayer::extensionPropertyType( type );
|
||||
|
||||
QFile myFile( myFileName );
|
||||
if ( myFile.open( QFile::WriteOnly | QFile::Truncate ) )
|
||||
@ -1310,12 +1456,27 @@ QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag )
|
||||
myDocument.save( myFileStream, 2 );
|
||||
myFile.close();
|
||||
resultFlag = true;
|
||||
return tr( "Created default style file as %1" ).arg( myFileName );
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
return tr( "Created default metadata file as %1" ).arg( myFileName );
|
||||
|
||||
case Style:
|
||||
return tr( "Created default style file as %1" ).arg( myFileName );
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
resultFlag = false;
|
||||
return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
return tr( "ERROR: Failed to created default metadata file as %1. Check file permissions and retry." ).arg( myFileName );
|
||||
|
||||
case Style:
|
||||
return tr( "ERROR: Failed to created default style file as %1. Check file permissions and retry." ).arg( myFileName );
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -1335,18 +1496,45 @@ QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag )
|
||||
QByteArray param0 = uri.toUtf8();
|
||||
QByteArray param1 = qml.toUtf8();
|
||||
|
||||
QString mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
|
||||
QString mySql;
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
mySql = QStringLiteral( "create table if not exists tbl_metadata(metadata varchar primary key,qmd varchar)" );
|
||||
break;
|
||||
|
||||
case Style:
|
||||
mySql = QStringLiteral( "create table if not exists tbl_styles(style varchar primary key,qml varchar)" );
|
||||
break;
|
||||
}
|
||||
|
||||
statement = database.prepare( mySql, myResult );
|
||||
if ( myResult == SQLITE_OK )
|
||||
{
|
||||
if ( sqlite3_step( statement.get() ) != SQLITE_DONE )
|
||||
{
|
||||
resultFlag = false;
|
||||
return tr( "The style table could not be created." );
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
return tr( "The metadata table could not be created." );
|
||||
|
||||
case Style:
|
||||
return tr( "The style table could not be created." );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
mySql = QStringLiteral( "insert into tbl_metadata(metadata,qmd) values (?,?)" );
|
||||
break;
|
||||
|
||||
case Style:
|
||||
mySql = QStringLiteral( "insert into tbl_styles(style,qml) values (?,?)" );
|
||||
break;
|
||||
}
|
||||
statement = database.prepare( mySql, myResult );
|
||||
if ( myResult == SQLITE_OK )
|
||||
{
|
||||
@ -1355,15 +1543,33 @@ QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag )
|
||||
sqlite3_step( statement.get() ) == SQLITE_DONE )
|
||||
{
|
||||
resultFlag = true;
|
||||
myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
myErrorMessage = tr( "The metadata %1 was saved to database" ).arg( uri );
|
||||
break;
|
||||
|
||||
case Style:
|
||||
myErrorMessage = tr( "The style %1 was saved to database" ).arg( uri );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !resultFlag )
|
||||
{
|
||||
QString mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
|
||||
statement = database.prepare( mySql, myResult );
|
||||
QString mySql;
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
mySql = QStringLiteral( "update tbl_metadata set qmd=? where metadata=?" );
|
||||
break;
|
||||
|
||||
case Style:
|
||||
mySql = QStringLiteral( "update tbl_styles set qml=? where style=?" );
|
||||
break;
|
||||
}
|
||||
statement = database.prepare( mySql, myResult );
|
||||
if ( myResult == SQLITE_OK )
|
||||
{
|
||||
if ( sqlite3_bind_text( statement.get(), 2, param0.data(), param0.length(), SQLITE_STATIC ) == SQLITE_OK &&
|
||||
@ -1371,18 +1577,45 @@ QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag )
|
||||
sqlite3_step( statement.get() ) == SQLITE_DONE )
|
||||
{
|
||||
resultFlag = true;
|
||||
myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
myErrorMessage = tr( "The metadata %1 was updated in the database." ).arg( uri );
|
||||
break;
|
||||
|
||||
case Style:
|
||||
myErrorMessage = tr( "The style %1 was updated in the database." ).arg( uri );
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resultFlag = false;
|
||||
myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
myErrorMessage = tr( "The metadata %1 could not be updated in the database." ).arg( uri );
|
||||
break;
|
||||
|
||||
case Style:
|
||||
myErrorMessage = tr( "The style %1 could not be updated in the database." ).arg( uri );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
resultFlag = false;
|
||||
myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
|
||||
switch ( type )
|
||||
{
|
||||
case Metadata:
|
||||
myErrorMessage = tr( "The metadata %1 could not be inserted into database." ).arg( uri );
|
||||
break;
|
||||
|
||||
case Style:
|
||||
myErrorMessage = tr( "The style %1 could not be inserted into database." ).arg( uri );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1390,6 +1623,11 @@ QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag )
|
||||
return myErrorMessage;
|
||||
}
|
||||
|
||||
QString QgsMapLayer::saveNamedStyle( const QString &uri, bool &resultFlag )
|
||||
{
|
||||
return saveNamedProperty( uri, QgsMapLayer::Style, resultFlag );
|
||||
}
|
||||
|
||||
void QgsMapLayer::exportSldStyle( QDomDocument &doc, QString &errorMsg ) const
|
||||
{
|
||||
QDomDocument myDocument = QDomDocument();
|
||||
|
@ -98,6 +98,16 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
PluginLayer
|
||||
};
|
||||
|
||||
/**
|
||||
* Maplayer has a style and a metadata property
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
enum PropertyType
|
||||
{
|
||||
Style = 0,
|
||||
Metadata,
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor for QgsMapLayer
|
||||
* \param type layer type
|
||||
@ -126,6 +136,13 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
*/
|
||||
QgsMapLayer::LayerType type() const;
|
||||
|
||||
/**
|
||||
* Returns the extension of a Property.
|
||||
* \returns The extension
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
static QString extensionPropertyType( PropertyType type );
|
||||
|
||||
//! Returns the layer's unique ID, which is used to access this layer from QgsProject.
|
||||
QString id() const;
|
||||
|
||||
@ -525,6 +542,96 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
*/
|
||||
static QString formatLayerName( const QString &name );
|
||||
|
||||
/**
|
||||
* Retrieve the metadata URI for this layer
|
||||
* (either as a .qmd file on disk or as a
|
||||
* record in the users style table in their personal qgis.db)
|
||||
* \returns a QString with the metadata file name
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual QString metadataUri() const;
|
||||
|
||||
/**
|
||||
* Export the current metadata of this layer as named metadata in a QDomDocument
|
||||
* \param doc the target QDomDocument
|
||||
* \param errorMsg this QString will be initialized on error
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
void exportNamedMetadata( QDomDocument &doc, QString &errorMsg ) const;
|
||||
|
||||
/**
|
||||
* Save the current metadata of this layer as the default metadata
|
||||
* (either as a .qmd file on disk or as a
|
||||
* record in the users style table in their personal qgis.db)
|
||||
* \param resultFlag a reference to a flag that will be set to false if
|
||||
* we did not manage to save the default metadata.
|
||||
* \returns a QString with any status messages
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual QString saveDefaultMetadata( bool &resultFlag SIP_OUT );
|
||||
|
||||
/**
|
||||
* Save the current metadata of this layer as a named metadata
|
||||
* (either as a .qmd file on disk or as a
|
||||
* record in the users style table in their personal qgis.db)
|
||||
* \param uri the file name or other URI for the
|
||||
* metadata file. First an attempt will be made to see if this
|
||||
* is a file and save to that, if that fails the qgis.db metadata
|
||||
* table will be used to create a metadata entry who's
|
||||
* key matches the URI.
|
||||
* \param resultFlag a reference to a flag that will be set to false if
|
||||
* we did not manage to save the default metadata.
|
||||
* \returns a QString with any status messages
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QString saveNamedMetadata( const QString &uri, bool &resultFlag );
|
||||
|
||||
/**
|
||||
* Retrieve a named metadata for this layer if one
|
||||
* exists (either as a .qmd file on disk or as a
|
||||
* record in the users style table in their personal qgis.db)
|
||||
* \param uri - the file name or other URI for the
|
||||
* metadata file. First an attempt will be made to see if this
|
||||
* is a file and load that, if that fails the qgis.db metadata
|
||||
* table will be consulted to see if there is a metadata who's
|
||||
* key matches the URI.
|
||||
* \param resultFlag a reference to a flag that will be set to false if
|
||||
* we did not manage to load the default metadata.
|
||||
* \returns a QString with any status messages
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
virtual QString loadNamedMetadata( const QString &uri, bool &resultFlag SIP_OUT );
|
||||
|
||||
/**
|
||||
* Retrieve the default metadata for this layer if one
|
||||
* exists (either as a .qmd file on disk or as a
|
||||
* record in the users metadata table in their personal qgis.db)
|
||||
* \param resultFlag a reference to a flag that will be set to false if
|
||||
* we did not manage to load the default metadata.
|
||||
* \returns a QString with any status messages
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
QString loadDefaultMetadata( bool &resultFlag );
|
||||
|
||||
/**
|
||||
* Retrieve a named metadata for this layer from a sqlite database.
|
||||
* \param db path to sqlite database
|
||||
* \param uri uri for table
|
||||
* \param qmd will be set to QMD xml metadata content from database
|
||||
* \returns true if style was successfully loaded
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
bool loadNamedMetadataFromDatabase( const QString &db, const QString &uri, QString &qmd );
|
||||
|
||||
/**
|
||||
* Import the metadata of this layer from a QDomDocument
|
||||
* \param document source QDomDocument
|
||||
* \param errorMessage this QString will be initialized on error
|
||||
* \returns true on success
|
||||
* \since QGIS 3.0
|
||||
*/
|
||||
bool importNamedMetadata( QDomDocument &document, QString &errorMessage );
|
||||
|
||||
/**
|
||||
* Retrieve the style URI for this layer
|
||||
* (either as a .qml file on disk or as a
|
||||
@ -1169,6 +1276,11 @@ class CORE_EXPORT QgsMapLayer : public QObject
|
||||
|
||||
private:
|
||||
|
||||
virtual QString baseURI( PropertyType type ) const;
|
||||
QString saveNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag );
|
||||
QString loadNamedProperty( const QString &uri, QgsMapLayer::PropertyType type, bool &resultFlag );
|
||||
bool loadNamedPropertyFromDatabase( const QString &db, const QString &uri, QString &xml, QgsMapLayer::PropertyType type );
|
||||
|
||||
/**
|
||||
* This method returns true by default but can be overwritten to specify
|
||||
* that a certain layer is writable.
|
||||
|
@ -820,6 +820,12 @@ void QgsMetadataWidget::acceptMetadata()
|
||||
mLayer->setMetadata( mMetadata );
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::setMetadata( const QgsLayerMetadata &metadata )
|
||||
{
|
||||
mMetadata = metadata;
|
||||
setPropertiesFromLayer();
|
||||
}
|
||||
|
||||
void QgsMetadataWidget::syncFromCategoriesTabToKeywordsTab() const
|
||||
{
|
||||
if ( mCategoriesModel->rowCount() > 0 )
|
||||
|
@ -66,6 +66,11 @@ class GUI_EXPORT QgsMetadataWidget : public QWidget, private Ui::QgsMetadataWidg
|
||||
*/
|
||||
void acceptMetadata();
|
||||
|
||||
/**
|
||||
* Sets the layer's \a metadata store.
|
||||
*/
|
||||
virtual void setMetadata( const QgsLayerMetadata &metadata );
|
||||
|
||||
/**
|
||||
* Returns a list of languages available by default in the wizard.
|
||||
*/
|
||||
|
@ -13,6 +13,7 @@ __copyright__ = 'Copyright 2017, The QGIS Project'
|
||||
__revision__ = '$Format:%H$'
|
||||
|
||||
import qgis # NOQA
|
||||
import tempfile
|
||||
|
||||
from qgis.core import (QgsReadWriteContext,
|
||||
QgsVectorLayer,
|
||||
@ -88,6 +89,22 @@ class TestQgsMapLayer(unittest.TestCase):
|
||||
self.assertTrue(layer2.hasAutoRefreshEnabled())
|
||||
self.assertEqual(layer2.autoRefreshInterval(), 56)
|
||||
|
||||
def testReadWriteMetadata(self):
|
||||
layer = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory")
|
||||
m = layer.metadata()
|
||||
# Only abstract, more tests are done in test_qgslayermetadata.py
|
||||
m.setAbstract('My abstract')
|
||||
layer.setMetadata(m)
|
||||
self.assertTrue(layer.metadata().abstract(), 'My abstract')
|
||||
destination = tempfile.NamedTemporaryFile(suffix='.qmd').name
|
||||
message, status = layer.saveNamedMetadata(destination)
|
||||
self.assertTrue(status, message)
|
||||
|
||||
layer2 = QgsVectorLayer("Point?field=fldtxt:string", "layer", "memory")
|
||||
message, status = layer2.loadNamedMetadata(destination)
|
||||
self.assertTrue(status)
|
||||
self.assertTrue(layer2.metadata().abstract(), 'My abstract')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
Loading…
x
Reference in New Issue
Block a user