QGIS API Documentation  3.4.15-Madeira (e83d02e274)
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 );
259  connect( widget, &QgsPanelWidget::widgetChanged, [ = ]() { emit widgetChanged(); emit symbolLevelsChanged(); } );
260  panel->openPanel( widget );
261  return;
262  }
263 
264  QgsSymbolLevelsDialog dlg( r, r->usingSymbolLevels(), panel );
265  if ( dlg.exec() )
266  {
267  emit widgetChanged();
268  emit symbolLevelsChanged();
269  }
270 }
271 
273 {
274  mContext = context;
275 }
276 
278 {
279  return mContext;
280 }
281 
283 {
284  apply();
285 }
286 
288 {
289  QgsProperty ddSize = symbol->dataDefinedSize();
290  if ( !ddSize || !ddSize.isActive() )
291  {
292  QMessageBox::warning( this, tr( "Data-defined Size Legend" ), tr( "Data-defined size is not enabled!" ) );
293  return nullptr;
294  }
295 
296  QgsDataDefinedSizeLegendWidget *panel = new QgsDataDefinedSizeLegendWidget( ddsLegend, ddSize, symbol->clone(), mContext.mapCanvas() );
298  return panel;
299 }
300 
301 
302 //
303 // QgsDataDefinedValueDialog
304 //
305 
306 QgsDataDefinedValueDialog::QgsDataDefinedValueDialog( const QList<QgsSymbol *> &symbolList, QgsVectorLayer *layer, const QString &label )
307  : mSymbolList( symbolList )
308  , mLayer( layer )
309 {
310  setupUi( this );
311  setWindowFlags( Qt::WindowStaysOnTopHint );
312  mLabel->setText( label );
314 }
315 
317 {
318  mContext = context;
319 }
320 
322 {
323  return mContext;
324 }
325 
326 QgsExpressionContext QgsDataDefinedValueDialog::createExpressionContext() const
327 {
328  QgsExpressionContext expContext;
332  if ( mContext.mapCanvas() )
333  {
336  }
337  else
338  {
340  }
341 
342  if ( vectorLayer() )
344 
345  // additional scopes
346  Q_FOREACH ( const QgsExpressionContextScope &scope, mContext.additionalExpressionContextScopes() )
347  {
348  expContext.appendScope( new QgsExpressionContextScope( scope ) );
349  }
350 
351  return expContext;
352 }
353 
354 void QgsDataDefinedValueDialog::init( int propertyKey )
355 {
356  QgsProperty dd( symbolDataDefined() );
357 
358  mDDBtn->init( propertyKey, dd, QgsSymbolLayer::propertyDefinitions(), mLayer );
359  mDDBtn->registerExpressionContextGenerator( this );
360 
361  QgsSymbol *initialSymbol = nullptr;
362  Q_FOREACH ( QgsSymbol *symbol, mSymbolList )
363  {
364  if ( symbol )
365  {
366  initialSymbol = symbol;
367  }
368  }
369  mSpinBox->setValue( initialSymbol ? value( initialSymbol ) : 0 );
370  mSpinBox->setEnabled( !mDDBtn->isActive() );
371 }
372 
373 QgsProperty QgsDataDefinedValueDialog::symbolDataDefined() const
374 {
375  if ( mSymbolList.isEmpty() || !mSymbolList.back() )
376  return QgsProperty();
377 
378  // check that all symbols share the same size expression
379  QgsProperty dd = symbolDataDefined( mSymbolList.back() );
380  Q_FOREACH ( QgsSymbol *it, mSymbolList )
381  {
382  QgsProperty symbolDD( symbolDataDefined( it ) );
383  if ( !it || !dd || !symbolDD || symbolDD != dd )
384  return QgsProperty();
385  }
386  return dd;
387 }
388 
390 {
391  QgsProperty dd( mDDBtn->toProperty() );
392  mSpinBox->setEnabled( !dd.isActive() );
393 
394  QgsProperty symbolDD( symbolDataDefined() );
395 
396  if ( // shall we remove datadefined expressions for layers ?
397  ( symbolDD && symbolDD.isActive() && !dd.isActive() )
398  // shall we set the "en masse" expression for properties ?
399  || dd.isActive() )
400  {
401  Q_FOREACH ( QgsSymbol *it, mSymbolList )
402  setDataDefined( it, dd );
403  }
404 }
405 
407 {
408  const QgsMarkerSymbol *marker = static_cast<const QgsMarkerSymbol *>( symbol );
409  return marker->dataDefinedSize();
410 }
411 
413 {
414  static_cast<QgsMarkerSymbol *>( symbol )->setDataDefinedSize( dd );
415  static_cast<QgsMarkerSymbol *>( symbol )->setScaleMethod( QgsSymbol::ScaleDiameter );
416 }
417 
418 
420 {
421  const QgsMarkerSymbol *marker = static_cast<const QgsMarkerSymbol *>( symbol );
422  return marker->dataDefinedAngle();
423 }
424 
426 {
427  static_cast<QgsMarkerSymbol *>( symbol )->setDataDefinedAngle( dd );
428 }
429 
430 
432 {
433  const QgsLineSymbol *line = static_cast<const QgsLineSymbol *>( symbol );
434  return line->dataDefinedWidth();
435 }
436 
438 {
439  static_cast<QgsLineSymbol *>( symbol )->setDataDefinedWidth( dd );
440 }
441 
442 void QgsRendererWidget::apply()
443 {
444 
445 }
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
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:61
virtual void refreshSymbolView()
void changeSymbolAngle()
Change marker angles of selected symbols.
void showSymbolLevelsDialog(QgsFeatureRenderer *r)
show a dialog with renderer&#39;s symbol level settings
bool isActive() const
Returns whether the property is currently active.
double value(const QgsSymbol *symbol) const override
QgsVectorLayer * mLayer
bool usingSymbolLevels() const
Definition: qgsrenderer.h:271
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
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
void symbolLevelsChanged()
Emitted when the symbol levels settings have been changed.
QgsSymbolWidgetContext context() const
Returns the context in which the symbol widget is shown, e.g., the associated map canvas and expressi...
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
qreal opacity() const
Returns the opacity for the symbol.
Definition: qgssymbol.h:339
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:732
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:920
The QgsMapSettings class contains configuration for rendering of the map.
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:259
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
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:346
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.
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.
QgsDataDefinedValueDialog(const QList< QgsSymbol * > &symbolList, QgsVectorLayer *layer, const QString &label)
Constructor.
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
QgsProperty dataDefinedWidth() const
Returns data defined width for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1708
A dialog which allows the user to modify the rendering order of symbol layers.
double value(const QgsSymbol *symbol) const override
void changed()
Emitted when property definition changes.
Marker symbol.
Definition: qgssymbol.h:85
const QgsVectorLayer * vectorLayer() const
Returns the vector layer associated with the widget.
static QgsExpressionContextScope * atlasScope(QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
void apply()
Apply button.
QgsProperty dataDefinedSize() const
Returns data defined size for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1430
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:560
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:411
void contextMenuViewCategories(QPoint p)
SymbolType type() const
Returns the symbol&#39;s type.
Definition: qgssymbol.h:120
QgsProperty symbolDataDefined(const QgsSymbol *symbol) const override
QList< QgsExpressionContextScope > additionalExpressionContextScopes() const
Returns the list of additional expression context scopes to show as available within the layer...
QgsWkbTypes::GeometryType geometryType() const
Returns point, line or polygon.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the symbol layer property definitions.
QgsSymbolWidgetContext context() const
Returns the context in which the renderer widget is shown, e.g., the associated map canvas and expres...
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
QgsProperty dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1233
QgsRendererWidget(QgsVectorLayer *layer, QgsStyle *style)
void changeSymbolColor()
Change color of selected symbols.
QColor color() const
Returns the symbol&#39;s color.
Definition: qgssymbol.cpp:459
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.
void changeSymbolUnit()
Change units mm/map units of selected symbols.
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:1590
void setDataDefined(QgsSymbol *symbol, const QgsProperty &dd) override
RenderUnit
Rendering size units.
Definition: qgsunittypes.h:110
void setColor(const QColor &color)
Sets the color for the symbol.
Definition: qgssymbol.cpp:450
QgsUnitTypes::RenderUnit outputUnit() const
Returns the units to use for sizes and widths within the symbol.
Definition: qgssymbol.cpp:214