QGIS API Documentation  3.2.0-Bonn (bc43194)
qgsrendererwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsrendererwidget.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 "qgsrendererwidget.h"
16 
18 #include "qgssymbol.h"
19 #include "qgsvectorlayer.h"
20 #include "qgscolordialog.h"
21 #include "qgssymbollevelsdialog.h"
22 #include "qgssymbollayer.h"
24 #include "qgsmapcanvas.h"
25 #include "qgspanelwidget.h"
26 #include "qgsproject.h"
27 
28 #include <QMessageBox>
29 #include <QInputDialog>
30 #include <QMenu>
31 
33  : mLayer( layer )
34  , mStyle( style )
35 {
36  contextMenu = new QMenu( tr( "Renderer Options" ), this );
37 
38  mCopyAction = contextMenu->addAction( tr( "Copy" ), this, SLOT( copy() ) );
39  mCopyAction->setShortcut( QKeySequence( QKeySequence::Copy ) );
40  mPasteAction = contextMenu->addAction( tr( "Paste" ), this, SLOT( paste() ) );
41  mPasteAction->setShortcut( QKeySequence( QKeySequence::Paste ) );
42 
43  contextMenu->addSeparator();
44  contextMenu->addAction( tr( "Change Color…" ), this, SLOT( changeSymbolColor() ) );
45  contextMenu->addAction( tr( "Change Opacity…" ), this, SLOT( changeSymbolOpacity() ) );
46  contextMenu->addAction( tr( "Change Output Unit…" ), this, SLOT( changeSymbolUnit() ) );
47 
49  {
50  contextMenu->addAction( tr( "Change Width…" ), this, SLOT( changeSymbolWidth() ) );
51  }
53  {
54  contextMenu->addAction( tr( "Change Size…" ), this, SLOT( changeSymbolSize() ) );
55  contextMenu->addAction( tr( "Change Angle…" ), this, SLOT( changeSymbolAngle() ) );
56  }
57 }
58 
60 {
61  contextMenu->exec( QCursor::pos() );
62 }
63 
65 {
66  QList<QgsSymbol *> symbolList = selectedSymbols();
67  if ( symbolList.isEmpty() )
68  {
69  return;
70  }
71 
72  QgsSymbol *firstSymbol = nullptr;
73  Q_FOREACH ( QgsSymbol *symbol, symbolList )
74  {
75  if ( symbol )
76  {
77  firstSymbol = symbol;
78  break;
79  }
80  }
81  if ( !firstSymbol )
82  return;
83 
84  QColor color = QgsColorDialog::getColor( firstSymbol->color(), this, QStringLiteral( "Change Symbol Color" ), true );
85  if ( color.isValid() )
86  {
87  Q_FOREACH ( QgsSymbol *symbol, symbolList )
88  {
89  if ( symbol )
90  symbol->setColor( color );
91  }
93  }
94 }
95 
97 {
98  QList<QgsSymbol *> symbolList = selectedSymbols();
99  if ( symbolList.isEmpty() )
100  {
101  return;
102  }
103 
104  QgsSymbol *firstSymbol = nullptr;
105  Q_FOREACH ( QgsSymbol *symbol, symbolList )
106  {
107  if ( symbol )
108  {
109  firstSymbol = symbol;
110  break;
111  }
112  }
113  if ( !firstSymbol )
114  return;
115 
116  bool ok;
117  double oldOpacity = firstSymbol->opacity() * 100; // convert to %
118  double opacity = QInputDialog::getDouble( this, tr( "Opacity" ), tr( "Change symbol opacity [%]" ), oldOpacity, 0.0, 100.0, 1, &ok );
119  if ( ok )
120  {
121  Q_FOREACH ( QgsSymbol *symbol, symbolList )
122  {
123  if ( symbol )
124  symbol->setOpacity( opacity / 100.0 );
125  }
127  }
128 }
129 
131 {
132  QList<QgsSymbol *> symbolList = selectedSymbols();
133  if ( symbolList.isEmpty() )
134  {
135  return;
136  }
137 
138  QgsSymbol *firstSymbol = nullptr;
139  Q_FOREACH ( QgsSymbol *symbol, symbolList )
140  {
141  if ( symbol )
142  {
143  firstSymbol = symbol;
144  break;
145  }
146  }
147  if ( !firstSymbol )
148  return;
149 
150  bool ok;
151  int currentUnit = ( firstSymbol->outputUnit() == QgsUnitTypes::RenderMillimeters ) ? 0 : 1;
152  QString item = QInputDialog::getItem( this, tr( "Symbol unit" ), tr( "Select symbol unit" ), QStringList() << tr( "Millimeter" ) << tr( "Map unit" ), currentUnit, false, &ok );
153  if ( ok )
154  {
155  QgsUnitTypes::RenderUnit unit = ( item.compare( tr( "Millimeter" ) ) == 0 ) ? QgsUnitTypes::RenderMillimeters : QgsUnitTypes::RenderMapUnits;
156 
157  Q_FOREACH ( QgsSymbol *symbol, symbolList )
158  {
159  if ( symbol )
160  symbol->setOutputUnit( unit );
161  }
163  }
164 }
165 
167 {
168  QList<QgsSymbol *> symbolList = selectedSymbols();
169  if ( symbolList.isEmpty() )
170  {
171  return;
172  }
173 
174  QgsDataDefinedWidthDialog dlg( symbolList, mLayer );
175 
176  dlg.setContext( mContext );
177 
178  if ( QDialog::Accepted == dlg.exec() )
179  {
180  if ( !dlg.mDDBtn->isActive() )
181  {
182  Q_FOREACH ( QgsSymbol *symbol, symbolList )
183  {
184  if ( !symbol )
185  continue;
186 
187  if ( symbol->type() == QgsSymbol::Line )
188  static_cast<QgsLineSymbol *>( symbol )->setWidth( dlg.mSpinBox->value() );
189  }
190  }
192  }
193 }
194 
196 {
197  QList<QgsSymbol *> symbolList = selectedSymbols();
198  if ( symbolList.isEmpty() )
199  {
200  return;
201  }
202 
203  QgsDataDefinedSizeDialog dlg( symbolList, mLayer );
204  dlg.setContext( mContext );
205 
206  if ( QDialog::Accepted == dlg.exec() )
207  {
208  if ( !dlg.mDDBtn->isActive() )
209  {
210  Q_FOREACH ( QgsSymbol *symbol, symbolList )
211  {
212  if ( !symbol )
213  continue;
214 
215  if ( symbol->type() == QgsSymbol::Marker )
216  static_cast<QgsMarkerSymbol *>( symbol )->setSize( dlg.mSpinBox->value() );
217  }
218  }
220  }
221 }
222 
224 {
225  QList<QgsSymbol *> symbolList = selectedSymbols();
226  if ( symbolList.isEmpty() )
227  {
228  return;
229  }
230 
231  QgsDataDefinedRotationDialog dlg( symbolList, mLayer );
232  dlg.setContext( mContext );
233 
234  if ( QDialog::Accepted == dlg.exec() )
235  {
236  if ( !dlg.mDDBtn->isActive() )
237  {
238  Q_FOREACH ( QgsSymbol *symbol, symbolList )
239  {
240  if ( !symbol )
241  continue;
242 
243  if ( symbol->type() == QgsSymbol::Marker )
244  static_cast<QgsMarkerSymbol *>( symbol )->setAngle( dlg.mSpinBox->value() );
245  }
246  }
248  }
249 }
250 
252 {
254  if ( panel && panel->dockMode() )
255  {
256  QgsSymbolLevelsWidget *widget = new QgsSymbolLevelsWidget( r, r->usingSymbolLevels(), panel );
257  widget->setPanelTitle( tr( "Symbol Levels" ) );
258  connect( widget, &QgsPanelWidget::widgetChanged, widget, &QgsSymbolLevelsWidget::apply );
260  panel->openPanel( widget );
261  return;
262  }
263 
264  QgsSymbolLevelsDialog dlg( r, r->usingSymbolLevels(), panel );
265  if ( dlg.exec() )
266  {
267  emit widgetChanged();
268  }
269 }
270 
272 {
273  mContext = context;
274 }
275 
277 {
278  return mContext;
279 }
280 
282 {
283  apply();
284 }
285 
287 {
288  QgsProperty ddSize = symbol->dataDefinedSize();
289  if ( !ddSize || !ddSize.isActive() )
290  {
291  QMessageBox::warning( this, tr( "Data-defined Size Legend" ), tr( "Data-defined size is not enabled!" ) );
292  return nullptr;
293  }
294 
295  QgsDataDefinedSizeLegendWidget *panel = new QgsDataDefinedSizeLegendWidget( ddsLegend, ddSize, symbol->clone(), mContext.mapCanvas() );
297  return panel;
298 }
299 
300 
301 //
302 // QgsDataDefinedValueDialog
303 //
304 
305 QgsDataDefinedValueDialog::QgsDataDefinedValueDialog( const QList<QgsSymbol *> &symbolList, QgsVectorLayer *layer, const QString &label )
306  : mSymbolList( symbolList )
307  , mLayer( layer )
308 {
309  setupUi( this );
310  setWindowFlags( Qt::WindowStaysOnTopHint );
311  mLabel->setText( label );
313 }
314 
316 {
317  mContext = context;
318 }
319 
321 {
322  return mContext;
323 }
324 
325 QgsExpressionContext QgsDataDefinedValueDialog::createExpressionContext() const
326 {
327  QgsExpressionContext expContext;
331  if ( mContext.mapCanvas() )
332  {
335  }
336  else
337  {
339  }
340 
341  if ( vectorLayer() )
343 
344  // additional scopes
345  Q_FOREACH ( const QgsExpressionContextScope &scope, mContext.additionalExpressionContextScopes() )
346  {
347  expContext.appendScope( new QgsExpressionContextScope( scope ) );
348  }
349 
350  return expContext;
351 }
352 
353 void QgsDataDefinedValueDialog::init( int propertyKey )
354 {
355  QgsProperty dd( symbolDataDefined() );
356 
357  mDDBtn->init( propertyKey, dd, QgsSymbolLayer::propertyDefinitions(), mLayer );
358  mDDBtn->registerExpressionContextGenerator( this );
359 
360  QgsSymbol *initialSymbol = nullptr;
361  Q_FOREACH ( QgsSymbol *symbol, mSymbolList )
362  {
363  if ( symbol )
364  {
365  initialSymbol = symbol;
366  }
367  }
368  mSpinBox->setValue( initialSymbol ? value( initialSymbol ) : 0 );
369  mSpinBox->setEnabled( !mDDBtn->isActive() );
370 }
371 
372 QgsProperty QgsDataDefinedValueDialog::symbolDataDefined() const
373 {
374  if ( mSymbolList.isEmpty() || !mSymbolList.back() )
375  return QgsProperty();
376 
377  // check that all symbols share the same size expression
378  QgsProperty dd = symbolDataDefined( mSymbolList.back() );
379  Q_FOREACH ( QgsSymbol *it, mSymbolList )
380  {
381  QgsProperty symbolDD( symbolDataDefined( it ) );
382  if ( !it || !dd || !symbolDD || symbolDD != dd )
383  return QgsProperty();
384  }
385  return dd;
386 }
387 
389 {
390  QgsProperty dd( mDDBtn->toProperty() );
391  mSpinBox->setEnabled( !dd.isActive() );
392 
393  QgsProperty symbolDD( symbolDataDefined() );
394 
395  if ( // shall we remove datadefined expressions for layers ?
396  ( symbolDD && symbolDD.isActive() && !dd.isActive() )
397  // shall we set the "en masse" expression for properties ?
398  || dd.isActive() )
399  {
400  Q_FOREACH ( QgsSymbol *it, mSymbolList )
401  setDataDefined( it, dd );
402  }
403 }
404 
406 {
407  const QgsMarkerSymbol *marker = static_cast<const QgsMarkerSymbol *>( symbol );
408  return marker->dataDefinedSize();
409 }
410 
412 {
413  static_cast<QgsMarkerSymbol *>( symbol )->setDataDefinedSize( dd );
414  static_cast<QgsMarkerSymbol *>( symbol )->setScaleMethod( QgsSymbol::ScaleDiameter );
415 }
416 
417 
419 {
420  const QgsMarkerSymbol *marker = static_cast<const QgsMarkerSymbol *>( symbol );
421  return marker->dataDefinedAngle();
422 }
423 
425 {
426  static_cast<QgsMarkerSymbol *>( symbol )->setDataDefinedAngle( dd );
427 }
428 
429 
431 {
432  const QgsLineSymbol *line = static_cast<const QgsLineSymbol *>( symbol );
433  return line->dataDefinedWidth();
434 }
435 
437 {
438  static_cast<QgsLineSymbol *>( symbol )->setDataDefinedWidth( dd );
439 }
440 
441 void QgsRendererWidget::apply()
442 {
443 
444 }
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
static QColor getColor(const QColor &initialColor, QWidget *parent, const QString &title=QString(), bool allowOpacity=false)
Returns a color selection from a color dialog.
void changeSymbolOpacity()
Change opacity of selected symbols.
void changeSymbolWidth()
Change line widths of selected symbols.
virtual void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the renderer widget is shown, e.g., the associated map canvas and expressio...
bool dockMode()
Returns the dock mode state.
Calculate scale by the diameter.
Definition: qgssymbol.h:97
double value(const QgsSymbol *symbol) const override
virtual void refreshSymbolView()
void changeSymbolAngle()
Change marker angles of selected symbols.
QgsSymbolWidgetContext context() const
Returns the context in which the renderer widget is shown, e.g., the associated map canvas and expres...
void showSymbolLevelsDialog(QgsFeatureRenderer *r)
show a dialog with renderer&#39;s symbol level settings
double value(const QgsSymbol *symbol) const override
QgsVectorLayer * mLayer
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
Base class for any widget that can be shown as a inline panel.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
Line symbol.
Definition: qgssymbol.h:86
QgsProperty symbolDataDefined(const QgsSymbol *symbol) const override
The QgsMapSettings class contains configuration for rendering of the map.
QgsUnitTypes::RenderUnit outputUnit() const
Returns the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:206
void applyChanges()
This method should be called whenever the renderer is actually set on the layer.
void setOutputUnit(QgsUnitTypes::RenderUnit unit)
Sets the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:251
QgsProperty dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1192
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QgsSymbolWidgetContext context() const
Returns the context in which the symbol widget is shown, e.g., the associated map canvas and expressi...
void setDataDefined(QgsSymbol *symbol, const QgsProperty &dd) override
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget...
Contains settings which reflect the context in which a symbol (or renderer) widget is shown...
void setOpacity(qreal opacity)
Sets the opacity for the symbol.
Definition: qgssymbol.h:264
Widget for configuration of appearance of legend for marker symbols with data-defined size...
A widget which allows the user to modify the rendering order of symbol layers.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void changeSymbolSize()
Change marker sizes of selected symbols.
QColor color() const
Definition: qgssymbol.cpp:449
QgsDataDefinedSizeLegendWidget * createDataDefinedSizeLegendWidget(const QgsMarkerSymbol *symbol, const QgsDataDefinedSizeLegend *ddsLegend)
Creates widget to setup data-defined size legend.
Single scope for storing variables and functions for use within a QgsExpressionContext.
A store for object properties.
Definition: qgsproperty.h:229
virtual void paste()
virtual void copy()
void widgetChanged()
Emitted when the widget state changes.
QgsProperty symbolDataDefined(const QgsSymbol *symbol) const override
A dialog which allows the user to modify the rendering order of symbol layers.
double value(const QgsSymbol *symbol) const override
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1374
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
void changed()
Emitted when property definition changes.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
Marker symbol.
Definition: qgssymbol.h:85
static QgsExpressionContextScope * atlasScope(QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
void apply()
Apply button.
const QgsVectorLayer * vectorLayer() const
Returns the vector layer associated with the widget.
bool usingSymbolLevels() const
Definition: qgsrenderer.h:271
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object...
QgsSymbolWidgetContext mContext
Context in which widget is shown.
QgsExpressionContextScope & expressionContextScope()
Returns a reference to the expression context scope for the map canvas.
Definition: qgsmapcanvas.h:558
SymbolType type() const
Definition: qgssymbol.h:113
virtual QList< QgsSymbol * > selectedSymbols()
Subclasses may provide the capability of changing multiple symbols at once by implementing the follow...
void init(int propertyKey)
Should be called in the constructor of child classes.
void setDataDefined(QgsSymbol *symbol, const QgsProperty &dd) override
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:391
void contextMenuViewCategories(QPoint p)
QgsProperty symbolDataDefined(const QgsSymbol *symbol) const override
QgsDataDefinedValueDialog(const QList< QgsSymbol *> &symbolList, QgsVectorLayer *layer, const QString &label)
Constructor.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:257
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the symbol layer property definitions.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
QgsRendererWidget(QgsVectorLayer *layer, QgsStyle *style)
void changeSymbolColor()
Change color of selected symbols.
Represents a vector layer which manages a vector based data sets.
Object that keeps configuration of appearance of marker symbol&#39;s data-defined size in legend...
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
QgsProperty dataDefinedWidth() const
Returns data defined width for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1631
void changeSymbolUnit()
Change units mm/map units of selected symbols.
QgsMarkerSymbol * clone() const override
Gets a deep copy of this symbol.
Definition: qgssymbol.cpp:1531
bool isActive() const
Returns whether the property is currently active.
void setDataDefined(QgsSymbol *symbol, const QgsProperty &dd) override
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:100
QList< QgsExpressionContextScope > additionalExpressionContextScopes() const
Returns the list of additional expression context scopes to show as available within the layer...
void setColor(const QColor &color)
Definition: qgssymbol.cpp:440