QGIS API Documentation  2.11.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
qgssymbolslistwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssymbolslist.cpp
3  ---------------------
4  begin : June 2012
5  copyright : (C) 2012 by Arunmozhi
6  email : aruntheguy at gmail.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 
16 
17 #include "qgssymbolslistwidget.h"
18 
19 #include "qgssizescalewidget.h"
20 
22 #include "qgsdatadefined.h"
23 
24 #include "qgssymbolv2.h"
25 #include "qgsstylev2.h"
26 #include "qgssymbollayerv2utils.h"
27 #include "qgsmarkersymbollayerv2.h"
28 
29 #include "qgsapplication.h"
30 
31 #include <QString>
32 #include <QStringList>
33 #include <QPainter>
34 #include <QIcon>
35 #include <QStandardItemModel>
36 #include <QColorDialog>
37 #include <QInputDialog>
38 #include <QMessageBox>
39 #include <QMenu>
40 #include <QScopedPointer>
41 
42 
44  : QWidget( parent )
45  , mSymbol( symbol )
46  , mStyle( style )
47  , mAdvancedMenu( 0 )
48  , mClipFeaturesAction( 0 )
49  , mLayer( layer )
50 {
51  setupUi( this );
52 
53  mSymbolUnitWidget->setUnits( QgsSymbolV2::OutputUnitList() << QgsSymbolV2::MM << QgsSymbolV2::MapUnit );
54 
55  btnAdvanced->hide(); // advanced button is hidden by default
56  if ( menu ) // show it if there is a menu pointer
57  {
58  mAdvancedMenu = menu;
59  btnAdvanced->show();
60  btnAdvanced->setMenu( mAdvancedMenu );
61  }
62  else
63  {
64  btnAdvanced->setMenu( new QMenu( this ) );
65  }
66  mClipFeaturesAction = new QAction( tr( "Clip features to canvas extent" ), this );
68  connect( mClipFeaturesAction, SIGNAL( toggled( bool ) ), this, SLOT( clipFeaturesToggled( bool ) ) );
69 
70  // populate the groups
71  groupsCombo->addItem( "" );
72  populateGroups();
73  QStringList groups = style->smartgroupNames();
74  foreach ( QString group, groups )
75  {
76  groupsCombo->addItem( group, QVariant( "smart" ) );
77  }
78 
79  QStandardItemModel* model = new QStandardItemModel( viewSymbols );
80  viewSymbols->setModel( model );
81  connect( viewSymbols->selectionModel(), SIGNAL( currentChanged( const QModelIndex &, const QModelIndex & ) ), this, SLOT( setSymbolFromStyle( const QModelIndex & ) ) );
82 
83  connect( mStyle, SIGNAL( symbolSaved( QString, QgsSymbolV2* ) ), this, SLOT( symbolAddedToStyle( QString, QgsSymbolV2* ) ) );
84  connect( openStyleManagerButton, SIGNAL( pressed() ), this, SLOT( openStyleManager() ) );
85 
86  lblSymbolName->setText( "" );
88 
89  if ( mSymbol )
90  {
92  }
93 
94  // select correct page in stacked widget
95  // there's a correspondence between symbol type number and page numbering => exploit it!
96  stackedWidget->setCurrentIndex( symbol->type() );
97  connect( btnColor, SIGNAL( colorChanged( const QColor& ) ), this, SLOT( setSymbolColor( const QColor& ) ) );
98  connect( spinAngle, SIGNAL( valueChanged( double ) ), this, SLOT( setMarkerAngle( double ) ) );
99  connect( spinSize, SIGNAL( valueChanged( double ) ), this, SLOT( setMarkerSize( double ) ) );
100  connect( spinWidth, SIGNAL( valueChanged( double ) ), this, SLOT( setLineWidth( double ) ) );
101 
102  connect( mRotationDDBtn, SIGNAL( dataDefinedChanged( const QString& ) ), this, SLOT( updateDataDefinedMarkerAngle() ) );
103  connect( mRotationDDBtn, SIGNAL( dataDefinedActivated( bool ) ), this, SLOT( updateDataDefinedMarkerAngle() ) );
104  connect( mSizeDDBtn, SIGNAL( dataDefinedChanged( const QString& ) ), this, SLOT( updateDataDefinedMarkerSize() ) );
105  connect( mSizeDDBtn, SIGNAL( dataDefinedActivated( bool ) ), this, SLOT( updateDataDefinedMarkerSize() ) );
106  connect( mWidthDDBtn, SIGNAL( dataDefinedChanged( const QString& ) ), this, SLOT( updateDataDefinedLineWidth() ) );
107  connect( mWidthDDBtn, SIGNAL( dataDefinedActivated( bool ) ), this, SLOT( updateDataDefinedLineWidth() ) );
108 
109  if ( mSymbol->type() == QgsSymbolV2::Marker && mLayer )
110  mSizeDDBtn->setAssistant( tr( "Size Assistant..." ), new QgsSizeScaleWidget( mLayer, static_cast<const QgsMarkerSymbolV2*>( mSymbol ) ) );
111 
112  // Live color updates are not undoable to child symbol layers
113  btnColor->setAcceptLiveUpdates( false );
114  btnColor->setAllowAlpha( true );
115  btnColor->setColorDialogTitle( tr( "Select color" ) );
116  btnColor->setContext( "symbology" );
117 }
118 
119 void QgsSymbolsListWidget::populateGroups( QString parent, QString prepend )
120 {
121  QgsSymbolGroupMap groups = mStyle->childGroupNames( parent );
123  while ( i != groups.constEnd() )
124  {
125  QString text;
126  if ( !prepend.isEmpty() )
127  {
128  text = prepend + "/" + i.value();
129  }
130  else
131  {
132  text = i.value();
133  }
134  groupsCombo->addItem( text, QVariant( i.key() ) );
135  populateGroups( i.value(), text );
136  ++i;
137  }
138 }
139 
141 {
143 }
144 
146 {
147  QSize previewSize = viewSymbols->iconSize();
148  QPixmap p( previewSize );
149  QPainter painter;
150 
151  QStandardItemModel* model = qobject_cast<QStandardItemModel*>( viewSymbols->model() );
152  if ( !model )
153  {
154  return;
155  }
156  model->clear();
157 
158  for ( int i = 0; i < names.count(); i++ )
159  {
160  QgsSymbolV2* s = mStyle->symbol( names[i] );
161  if ( s->type() != mSymbol->type() )
162  {
163  delete s;
164  continue;
165  }
166  QStandardItem* item = new QStandardItem( names[i] );
167  item->setData( names[i], Qt::UserRole ); //so we can load symbol with that name
168  item->setText( names[i] );
169  item->setToolTip( names[i] );
170  item->setFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
171  // Set font to 10points to show reasonable text
172  QFont itemFont = item->font();
173  itemFont.setPointSize( 10 );
174  item->setFont( itemFont );
175  // create preview icon
177  item->setIcon( icon );
178  // add to model
179  model->appendRow( item );
180  delete s;
181  }
182 }
183 
185 {
186  QgsStyleV2ManagerDialog dlg( mStyle, this );
187  dlg.exec();
188 
190 }
191 
193 {
194  if ( !mSymbol )
195  return;
196 
197  mSymbol->setClipFeaturesToExtent( checked );
198  emit changed();
199 }
200 
202 {
203  mSymbol->setColor( color );
204  emit changed();
205 }
206 
208 {
209  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mSymbol );
210  if ( markerSymbol->angle() == angle )
211  return;
212  markerSymbol->setAngle( angle );
213  emit changed();
214 }
215 
217 {
218  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mSymbol );
219  QgsDataDefined dd = mRotationDDBtn->currentDataDefined();
220 
221  spinAngle->setEnabled( !mRotationDDBtn->isActive() );
222 
223  bool isDefault = dd.hasDefaultValues();
224 
225  if ( // shall we remove datadefined expressions for layers ?
226  ( markerSymbol->dataDefinedAngle().hasDefaultValues() && isDefault )
227  // shall we set the "en masse" expression for properties ?
228  || !isDefault )
229  {
230  markerSymbol->setDataDefinedAngle( dd );
231  emit changed();
232  }
233 }
234 
236 {
237  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mSymbol );
238  if ( markerSymbol->size() == size )
239  return;
240  markerSymbol->setSize( size );
241  emit changed();
242 }
243 
245 {
246  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mSymbol );
247  QgsDataDefined dd = mSizeDDBtn->currentDataDefined();
248 
249  spinSize->setEnabled( !mSizeDDBtn->isActive() );
250 
251  bool isDefault = dd.hasDefaultValues();
252 
253  if ( // shall we remove datadefined expressions for layers ?
254  ( !markerSymbol->dataDefinedSize().hasDefaultValues() && isDefault )
255  // shall we set the "en masse" expression for properties ?
256  || !isDefault )
257  {
258  markerSymbol->setDataDefinedSize( dd );
259  emit changed();
260  }
261 }
262 
264 {
265  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mSymbol );
266  if ( lineSymbol->width() == width )
267  return;
268  lineSymbol->setWidth( width );
269  emit changed();
270 }
271 
273 {
274  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mSymbol );
275  QgsDataDefined dd = mWidthDDBtn->currentDataDefined();
276 
277  spinWidth->setEnabled( !mWidthDDBtn->isActive() );
278 
279  bool isDefault = dd.hasDefaultValues();
280 
281  if ( // shall we remove datadefined expressions for layers ?
282  ( !lineSymbol->dataDefinedWidth().hasDefaultValues() && isDefault )
283  // shall we set the "en masse" expression for properties ?
284  || !isDefault )
285  {
286  lineSymbol->setDataDefinedWidth( dd );
287  emit changed();
288  }
289 }
290 
292 {
293  Q_UNUSED( name );
294  Q_UNUSED( symbol );
296 }
297 
299 {
300  bool ok;
301  QString name = QInputDialog::getText( this, tr( "Symbol name" ),
302  tr( "Please enter name for the symbol:" ), QLineEdit::Normal, tr( "New symbol" ), &ok );
303  if ( !ok || name.isEmpty() )
304  return;
305 
306  // check if there is no symbol with same name
307  if ( mStyle->symbolNames().contains( name ) )
308  {
309  int res = QMessageBox::warning( this, tr( "Save symbol" ),
310  tr( "Symbol with name '%1' already exists. Overwrite?" )
311  .arg( name ),
312  QMessageBox::Yes | QMessageBox::No );
313  if ( res != QMessageBox::Yes )
314  {
315  return;
316  }
317  }
318 
319  // add new symbol to style and re-populate the list
320  mStyle->addSymbol( name, mSymbol->clone() );
321 
322  // make sure the symbol is stored
323  mStyle->saveSymbol( name, mSymbol->clone(), 0, QStringList() );
325 }
326 
328 {
329  if ( mSymbol )
330  {
331 
332  mSymbol->setOutputUnit( mSymbolUnitWidget->unit() );
333  mSymbol->setMapUnitScale( mSymbolUnitWidget->getMapUnitScale() );
334 
335  emit changed();
336  }
337 }
338 
340 {
341  if ( mSymbol )
342  {
343  double alpha = 1 - ( value / 255.0 );
344  mSymbol->setAlpha( alpha );
345  displayTransparency( alpha );
346  emit changed();
347  }
348 }
349 
350 void QgsSymbolsListWidget::displayTransparency( double alpha )
351 {
352  double transparencyPercent = ( 1 - alpha ) * 100;
353  mTransparencyLabel->setText( tr( "Transparency %1%" ).arg(( int ) transparencyPercent ) );
354 }
355 
357 {
358  btnColor->blockSignals( true );
359  btnColor->setColor( mSymbol->color() );
360  btnColor->blockSignals( false );
361 }
362 
364 {
366 
367  if ( mSymbol->type() == QgsSymbolV2::Marker )
368  {
369  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mSymbol );
370  spinSize->setValue( markerSymbol->size() );
371  spinAngle->setValue( markerSymbol->angle() );
372 
373  if ( mLayer )
374  {
375  QgsDataDefined ddSize = markerSymbol->dataDefinedSize();
377  spinSize->setEnabled( !mSizeDDBtn->isActive() );
378  QgsDataDefined ddAngle( markerSymbol->dataDefinedAngle() );
379  mRotationDDBtn->init( mLayer, &ddAngle, QgsDataDefinedButton::AnyType, QgsDataDefinedButton::doubleDesc() );
380  spinAngle->setEnabled( !mRotationDDBtn->isActive() );
381  }
382  else
383  {
384  mSizeDDBtn->setEnabled( false );
385  mRotationDDBtn->setEnabled( false );
386  }
387  }
388  else if ( mSymbol->type() == QgsSymbolV2::Line )
389  {
390  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mSymbol );
391  spinWidth->setValue( lineSymbol->width() );
392 
393  if ( mLayer )
394  {
395  QgsDataDefined dd( lineSymbol->dataDefinedWidth() );
397  spinWidth->setEnabled( !mWidthDDBtn->isActive() );
398  }
399  else
400  {
401  mWidthDDBtn->setEnabled( false );
402  }
403  }
404 
405  mSymbolUnitWidget->blockSignals( true );
406  mSymbolUnitWidget->setUnit( mSymbol->outputUnit() );
407  mSymbolUnitWidget->setMapUnitScale( mSymbol->mapUnitScale() );
408  mSymbolUnitWidget->blockSignals( false );
409 
410  mTransparencySlider->blockSignals( true );
411  double transparency = 1 - mSymbol->alpha();
412  mTransparencySlider->setValue( transparency * 255 );
413  displayTransparency( mSymbol->alpha() );
414  mTransparencySlider->blockSignals( false );
415 
417  {
418  //add clip features option for line or fill symbols
419  btnAdvanced->menu()->addAction( mClipFeaturesAction );
420  }
421  else
422  {
423  btnAdvanced->menu()->removeAction( mClipFeaturesAction );
424  }
425  btnAdvanced->setVisible( mAdvancedMenu || !btnAdvanced->menu()->isEmpty() );
426 
430 }
431 
433 {
434  QString symbolName = index.data( Qt::UserRole ).toString();
435  lblSymbolName->setText( symbolName );
436  // get new instance of symbol from style
437  QgsSymbolV2* s = mStyle->symbol( symbolName );
439  // remove all symbol layers from original symbol
440  while ( mSymbol->symbolLayerCount() )
442  // move all symbol layers to our symbol
443  while ( s->symbolLayerCount() )
444  {
445  QgsSymbolLayerV2* sl = s->takeSymbolLayer( 0 );
446  mSymbol->appendSymbolLayer( sl );
447  }
448  mSymbol->setAlpha( s->alpha() );
449  mSymbol->setOutputUnit( unit );
450  // delete the temporary symbol
451  delete s;
452 
454  emit changed();
455 }
456 
458 {
459  QStringList symbols;
460  QString text = groupsCombo->itemText( index );
461  // List all symbols when empty list item is selected
462  if ( text.isEmpty() )
463  {
464  symbols = mStyle->symbolNames();
465  }
466  else
467  {
468  int groupid;
469  if ( groupsCombo->itemData( index ).toString() == "smart" )
470  {
471  groupid = mStyle->smartgroupId( text );
472  symbols = mStyle->symbolsOfSmartgroup( QgsStyleV2::SymbolEntity, groupid );
473  }
474  else
475  {
476  groupid = groupsCombo->itemData( index ).toInt();
477  symbols = mStyle->symbolsOfGroup( QgsStyleV2::SymbolEntity, groupid );
478  }
479  }
480  populateSymbols( symbols );
481 }
482 
484 {
486  populateSymbols( symbols );
487 }
void populateSymbols(QStringList symbols)
void setToolTip(const QString &toolTip)
bool deleteSymbolLayer(int index)
delete symbol layer at specified index
static unsigned index
void setPointSize(int pointSize)
void setClipFeaturesToExtent(bool clipFeaturesToExtent)
Sets whether features drawn by the symbol should be clipped to the render context's extent...
Definition: qgssymbolv2.h:193
void symbolAddedToStyle(QString name, QgsSymbolV2 *symbol)
void on_mTransparencySlider_valueChanged(int value)
void setLineWidth(double width)
void setupUi(QWidget *widget)
bool saveSymbol(QString name, QgsSymbolV2 *symbol, int groupid, QStringList tags)
add the symbol to the DB with the tags
Definition: qgsstylev2.cpp:107
void setIcon(const QIcon &icon)
void setDataDefinedAngle(const QgsDataDefined &dd)
Set data defined angle for whole symbol (including all symbol layers).
A container class for data source field mapping or expression.
void setSymbolFromStyle(const QModelIndex &index)
static QString doublePosDesc()
SymbolType type() const
Definition: qgssymbolv2.h:86
void setDataDefinedSize(const QgsDataDefined &dd)
Set data defined size for whole symbol (including all symbol layers).
void setChecked(bool)
double size() const
virtual QgsSymbolV2 * clone() const =0
QgsDataDefined dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
const_iterator constBegin() const
QStringList symbolsOfGroup(StyleEntity type, int groupid)
returns the symbolnames of a given groupid
Definition: qgsstylev2.cpp:527
double clipFeaturesToExtent() const
Returns whether features drawn by the symbol will be clipped to the render context's extent...
Definition: qgssymbolv2.h:203
bool contains(const QString &str, Qt::CaseSensitivity cs) const
QgsMapUnitScale mapUnitScale() const
int exec()
QgsSymbolV2 * symbol(QString name)
return a NEW copy of symbol
Definition: qgsstylev2.cpp:166
const QPixmap * icon() const
void setMarkerSize(double size)
void on_groupsCombo_editTextChanged(const QString &text)
QString tr(const char *sourceText, const char *disambiguation, int n)
const QgsVectorLayer * mLayer
void setWidth(double width)
QgsDataDefined dataDefinedWidth() const
Returns data defined size for whole symbol (including all symbol layers).
virtual void setData(const QVariant &value, int role)
void setMapUnitScale(const QgsMapUnitScale &scale)
QgsSymbolGroupMap childGroupNames(QString parent="")
return a map of groupid and names for the given parent group
Definition: qgsstylev2.cpp:480
bool addSymbol(QString name, QgsSymbolV2 *symbol, bool update=false)
add symbol to style. takes symbol's ownership
Definition: qgsstylev2.cpp:83
bool isEmpty() const
int width() const
QSize size() const
void setColor(const QColor &color)
const char * name() const
static QIcon symbolPreviewIcon(QgsSymbolV2 *symbol, QSize size)
int count(const T &value) const
double width() const
bool appendSymbolLayer(QgsSymbolLayerV2 *layer)
Append symbol layer at the end of the list Ownership will be transferred.
const Key & key() const
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:178
QgsSymbolsListWidget(QgsSymbolV2 *symbol, QgsStyleV2 *style, QMenu *menu, QWidget *parent, const QgsVectorLayer *layer=0)
void setFlags(QFlags< Qt::ItemFlag > flags)
bool isEmpty() const
const_iterator constEnd() const
double angle() const
void setAngle(double angle)
void setSymbolColor(const QColor &color)
int symbolLayerCount()
Returns total number of symbol layers contained in the symbol.
Definition: qgssymbolv2.h:113
void setSize(double size)
const T & value() const
void setMarkerAngle(double angle)
QStringList symbolsOfSmartgroup(StyleEntity type, int id)
returns the symbols for the smartgroup
QStringList symbolNames()
return a list of names of symbols
Definition: qgsstylev2.cpp:182
void setFont(const QFont &font)
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)
double ANALYSIS_EXPORT angle(Point3D *p1, Point3D *p2, Point3D *p3, Point3D *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
bool blockSignals(bool block)
void on_groupsCombo_currentIndexChanged(int index)
void setCheckable(bool)
void setText(const QString &text)
void setDataDefinedWidth(const QgsDataDefined &dd)
Set data defined width for whole symbol (including all symbol layers).
void clipFeaturesToggled(bool checked)
QStringList smartgroupNames()
returns the smart groups list
QFont font() const
QgsDataDefined dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
QVariant data(int role) const
QgsSymbolV2::OutputUnit outputUnit() const
StandardButton warning(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
void show()
QgsSymbolLayerV2 * takeSymbolLayer(int index)
Remove symbol layer from the list and return pointer to it.
bool hasDefaultValues() const
Returns whether the data defined container is set to all the default values, ie, disabled, with empty expression and no assigned field.
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QStringList findSymbols(StyleEntity type, QString qword)
return the names of the symbols which have a matching 'substring' in its defintion ...
Definition: qgsstylev2.cpp:764
Represents a vector layer which manages a vector based data sets.
QString toString() const
int smartgroupId(QString smartgroup)
return the DB id for the given smartgroup name
Definition: qgsstylev2.cpp:972
void setOutputUnit(QgsSymbolV2::OutputUnit u)
void appendRow(const QList< QStandardItem * > &items)
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:180
QColor color() const