QGIS API Documentation 3.41.0-Master (af5edcb665c)
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 ) {
53 mFromDbWidget->setVisible( type == QgsLayerPropertiesDialog::StyleType::DatasourceDatabase );
55
56 mStyleCategoriesListView->setEnabled( currentStyleType() != QgsLayerPropertiesDialog::StyleType::SLD );
57 updateLoadButtonState();
58 } );
59 mStyleTypeComboBox->addItem( tr( "From file" ), QgsLayerPropertiesDialog::QML ); // QML is used as entry, but works for SLD too, see currentStyleType()
60 mStyleTypeComboBox->addItem( tr( "Default from local database" ), QgsLayerPropertiesDialog::UserDatabase );
61
63 {
64 mStyleTypeComboBox->addItem( tr( "From datasource database" ), QgsLayerPropertiesDialog::StyleType::DatasourceDatabase );
65 if ( settings.value( QStringLiteral( "style/lastLoadStyleTypeSelection" ) ) == QgsLayerPropertiesDialog::StyleType::DatasourceDatabase )
66 {
67 mStyleTypeComboBox->setCurrentIndex( mStyleTypeComboBox->findData( QgsLayerPropertiesDialog::StyleType::DatasourceDatabase ) );
68 }
69 }
70
71 // fill style categories
72 mModel = new QgsMapLayerStyleCategoriesModel( mLayer->type(), this );
73 const QgsMapLayer::StyleCategories lastStyleCategories = settings.flagValue( QStringLiteral( "style/lastStyleCategories" ), QgsMapLayer::AllStyleCategories );
74 mModel->setCategories( lastStyleCategories );
75 mStyleCategoriesListView->setModel( mModel );
76 mStyleCategoriesListView->setWordWrap( true );
77 mStyleCategoriesListView->setItemDelegate( new QgsCategoryDisplayLabelDelegate( this ) );
78
79 // load from file setup
80 switch ( mLayer->type() )
81 {
83 mFileWidget->setFilter( tr( "QGIS Layer Style File, SLD File" ) + QStringLiteral( " (*.qml *.sld)" ) );
84 break;
85
87 mFileWidget->setFilter( tr( "All Styles" ) + QStringLiteral( " (*.qml *.json);;" ) + tr( "QGIS Layer Style File" ) + QStringLiteral( " (*.qml);;" ) + tr( "MapBox GL Style JSON File" ) + QStringLiteral( " (*.json)" ) );
88 break;
89
97 break;
98 }
99
100 mFileWidget->setStorageMode( QgsFileWidget::GetFile );
101 mFileWidget->setDefaultRoot( myLastUsedDir );
102 connect( mFileWidget, &QgsFileWidget::fileChanged, this, [=]( const QString &path ) {
103 mStyleCategoriesListView->setEnabled( currentStyleType() != QgsLayerPropertiesDialog::SLD );
104 QgsSettings settings;
105 const QFileInfo tmplFileInfo( path );
106 settings.setValue( QStringLiteral( "style/lastStyleDir" ), tmplFileInfo.absolutePath() );
107
108 updateLoadButtonState();
109 } );
110
111 // load from DB
112 mLoadButton->setDisabled( true );
113 mDeleteButton->setDisabled( true );
114 mRelatedTable->setEditTriggers( QTableWidget::NoEditTriggers );
115 mRelatedTable->horizontalHeader()->setStretchLastSection( true );
116 mRelatedTable->setSelectionBehavior( QTableWidget::SelectRows );
117 mRelatedTable->verticalHeader()->setVisible( false );
118 mOthersTable->setEditTriggers( QTableWidget::NoEditTriggers );
119 mOthersTable->horizontalHeader()->setStretchLastSection( true );
120 mOthersTable->setSelectionBehavior( QTableWidget::SelectRows );
121 mOthersTable->verticalHeader()->setVisible( false );
122 connect( mRelatedTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onRelatedTableSelectionChanged );
123 connect( mOthersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onOthersTableSelectionChanged );
124 connect( mRelatedTable, &QTableWidget::doubleClicked, this, &QDialog::accept );
125 connect( mOthersTable, &QTableWidget::doubleClicked, this, &QDialog::accept );
126 connect( mCancelButton, &QPushButton::clicked, this, &QDialog::reject );
127 connect( mButtonBox, &QDialogButtonBox::helpRequested, this, &QgsMapLayerLoadStyleDialog::showHelp );
128 connect( mLoadButton, &QPushButton::clicked, this, &QDialog::accept );
129 connect( mDeleteButton, &QPushButton::clicked, this, &QgsMapLayerLoadStyleDialog::deleteStyleFromDB );
130 connect( this, &QgsMapLayerLoadStyleDialog::rejected, [=] {
131 QgsSettings().setValue( QStringLiteral( "style/lastLoadStyleTypeSelection" ), currentStyleType() );
132 } );
133
134 setTabOrder( mRelatedTable, mOthersTable );
135
136 mStyleCategoriesListView->adjustSize();
137
138 // select and deselect all categories
139 connect( mSelectAllButton, &QPushButton::clicked, this, &QgsMapLayerLoadStyleDialog::selectAll );
140 connect( mDeselectAllButton, &QPushButton::clicked, this, &QgsMapLayerLoadStyleDialog::deselectAll );
141 connect( mInvertSelectionButton, &QPushButton::clicked, this, &QgsMapLayerLoadStyleDialog::invertSelection );
142}
143
144void QgsMapLayerLoadStyleDialog::invertSelection()
145{
146 for ( int i = 0; i < mModel->rowCount( QModelIndex() ); i++ )
147 {
148 QModelIndex index = mModel->index( i, 0 );
149 Qt::CheckState currentState = Qt::CheckState( mModel->data( index, Qt::CheckStateRole ).toInt() );
150 Qt::CheckState newState = ( currentState == Qt::Checked ) ? Qt::Unchecked : Qt::Checked;
151 mModel->setData( index, newState, Qt::CheckStateRole );
152 }
153}
154
155void QgsMapLayerLoadStyleDialog::selectAll()
156{
157 for ( int i = 0; i < mModel->rowCount( QModelIndex() ); i++ )
158 {
159 QModelIndex index = mModel->index( i, 0 );
160 mModel->setData( index, Qt::Checked, Qt::CheckStateRole );
161 }
162}
163
164void QgsMapLayerLoadStyleDialog::deselectAll()
165{
166 for ( int i = 0; i < mModel->rowCount( QModelIndex() ); i++ )
167 {
168 QModelIndex index = mModel->index( i, 0 );
169 mModel->setData( index, Qt::Unchecked, Qt::CheckStateRole );
170 }
171}
172
177
179{
180 QgsLayerPropertiesDialog::StyleType type = mStyleTypeComboBox->currentData().value<QgsLayerPropertiesDialog::StyleType>();
181 if ( type == QgsLayerPropertiesDialog::QML )
182 {
183 const QFileInfo fi( mFileWidget->filePath() );
184 if ( fi.exists() && fi.suffix().compare( QStringLiteral( "sld" ), Qt::CaseInsensitive ) == 0 )
186 }
187 return type;
188}
189
191{
192 return QFileInfo( mFileWidget->filePath() ).suffix();
193}
194
196{
197 return mFileWidget->filePath();
198}
199
200void QgsMapLayerLoadStyleDialog::initializeLists( const QStringList &ids, const QStringList &names, const QStringList &descriptions, int sectionLimit )
201{
202 // -1 means no ids
203 mSectionLimit = sectionLimit;
204 const int relatedTableNOfCols = sectionLimit > 0 ? 2 : 1;
205 const int othersTableNOfCols = ( sectionLimit >= 0 && ids.count() - sectionLimit > 0 ) ? 2 : 1;
206 const QString twoColsHeader( QStringLiteral( "Name;Description" ) );
207 const QString oneColsHeader( QStringLiteral( "No styles found in the database" ) );
208 const QString relatedTableHeader = relatedTableNOfCols == 1 ? oneColsHeader : twoColsHeader;
209 const QString othersTableHeader = othersTableNOfCols == 1 ? oneColsHeader : twoColsHeader;
210
211 mRelatedTable->setColumnCount( relatedTableNOfCols );
212 mOthersTable->setColumnCount( othersTableNOfCols );
213 mRelatedTable->setHorizontalHeaderLabels( relatedTableHeader.split( ';' ) );
214 mOthersTable->setHorizontalHeaderLabels( othersTableHeader.split( ';' ) );
215 mRelatedTable->setRowCount( sectionLimit );
216 mOthersTable->setRowCount( sectionLimit >= 0 ? ( ids.count() - sectionLimit ) : 0 );
217 mRelatedTable->setDisabled( relatedTableNOfCols == 1 );
218 mOthersTable->setDisabled( othersTableNOfCols == 1 );
219
220 if ( sectionLimit >= 0 )
221 {
222 for ( int i = 0; i < sectionLimit; i++ )
223 {
224 QTableWidgetItem *item = new QTableWidgetItem( names.value( i, QString() ) );
225 item->setData( Qt::UserRole, ids[i] );
226 mRelatedTable->setItem( i, 0, item );
227 mRelatedTable->setItem( i, 1, new QTableWidgetItem( descriptions.value( i, QString() ) ) );
228 }
229 for ( int i = sectionLimit; i < ids.count(); i++ )
230 {
231 const int j = i - sectionLimit;
232 QTableWidgetItem *item = new QTableWidgetItem( names.value( i, QString() ) );
233 item->setData( Qt::UserRole, ids[i] );
234 mOthersTable->setItem( j, 0, item );
235 mOthersTable->setItem( j, 1, new QTableWidgetItem( descriptions.value( i, QString() ) ) );
236 }
237 }
238}
239
241{
242 return mSelectedStyleId;
243}
244
245void QgsMapLayerLoadStyleDialog::onRelatedTableSelectionChanged()
246{
247 selectionChanged( mRelatedTable );
248 if ( mRelatedTable->selectionModel()->hasSelection() )
249 {
250 if ( mOthersTable->selectionModel()->hasSelection() )
251 {
252 disconnect( mOthersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onOthersTableSelectionChanged );
253 const QTableWidgetSelectionRange range( 0, 0, mOthersTable->rowCount() - 1, mOthersTable->columnCount() - 1 );
254 mOthersTable->setRangeSelected( range, false );
255 connect( mOthersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onOthersTableSelectionChanged );
256 }
257 }
258}
259
260void QgsMapLayerLoadStyleDialog::onOthersTableSelectionChanged()
261{
262 selectionChanged( mOthersTable );
263 if ( mOthersTable->selectionModel()->hasSelection() )
264 {
265 if ( mRelatedTable->selectionModel()->hasSelection() )
266 {
267 disconnect( mRelatedTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onRelatedTableSelectionChanged );
268 const QTableWidgetSelectionRange range( 0, 0, mRelatedTable->rowCount() - 1, mRelatedTable->columnCount() - 1 );
269 mRelatedTable->setRangeSelected( range, false );
270 connect( mRelatedTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onRelatedTableSelectionChanged );
271 }
272 }
273}
274
275void QgsMapLayerLoadStyleDialog::selectionChanged( QTableWidget *styleTable )
276{
277 QTableWidgetItem *item = nullptr;
278 const QList<QTableWidgetItem *> selected = styleTable->selectedItems();
279
280 if ( !selected.isEmpty() )
281 {
282 item = selected.at( 0 );
283 mSelectedStyleName = item->text();
284 mSelectedStyleId = item->data( Qt::UserRole ).toString();
285 mLoadButton->setEnabled( true );
286 mDeleteButton->setEnabled( true );
287 }
288 else
289 {
290 mSelectedStyleName.clear();
291 mSelectedStyleId.clear();
292 mLoadButton->setEnabled( false );
293 mDeleteButton->setEnabled( false );
294 }
295
296 updateLoadButtonState();
297}
298
300{
301 QgsSettings settings;
302 settings.setFlagValue( QStringLiteral( "style/lastStyleCategories" ), styleCategories() );
303 settings.setValue( QStringLiteral( "style/lastLoadStyleTypeSelection" ), currentStyleType() );
304 QDialog::accept();
305}
306
307void QgsMapLayerLoadStyleDialog::deleteStyleFromDB()
308{
309 QString msgError;
310 const QString opInfo = QObject::tr( "Delete style %1 from %2" ).arg( mSelectedStyleName, mLayer->providerType() );
311
312 if ( QMessageBox::question( nullptr, QObject::tr( "Delete Style" ), QObject::tr( "Are you sure you want to delete the style %1?" ).arg( mSelectedStyleName ), QMessageBox::Yes | QMessageBox::No, QMessageBox::No ) != QMessageBox::Yes )
313 return;
314
315 mLayer->deleteStyleFromDatabase( mSelectedStyleId, msgError );
316 if ( !msgError.isNull() )
317 {
318 QgsDebugError( opInfo + " failed." );
319 QMessageBox::warning( this, opInfo, tr( "%1: fail. %2" ).arg( opInfo, msgError ) );
320 }
321 else
322 {
323 // QgisApp::instance()->messageBar()->pushMessage( opInfo, tr( "%1: success" ).arg( opInfo ), Qgis::MessageLevel::Info, QgisApp::instance()->messageTimeout() );
324
325 //Delete all rows from the UI table widgets
326 mRelatedTable->setRowCount( 0 );
327 mOthersTable->setRowCount( 0 );
328
329 //Fill UI widgets again from DB. Other users might have changed the styles meanwhile.
330 QString errorMsg;
331 QStringList ids, names, descriptions;
332 //get the list of styles in the db
333 const int sectionLimit = mLayer->listStylesInDatabase( ids, names, descriptions, errorMsg );
334 if ( !errorMsg.isNull() )
335 {
336 QMessageBox::warning( this, tr( "Error occurred while retrieving styles from database" ), errorMsg );
337 }
338 else
339 {
340 initializeLists( ids, names, descriptions, sectionLimit );
341 }
342 }
343}
344
345void QgsMapLayerLoadStyleDialog::updateLoadButtonState()
346{
348 mLoadButton->setEnabled( ( type == QgsLayerPropertiesDialog::DatasourceDatabase && ( mRelatedTable->selectionModel()->hasSelection() || mOthersTable->selectionModel()->hasSelection() ) ) || ( type != QgsLayerPropertiesDialog::DatasourceDatabase && !mFileWidget->filePath().isEmpty() ) || type == QgsLayerPropertiesDialog::UserDatabase );
349}
350
351void QgsMapLayerLoadStyleDialog::showHelp()
352{
353 QgsHelp::openHelp( QStringLiteral( "introduction/general_tools.html#save-and-share-layer-properties" ) );
354}
@ 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:210
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