QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator 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 
43 QgsSymbolsListWidget::QgsSymbolsListWidget( QgsSymbolV2* symbol, QgsStyleV2* style, QMenu* menu, QWidget* parent, const QgsVectorLayer * layer )
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 );
67  mClipFeaturesAction->setCheckable( true );
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( 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 );
122  QgsSymbolGroupMap::const_iterator i = groups.constBegin();
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 
145 void QgsSymbolsListWidget::populateSymbols( QStringList names )
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
176  QIcon icon = QgsSymbolLayerV2Utils::symbolPreviewIcon( s, previewSize );
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 
201 void QgsSymbolsListWidget::setSymbolColor( const QColor& color )
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  bool isDefault = dd.hasDefaultValues();
222 
223  if ( // shall we remove datadefined expressions for layers ?
224  ( markerSymbol->dataDefinedAngle().hasDefaultValues() && isDefault )
225  // shall we set the "en masse" expression for properties ?
226  || !isDefault )
227  {
228  markerSymbol->setDataDefinedAngle( dd );
229  emit changed();
230  }
231 }
232 
234 {
235  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mSymbol );
236  if ( markerSymbol->size() == size )
237  return;
238  markerSymbol->setSize( size );
239  emit changed();
240 }
241 
243 {
244  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mSymbol );
245  QgsDataDefined dd = mSizeDDBtn->currentDataDefined();
246 
247  bool isDefault = dd.hasDefaultValues();
248 
249  if ( // shall we remove datadefined expressions for layers ?
250  ( !markerSymbol->dataDefinedSize().hasDefaultValues() && isDefault )
251  // shall we set the "en masse" expression for properties ?
252  || !isDefault )
253  {
254  markerSymbol->setDataDefinedSize( dd );
255  emit changed();
256  }
257 }
258 
260 {
261  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mSymbol );
262  if ( lineSymbol->width() == width )
263  return;
264  lineSymbol->setWidth( width );
265  emit changed();
266 }
267 
269 {
270  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mSymbol );
271  QgsDataDefined dd = mWidthDDBtn->currentDataDefined();
272 
273  bool isDefault = dd.hasDefaultValues();
274 
275  if ( // shall we remove datadefined expressions for layers ?
276  ( !lineSymbol->dataDefinedWidth().hasDefaultValues() && isDefault )
277  // shall we set the "en masse" expression for properties ?
278  || !isDefault )
279  {
280  lineSymbol->setDataDefinedWidth( dd );
281  emit changed();
282  }
283 }
284 
286 {
287  Q_UNUSED( name );
288  Q_UNUSED( symbol );
290 }
291 
293 {
294  bool ok;
295  QString name = QInputDialog::getText( this, tr( "Symbol name" ),
296  tr( "Please enter name for the symbol:" ), QLineEdit::Normal, tr( "New symbol" ), &ok );
297  if ( !ok || name.isEmpty() )
298  return;
299 
300  // check if there is no symbol with same name
301  if ( mStyle->symbolNames().contains( name ) )
302  {
303  int res = QMessageBox::warning( this, tr( "Save symbol" ),
304  tr( "Symbol with name '%1' already exists. Overwrite?" )
305  .arg( name ),
306  QMessageBox::Yes | QMessageBox::No );
307  if ( res != QMessageBox::Yes )
308  {
309  return;
310  }
311  }
312 
313  // add new symbol to style and re-populate the list
314  mStyle->addSymbol( name, mSymbol->clone() );
315 
316  // make sure the symbol is stored
317  mStyle->saveSymbol( name, mSymbol->clone(), 0, QStringList() );
319 }
320 
322 {
323  if ( mSymbol )
324  {
325 
326  mSymbol->setOutputUnit( mSymbolUnitWidget->unit() );
327  mSymbol->setMapUnitScale( mSymbolUnitWidget->getMapUnitScale() );
328 
329  emit changed();
330  }
331 }
332 
334 {
335  if ( mSymbol )
336  {
337  double alpha = 1 - ( value / 255.0 );
338  mSymbol->setAlpha( alpha );
339  displayTransparency( alpha );
340  emit changed();
341  }
342 }
343 
344 void QgsSymbolsListWidget::displayTransparency( double alpha )
345 {
346  double transparencyPercent = ( 1 - alpha ) * 100;
347  mTransparencyLabel->setText( tr( "Transparency %1%" ).arg(( int ) transparencyPercent ) );
348 }
349 
351 {
352  btnColor->blockSignals( true );
353  btnColor->setColor( mSymbol->color() );
354  btnColor->blockSignals( false );
355 }
356 
358 {
360 
361  if ( mSymbol->type() == QgsSymbolV2::Marker )
362  {
363  QgsMarkerSymbolV2* markerSymbol = static_cast<QgsMarkerSymbolV2*>( mSymbol );
364  spinSize->setValue( markerSymbol->size() );
365  spinAngle->setValue( markerSymbol->angle() );
366 
367  if ( mLayer )
368  {
369  QgsDataDefined ddSize = markerSymbol->dataDefinedSize();
371  spinSize->setEnabled( !mSizeDDBtn->isActive() );
372  QgsDataDefined ddAngle( markerSymbol->dataDefinedAngle() );
373  mRotationDDBtn->init( mLayer, &ddAngle, QgsDataDefinedButton::AnyType, QgsDataDefinedButton::doubleDesc() );
374  spinAngle->setEnabled( !mRotationDDBtn->isActive() );
375  }
376  else
377  {
378  mSizeDDBtn->setEnabled( false );
379  mRotationDDBtn->setEnabled( false );
380  }
381  }
382  else if ( mSymbol->type() == QgsSymbolV2::Line )
383  {
384  QgsLineSymbolV2* lineSymbol = static_cast<QgsLineSymbolV2*>( mSymbol );
385  spinWidth->setValue( lineSymbol->width() );
386 
387  if ( mLayer )
388  {
389  QgsDataDefined dd( lineSymbol->dataDefinedWidth() );
391  spinWidth->setEnabled( !mWidthDDBtn->isActive() );
392  }
393  else
394  {
395  mWidthDDBtn->setEnabled( false );
396  }
397  }
398 
399  mSymbolUnitWidget->blockSignals( true );
400  mSymbolUnitWidget->setUnit( mSymbol->outputUnit() );
401  mSymbolUnitWidget->setMapUnitScale( mSymbol->mapUnitScale() );
402  mSymbolUnitWidget->blockSignals( false );
403 
404  mTransparencySlider->blockSignals( true );
405  double transparency = 1 - mSymbol->alpha();
406  mTransparencySlider->setValue( transparency * 255 );
407  displayTransparency( mSymbol->alpha() );
408  mTransparencySlider->blockSignals( false );
409 
411  {
412  //add clip features option for line or fill symbols
413  btnAdvanced->menu()->addAction( mClipFeaturesAction );
414  }
415  else
416  {
417  btnAdvanced->menu()->removeAction( mClipFeaturesAction );
418  }
419  btnAdvanced->setVisible( mAdvancedMenu || !btnAdvanced->menu()->isEmpty() );
420 
421  mClipFeaturesAction->blockSignals( true );
423  mClipFeaturesAction->blockSignals( false );
424 }
425 
427 {
428  QString symbolName = index.data( Qt::UserRole ).toString();
429  lblSymbolName->setText( symbolName );
430  // get new instance of symbol from style
431  QgsSymbolV2* s = mStyle->symbol( symbolName );
433  // remove all symbol layers from original symbol
434  while ( mSymbol->symbolLayerCount() )
436  // move all symbol layers to our symbol
437  while ( s->symbolLayerCount() )
438  {
439  QgsSymbolLayerV2* sl = s->takeSymbolLayer( 0 );
440  mSymbol->appendSymbolLayer( sl );
441  }
442  mSymbol->setAlpha( s->alpha() );
443  mSymbol->setOutputUnit( unit );
444  // delete the temporary symbol
445  delete s;
446 
448  emit changed();
449 }
450 
452 {
453  QStringList symbols;
454  QString text = groupsCombo->itemText( index );
455  // List all symbols when empty list item is selected
456  if ( text.isEmpty() )
457  {
458  symbols = mStyle->symbolNames();
459  }
460  else
461  {
462  int groupid;
463  if ( groupsCombo->itemData( index ).toString() == "smart" )
464  {
465  groupid = mStyle->smartgroupId( text );
466  symbols = mStyle->symbolsOfSmartgroup( QgsStyleV2::SymbolEntity, groupid );
467  }
468  else
469  {
470  groupid = groupsCombo->itemData( index ).toInt();
471  symbols = mStyle->symbolsOfGroup( QgsStyleV2::SymbolEntity, groupid );
472  }
473  }
474  populateSymbols( symbols );
475 }
476 
478 {
479  QStringList symbols = mStyle->findSymbols( QgsStyleV2::SymbolEntity, text );
480  populateSymbols( symbols );
481 }
void populateSymbols(QStringList symbols)
bool deleteSymbolLayer(int index)
delete symbol layer at specified index
static unsigned index
void setClipFeaturesToExtent(bool clipFeaturesToExtent)
Sets whether features drawn by the symbol should be clipped to the render context's extent...
Definition: qgssymbolv2.h:173
void symbolAddedToStyle(QString name, QgsSymbolV2 *symbol)
void on_mTransparencySlider_valueChanged(int value)
void setLineWidth(double width)
bool saveSymbol(QString name, QgsSymbolV2 *symbol, int groupid, QStringList tags)
add the symbol to the DB with the tags
Definition: qgsstylev2.cpp:107
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).
double size() const
virtual QgsSymbolV2 * clone() const =0
QList< OutputUnit > OutputUnitList
Definition: qgssymbolv2.h:60
QgsDataDefined dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
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:183
QgsMapUnitScale mapUnitScale() const
QgsSymbolV2 * symbol(QString name)
return a NEW copy of symbol
Definition: qgsstylev2.cpp:166
void setMarkerSize(double size)
void on_groupsCombo_editTextChanged(const QString &text)
const QgsVectorLayer * mLayer
void setWidth(double width)
QgsDataDefined dataDefinedWidth() const
Returns data defined size for whole symbol (including all symbol layers).
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
void setColor(const QColor &color)
static QIcon symbolPreviewIcon(QgsSymbolV2 *symbol, QSize size)
double width() const
bool appendSymbolLayer(QgsSymbolLayerV2 *layer)
append symbol layer at the end of the list
qreal alpha() const
Get alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:158
QgsSymbolsListWidget(QgsSymbolV2 *symbol, QgsStyleV2 *style, QMenu *menu, QWidget *parent, const QgsVectorLayer *layer=0)
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)
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
QMap< int, QString > QgsSymbolGroupMap
Definition: qgsstylev2.h:35
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)
void on_groupsCombo_currentIndexChanged(int index)
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
QgsDataDefined dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
QgsSymbolV2::OutputUnit outputUnit() const
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.
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.
double size
Definition: qgssvgcache.cpp:77
int smartgroupId(QString smartgroup)
return the DB id for the given smartgroup name
Definition: qgsstylev2.cpp:972
void setOutputUnit(QgsSymbolV2::OutputUnit u)
void setAlpha(qreal alpha)
Set alpha transparency 1 for opaque, 0 for invisible.
Definition: qgssymbolv2.h:160
QColor color() const
#define tr(sourceText)