QGIS API Documentation  2.18.21-Las Palmas (9fba24a)
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 <QSettings>
21 #include <QFileDialog>
22 
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 
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( "symbologyAdd.svg" ) );
47  connect( addAction, SIGNAL( triggered() ), this, SLOT( addStyle() ) );
48  QAction* removeAction = toolbar->addAction( tr( "Remove Current" ) );
49  removeAction->setIcon( QgsApplication::getThemeIcon( "symbologyRemove.svg" ) );
50  connect( removeAction, SIGNAL( triggered() ), this, SLOT( removeStyle() ) );
51  QAction* loadFromFileAction = toolbar->addAction( tr( "Load Style" ) );
52  loadFromFileAction->setIcon( QgsApplication::getThemeIcon( "/mActionFileOpen.svg" ) );
53  connect( loadFromFileAction, SIGNAL( triggered() ), this, SLOT( loadStyle() ) );
54  QAction* saveAsDefaultAction = toolbar->addAction( tr( "Save as default" ) );
55  connect( saveAsDefaultAction, SIGNAL( triggered() ), this, SLOT( saveAsDefault() ) );
56  QAction* loadDefaultAction = toolbar->addAction( tr( "Restore default" ) );
57  connect( loadDefaultAction, SIGNAL( triggered() ), this, SLOT( 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  connect( canvas, SIGNAL( mapCanvasRefreshed() ), this, SLOT( updateCurrent() ) );
65 
66  connect( mStyleList, SIGNAL( clicked( QModelIndex ) ), this, SLOT( styleClicked( QModelIndex ) ) );
67 
68  setLayout( new QVBoxLayout() );
69  layout()->setContentsMargins( 0, 0, 0, 0 );
70  layout()->addWidget( toolbar );
71  layout()->addWidget( mStyleList );
72 
73  connect( mLayer->styleManager(), SIGNAL( currentStyleChanged( QString ) ), this, SLOT( currentStyleChanged( QString ) ) );
74  connect( mLayer->styleManager(), SIGNAL( styleAdded( QString ) ), this, SLOT( styleAdded( QString ) ) );
75  connect( mLayer->styleManager(), SIGNAL( styleremoved( QString ) ), this, SLOT( styleRemoved( QString ) ) );
76  connect( mLayer->styleManager(), SIGNAL( styleRenamed( QString, QString ) ), this, SLOT( styleRenamed( QString, QString ) ) );
77 
78  mModel->clear();
79 
80  Q_FOREACH ( const QString name, mLayer->styleManager()->styles() )
81  {
82  QString stylename = name;
83 
84  if ( stylename.isEmpty() )
85  stylename = "(default)";
86 
87  QStandardItem* item = new QStandardItem( stylename );
88  mModel->appendRow( item );
89  }
90 
91  QString active = mLayer->styleManager()->currentStyle();
92  currentStyleChanged( active );
93 }
94 
95 void QgsMapLayerStyleManagerWidget::styleClicked( QModelIndex index )
96 {
97  if ( !mLayer || !index.isValid() )
98  return;
99 
100  QString name = index.data().toString();
101  if ( name == "(default)" )
102  name = "";
103 
104  mLayer->styleManager()->setCurrentStyle( name );
105 }
106 
107 void QgsMapLayerStyleManagerWidget::currentStyleChanged( QString name )
108 {
109  QList<QStandardItem*> items = mModel->findItems( name );
110  if ( items.isEmpty() )
111  return;
112 
113  QStandardItem* item = items.at( 0 );
114 
115  mStyleList->setCurrentIndex( item->index() );
116 }
117 
118 void QgsMapLayerStyleManagerWidget::styleAdded( QString name )
119 {
120  QgsDebugMsg( "Style added" );
121  QStandardItem* item = new QStandardItem( name );
122  mModel->appendRow( item );
123 }
124 
125 void QgsMapLayerStyleManagerWidget::styleRemoved( QString name )
126 {
127  QList<QStandardItem*> items = mModel->findItems( name );
128  if ( items.isEmpty() )
129  return;
130 
131  QStandardItem* item = items.at( 0 );
132  mModel->removeRow( item->row() );
133 }
134 
135 void QgsMapLayerStyleManagerWidget::styleRenamed( QString oldname, QString newname )
136 {
137  QList<QStandardItem*> items = mModel->findItems( oldname );
138  if ( items.isEmpty() )
139  return;
140 
141  QStandardItem* item = items.at( 0 );
142  item->setText( newname );
143 }
144 
145 void QgsMapLayerStyleManagerWidget::addStyle()
146 {
147  bool ok;
148  QString text = QInputDialog::getText( nullptr, tr( "New style" ),
149  tr( "Style name:" ), QLineEdit::Normal,
150  "new style", &ok );
151  if ( !ok || text.isEmpty() )
152  return;
153 
154  bool res = mLayer->styleManager()->addStyleFromLayer( text );
155  if ( res ) // make it active!
156  {
157  mLayer->styleManager()->setCurrentStyle( text );
158  }
159  else
160  {
161  QgsDebugMsg( "Failed to add style: " + text );
162  }
163 }
164 
165 void QgsMapLayerStyleManagerWidget::removeStyle()
166 {
167  QString current = mLayer->styleManager()->currentStyle();
168  QList<QStandardItem*> items = mModel->findItems( current );
169  if ( items.isEmpty() )
170  return;
171 
172  QStandardItem* item = items.at( 0 );
173  bool res = mLayer->styleManager()->removeStyle( current );
174  if ( res )
175  {
176  mModel->removeRow( item->row() );
177  }
178  else
179  {
180  QgsDebugMsg( "Failed to remove current style" );
181  }
182 
183 }
184 
185 void QgsMapLayerStyleManagerWidget::saveAsDefault()
186 {
187  QString errorMsg;
188 
189  if ( QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( mLayer ) )
190  {
191  if ( layer->dataProvider()->isSaveAndLoadStyleToDBSupported() )
192  {
193  QMessageBox askToUser;
194  askToUser.setText( tr( "Save default style to: " ) );
195  askToUser.setIcon( QMessageBox::Question );
196  askToUser.addButton( tr( "Cancel" ), QMessageBox::RejectRole );
197  askToUser.addButton( tr( "Local database" ), QMessageBox::NoRole );
198  askToUser.addButton( tr( "Datasource database" ), QMessageBox::YesRole );
199 
200  switch ( askToUser.exec() )
201  {
202  case 0:
203  return;
204  case 2:
205  layer->saveStyleToDatabase( "", "", true, "", errorMsg );
206  if ( errorMsg.isNull() )
207  {
208  return;
209  }
210  break;
211  default:
212  break;
213  }
214  }
215  }
216 
217  bool defaultSavedFlag = false;
218  errorMsg = mLayer->saveDefaultStyle( defaultSavedFlag );
219  if ( !defaultSavedFlag )
220  {
221  QMessageBox::warning( this, tr( "Default Style" ), errorMsg );
222  }
223 
224 }
225 
226 void QgsMapLayerStyleManagerWidget::loadDefault()
227 {
228  QString msg;
229  bool defaultLoadedFlag = false;
230 
231  if ( QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( mLayer ) )
232  {
233  if ( layer->dataProvider()->isSaveAndLoadStyleToDBSupported() )
234  {
235  QMessageBox askToUser;
236  askToUser.setText( tr( "Load default style from: " ) );
237  askToUser.setIcon( QMessageBox::Question );
238  askToUser.addButton( tr( "Cancel" ), QMessageBox::RejectRole );
239  askToUser.addButton( tr( "Local database" ), QMessageBox::NoRole );
240  askToUser.addButton( tr( "Datasource database" ), QMessageBox::YesRole );
241 
242  switch ( askToUser.exec() )
243  {
244  case 0:
245  return;
246  case 2:
247  msg = layer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag );
248  if ( !defaultLoadedFlag )
249  {
250  //something went wrong - let them know why
251  QMessageBox::information( this, tr( "Default Style" ), msg );
252  }
253  if ( msg.compare( tr( "Loaded from Provider" ) ) )
254  {
255  QMessageBox::information( this, tr( "Default Style" ),
256  tr( "No default style was found for this layer" ) );
257  }
258  return;
259  default:
260  break;
261  }
262  }
263  }
264 
265  QString myMessage;
266  if ( QgsVectorLayer* layer = qobject_cast<QgsVectorLayer*>( mLayer ) )
267  {
268  myMessage = layer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag, true );
269  }
270  if ( QgsRasterLayer* layer = qobject_cast<QgsRasterLayer*>( mLayer ) )
271  {
272  myMessage = layer->loadNamedStyle( mLayer->styleURI(), defaultLoadedFlag );
273  }
274 
275 // QString myMessage = layer->loadDefaultStyle( defaultLoadedFlag );
276  //reset if the default style was loaded ok only
277 
278 
279  if ( !defaultLoadedFlag )
280  {
281  //something went wrong - let them know why
282  QMessageBox::information( this, tr( "Default Style" ), myMessage );
283  }
284  else
285  {
286  emit widgetChanged();
287  }
288 
289 }
290 
291 void QgsMapLayerStyleManagerWidget::saveStyle()
292 {
293 
294 }
295 
296 void QgsMapLayerStyleManagerWidget::loadStyle()
297 {
298  QSettings myQSettings; // where we keep last used filter in persistent state
299  QString myLastUsedDir = myQSettings.value( "style/lastStyleDir", QDir::homePath() ).toString();
300 
301  QString myFileName = QFileDialog::getOpenFileName( this, tr( "Load layer properties from style file" ), myLastUsedDir,
302  tr( "QGIS Layer Style File" ) + " (*.qml);;" + tr( "SLD File" ) + " (*.sld)" );
303  if ( myFileName.isNull() )
304  {
305  return;
306  }
307 
308  QString myMessage;
309  bool defaultLoadedFlag = false;
310 
311  if ( myFileName.endsWith( ".sld", Qt::CaseInsensitive ) )
312  {
313  // load from SLD
314  myMessage = mLayer->loadSldStyle( myFileName, defaultLoadedFlag );
315  }
316  else
317  {
318  myMessage = mLayer->loadNamedStyle( myFileName, defaultLoadedFlag );
319  }
320  //reset if the default style was loaded ok only
321  if ( defaultLoadedFlag )
322  {
323  emit widgetChanged();
324  }
325  else
326  {
327  //let the user know what went wrong
328  QMessageBox::warning( this, tr( "Load Style" ), myMessage );
329  }
330 
331  QFileInfo myFI( myFileName );
332  QString myPath = myFI.path();
333  myQSettings.setValue( "style/lastStyleDir", myPath );
334 
335 }
QLayout * layout() const
A panel widget that can be shown in the map style dock.
static unsigned index
Base class for all map layer types.
Definition: qgsmaplayer.h:49
QStringList styles() const
Return list of all defined style names.
void setContentsMargins(int left, int top, int right, int bottom)
void setViewMode(ViewMode mode)
QString path() const
virtual QString loadSldStyle(const QString &theURI, bool &theResultFlag)
void setCurrentIndex(const QModelIndex &index)
void addAction(QAction *action)
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
This class provides qgis with the ability to render raster datasets onto the mapcanvas.
bool removeRow(int row, const QModelIndex &parent)
static QIcon getThemeIcon(const QString &theName)
Helper to get a theme icon.
virtual void setModel(QAbstractItemModel *model)
void setIcon(const QIcon &icon)
const T & at(int i) const
QgsMapLayerStyleManagerWidget(QgsMapLayer *layer, QgsMapCanvas *canvas, QWidget *parent=0)
Style manager widget to manage the layers styles.
virtual QString saveDefaultStyle(bool &theResultFlag)
Save the properties of this layer as the default style (either as a .qml file on disk or as a record ...
QString homePath()
QString tr(const char *sourceText, const char *disambiguation, int n)
StandardButton information(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:109
bool isNull() const
QgsMapLayerStyleManager * styleManager() const
Get access to the layer&#39;s style manager.
void setValue(const QString &key, const QVariant &value)
const char * name() const
bool removeStyle(const QString &name)
Remove a stored style.
bool isValid() const
void setLayout(QLayout *layout)
bool isEmpty() const
bool isEmpty() const
void setText(const QString &text)
QList< QStandardItem * > findItems(const QString &text, QFlags< Qt::MatchFlag > flags, int column) const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const
void setIcon(Icon)
void addWidget(QWidget *w)
void widgetChanged()
Emitted when the widget state changes.
QString getText(QWidget *parent, const QString &title, const QString &label, QLineEdit::EchoMode mode, const QString &text, bool *ok, QFlags< Qt::WindowType > flags, QFlags< Qt::InputMethodHint > inputMethodHints)
bool addStyleFromLayer(const QString &name)
Add style by cloning the current one.
QString currentStyle() const
Return name of the current style.
void setText(const QString &text)
QVariant value(const QString &key, const QVariant &defaultValue) const
QVariant data(int role) const
void removeAction(QAction *action)
QModelIndex index() const
StandardButton warning(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
virtual QString loadNamedStyle(const QString &theURI, bool &theResultFlag)
Retrieve a named style for this layer if one exists (either as a .qml file on disk or as a record in ...
void addButton(QAbstractButton *button, ButtonRole role)
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFlags< QFileDialog::Option > options)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
virtual QString styleURI()
Retrieve the style URI for this layer (either as a .qml file on disk or as a record in the users styl...
Represents a vector layer which manages a vector based data sets.
void setResizeMode(ResizeMode mode)
int compare(const QString &other) const
void addAction(QAction *action)
QString toString() const
int row() const
void appendRow(const QList< QStandardItem * > &items)
bool setCurrentStyle(const QString &name)
Set a different style as the current style - will apply it to the layer.