QGIS API Documentation  3.8.0-Zanzibar (11aff65)
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"
28 
29 #include <QMessageBox>
30 #include <QInputDialog>
31 #include <QMenu>
32 
34  : mLayer( layer )
35  , mStyle( style )
36 {
37  contextMenu = new QMenu( tr( "Renderer Options" ), this );
38 
39  mCopyAction = contextMenu->addAction( tr( "Copy" ), this, SLOT( copy() ) );
40  mCopyAction->setShortcut( QKeySequence( QKeySequence::Copy ) );
41  mPasteAction = contextMenu->addAction( tr( "Paste" ), this, SLOT( paste() ) );
42  mPasteAction->setShortcut( QKeySequence( QKeySequence::Paste ) );
43 
44  contextMenu->addSeparator();
45  contextMenu->addAction( tr( "Change Color…" ), this, SLOT( changeSymbolColor() ) );
46  contextMenu->addAction( tr( "Change Opacity…" ), this, SLOT( changeSymbolOpacity() ) );
47  contextMenu->addAction( tr( "Change Output Unit…" ), this, SLOT( changeSymbolUnit() ) );
48 
50  {
51  contextMenu->addAction( tr( "Change Width…" ), this, SLOT( changeSymbolWidth() ) );
52  }
54  {
55  contextMenu->addAction( tr( "Change Size…" ), this, SLOT( changeSymbolSize() ) );
56  contextMenu->addAction( tr( "Change Angle…" ), this, SLOT( changeSymbolAngle() ) );
57  }
58 }
59 
61 {
62  contextMenu->exec( QCursor::pos() );
63 }
64 
66 {
67  QList<QgsSymbol *> symbolList = selectedSymbols();
68  if ( symbolList.isEmpty() )
69  {
70  return;
71  }
72 
73  QgsSymbol *firstSymbol = nullptr;
74  const auto constSymbolList = symbolList;
75  for ( QgsSymbol *symbol : constSymbolList )
76  {
77  if ( symbol )
78  {
79  firstSymbol = symbol;
80  break;
81  }
82  }
83  if ( !firstSymbol )
84  return;
85 
86  QColor color = QgsColorDialog::getColor( firstSymbol->color(), this, QStringLiteral( "Change Symbol Color" ), true );
87  if ( color.isValid() )
88  {
89  const auto constSymbolList = symbolList;
90  for ( QgsSymbol *symbol : constSymbolList )
91  {
92  if ( symbol )
93  symbol->setColor( color );
94  }
96  }
97 }
98 
100 {
101  QList<QgsSymbol *> symbolList = selectedSymbols();
102  if ( symbolList.isEmpty() )
103  {
104  return;
105  }
106 
107  QgsSymbol *firstSymbol = nullptr;
108  const auto constSymbolList = symbolList;
109  for ( QgsSymbol *symbol : constSymbolList )
110  {
111  if ( symbol )
112  {
113  firstSymbol = symbol;
114  break;
115  }
116  }
117  if ( !firstSymbol )
118  return;
119 
120  bool ok;
121  double oldOpacity = firstSymbol->opacity() * 100; // convert to %
122  double opacity = QInputDialog::getDouble( this, tr( "Opacity" ), tr( "Change symbol opacity [%]" ), oldOpacity, 0.0, 100.0, 1, &ok );
123  if ( ok )
124  {
125  const auto constSymbolList = symbolList;
126  for ( QgsSymbol *symbol : constSymbolList )
127  {
128  if ( symbol )
129  symbol->setOpacity( opacity / 100.0 );
130  }
132  }
133 }
134 
136 {
137  QList<QgsSymbol *> symbolList = selectedSymbols();
138  if ( symbolList.isEmpty() )
139  {
140  return;
141  }
142 
143  QgsSymbol *firstSymbol = nullptr;
144  const auto constSymbolList = symbolList;
145  for ( QgsSymbol *symbol : constSymbolList )
146  {
147  if ( symbol )
148  {
149  firstSymbol = symbol;
150  break;
151  }
152  }
153  if ( !firstSymbol )
154  return;
155 
156  bool ok;
157  int currentUnit = ( firstSymbol->outputUnit() == QgsUnitTypes::RenderMillimeters ) ? 0 : 1;
158  QString item = QInputDialog::getItem( this, tr( "Symbol unit" ), tr( "Select symbol unit" ), QStringList() << tr( "Millimeter" ) << tr( "Map unit" ), currentUnit, false, &ok );
159  if ( ok )
160  {
161  QgsUnitTypes::RenderUnit unit = ( item.compare( tr( "Millimeter" ) ) == 0 ) ? QgsUnitTypes::RenderMillimeters : QgsUnitTypes::RenderMapUnits;
162 
163  const auto constSymbolList = symbolList;
164  for ( QgsSymbol *symbol : constSymbolList )
165  {
166  if ( symbol )
167  symbol->setOutputUnit( unit );
168  }
170  }
171 }
172 
174 {
175  QList<QgsSymbol *> symbolList = selectedSymbols();
176  if ( symbolList.isEmpty() )
177  {
178  return;
179  }
180 
181  QgsDataDefinedWidthDialog dlg( symbolList, mLayer );
182 
183  dlg.setContext( mContext );
184 
185  if ( QDialog::Accepted == dlg.exec() )
186  {
187  if ( !dlg.mDDBtn->isActive() )
188  {
189  const auto constSymbolList = symbolList;
190  for ( QgsSymbol *symbol : constSymbolList )
191  {
192  if ( !symbol )
193  continue;
194 
195  if ( symbol->type() == QgsSymbol::Line )
196  static_cast<QgsLineSymbol *>( symbol )->setWidth( dlg.mSpinBox->value() );
197  }
198  }
200  }
201 }
202 
204 {
205  QList<QgsSymbol *> symbolList = selectedSymbols();
206  if ( symbolList.isEmpty() )
207  {
208  return;
209  }
210 
211  QgsDataDefinedSizeDialog dlg( symbolList, mLayer );
212  dlg.setContext( mContext );
213 
214  if ( QDialog::Accepted == dlg.exec() )
215  {
216  if ( !dlg.mDDBtn->isActive() )
217  {
218  const auto constSymbolList = symbolList;
219  for ( QgsSymbol *symbol : constSymbolList )
220  {
221  if ( !symbol )
222  continue;
223 
224  if ( symbol->type() == QgsSymbol::Marker )
225  static_cast<QgsMarkerSymbol *>( symbol )->setSize( dlg.mSpinBox->value() );
226  }
227  }
229  }
230 }
231 
233 {
234  QList<QgsSymbol *> symbolList = selectedSymbols();
235  if ( symbolList.isEmpty() )
236  {
237  return;
238  }
239 
240  QgsDataDefinedRotationDialog dlg( symbolList, mLayer );
241  dlg.setContext( mContext );
242 
243  if ( QDialog::Accepted == dlg.exec() )
244  {
245  if ( !dlg.mDDBtn->isActive() )
246  {
247  const auto constSymbolList = symbolList;
248  for ( QgsSymbol *symbol : constSymbolList )
249  {
250  if ( !symbol )
251  continue;
252 
253  if ( symbol->type() == QgsSymbol::Marker )
254  static_cast<QgsMarkerSymbol *>( symbol )->setAngle( dlg.mSpinBox->value() );
255  }
256  }
258  }
259 }
260 
262 {
264  if ( panel && panel->dockMode() )
265  {
266  QgsSymbolLevelsWidget *widget = new QgsSymbolLevelsWidget( r, r->usingSymbolLevels(), panel );
267  widget->setPanelTitle( tr( "Symbol Levels" ) );
268  connect( widget, &QgsPanelWidget::widgetChanged, widget, &QgsSymbolLevelsWidget::apply );
270  panel->openPanel( widget );
271  return;
272  }
273 
274  QgsSymbolLevelsDialog dlg( r, r->usingSymbolLevels(), panel );
275  if ( dlg.exec() )
276  {
277  emit widgetChanged();
278  }
279 }
280 
282 {
283  mContext = context;
284 }
285 
287 {
288  return mContext;
289 }
290 
292 {
293  apply();
294 }
295 
297 {
298  QgsProperty ddSize = symbol->dataDefinedSize();
299  if ( !ddSize || !ddSize.isActive() )
300  {
301  QMessageBox::warning( this, tr( "Data-defined Size Legend" ), tr( "Data-defined size is not enabled!" ) );
302  return nullptr;
303  }
304 
305  QgsDataDefinedSizeLegendWidget *panel = new QgsDataDefinedSizeLegendWidget( ddsLegend, ddSize, symbol->clone(), mContext.mapCanvas() );
307  return panel;
308 }
309 
310 
311 //
312 // QgsDataDefinedValueDialog
313 //
314 
315 QgsDataDefinedValueDialog::QgsDataDefinedValueDialog( const QList<QgsSymbol *> &symbolList, QgsVectorLayer *layer, const QString &label )
316  : mSymbolList( symbolList )
317  , mLayer( layer )
318 {
319  setupUi( this );
320  setWindowFlags( Qt::WindowStaysOnTopHint );
321  mLabel->setText( label );
323 }
324 
326 {
327  mContext = context;
328 }
329 
331 {
332  return mContext;
333 }
334 
335 QgsExpressionContext QgsDataDefinedValueDialog::createExpressionContext() const
336 {
337  QgsExpressionContext expContext;
341  if ( mContext.mapCanvas() )
342  {
345  }
346  else
347  {
349  }
350 
351  if ( vectorLayer() )
353 
354  // additional scopes
355  const auto constAdditionalExpressionContextScopes = mContext.additionalExpressionContextScopes();
356  for ( const QgsExpressionContextScope &scope : constAdditionalExpressionContextScopes )
357  {
358  expContext.appendScope( new QgsExpressionContextScope( scope ) );
359  }
360 
361  return expContext;
362 }
363 
364 void QgsDataDefinedValueDialog::init( int propertyKey )
365 {
366  QgsProperty dd( symbolDataDefined() );
367 
368  mDDBtn->init( propertyKey, dd, QgsSymbolLayer::propertyDefinitions(), mLayer );
369  mDDBtn->registerExpressionContextGenerator( this );
370 
371  QgsSymbol *initialSymbol = nullptr;
372  const auto constMSymbolList = mSymbolList;
373  for ( QgsSymbol *symbol : constMSymbolList )
374  {
375  if ( symbol )
376  {
377  initialSymbol = symbol;
378  }
379  }
380  mSpinBox->setValue( initialSymbol ? value( initialSymbol ) : 0 );
381  mSpinBox->setEnabled( !mDDBtn->isActive() );
382 }
383 
384 QgsProperty QgsDataDefinedValueDialog::symbolDataDefined() const
385 {
386  if ( mSymbolList.isEmpty() || !mSymbolList.back() )
387  return QgsProperty();
388 
389  // check that all symbols share the same size expression
390  QgsProperty dd = symbolDataDefined( mSymbolList.back() );
391  const auto constMSymbolList = mSymbolList;
392  for ( QgsSymbol *it : constMSymbolList )
393  {
394  QgsProperty symbolDD( symbolDataDefined( it ) );
395  if ( !it || !dd || !symbolDD || symbolDD != dd )
396  return QgsProperty();
397  }
398  return dd;
399 }
400 
402 {
403  QgsProperty dd( mDDBtn->toProperty() );
404  mSpinBox->setEnabled( !dd.isActive() );
405 
406  QgsProperty symbolDD( symbolDataDefined() );
407 
408  if ( // shall we remove datadefined expressions for layers ?
409  ( symbolDD && symbolDD.isActive() && !dd.isActive() )
410  // shall we set the "en masse" expression for properties ?
411  || dd.isActive() )
412  {
413  const auto constMSymbolList = mSymbolList;
414  for ( QgsSymbol *it : constMSymbolList )
415  setDataDefined( it, dd );
416  }
417 }
418 
420 {
421  const QgsMarkerSymbol *marker = static_cast<const QgsMarkerSymbol *>( symbol );
422  return marker->dataDefinedSize();
423 }
424 
426 {
427  static_cast<QgsMarkerSymbol *>( symbol )->setDataDefinedSize( dd );
428  static_cast<QgsMarkerSymbol *>( symbol )->setScaleMethod( QgsSymbol::ScaleDiameter );
429 }
430 
431 
433 {
434  const QgsMarkerSymbol *marker = static_cast<const QgsMarkerSymbol *>( symbol );
435  return marker->dataDefinedAngle();
436 }
437 
439 {
440  static_cast<QgsMarkerSymbol *>( symbol )->setDataDefinedAngle( dd );
441 }
442 
443 
445 {
446  const QgsLineSymbol *line = static_cast<const QgsLineSymbol *>( symbol );
447  return line->dataDefinedWidth();
448 }
449 
451 {
452  static_cast<QgsLineSymbol *>( symbol )->setDataDefinedWidth( dd );
453 }
454 
455 void QgsRendererWidget::apply()
456 {
457 
458 }
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.
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
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:766
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgssymbol.h:966
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:230
void applyChanges()
This method should be called whenever the renderer is actually set on the layer.
QgsProperty dataDefinedAngle() const
Returns data defined angle for whole symbol (including all symbol layers).
Definition: qgssymbol.cpp:1271
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...
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
Returns the symbol&#39;s color.
Definition: qgssymbol.cpp:480
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:1476
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:561
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:438
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:339
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:1762
void changeSymbolUnit()
Change units mm/map units of selected symbols.
QgsMarkerSymbol * clone() const override
Returns a deep copy of this symbol.
Definition: qgssymbol.cpp:1641
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:111
QList< QgsExpressionContextScope > additionalExpressionContextScopes() const
Returns the list of additional expression context scopes to show as available within the layer...