QGIS API Documentation  3.13.0-Master (740be229cb)
qgsmaplayerstylemanagerwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsmaplayerstylemanagerwidget.cpp
3  ---------------------
4  begin : June 2016
5  copyright : (C) 2016 by Nathan Woodrow
6  email : woodrow dot nathan at gmail dot com
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 #include <QAction>
16 #include <QVBoxLayout>
17 #include <QToolBar>
18 #include <QInputDialog>
19 #include <QMessageBox>
20 #include <QFileDialog>
21 
23 #include "qgssettings.h"
24 #include "qgslogger.h"
25 #include "qgsmaplayer.h"
26 #include "qgsmapcanvas.h"
29 #include "qgsvectordataprovider.h"
30 #include "qgsrasterdataprovider.h"
31 #include "qgsvectorlayer.h"
32 #include "qgsrasterlayer.h"
33 #include "qgsapplication.h"
34 
36  : QgsMapLayerConfigWidget( layer, canvas, parent )
37 {
38  mModel = new QStandardItemModel( this );
39  mStyleList = new QListView( this );
40  mStyleList->setModel( mModel );
41  mStyleList->setViewMode( QListView::ListMode );
42  mStyleList->setResizeMode( QListView::Adjust );
43 
44  QToolBar *toolbar = new QToolBar( this );
45  QAction *addAction = toolbar->addAction( tr( "Add" ) );
46  addAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "symbologyAdd.svg" ) ) );
47  connect( addAction, &QAction::triggered, this, &QgsMapLayerStyleManagerWidget::addStyle );
48  QAction *removeAction = toolbar->addAction( tr( "Remove Current" ) );
49  removeAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "symbologyRemove.svg" ) ) );
50  connect( removeAction, &QAction::triggered, this, &QgsMapLayerStyleManagerWidget::removeStyle );
51  QAction *loadFromFileAction = toolbar->addAction( tr( "Load Style" ) );
52  loadFromFileAction->setIcon( QgsApplication::getThemeIcon( QStringLiteral( "/mActionFileOpen.svg" ) ) );
53  connect( loadFromFileAction, &QAction::triggered, this, &QgsMapLayerStyleManagerWidget::loadStyle );
54  QAction *saveAsDefaultAction = toolbar->addAction( tr( "Save as Default" ) );
55  connect( saveAsDefaultAction, &QAction::triggered, this, &QgsMapLayerStyleManagerWidget::saveAsDefault );
56  QAction *loadDefaultAction = toolbar->addAction( tr( "Restore Default" ) );
57  connect( loadDefaultAction, &QAction::triggered, this, &QgsMapLayerStyleManagerWidget::loadDefault );
58 
59 
60  // Save style doesn't work correctly yet so just disable for now.
61 // QAction* saveToFileAction = toolbar->addAction( tr( "Save Style" ) );
62 // connect( saveToFileAction, SIGNAL( triggered() ), this, SLOT( saveStyle() ) );
63 
64  //broken connect - not sure what the purpose of this was?
65 // connect( canvas, &QgsMapCanvas::mapCanvasRefreshed, this, SLOT( updateCurrent() ) );
66 
67  connect( mStyleList, &QAbstractItemView::clicked, this, &QgsMapLayerStyleManagerWidget::styleClicked );
68 
69  setLayout( new QVBoxLayout() );
70  layout()->setContentsMargins( 0, 0, 0, 0 );
71  layout()->addWidget( toolbar );
72  layout()->addWidget( mStyleList );
73 
74  connect( mLayer->styleManager(), &QgsMapLayerStyleManager::currentStyleChanged, this, &QgsMapLayerStyleManagerWidget::currentStyleChanged );
75  connect( mLayer->styleManager(), &QgsMapLayerStyleManager::styleAdded, this, &QgsMapLayerStyleManagerWidget::styleAdded );
76  connect( mLayer->styleManager(), &QgsMapLayerStyleManager::styleRemoved, this, &QgsMapLayerStyleManagerWidget::styleRemoved );
77  connect( mLayer->styleManager(), &QgsMapLayerStyleManager::styleRenamed, this, &QgsMapLayerStyleManagerWidget::styleRenamed );
78 
79  mModel->clear();
80 
81  const QStringList styles = mLayer->styleManager()->styles();
82  for ( const QString &styleName : styles )
83  {
84  QStandardItem *item = new QStandardItem( styleName );
85  item->setData( styleName );
86  mModel->appendRow( item );
87  }
88 
89  QString active = mLayer->styleManager()->currentStyle();
90  currentStyleChanged( active );
91 
92  connect( mModel, &QStandardItemModel::itemChanged, this, &QgsMapLayerStyleManagerWidget::renameStyle );
93 }
94 
95 void QgsMapLayerStyleManagerWidget::styleClicked( const QModelIndex &index )
96 {
97  if ( !mLayer || !index.isValid() )
98  return;
99 
100  QString name = index.data().toString();
101  mLayer->styleManager()->setCurrentStyle( name );
102 }
103 
104 void QgsMapLayerStyleManagerWidget::currentStyleChanged( const QString &name )
105 {
106  QList<QStandardItem *> items = mModel->findItems( name );
107  if ( items.isEmpty() )
108  return;
109 
110  QStandardItem *item = items.at( 0 );
111 
112  mStyleList->setCurrentIndex( item->index() );
113 }
114 
115 void QgsMapLayerStyleManagerWidget::styleAdded( const QString &name )
116 {
117  QgsDebugMsg( QStringLiteral( "Style added" ) );
118  QStandardItem *item = new QStandardItem( name );
119  item->setData( name );
120  mModel->appendRow( item );
121 }
122 
123 void QgsMapLayerStyleManagerWidget::styleRemoved( const QString &name )
124 {
125  QList<QStandardItem *> items = mModel->findItems( name );
126  if ( items.isEmpty() )
127  return;
128 
129  QStandardItem *item = items.at( 0 );
130  mModel->removeRow( item->row() );
131 }
132 
133 void QgsMapLayerStyleManagerWidget::styleRenamed( const QString &oldname, const QString &newname )
134 {
135  QList<QStandardItem *> items = mModel->findItems( oldname );
136  if ( items.isEmpty() )
137  return;
138 
139  QStandardItem *item = items.at( 0 );
140  item->setText( newname );
141  item->setData( newname );
142 }
143 
144 void QgsMapLayerStyleManagerWidget::addStyle()
145 {
146  bool ok;
147  QString text = QInputDialog::getText( nullptr, tr( "New Style" ),
148  tr( "Style name:" ), QLineEdit::Normal,
149  QStringLiteral( "new style" ), &ok );
150  if ( !ok || text.isEmpty() )
151  return;
152 
153  bool res = mLayer->styleManager()->addStyleFromLayer( text );
154  if ( res ) // make it active!
155  {
156  mLayer->styleManager()->setCurrentStyle( text );
157  }
158  else
159  {
160  QgsDebugMsg( "Failed to add style: " + text );
161  }
162 }
163 
164 void QgsMapLayerStyleManagerWidget::removeStyle()
165 {
166  QString current = mLayer->styleManager()->currentStyle();
167  QList<QStandardItem *> items = mModel->findItems( current );
168  if ( items.isEmpty() )
169  return;
170 
171  QStandardItem *item = items.at( 0 );
172  bool res = mLayer->styleManager()->removeStyle( current );
173  if ( res )
174  {
175  mModel->removeRow( item->row() );
176  }
177  else
178  {
179  QgsDebugMsg( QStringLiteral( "Failed to remove current style" ) );
180  }
181 
182 }
183 
184 void QgsMapLayerStyleManagerWidget::renameStyle( QStandardItem *item )
185 {
186  const QString oldName = item->data().toString();
187  const QString newName = item->text();
188  item->setData( newName );
189  whileBlocking( this )->mLayer->styleManager()->renameStyle( oldName, newName );
190 }
191 
192 void QgsMapLayerStyleManagerWidget::saveAsDefault()
193 {
194  QString errorMsg;
195 
196  if ( QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mLayer ) )
197  {
198  if ( layer->dataProvider()->isSaveAndLoadStyleToDatabaseSupported() )
199  {
200  QMessageBox askToUser;
201  askToUser.setWindowTitle( tr( "Save Style" ) );
202  askToUser.setText( tr( "Save default style to: " ) );
203  askToUser.setIcon( QMessageBox::Question );
204  askToUser.addButton( tr( "Cancel" ), QMessageBox::RejectRole );
205  askToUser.addButton( tr( "Local Database" ), QMessageBox::NoRole );
206  askToUser.addButton( tr( "Datasource Database" ), QMessageBox::YesRole );
207 
208  switch ( askToUser.exec() )
209  {
210  case 0:
211  return;
212  case 2:
213  layer->saveStyleToDatabase( QString(), QString(), true, QString(), errorMsg );
214  if ( errorMsg.isNull() )
215  {
216  return;
217  }
218  break;
219  default:
220  break;
221  }
222  }
223  }
224 
225  bool defaultSavedFlag = false;
226  errorMsg = mLayer->saveDefaultStyle( defaultSavedFlag );
227  if ( !defaultSavedFlag )
228  {
229  QMessageBox::warning( this, tr( "Default Style" ), errorMsg );
230  }
231 
232 }
233 
234 void QgsMapLayerStyleManagerWidget::loadDefault()
235 {
236  QString msg;
237  bool defaultLoadedFlag = false;
238 
239  if ( QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mLayer ) )
240  {
241  if ( layer->dataProvider()->isSaveAndLoadStyleToDatabaseSupported() )
242  {
243  QMessageBox askToUser;
244  askToUser.setWindowTitle( tr( "Load Style" ) );
245  askToUser.setText( tr( "Load default style from: " ) );
246  askToUser.setIcon( QMessageBox::Question );
247  askToUser.addButton( tr( "Cancel" ), QMessageBox::RejectRole );
248  askToUser.addButton( tr( "Local Database" ), QMessageBox::NoRole );
249  askToUser.addButton( tr( "Datasource Database" ), QMessageBox::YesRole );
250 
251  switch ( askToUser.exec() )
252  {
253  case 0:
254  return;
255  case 2:
256  msg = layer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag );
257  if ( !defaultLoadedFlag )
258  {
259  //something went wrong - let them know why
260  QMessageBox::information( this, tr( "Default Style" ), msg );
261  }
262  if ( msg.compare( tr( "Loaded from Provider" ) ) )
263  {
264  QMessageBox::information( this, tr( "Default Style" ),
265  tr( "No default style was found for this layer" ) );
266  }
267  return;
268  default:
269  break;
270  }
271  }
272  }
273 
274  QString myMessage;
275  if ( QgsVectorLayer *layer = qobject_cast<QgsVectorLayer *>( mLayer ) )
276  {
277  myMessage = layer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag, true );
278  }
279  if ( QgsRasterLayer *layer = qobject_cast<QgsRasterLayer *>( mLayer ) )
280  {
281  myMessage = layer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag );
282  }
283 
284 // QString myMessage = layer->loadDefaultStyle( defaultLoadedFlag );
285  //reset if the default style was loaded OK only
286 
287 
288  if ( !defaultLoadedFlag )
289  {
290  //something went wrong - let them know why
291  QMessageBox::information( this, tr( "Default Style" ), myMessage );
292  }
293  else
294  {
295  emit widgetChanged();
296  }
297 
298 }
299 
300 void QgsMapLayerStyleManagerWidget::saveStyle()
301 {
302 
303 }
304 
305 void QgsMapLayerStyleManagerWidget::loadStyle()
306 {
307  QgsSettings myQSettings; // where we keep last used filter in persistent state
308  QString myLastUsedDir = myQSettings.value( QStringLiteral( "style/lastStyleDir" ), QDir::homePath() ).toString();
309 
310  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load layer properties from style file" ), myLastUsedDir,
311  tr( "QGIS Layer Style File" ) + " (*.qml);;" + tr( "SLD File" ) + " (*.sld)" );
312  if ( myFileName.isNull() )
313  {
314  return;
315  }
316 
317  QString myMessage;
318  bool defaultLoadedFlag = false;
319 
320  if ( myFileName.endsWith( QLatin1String( ".sld" ), Qt::CaseInsensitive ) )
321  {
322  // load from SLD
323  myMessage = mLayer->loadSldStyle( myFileName, defaultLoadedFlag );
324  }
325  else
326  {
327  myMessage = mLayer->loadNamedStyle( myFileName, defaultLoadedFlag );
328  }
329  //reset if the default style was loaded OK only
330  if ( defaultLoadedFlag )
331  {
332  emit widgetChanged();
333  }
334  else
335  {
336  //let the user know what went wrong
337  QMessageBox::warning( this, tr( "Load Style" ), myMessage );
338  }
339 
340  QFileInfo myFI( myFileName );
341  QString myPath = myFI.path();
342  myQSettings.setValue( QStringLiteral( "style/lastStyleDir" ), myPath );
343 
344 }
A panel widget that can be shown in the map style dock.
Base class for all map layer types.
Definition: qgsmaplayer.h:80
QStringList styles() const
Returns list of all defined style names.
void currentStyleChanged(const QString &currentName)
Emitted when the current style has been changed.
virtual QString loadSldStyle(const QString &uri, bool &resultFlag)
Attempts to style the layer using the formatting from an SLD type file.
void styleRenamed(const QString &oldName, const QString &newName)
Emitted when a style has been renamed.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:61
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
Represents a raster layer.
static QIcon getThemeIcon(const QString &name)
Helper to get a theme icon.
virtual QString styleURI() const
Retrieve the style URI for this layer (either as a .qml file on disk or as a record in the users styl...
bool isValid() const
Returns the status of the layer.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:78
QgsMapLayerStyleManager * styleManager() const
Gets access to the layer&#39;s style manager.
void styleAdded(const QString &name)
Emitted when a new style has been added.
bool removeStyle(const QString &name)
Remove a stored style.
void styleRemoved(const QString &name)
Emitted when a style has been removed.
QgsMapLayerStyleManagerWidget(QgsMapLayer *layer, QgsMapCanvas *canvas, QWidget *parent=nullptr)
Style manager widget to manage the layers styles.
void widgetChanged()
Emitted when the widget state changes.
bool addStyleFromLayer(const QString &name)
Add style by cloning the current one.
QString currentStyle() const
Returns name of the current style.
virtual QString saveDefaultStyle(bool &resultFlag)
Save the properties of this layer as the default style (either as a .qml file on disk or as a record ...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition: qgis.h:262
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
virtual QString loadNamedStyle(const QString &uri, bool &resultFlag, QgsMapLayer::StyleCategories categories=QgsMapLayer::AllStyleCategories)
Retrieve a named style for this layer if one exists (either as a .qml file on disk or as a record in ...
Represents a vector layer which manages a vector based data sets.
bool setCurrentStyle(const QString &name)
Set a different style as the current style - will apply it to the layer.