QGIS API Documentation 3.41.0-Master (45a0abf3bec)
Loading...
Searching...
No Matches
qgsmaplayerloadstyledialog.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsmaplayerloadstyledialog.cpp
3 ---------------------
4 begin : April 2013
5 copyright : (C) 2013 by Emilio Loi
6 email : loi at faunalia dot it
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16#include <QMessageBox>
17#include <QVector>
18
20#include "moc_qgsmaplayerloadstyledialog.cpp"
21#include "qgslogger.h"
22#include "qgssettings.h"
25#include "qgshelp.h"
26#include "qgsapplication.h"
27#include "qgsgui.h"
28
30 : QDialog( parent )
31 , mLayer( layer )
32{
33 setupUi( this );
35 setWindowTitle( tr( "Database Styles Manager" ) );
36
37 mDeleteButton = mButtonBox->button( QDialogButtonBox::StandardButton::Close );
38 mDeleteButton->setText( tr( "Delete Style" ) );
39 mDeleteButton->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionDeleteSelected.svg" ) ) );
40 mLoadButton = mButtonBox->button( QDialogButtonBox::StandardButton::Open );
41 mLoadButton->setText( tr( "Load Style" ) );
42 mCancelButton = mButtonBox->button( QDialogButtonBox::StandardButton::Cancel );
43
44 QgsSettings settings;
45
46 const QString myLastUsedDir = settings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
47
48 // load style type combobox
49 connect( mStyleTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [ = ]( int )
50 {
54 mFromDbWidget->setVisible( type == QgsLayerPropertiesDialog::StyleType::DatasourceDatabase );
56
57 mStyleCategoriesListView->setEnabled( currentStyleType() != QgsLayerPropertiesDialog::StyleType::SLD );
58 updateLoadButtonState();
59 } );
60 mStyleTypeComboBox->addItem( tr( "From file" ), QgsLayerPropertiesDialog::QML ); // QML is used as entry, but works for SLD too, see currentStyleType()
61 mStyleTypeComboBox->addItem( tr( "Default from local database" ), QgsLayerPropertiesDialog::UserDatabase );
62
64 {
65 mStyleTypeComboBox->addItem( tr( "From datasource database" ), QgsLayerPropertiesDialog::StyleType::DatasourceDatabase );
66 if ( settings.value( QStringLiteral( "style/lastLoadStyleTypeSelection" ) ) == QgsLayerPropertiesDialog::StyleType::DatasourceDatabase )
67 {
68 mStyleTypeComboBox->setCurrentIndex( mStyleTypeComboBox->findData( QgsLayerPropertiesDialog::StyleType::DatasourceDatabase ) );
69 }
70 }
71
72 // fill style categories
73 mModel = new QgsMapLayerStyleCategoriesModel( mLayer->type(), this );
74 const QgsMapLayer::StyleCategories lastStyleCategories = settings.flagValue( QStringLiteral( "style/lastStyleCategories" ), QgsMapLayer::AllStyleCategories );
75 mModel->setCategories( lastStyleCategories );
76 mStyleCategoriesListView->setModel( mModel );
77 mStyleCategoriesListView->setWordWrap( true );
78 mStyleCategoriesListView->setItemDelegate( new QgsCategoryDisplayLabelDelegate( this ) );
79
80 // load from file setup
81 switch ( mLayer->type() )
82 {
84 mFileWidget->setFilter( tr( "QGIS Layer Style File, SLD File" ) + QStringLiteral( " (*.qml *.sld)" ) );
85 break;
86
88 mFileWidget->setFilter( tr( "All Styles" ) + QStringLiteral( " (*.qml *.json);;" )
89 + tr( "QGIS Layer Style File" ) + QStringLiteral( " (*.qml);;" )
90 + tr( "MapBox GL Style JSON File" ) + QStringLiteral( " (*.json)" ) );
91 break;
92
100 break;
101
102 }
103
104 mFileWidget->setStorageMode( QgsFileWidget::GetFile );
105 mFileWidget->setDefaultRoot( myLastUsedDir );
106 connect( mFileWidget, &QgsFileWidget::fileChanged, this, [ = ]( const QString & path )
107 {
108 mStyleCategoriesListView->setEnabled( currentStyleType() != QgsLayerPropertiesDialog::SLD );
109 QgsSettings settings;
110 const QFileInfo tmplFileInfo( path );
111 settings.setValue( QStringLiteral( "style/lastStyleDir" ), tmplFileInfo.absolutePath() );
112
113 updateLoadButtonState();
114 } );
115
116 // load from DB
117 mLoadButton->setDisabled( true );
118 mDeleteButton->setDisabled( true );
119 mRelatedTable->setEditTriggers( QTableWidget::NoEditTriggers );
120 mRelatedTable->horizontalHeader()->setStretchLastSection( true );
121 mRelatedTable->setSelectionBehavior( QTableWidget::SelectRows );
122 mRelatedTable->verticalHeader()->setVisible( false );
123 mOthersTable->setEditTriggers( QTableWidget::NoEditTriggers );
124 mOthersTable->horizontalHeader()->setStretchLastSection( true );
125 mOthersTable->setSelectionBehavior( QTableWidget::SelectRows );
126 mOthersTable->verticalHeader()->setVisible( false );
127 connect( mRelatedTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onRelatedTableSelectionChanged );
128 connect( mOthersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onOthersTableSelectionChanged );
129 connect( mRelatedTable, &QTableWidget::doubleClicked, this, &QDialog::accept );
130 connect( mOthersTable, &QTableWidget::doubleClicked, this, &QDialog::accept );
131 connect( mCancelButton, &QPushButton::clicked, this, &QDialog::reject );
132 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsMapLayerLoadStyleDialog::showHelp );
133 connect( mLoadButton, &QPushButton::clicked, this, &QDialog::accept );
134 connect( mDeleteButton, &QPushButton::clicked, this, &QgsMapLayerLoadStyleDialog::deleteStyleFromDB );
135 connect( this, &QgsMapLayerLoadStyleDialog::rejected, [ = ]
136 {
137 QgsSettings().setValue( QStringLiteral( "style/lastLoadStyleTypeSelection" ), currentStyleType() );
138 } );
139
140 setTabOrder( mRelatedTable, mOthersTable );
141
142 mStyleCategoriesListView->adjustSize();
143
144 // select and deselect all categories
145 connect( mSelectAllButton, &QPushButton::clicked, this, &QgsMapLayerLoadStyleDialog::selectAll );
146 connect( mDeselectAllButton, &QPushButton::clicked, this, &QgsMapLayerLoadStyleDialog::deselectAll );
147 connect( mInvertSelectionButton, &QPushButton::clicked, this, &QgsMapLayerLoadStyleDialog::invertSelection );
148}
149
150void QgsMapLayerLoadStyleDialog::invertSelection()
151{
152 for ( int i = 0; i < mModel->rowCount( QModelIndex() ); i++ )
153 {
154 QModelIndex index = mModel->index( i, 0 );
155 Qt::CheckState currentState = Qt::CheckState( mModel->data( index, Qt::CheckStateRole ).toInt() );
156 Qt::CheckState newState = ( currentState == Qt::Checked ) ? Qt::Unchecked : Qt::Checked;
157 mModel->setData( index, newState, Qt::CheckStateRole );
158 }
159}
160
161void QgsMapLayerLoadStyleDialog::selectAll()
162{
163 for ( int i = 0; i < mModel->rowCount( QModelIndex() ); i++ )
164 {
165 QModelIndex index = mModel->index( i, 0 );
166 mModel->setData( index, Qt::Checked, Qt::CheckStateRole );
167 }
168}
169
170void QgsMapLayerLoadStyleDialog::deselectAll()
171{
172 for ( int i = 0; i < mModel->rowCount( QModelIndex() ); i++ )
173 {
174 QModelIndex index = mModel->index( i, 0 );
175 mModel->setData( index, Qt::Unchecked, Qt::CheckStateRole );
176 }
177}
178
183
185{
186 QgsLayerPropertiesDialog::StyleType type = mStyleTypeComboBox->currentData().value<QgsLayerPropertiesDialog::StyleType>();
187 if ( type == QgsLayerPropertiesDialog::QML )
188 {
189 const QFileInfo fi( mFileWidget->filePath() );
190 if ( fi.exists() && fi.suffix().compare( QStringLiteral( "sld" ), Qt::CaseInsensitive ) == 0 )
192 }
193 return type;
194}
195
197{
198 return QFileInfo( mFileWidget->filePath() ).suffix();
199}
200
202{
203 return mFileWidget->filePath();
204}
205
206void QgsMapLayerLoadStyleDialog::initializeLists( const QStringList &ids, const QStringList &names, const QStringList &descriptions, int sectionLimit )
207{
208 // -1 means no ids
209 mSectionLimit = sectionLimit;
210 const int relatedTableNOfCols = sectionLimit > 0 ? 2 : 1;
211 const int othersTableNOfCols = ( sectionLimit >= 0 && ids.count() - sectionLimit > 0 ) ? 2 : 1;
212 const QString twoColsHeader( QStringLiteral( "Name;Description" ) );
213 const QString oneColsHeader( QStringLiteral( "No styles found in the database" ) );
214 const QString relatedTableHeader = relatedTableNOfCols == 1 ? oneColsHeader : twoColsHeader;
215 const QString othersTableHeader = othersTableNOfCols == 1 ? oneColsHeader : twoColsHeader;
216
217 mRelatedTable->setColumnCount( relatedTableNOfCols );
218 mOthersTable->setColumnCount( othersTableNOfCols );
219 mRelatedTable->setHorizontalHeaderLabels( relatedTableHeader.split( ';' ) );
220 mOthersTable->setHorizontalHeaderLabels( othersTableHeader.split( ';' ) );
221 mRelatedTable->setRowCount( sectionLimit );
222 mOthersTable->setRowCount( sectionLimit >= 0 ? ( ids.count() - sectionLimit ) : 0 );
223 mRelatedTable->setDisabled( relatedTableNOfCols == 1 );
224 mOthersTable->setDisabled( othersTableNOfCols == 1 );
225
226 if ( sectionLimit >= 0 )
227 {
228 for ( int i = 0; i < sectionLimit; i++ )
229 {
230 QTableWidgetItem *item = new QTableWidgetItem( names.value( i, QString() ) );
231 item->setData( Qt::UserRole, ids[i] );
232 mRelatedTable->setItem( i, 0, item );
233 mRelatedTable->setItem( i, 1, new QTableWidgetItem( descriptions.value( i, QString() ) ) );
234 }
235 for ( int i = sectionLimit; i < ids.count(); i++ )
236 {
237 const int j = i - sectionLimit;
238 QTableWidgetItem *item = new QTableWidgetItem( names.value( i, QString() ) );
239 item->setData( Qt::UserRole, ids[i] );
240 mOthersTable->setItem( j, 0, item );
241 mOthersTable->setItem( j, 1, new QTableWidgetItem( descriptions.value( i, QString() ) ) );
242 }
243 }
244}
245
247{
248 return mSelectedStyleId;
249}
250
251void QgsMapLayerLoadStyleDialog::onRelatedTableSelectionChanged()
252{
253 selectionChanged( mRelatedTable );
254 if ( mRelatedTable->selectionModel()->hasSelection() )
255 {
256 if ( mOthersTable->selectionModel()->hasSelection() )
257 {
258 disconnect( mOthersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onOthersTableSelectionChanged );
259 const QTableWidgetSelectionRange range( 0, 0, mOthersTable->rowCount() - 1, mOthersTable->columnCount() - 1 );
260 mOthersTable->setRangeSelected( range, false );
261 connect( mOthersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onOthersTableSelectionChanged );
262 }
263 }
264}
265
266void QgsMapLayerLoadStyleDialog::onOthersTableSelectionChanged()
267{
268 selectionChanged( mOthersTable );
269 if ( mOthersTable->selectionModel()->hasSelection() )
270 {
271 if ( mRelatedTable->selectionModel()->hasSelection() )
272 {
273 disconnect( mRelatedTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onRelatedTableSelectionChanged );
274 const QTableWidgetSelectionRange range( 0, 0, mRelatedTable->rowCount() - 1, mRelatedTable->columnCount() - 1 );
275 mRelatedTable->setRangeSelected( range, false );
276 connect( mRelatedTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onRelatedTableSelectionChanged );
277 }
278 }
279}
280
281void QgsMapLayerLoadStyleDialog::selectionChanged( QTableWidget *styleTable )
282{
283 QTableWidgetItem *item = nullptr;
284 const QList<QTableWidgetItem *> selected = styleTable->selectedItems();
285
286 if ( !selected.isEmpty() )
287 {
288 item = selected.at( 0 );
289 mSelectedStyleName = item->text();
290 mSelectedStyleId = item->data( Qt::UserRole ).toString();
291 mLoadButton->setEnabled( true );
292 mDeleteButton->setEnabled( true );
293 }
294 else
295 {
296 mSelectedStyleName.clear();
297 mSelectedStyleId.clear();
298 mLoadButton->setEnabled( false );
299 mDeleteButton->setEnabled( false );
300 }
301
302 updateLoadButtonState();
303}
304
306{
307 QgsSettings settings;
308 settings.setFlagValue( QStringLiteral( "style/lastStyleCategories" ), styleCategories() );
309 settings.setValue( QStringLiteral( "style/lastLoadStyleTypeSelection" ), currentStyleType() );
310 QDialog::accept();
311}
312
313void QgsMapLayerLoadStyleDialog::deleteStyleFromDB()
314{
315 QString msgError;
316 const QString opInfo = QObject::tr( "Delete style %1 from %2" ).arg( mSelectedStyleName, mLayer->providerType() );
317
318 if ( QMessageBox::question( nullptr, QObject::tr( "Delete Style" ),
319 QObject::tr( "Are you sure you want to delete the style %1?" ).arg( mSelectedStyleName ),
320 QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
321 return;
322
323 mLayer->deleteStyleFromDatabase( mSelectedStyleId, msgError );
324 if ( !msgError.isNull() )
325 {
326 QgsDebugError( opInfo + " failed." );
327 QMessageBox::warning( this, opInfo, tr( "%1: fail. %2" ).arg( opInfo, msgError ) );
328 }
329 else
330 {
331// QgisApp::instance()->messageBar()->pushMessage( opInfo, tr( "%1: success" ).arg( opInfo ), Qgis::MessageLevel::Info, QgisApp::instance()->messageTimeout() );
332
333 //Delete all rows from the UI table widgets
334 mRelatedTable->setRowCount( 0 );
335 mOthersTable->setRowCount( 0 );
336
337 //Fill UI widgets again from DB. Other users might have changed the styles meanwhile.
338 QString errorMsg;
339 QStringList ids, names, descriptions;
340 //get the list of styles in the db
341 const int sectionLimit = mLayer->listStylesInDatabase( ids, names, descriptions, errorMsg );
342 if ( !errorMsg.isNull() )
343 {
344 QMessageBox::warning( this, tr( "Error occurred while retrieving styles from database" ), errorMsg );
345 }
346 else
347 {
348 initializeLists( ids, names, descriptions, sectionLimit );
349 }
350 }
351}
352
353void QgsMapLayerLoadStyleDialog::updateLoadButtonState()
354{
356 mLoadButton->setEnabled( ( type == QgsLayerPropertiesDialog::DatasourceDatabase
357 && ( mRelatedTable->selectionModel()->hasSelection() || mOthersTable->selectionModel()->hasSelection()
358 ) ) ||
359 ( type != QgsLayerPropertiesDialog::DatasourceDatabase && !mFileWidget->filePath().isEmpty() ) ||
361}
362
363void QgsMapLayerLoadStyleDialog::showHelp()
364{
365 QgsHelp::openHelp( QStringLiteral( "introduction/general_tools.html#save-and-share-layer-properties" ) );
366}
@ Group
Composite group layer. Added in QGIS 3.24.
@ Plugin
Plugin based layer.
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
@ Vector
Vector layer.
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
@ Mesh
Mesh layer. Added in QGIS 3.2.
@ Raster
Raster layer.
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
A label delegate being able to display html encoded content.
virtual Qgis::ProviderStyleStorageCapabilities styleStorageCapabilities() const
Returns the style storage capabilities.
@ GetFile
Select a single file.
void fileChanged(const QString &path)
Emitted whenever the current file or directory path is changed.
static void enableAutoGeometryRestore(QWidget *widget, const QString &key=QString())
Register the widget to allow its position to be automatically saved and restored when open and closed...
Definition qgsgui.cpp:209
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:39
QgsMapLayer::StyleCategories styleCategories() const
Returns the list of selected style categories the user has opted to load.
void initializeLists(const QStringList &ids, const QStringList &names, const QStringList &descriptions, int sectionLimit)
Initialize list of database stored styles.
QString selectedStyleId()
Returns the ID of the selected database stored style.
QgsMapLayerLoadStyleDialog(QgsMapLayer *layer, QWidget *parent=nullptr)
Constructor for QgsMapLayerLoadStyleDialog, associated with the specified map layer.
QString filePath() const
Returns the full path to the selected layer style source file.
QString fileExtension() const
Returns the file extension for the selected layer style source file.
QgsLayerPropertiesDialog::StyleType currentStyleType() const
Returns the selected style type.
void setCategories(QgsMapLayer::StyleCategories categories)
Reset the model data.
QVariant data(const QModelIndex &index, int role) const override
bool setData(const QModelIndex &index, const QVariant &value, int role) override
QgsMapLayer::StyleCategories categories() const
Returns the categories as defined in the model.
int rowCount(const QModelIndex &=QModelIndex()) const override
Base class for all map layer types.
Definition qgsmaplayer.h:76
virtual bool deleteStyleFromDatabase(const QString &styleId, QString &msgError)
Deletes a style from the database.
QString providerType() const
Returns the provider type (provider key) for this layer.
virtual int listStylesInDatabase(QStringList &ids, QStringList &names, QStringList &descriptions, QString &msgError)
Lists all the style in db split into related to the layer and not related to.
Qgis::LayerType type
Definition qgsmaplayer.h:86
QFlags< StyleCategory > StyleCategories
virtual Q_INVOKABLE QgsDataProvider * dataProvider()
Returns the layer's data provider, it may be nullptr.
This class is a composition of two QSettings instances:
Definition qgssettings.h:64
T flagValue(const QString &key, const T &defaultValue, const Section section=NoSection)
Returns the setting value for a setting based on a flag.
void setFlagValue(const QString &key, const T &value, const Section section=NoSection)
Set the value of a setting based on a flag.
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
#define QgsDebugError(str)
Definition qgslogger.h:38