QGIS API Documentation  2.9.0-Master
qgsrendererv2widget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrendererv2widget.cpp
3  ---------------------
4  begin : November 2009
5  copyright : (C) 2009 by Martin Dobias
6  email : wonder dot sk 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 "qgsrendererv2widget.h"
16 #include "qgssymbolv2.h"
17 #include "qgsvectorlayer.h"
18 #include "qgscolordialog.h"
21 
22 #include <QMessageBox>
23 #include <QInputDialog>
24 #include <QMenu>
25 
27  : QWidget(), mLayer( layer ), mStyle( style )
28 {
29  contextMenu = new QMenu( "Renderer Options " );
30 
31  mCopyAction = contextMenu->addAction( tr( "Copy" ), this, SLOT( copy() ) );
32  mCopyAction->setShortcut( QKeySequence( QKeySequence::Copy ) );
33  mPasteAction = contextMenu->addAction( tr( "Paste" ), this, SLOT( paste() ) );
34  mPasteAction->setShortcut( QKeySequence( QKeySequence::Paste ) );
35 
36  contextMenu->addSeparator();
37  contextMenu->addAction( tr( "Change color" ), this, SLOT( changeSymbolColor() ) );
38  contextMenu->addAction( tr( "Change transparency" ), this, SLOT( changeSymbolTransparency() ) );
39  contextMenu->addAction( tr( "Change output unit" ), this, SLOT( changeSymbolUnit() ) );
40 
41  if ( mLayer && mLayer->geometryType() == QGis::Line )
42  {
43  contextMenu->addAction( tr( "Change width" ), this, SLOT( changeSymbolWidth() ) );
44  }
45  else if ( mLayer && mLayer->geometryType() == QGis::Point )
46  {
47  contextMenu->addAction( tr( "Change size" ), this, SLOT( changeSymbolSize() ) );
48  contextMenu->addAction( tr( "Change angle" ), this, SLOT( changeSymbolAngle() ) );
49  }
50 }
51 
53 {
54  contextMenu->exec( QCursor::pos() );
55 }
56 
58 {
59  QList<QgsSymbolV2*> symbolList = selectedSymbols();
60  if ( symbolList.size() < 1 )
61  {
62  return;
63  }
64 
65  QColor color = QgsColorDialogV2::getColor( symbolList.at( 0 )->color(), this, "Change Symbol Color", true );
66  if ( color.isValid() )
67  {
68  QList<QgsSymbolV2*>::iterator symbolIt = symbolList.begin();
69  for ( ; symbolIt != symbolList.end(); ++symbolIt )
70  {
71  ( *symbolIt )->setColor( color );
72  }
74  }
75 }
76 
78 {
79  QList<QgsSymbolV2*> symbolList = selectedSymbols();
80  if ( symbolList.size() < 1 )
81  {
82  return;
83  }
84 
85  bool ok;
86  double oldTransparency = ( 1 - symbolList.at( 0 )->alpha() ) * 100; // convert to percents
87  double transparency = QInputDialog::getDouble( this, tr( "Transparency" ), tr( "Change symbol transparency [%]" ), oldTransparency, 0.0, 100.0, 0, &ok );
88  if ( ok )
89  {
90  QList<QgsSymbolV2*>::iterator symbolIt = symbolList.begin();
91  for ( ; symbolIt != symbolList.end(); ++symbolIt )
92  {
93  ( *symbolIt )->setAlpha( 1 - transparency / 100 );
94  }
96  }
97 }
98 
100 {
101  QList<QgsSymbolV2*> symbolList = selectedSymbols();
102  if ( symbolList.size() < 1 )
103  {
104  return;
105  }
106 
107  bool ok;
108  int currentUnit = ( symbolList.at( 0 )->outputUnit() == QgsSymbolV2::MM ) ? 0 : 1;
109  QString item = QInputDialog::getItem( this, tr( "Symbol unit" ), tr( "Select symbol unit" ), QStringList() << tr( "Millimeter" ) << tr( "Map unit" ), currentUnit, false, &ok );
110  if ( ok )
111  {
112  QgsSymbolV2::OutputUnit unit = ( item.compare( tr( "Millimeter" ) ) == 0 ) ? QgsSymbolV2::MM : QgsSymbolV2::MapUnit;
113 
114  QList<QgsSymbolV2*>::iterator symbolIt = symbolList.begin();
115  for ( ; symbolIt != symbolList.end(); ++symbolIt )
116  {
117  ( *symbolIt )->setOutputUnit( unit );
118  }
120  }
121 }
122 
124 {
125  QList<QgsSymbolV2*> symbolList = selectedSymbols();
126  if ( symbolList.size() < 1 )
127  {
128  return;
129  }
130 
131  QgsDataDefinedWidthDialog dlg( symbolList, mLayer );
132 
133  if ( QMessageBox::Ok == dlg.exec() )
134  {
135  if ( !dlg.mDDBtn->isActive() )
136  {
137  QList<QgsSymbolV2*>::iterator symbolIt = symbolList.begin();
138  for ( ; symbolIt != symbolList.end(); ++symbolIt )
139  {
140  dynamic_cast<QgsLineSymbolV2*>( *symbolIt )->setWidth( dlg.mSpinBox->value() );
141  }
142  }
144  }
145 }
146 
148 {
149  QList<QgsSymbolV2*> symbolList = selectedSymbols();
150  if ( symbolList.size() < 1 )
151  {
152  return;
153  }
154 
155  QgsDataDefinedSizeDialog dlg( symbolList, mLayer );
156 
157  if ( QMessageBox::Ok == dlg.exec() )
158  {
159  if ( !dlg.mDDBtn->isActive() )
160  {
161  QList<QgsSymbolV2*>::iterator symbolIt = symbolList.begin();
162  for ( ; symbolIt != symbolList.end(); ++symbolIt )
163  {
164  dynamic_cast<QgsMarkerSymbolV2*>( *symbolIt )->setSize( dlg.mSpinBox->value() );
165  }
166  }
168  }
169 }
170 
172 {
173  QList<QgsSymbolV2*> symbolList = selectedSymbols();
174  if ( symbolList.size() < 1 )
175  {
176  return;
177  }
178 
179  QgsDataDefinedRotationDialog dlg( symbolList, mLayer );
180 
181  if ( QMessageBox::Ok == dlg.exec() )
182  {
183  if ( !dlg.mDDBtn->isActive() )
184  {
185  QList<QgsSymbolV2*>::iterator symbolIt = symbolList.begin();
186  for ( ; symbolIt != symbolList.end(); ++symbolIt )
187  {
188  dynamic_cast<QgsMarkerSymbolV2*>( *symbolIt )->setAngle( dlg.mSpinBox->value() );
189  }
190  }
192  }
193 }
194 
196 {
197  QgsLegendSymbolList symbols = r->legendSymbolItems();
198 
199  QgsSymbolLevelsV2Dialog dlg( symbols, r->usingSymbolLevels(), this );
200 
201  if ( dlg.exec() )
202  {
203  r->setUsingSymbolLevels( dlg.usingLevels() );
204  }
205 }
206 
207 
209 
210 #include "qgsfield.h"
211 
212 QgsRendererV2DataDefinedMenus::QgsRendererV2DataDefinedMenus( QMenu* menu, QgsVectorLayer* layer, QString rotationField, QString sizeScaleField, QgsSymbolV2::ScaleMethod scaleMethod )
213  : QObject( menu ), mLayer( layer )
214 {
215  mRotationMenu = new QMenu( tr( "Rotation field" ) );
216  mSizeScaleMenu = new QMenu( tr( "Size scale field" ) );
217 
218  mRotationAttributeActionGroup = new QActionGroup( mRotationMenu );
219  mSizeAttributeActionGroup = new QActionGroup( mSizeScaleMenu );
220  mSizeMethodActionGroup = new QActionGroup( mSizeScaleMenu );
221 
224 
225  mSizeScaleMenu->addSeparator();
226 
227  QAction* aScaleByArea = new QAction( tr( "Scale area" ), mSizeMethodActionGroup );
228  QAction* aScaleByDiameter = new QAction( tr( "Scale diameter" ), mSizeMethodActionGroup );
229 
230  aScaleByArea->setCheckable( true );
231  aScaleByDiameter->setCheckable( true );
232 
233  if ( scaleMethod == QgsSymbolV2::ScaleDiameter )
234  {
235  aScaleByDiameter->setChecked( true );
236  }
237  else
238  {
239  aScaleByArea->setChecked( true );
240  }
241 
242  mSizeScaleMenu->addActions( mSizeMethodActionGroup->actions() );
243 
244  //@todo cleanup the class since Rotation and SizeScale are now
245  //defined using QgsDataDefinedButton
246  //
247  //menu->addMenu( mRotationMenu );
248  //menu->addMenu( mSizeScaleMenu );
249 
250  connect( mSizeMethodActionGroup, SIGNAL( triggered( QAction* ) ), this, SLOT( scaleMethodSelected( QAction* ) ) );
251  connect( mRotationAttributeActionGroup, SIGNAL( triggered( QAction* ) ), this, SLOT( rotationFieldSelected( QAction* ) ) );
252  connect( mSizeAttributeActionGroup, SIGNAL( triggered( QAction* ) ), this, SLOT( sizeScaleFieldSelected( QAction* ) ) );
253 }
254 
256 {
257  delete mSizeMethodActionGroup;
260  delete mRotationMenu;
261  delete mSizeScaleMenu;
262 }
263 
264 void QgsRendererV2DataDefinedMenus::populateMenu( QMenu* menu, QString fieldName, QActionGroup *actionGroup )
265 {
266  QAction* aExpr = new QAction( tr( "- expression -" ), actionGroup );
267  aExpr->setCheckable( true );
268  menu->addAction( aExpr );
269  menu->addSeparator();
270  QAction* aNo = new QAction( tr( "- no field -" ), actionGroup );
271  aNo->setCheckable( true );
272  menu->addAction( aNo );
273  menu->addSeparator();
274 
275  bool hasField = false;
276  const QgsFields & flds = mLayer->pendingFields();
277  for ( int idx = 0; idx < flds.count(); ++idx )
278  {
279  const QgsField& fld = flds[idx];
280  if ( fld.type() == QVariant::Int || fld.type() == QVariant::Double )
281  {
282  QAction* a = new QAction( fld.name(), actionGroup );
283  a->setCheckable( true );
284  if ( fieldName == fld.name() )
285  {
286  a->setChecked( true );
287  hasField = true;
288  }
289  menu->addAction( a );
290  }
291  }
292 
293  if ( !hasField )
294  {
295  if ( fieldName.isEmpty() )
296  {
297  aNo->setChecked( true );
298  }
299  else
300  {
301  aExpr->setChecked( true );
302  aExpr->setText( tr( "- expression -" ) + fieldName );
303  }
304  }
305 
306 }
307 
309 {
310  if ( a == NULL )
311  return;
312 
313  QString fldName = a->text();
314 #if 0
315  updateMenu( mRotationAttributeActionGroup, fldName );
316 #endif
317  if ( fldName == tr( "- no field -" ) )
318  {
319  fldName = QString();
320  }
321  else if ( fldName.startsWith( tr( "- expression -" ) ) )
322  {
323  QString expr( fldName );
324  expr.replace( 0, tr( "- expression -" ).length(), "" );
325  QgsExpressionBuilderDialog dialog( mLayer, expr );
326  if ( !dialog.exec() ) return;
327  fldName = dialog.expressionText();
328  Q_ASSERT( !QgsExpression( fldName ).hasParserError() );
329  a->setText( tr( "- expression -" ) + fldName );
330  }
331 
332  emit rotationFieldChanged( fldName );
333 }
334 
336 {
337  if ( a == NULL )
338  return;
339 
340  QString fldName = a->text();
341 #if 0
342  updateMenu( mSizeAttributeActionGroup, fldName );
343 #endif
344  if ( fldName == tr( "- no field -" ) )
345  {
346  fldName = QString();
347  }
348  else if ( fldName.startsWith( tr( "- expression -" ) ) )
349  {
350  QString expr( fldName );
351  expr.replace( 0, tr( "- expression -" ).length(), "" );
352  QgsExpressionBuilderDialog dialog( mLayer, expr );
353  if ( !dialog.exec() ) return;
354  fldName = dialog.expressionText();
355  Q_ASSERT( !QgsExpression( fldName ).hasParserError() );
356  a->setText( tr( "- expression -" ) + fldName );
357  }
358 
359  emit sizeScaleFieldChanged( fldName );
360 }
361 
363 {
364  if ( a == NULL )
365  return;
366 
367  if ( a->text() == tr( "Scale area" ) )
368  {
370  }
371  else if ( a->text() == tr( "Scale diameter" ) )
372  {
374  }
375 }
376 #if 0 // MK: is there any reason for this?
377 void QgsRendererV2DataDefinedMenus::updateMenu( QActionGroup* actionGroup, QString fieldName )
378 {
379  foreach ( QAction* a, actionGroup->actions() )
380  {
381  a->setChecked( a->text() == fieldName );
382  }
383 }
384 #endif
385 
386 QgsDataDefinedValueDialog::QgsDataDefinedValueDialog( const QList<QgsSymbolV2*>& symbolList, QgsVectorLayer * layer, const QString & label )
387  : mSymbolList( symbolList )
388  , mLayer( layer )
389 {
390  setupUi( this );
391  setWindowFlags( Qt::WindowStaysOnTopHint );
392  mLabel->setText( label );
393  connect( mDDBtn, SIGNAL( dataDefinedChanged( const QString& ) ), this, SLOT( dataDefinedChanged() ) );
394  connect( mDDBtn, SIGNAL( dataDefinedActivated( bool ) ), this, SLOT( dataDefinedChanged() ) );
395 
396 }
397 
398 void QgsDataDefinedValueDialog::init( const QString & description )
399 {
401  mDDBtn->init( mLayer, &dd, QgsDataDefinedButton::Double, description );
402  mSpinBox->setValue( value( mSymbolList.back() ) );
403  mSpinBox->setEnabled( !mDDBtn->isActive() );
404 }
405 
407 {
408  // check that all symbols share the same size expression
410  foreach ( QgsSymbolV2 * it, mSymbolList )
411  {
412  if ( symbolDataDefined( it ) != dd ) return QgsDataDefined();
413  }
414  return dd;
415 }
416 
418 {
419  QgsDataDefined dd = mDDBtn->currentDataDefined();
420  mSpinBox->setEnabled( !dd.isActive() );
421 
422  if ( // shall we remove datadefined expressions for layers ?
423  ( symbolDataDefined().isActive() && !dd.isActive() )
424  // shall we set the "en masse" expression for properties ?
425  || dd.isActive() )
426  {
427  foreach ( QgsSymbolV2 * it, mSymbolList )
428  setDataDefined( it, dd );
429  }
430 }
431 
433 {
434  const QgsMarkerSymbolV2* marker = static_cast<const QgsMarkerSymbolV2*>( symbol );
435  return marker->dataDefinedSize();
436 }
437 
439 {
440  static_cast<QgsMarkerSymbolV2*>( symbol )->setDataDefinedSize( dd );
441 }
442 
443 
445 {
446  const QgsMarkerSymbolV2* marker = static_cast<const QgsMarkerSymbolV2*>( symbol );
447  return marker->dataDefinedAngle();
448 }
449 
451 {
452  static_cast<QgsMarkerSymbolV2*>( symbol )->setDataDefinedAngle( dd );
453 }
454 
455 
457 {
458  const QgsLineSymbolV2* line = static_cast<const QgsLineSymbolV2*>( symbol );
459  return line->dataDefinedWidth();
460 }
461 
463 {
464  static_cast<QgsLineSymbolV2*>( symbol )->setDataDefinedWidth( dd );
465 }
double value(const QgsSymbolV2 *symbol) const override
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:86
void showSymbolLevelsDialog(QgsFeatureRendererV2 *r)
show a dialog with renderer's symbol level settings
const QString & name() const
Gets the name of the field.
Definition: qgsfield.cpp:69
virtual QList< QgsSymbolV2 * > selectedSymbols()
Subclasses may provide the capability of changing multiple symbols at once by implementing the follow...
void changeSymbolTransparency()
Change opacity of selected symbols.
A container class for data source field mapping or expression.
void init(const QString &description)
void changeSymbolSize()
Change marker sizes of selected symbols.
void contextMenuViewCategories(const QPoint &p)
void setDataDefined(QgsSymbolV2 *symbol, const QgsDataDefined &dd) override
void setDataDefined(QgsSymbolV2 *symbol, const QgsDataDefined &dd) override
QgsDataDefined dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
virtual QgsLegendSymbolList legendSymbolItems(double scaleDenominator=-1, QString rule="")
return a list of item text / symbol
Container of fields for a vector layer.
Definition: qgsfield.h:173
void populateMenu(QMenu *menu, QString fieldName, QActionGroup *actionGroup)
void changeSymbolWidth()
Change line widths of selected symbols.
double value(const QgsSymbolV2 *symbol) const override
void setWidth(double width)
QgsDataDefined dataDefinedWidth() const
Returns data defined size for whole symbol (including all symbol layers).
QgsDataDefined symbolDataDefined() const
void changeSymbolAngle()
Change marker angles of selected symbols.
QgsVectorLayer * mLayer
void changeSymbolUnit()
Change units mm/map units of selected symbols.
void setAngle(double angle)
void rotationFieldChanged(QString fldName)
void setSize(double size)
void changeSymbolColor()
Change color of selected symbols.
int count() const
Return number of items.
Definition: qgsfield.cpp:283
QGis::GeometryType geometryType() const
Returns point, line or polygon.
double value(const QgsSymbolV2 *symbol) const override
Encapsulate a field in an attribute table or data source.
Definition: qgsfield.h:38
void scaleMethodChanged(QgsSymbolV2::ScaleMethod scaleMethod)
virtual double value(const QgsSymbolV2 *) const =0
QgsRendererV2Widget(QgsVectorLayer *layer, QgsStyleV2 *style)
void setDataDefined(QgsSymbolV2 *symbol, const QgsDataDefined &dd) override
void setUsingSymbolLevels(bool usingSymbolLevels)
QList< QgsSymbolV2 * > mSymbolList
static QColor getColor(const QColor &initialColor, QWidget *parent, const QString &title=QString(), const bool allowAlpha=false)
Return a color selection from a color dialog.
QgsDataDefined dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
virtual void setDataDefined(QgsSymbolV2 *symbol, const QgsDataDefined &dd)=0
void sizeScaleFieldChanged(QString fldName)
bool usingSymbolLevels() const
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
virtual void refreshSymbolView()
QgsRendererV2DataDefinedMenus(QMenu *menu, QgsVectorLayer *layer, QString rotationField, QString sizeScaleField, QgsSymbolV2::ScaleMethod scaleMethod)
Represents a vector layer which manages a vector based data sets.
QList< QPair< QString, QgsSymbolV2 * > > QgsLegendSymbolList
Definition: qgsrendererv2.h:43
bool isActive() const
A generic dialog for building expression strings.
QgsDataDefinedValueDialog(const QList< QgsSymbolV2 * > &symbolList, QgsVectorLayer *layer, const QString &label)
Constructor.
QVariant::Type type() const
Gets variant type of the field as it will be retrieved from data source.
Definition: qgsfield.cpp:74
#define tr(sourceText)