QGIS API Documentation 3.99.0-Master (d270888f95f)
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
17
18#include "qgsapplication.h"
19#include "qgsgui.h"
20#include "qgshelp.h"
22#include "qgslogger.h"
24#include "qgssettings.h"
25
26#include <QMessageBox>
27#include <QString>
28#include <QVector>
29
30#include "moc_qgsmaplayerloadstyledialog.cpp"
31
32using namespace Qt::StringLiterals;
33
35 : QDialog( parent )
36 , mLayer( layer )
37{
38 setupUi( this );
40 setWindowTitle( tr( "Database Styles Manager" ) );
41
42 mDeleteButton = mButtonBox->button( QDialogButtonBox::StandardButton::Close );
43 mDeleteButton->setText( tr( "Delete Style" ) );
44 mDeleteButton->setIcon( QgsApplication::getThemeIcon( u"/mActionDeleteSelected.svg"_s ) );
45 mLoadButton = mButtonBox->button( QDialogButtonBox::StandardButton::Open );
46 mLoadButton->setText( tr( "Load Style" ) );
47 mCancelButton = mButtonBox->button( QDialogButtonBox::StandardButton::Cancel );
48
49 QgsSettings settings;
50
51 const QString myLastUsedDir = settings.value( u"style/lastStyleDir"_s, QDir::homePath() ).toString();
52
53 // load style type combobox
54 connect( mStyleTypeComboBox, qOverload<int>( &QComboBox::currentIndexChanged ), this, [this]( int ) {
58 mFromDbWidget->setVisible( type == QgsLayerPropertiesDialog::StyleType::DatasourceDatabase );
59 mDeleteButton->setVisible( type == QgsLayerPropertiesDialog::StyleType::DatasourceDatabase && mLayer->dataProvider()->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::DeleteFromDatabase ) );
60
61 mStyleCategoriesListView->setEnabled( currentStyleType() != QgsLayerPropertiesDialog::StyleType::SLD );
62 updateLoadButtonState();
63 } );
64 mStyleTypeComboBox->addItem( tr( "From file" ), QgsLayerPropertiesDialog::QML ); // QML is used as entry, but works for SLD too, see currentStyleType()
65 mStyleTypeComboBox->addItem( tr( "Default from local database" ), QgsLayerPropertiesDialog::UserDatabase );
66
67 if ( mLayer->dataProvider()->styleStorageCapabilities().testFlag( Qgis::ProviderStyleStorageCapability::LoadFromDatabase ) )
68 {
69 mStyleTypeComboBox->addItem( tr( "From datasource database" ), QgsLayerPropertiesDialog::StyleType::DatasourceDatabase );
70 if ( settings.value( u"style/lastLoadStyleTypeSelection"_s ) == QgsLayerPropertiesDialog::StyleType::DatasourceDatabase )
71 {
72 mStyleTypeComboBox->setCurrentIndex( mStyleTypeComboBox->findData( QgsLayerPropertiesDialog::StyleType::DatasourceDatabase ) );
73 }
74 }
75
76 // fill style categories
77 mModel = new QgsMapLayerStyleCategoriesModel( mLayer->type(), this );
78 const QgsMapLayer::StyleCategories lastStyleCategories = settings.flagValue( u"style/lastStyleCategories"_s, QgsMapLayer::AllStyleCategories );
79 mModel->setCategories( lastStyleCategories );
80 mStyleCategoriesListView->setModel( mModel );
81 mStyleCategoriesListView->setWordWrap( true );
82 mStyleCategoriesListView->setItemDelegate( new QgsCategoryDisplayLabelDelegate( this ) );
83
84 // load from file setup
85 switch ( mLayer->type() )
86 {
88 mFileWidget->setFilter( tr( "QGIS Layer Style File, SLD File" ) + u" (*.qml *.sld)"_s );
89 break;
90
92 mFileWidget->setFilter( tr( "All Styles" ) + u" (*.qml *.json);;"_s + tr( "QGIS Layer Style File" ) + u" (*.qml);;"_s + tr( "MapBox GL Style JSON File" ) + u" (*.json)"_s );
93 break;
94
102 break;
103 }
104
105 mFileWidget->setStorageMode( QgsFileWidget::GetFile );
106 mFileWidget->setDefaultRoot( myLastUsedDir );
107 connect( mFileWidget, &QgsFileWidget::fileChanged, this, [this]( const QString &path ) {
108 mStyleCategoriesListView->setEnabled( currentStyleType() != QgsLayerPropertiesDialog::SLD );
109 QgsSettings settings;
110 const QFileInfo tmplFileInfo( path );
111 settings.setValue( u"style/lastStyleDir"_s, 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, [this] {
136 QgsSettings().setValue( u"style/lastLoadStyleTypeSelection"_s, currentStyleType() );
137 } );
138
139 setTabOrder( mRelatedTable, mOthersTable );
140
141 mStyleCategoriesListView->adjustSize();
142
143 // select and deselect all categories
144 connect( mSelectAllButton, &QPushButton::clicked, this, &QgsMapLayerLoadStyleDialog::selectAll );
145 connect( mDeselectAllButton, &QPushButton::clicked, this, &QgsMapLayerLoadStyleDialog::deselectAll );
146 connect( mInvertSelectionButton, &QPushButton::clicked, this, &QgsMapLayerLoadStyleDialog::invertSelection );
147}
148
149void QgsMapLayerLoadStyleDialog::invertSelection()
150{
151 for ( int i = 0; i < mModel->rowCount( QModelIndex() ); i++ )
152 {
153 QModelIndex index = mModel->index( i, 0 );
154 Qt::CheckState currentState = Qt::CheckState( mModel->data( index, Qt::CheckStateRole ).toInt() );
155 Qt::CheckState newState = ( currentState == Qt::Checked ) ? Qt::Unchecked : Qt::Checked;
156 mModel->setData( index, newState, Qt::CheckStateRole );
157 }
158}
159
160void QgsMapLayerLoadStyleDialog::selectAll()
161{
162 for ( int i = 0; i < mModel->rowCount( QModelIndex() ); i++ )
163 {
164 QModelIndex index = mModel->index( i, 0 );
165 mModel->setData( index, Qt::Checked, Qt::CheckStateRole );
166 }
167}
168
169void QgsMapLayerLoadStyleDialog::deselectAll()
170{
171 for ( int i = 0; i < mModel->rowCount( QModelIndex() ); i++ )
172 {
173 QModelIndex index = mModel->index( i, 0 );
174 mModel->setData( index, Qt::Unchecked, Qt::CheckStateRole );
175 }
176}
177
179{
180 return mModel->categories();
181}
182
184{
185 QgsLayerPropertiesDialog::StyleType type = mStyleTypeComboBox->currentData().value<QgsLayerPropertiesDialog::StyleType>();
186 if ( type == QgsLayerPropertiesDialog::QML )
187 {
188 const QFileInfo fi( mFileWidget->filePath() );
189 if ( fi.exists() && fi.suffix().compare( u"sld"_s, Qt::CaseInsensitive ) == 0 )
191 }
192 return type;
193}
194
196{
197 return QFileInfo( mFileWidget->filePath() ).suffix();
198}
199
201{
202 return mFileWidget->filePath();
203}
204
205void QgsMapLayerLoadStyleDialog::initializeLists( const QStringList &ids, const QStringList &names, const QStringList &descriptions, int sectionLimit )
206{
207 // -1 means no ids
208 mSectionLimit = sectionLimit;
209 const int relatedTableNOfCols = sectionLimit > 0 ? 2 : 1;
210 const int othersTableNOfCols = ( sectionLimit >= 0 && ids.count() - sectionLimit > 0 ) ? 2 : 1;
211 const QString twoColsHeader( u"Name;Description"_s );
212 const QString oneColsHeader( u"No styles found in the database"_s );
213 const QString relatedTableHeader = relatedTableNOfCols == 1 ? oneColsHeader : twoColsHeader;
214 const QString othersTableHeader = othersTableNOfCols == 1 ? oneColsHeader : twoColsHeader;
215
216 mRelatedTable->setColumnCount( relatedTableNOfCols );
217 mOthersTable->setColumnCount( othersTableNOfCols );
218 mRelatedTable->setHorizontalHeaderLabels( relatedTableHeader.split( ';' ) );
219 mOthersTable->setHorizontalHeaderLabels( othersTableHeader.split( ';' ) );
220 mRelatedTable->setRowCount( sectionLimit );
221 mOthersTable->setRowCount( sectionLimit >= 0 ? ( ids.count() - sectionLimit ) : 0 );
222 mRelatedTable->setDisabled( relatedTableNOfCols == 1 );
223 mOthersTable->setDisabled( othersTableNOfCols == 1 );
224
225 if ( sectionLimit >= 0 )
226 {
227 for ( int i = 0; i < sectionLimit; i++ )
228 {
229 QTableWidgetItem *item = new QTableWidgetItem( names.value( i, QString() ) );
230 item->setData( Qt::UserRole, ids[i] );
231 mRelatedTable->setItem( i, 0, item );
232 mRelatedTable->setItem( i, 1, new QTableWidgetItem( descriptions.value( i, QString() ) ) );
233 }
234 for ( int i = sectionLimit; i < ids.count(); i++ )
235 {
236 const int j = i - sectionLimit;
237 QTableWidgetItem *item = new QTableWidgetItem( names.value( i, QString() ) );
238 item->setData( Qt::UserRole, ids[i] );
239 mOthersTable->setItem( j, 0, item );
240 mOthersTable->setItem( j, 1, new QTableWidgetItem( descriptions.value( i, QString() ) ) );
241 }
242 }
243}
244
246{
247 return mSelectedStyleId;
248}
249
250void QgsMapLayerLoadStyleDialog::onRelatedTableSelectionChanged()
251{
252 selectionChanged( mRelatedTable );
253 if ( mRelatedTable->selectionModel()->hasSelection() )
254 {
255 if ( mOthersTable->selectionModel()->hasSelection() )
256 {
257 disconnect( mOthersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onOthersTableSelectionChanged );
258 const QTableWidgetSelectionRange range( 0, 0, mOthersTable->rowCount() - 1, mOthersTable->columnCount() - 1 );
259 mOthersTable->setRangeSelected( range, false );
260 connect( mOthersTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onOthersTableSelectionChanged );
261 }
262 }
263}
264
265void QgsMapLayerLoadStyleDialog::onOthersTableSelectionChanged()
266{
267 selectionChanged( mOthersTable );
268 if ( mOthersTable->selectionModel()->hasSelection() )
269 {
270 if ( mRelatedTable->selectionModel()->hasSelection() )
271 {
272 disconnect( mRelatedTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onRelatedTableSelectionChanged );
273 const QTableWidgetSelectionRange range( 0, 0, mRelatedTable->rowCount() - 1, mRelatedTable->columnCount() - 1 );
274 mRelatedTable->setRangeSelected( range, false );
275 connect( mRelatedTable->selectionModel(), &QItemSelectionModel::selectionChanged, this, &QgsMapLayerLoadStyleDialog::onRelatedTableSelectionChanged );
276 }
277 }
278}
279
280void QgsMapLayerLoadStyleDialog::selectionChanged( QTableWidget *styleTable )
281{
282 QTableWidgetItem *item = nullptr;
283 const QList<QTableWidgetItem *> selected = styleTable->selectedItems();
284
285 if ( !selected.isEmpty() )
286 {
287 item = selected.at( 0 );
288 mSelectedStyleName = item->text();
289 mSelectedStyleId = item->data( Qt::UserRole ).toString();
290 mLoadButton->setEnabled( true );
291 mDeleteButton->setEnabled( true );
292 }
293 else
294 {
295 mSelectedStyleName.clear();
296 mSelectedStyleId.clear();
297 mLoadButton->setEnabled( false );
298 mDeleteButton->setEnabled( false );
299 }
300
301 updateLoadButtonState();
302}
303
305{
306 QgsSettings settings;
307 settings.setFlagValue( u"style/lastStyleCategories"_s, styleCategories() );
308 settings.setValue( u"style/lastLoadStyleTypeSelection"_s, currentStyleType() );
309 QDialog::accept();
310}
311
312void QgsMapLayerLoadStyleDialog::deleteStyleFromDB()
313{
314 QString msgError;
315 const QString opInfo = QObject::tr( "Delete style %1 from %2" ).arg( mSelectedStyleName, mLayer->providerType() );
316
317 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 )
318 return;
319
320 mLayer->deleteStyleFromDatabase( mSelectedStyleId, msgError );
321 if ( !msgError.isNull() )
322 {
323 QgsDebugError( opInfo + " failed." );
324 QMessageBox::warning( this, opInfo, tr( "%1: fail. %2" ).arg( opInfo, msgError ) );
325 }
326 else
327 {
328 // QgisApp::instance()->messageBar()->pushMessage( opInfo, tr( "%1: success" ).arg( opInfo ), Qgis::MessageLevel::Info, QgisApp::instance()->messageTimeout() );
329
330 //Delete all rows from the UI table widgets
331 mRelatedTable->setRowCount( 0 );
332 mOthersTable->setRowCount( 0 );
333
334 //Fill UI widgets again from DB. Other users might have changed the styles meanwhile.
335 QString errorMsg;
336 QStringList ids, names, descriptions;
337 //get the list of styles in the db
338 const int sectionLimit = mLayer->listStylesInDatabase( ids, names, descriptions, errorMsg );
339 if ( !errorMsg.isNull() )
340 {
341 QMessageBox::warning( this, tr( "Error occurred while retrieving styles from database" ), errorMsg );
342 }
343 else
344 {
345 initializeLists( ids, names, descriptions, sectionLimit );
346 }
347 }
348}
349
350void QgsMapLayerLoadStyleDialog::updateLoadButtonState()
351{
353 mLoadButton->setEnabled( ( type == QgsLayerPropertiesDialog::DatasourceDatabase && ( mRelatedTable->selectionModel()->hasSelection() || mOthersTable->selectionModel()->hasSelection() ) ) || ( type != QgsLayerPropertiesDialog::DatasourceDatabase && !mFileWidget->filePath().isEmpty() ) || type == QgsLayerPropertiesDialog::UserDatabase );
354}
355
356void QgsMapLayerLoadStyleDialog::showHelp()
357{
358 QgsHelp::openHelp( u"introduction/general_tools.html#save-and-share-layer-properties"_s );
359}
@ Group
Composite group layer. Added in QGIS 3.24.
Definition qgis.h:201
@ Plugin
Plugin based layer.
Definition qgis.h:196
@ TiledScene
Tiled scene layer. Added in QGIS 3.34.
Definition qgis.h:202
@ Annotation
Contains freeform, georeferenced annotations. Added in QGIS 3.16.
Definition qgis.h:199
@ Vector
Vector layer.
Definition qgis.h:194
@ VectorTile
Vector tile layer. Added in QGIS 3.14.
Definition qgis.h:198
@ Mesh
Mesh layer. Added in QGIS 3.2.
Definition qgis.h:197
@ Raster
Raster layer.
Definition qgis.h:195
@ PointCloud
Point cloud layer. Added in QGIS 3.18.
Definition qgis.h:200
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
A label delegate able to display HTML encoded content.
@ 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:224
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:41
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.
QVariant data(const QModelIndex &index, int role) const override
bool setData(const QModelIndex &index, const QVariant &value, int role) override
int rowCount(const QModelIndex &=QModelIndex()) const override
Base class for all map layer types.
Definition qgsmaplayer.h:83
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.
QFlags< StyleCategory > StyleCategories
Stores settings for use within QGIS.
Definition qgssettings.h:68
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:59