QGIS API Documentation  2.9.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups 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 }