Skip to content

Commit

Permalink
Merge pull request #32628 from elpaso/save-multiple-styles
Browse files Browse the repository at this point in the history
[feature] Add save multiple styles action to style menu
  • Loading branch information
elpaso committed Nov 11, 2019
2 parents b490f86 + 102911c commit 956c468
Show file tree
Hide file tree
Showing 6 changed files with 357 additions and 126 deletions.
137 changes: 134 additions & 3 deletions src/app/qgsvectorlayerproperties.cpp
Expand Up @@ -132,8 +132,20 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
QMenu *menuStyle = new QMenu( this );
mActionLoadStyle = menuStyle->addAction( tr( "Load Style…" ) );
connect( mActionLoadStyle, &QAction::triggered, this, &QgsVectorLayerProperties::loadStyle );
mActionSaveStyle = menuStyle->addAction( tr( "Save Style…" ) );

// If we have multiple styles, offer an option to save them at once
if ( lyr->styleManager()->styles().count() > 1 )
{
mActionSaveStyle = menuStyle->addAction( tr( "Save Current Style…" ) );
mActionSaveMultipleStyles = menuStyle->addAction( tr( "Save All Styles…" ) );
connect( mActionSaveMultipleStyles, &QAction::triggered, this, &QgsVectorLayerProperties::saveMultipleStylesAs );
}
else
{
mActionSaveStyle = menuStyle->addAction( tr( "Save Style…" ) );
}
connect( mActionSaveStyle, &QAction::triggered, this, &QgsVectorLayerProperties::saveStyleAs );

menuStyle->addSeparator();
menuStyle->addAction( tr( "Save as Default" ), this, &QgsVectorLayerProperties::saveDefaultStyle_clicked );
menuStyle->addAction( tr( "Restore Default" ), this, &QgsVectorLayerProperties::loadDefaultStyle_clicked );
Expand Down Expand Up @@ -380,12 +392,12 @@ QgsVectorLayerProperties::QgsVectorLayerProperties(
mLayersDependenciesTreeGroup->setItemVisibilityChecked( false );

QSet<QString> dependencySources;
const auto constDependencies = mLayer->dependencies();
const QSet<QgsMapLayerDependency> constDependencies = mLayer->dependencies();
for ( const QgsMapLayerDependency &dep : constDependencies )
{
dependencySources << dep.layerId();
}
const auto constFindLayers = mLayersDependenciesTreeGroup->findLayers();
const QList<QgsLayerTreeLayer *> constFindLayers = mLayersDependenciesTreeGroup->findLayers();
for ( QgsLayerTreeLayer *layer : constFindLayers )
{
layer->setItemVisibilityChecked( dependencySources.contains( layer->layerId() ) );
Expand Down Expand Up @@ -1262,6 +1274,125 @@ void QgsVectorLayerProperties::saveStyleAs()
}
}

void QgsVectorLayerProperties::saveMultipleStylesAs()
{
QgsVectorLayerSaveStyleDialog dlg( mLayer );
dlg.setSaveOnlyCurrentStyle( false );
QgsSettings settings;

if ( dlg.exec() )
{
apply();

// Store the original style, that we can restore at the end
const QString originalStyle { mLayer->styleManager()->currentStyle() };
const QListWidget *stylesWidget { dlg.stylesWidget() };

// Collect selected (checked) styles for export/save
QStringList stylesSelected;
for ( int i = 0; i < stylesWidget->count(); i++ )
{
if ( stylesWidget->item( i )->checkState() == Qt::CheckState::Checked )
{
stylesSelected.push_back( stylesWidget->item( i )->text() );
}
}

if ( ! stylesSelected.isEmpty() )
{
int styleIndex = 0;
for ( const QString &styleName : qgis::as_const( stylesSelected ) )
{
bool defaultLoadedFlag = false;

StyleType type = dlg.currentStyleType();
mLayer->styleManager()->setCurrentStyle( styleName );
switch ( type )
{
case QML:
case SLD:
{
QString message;
const QString filePath { dlg.outputFilePath() };
QString safePath { filePath };
if ( styleIndex > 0 && stylesSelected.count( ) > 1 )
{
int i = 1;
while ( QFile::exists( safePath ) )
{
const QFileInfo fi { filePath };
safePath = QString( filePath ).replace( '.' + fi.completeSuffix(), QStringLiteral( "_%1.%2" )
.arg( QString::number( i ) )
.arg( fi.completeSuffix() ) );
i++;
}
}
if ( type == QML )
message = mLayer->saveNamedStyle( safePath, defaultLoadedFlag, dlg.styleCategories() );
else
message = mLayer->saveSldStyle( safePath, 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( "Save Style" ), message );
}

break;
}
case DB:
{
QString infoWindowTitle = QObject::tr( "Save style '%1' to DB (%2)" )
.arg( styleName )
.arg( mLayer->providerType() );
QString msgError;

QgsVectorLayerSaveStyleDialog::SaveToDbSettings dbSettings = dlg.saveToDbSettings();

// If a name is defined, we add _1 etc. else we use the style name
QString name { dbSettings.name };
if ( name.isEmpty() )
{
name = styleName;
}
else
{
QStringList ids, names, descriptions;
mLayer->listStylesInDatabase( ids, names, descriptions, msgError );
int i = 1;
while ( names.contains( name ) )
{
name = QStringLiteral( "%1 %2" ).arg( name ).arg( QString::number( i ) );
i++;
}
}
mLayer->saveStyleToDatabase( name, dbSettings.description, dbSettings.isDefault, dbSettings.uiFileContent, msgError );

if ( !msgError.isNull() )
{
QgisApp::instance()->messageBar()->pushMessage( infoWindowTitle, msgError, Qgis::Warning, QgisApp::instance()->messageTimeout() );
}
else
{
QgisApp::instance()->messageBar()->pushMessage( infoWindowTitle, tr( "Style '%1' saved" ).arg( styleName ),
Qgis::Info, QgisApp::instance()->messageTimeout() );
}
break;
}
}
styleIndex ++;
}
// Restore original style
mLayer->styleManager()->setCurrentStyle( originalStyle );
}
} // Nothing selected!
}

void QgsVectorLayerProperties::aboutToShowStyleMenu()
{
// this should be unified with QgsRasterLayerProperties::aboutToShowStyleMenu()
Expand Down
4 changes: 4 additions & 0 deletions src/app/qgsvectorlayerproperties.h
Expand Up @@ -150,6 +150,9 @@ class APP_EXPORT QgsVectorLayerProperties : public QgsOptionsDialogBase, private
//! Save the style
void saveStyleAs();

//! Save multiple styles
void saveMultipleStylesAs();

//! Load the style
void loadStyle();

Expand Down Expand Up @@ -199,6 +202,7 @@ class APP_EXPORT QgsVectorLayerProperties : public QgsOptionsDialogBase, private

QAction *mActionLoadStyle = nullptr;
QAction *mActionSaveStyle = nullptr;
QAction *mActionSaveMultipleStyles = nullptr;

//! Renderer dialog which is shown
QgsRendererPropertiesDialog *mRendererDialog = nullptr;
Expand Down
80 changes: 78 additions & 2 deletions src/app/qgsvectorlayersavestyledialog.cpp
Expand Up @@ -85,6 +85,9 @@ QgsVectorLayerSaveStyleDialog::QgsVectorLayerSaveStyleDialog( QgsVectorLayer *la
mStyleCategoriesListView->setModel( mModel );

mStyleCategoriesListView->adjustSize();

setupMultipleStyles();

}

void QgsVectorLayerSaveStyleDialog::accept()
Expand All @@ -96,8 +99,25 @@ void QgsVectorLayerSaveStyleDialog::accept()
void QgsVectorLayerSaveStyleDialog::updateSaveButtonState()
{
QgsVectorLayerProperties::StyleType type = currentStyleType();
buttonBox->button( QDialogButtonBox::Ok )->setEnabled( ( type == QgsVectorLayerProperties::DB && !mDbStyleNameEdit->text().isEmpty() ) ||
( type != QgsVectorLayerProperties::DB && !mFileWidget->filePath().isEmpty() ) );
bool enabled { false };
switch ( type )
{
case QgsVectorLayerProperties::DB:
if ( saveOnlyCurrentStyle( ) )
{
enabled = ! mDbStyleNameEdit->text().isEmpty();
}
else
{
enabled = true;
}
break;
case QgsVectorLayerProperties::QML:
case QgsVectorLayerProperties::SLD:
enabled = ! mFileWidget->filePath().isEmpty();
break;
}
buttonBox->button( QDialogButtonBox::Ok )->setEnabled( enabled );
}

QgsVectorLayerSaveStyleDialog::SaveToDbSettings QgsVectorLayerSaveStyleDialog::saveToDbSettings() const
Expand Down Expand Up @@ -156,6 +176,62 @@ void QgsVectorLayerSaveStyleDialog::readUiFileContent( const QString &filePath )
}
}

void QgsVectorLayerSaveStyleDialog::setupMultipleStyles()
{
// Show/hide part of the UI according to multiple style support
if ( ! mSaveOnlyCurrentStyle )
{
const QgsMapLayerStyleManager *styleManager { mLayer->styleManager() };
const QStringList constStyles = styleManager->styles();
for ( const QString &name : constStyles )
{
QListWidgetItem *item = new QListWidgetItem( name, mStylesWidget );
item->setCheckState( Qt::CheckState::Checked );
// Highlight the current style
if ( name == styleManager->currentStyle() )
{
item->setToolTip( tr( "Current style" ) );
QFont font { item->font() };
font.setItalic( true );
item->setFont( font );
}
mStylesWidget->addItem( item );
}
mDbStyleNameEdit->setToolTip( tr( "Leave blank to use style names or set the base name (an incremental number will be automatically appended)" ) );
}
else
{
mDbStyleNameEdit->setToolTip( QString() );
}

mStylesWidget->setVisible( ! mSaveOnlyCurrentStyle );
mStylesWidgetLabel->setVisible( ! mSaveOnlyCurrentStyle );

mDbStyleDescriptionEdit->setVisible( mSaveOnlyCurrentStyle );
descriptionLabel->setVisible( mSaveOnlyCurrentStyle );
mDbStyleUseAsDefault->setVisible( mSaveOnlyCurrentStyle );
}

bool QgsVectorLayerSaveStyleDialog::saveOnlyCurrentStyle() const
{
return mSaveOnlyCurrentStyle;
}

void QgsVectorLayerSaveStyleDialog::setSaveOnlyCurrentStyle( bool saveOnlyCurrentStyle )
{
if ( mSaveOnlyCurrentStyle != saveOnlyCurrentStyle )
{
mSaveOnlyCurrentStyle = saveOnlyCurrentStyle;
setupMultipleStyles();
}
}

const QListWidget *QgsVectorLayerSaveStyleDialog::stylesWidget()
{
return mStylesWidget;
}


void QgsVectorLayerSaveStyleDialog::showHelp()
{
QgsHelp::openHelp( QStringLiteral( "introduction/general_tools.html#save-and-share-layer-properties" ) );
Expand Down
12 changes: 12 additions & 0 deletions src/app/qgsvectorlayersavestyledialog.h
Expand Up @@ -24,6 +24,11 @@ class QgsVectorLayer;
class QgsMapLayerStyleCategoriesModel;


/**
* The QgsVectorLayerSaveStyleDialog class provides the UI to save the current style
* or multiple styles into different storage containers (QML, SLD and DB).
* The user can select what categories must be saved.
*/
class QgsVectorLayerSaveStyleDialog : public QDialog, private Ui::QgsVectorLayerSaveStyleDialog
{
Q_OBJECT
Expand All @@ -47,6 +52,11 @@ class QgsVectorLayerSaveStyleDialog : public QDialog, private Ui::QgsVectorLayer

QgsVectorLayerProperties::StyleType currentStyleType() const;

bool saveOnlyCurrentStyle() const;
void setSaveOnlyCurrentStyle( bool saveCurrentStyle );

const QListWidget *stylesWidget( );

public slots:
void accept() override;

Expand All @@ -56,9 +66,11 @@ class QgsVectorLayerSaveStyleDialog : public QDialog, private Ui::QgsVectorLayer
void readUiFileContent( const QString &filePath );

private:
void setupMultipleStyles();
QgsVectorLayer *mLayer = nullptr;
QgsMapLayerStyleCategoriesModel *mModel;
QString mUiFileContent;
bool mSaveOnlyCurrentStyle = true;
};

#endif // QGSVECTORLAYERSAVESTYLE_H

0 comments on commit 956c468

Please sign in to comment.