QGIS API Documentation  3.4.15-Madeira (e83d02e274)
qgslayerpropertieswidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayerpropertieswidget.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 
17 
18 #include <QFile>
19 #include <QStandardItem>
20 #include <QKeyEvent>
21 #include <QMessageBox>
22 #include <QPicture>
23 
24 #include "qgssymbollayer.h"
25 #include "qgssymbollayerregistry.h"
26 
27 #include "qgsapplication.h"
28 #include "qgslogger.h"
29 
30 #include "qgssymbollayerwidget.h"
34 #include "qgssymbol.h" //for the unit
35 #include "qgspanelwidget.h"
36 #include "qgsmapcanvas.h"
37 #include "qgspainteffect.h"
38 #include "qgsproject.h"
39 #include "qgsvectorlayer.h"
40 
41 static bool _initWidgetFunction( const QString &name, QgsSymbolLayerWidgetFunc f )
42 {
44 
45  QgsSymbolLayerAbstractMetadata *abstractMetadata = reg->symbolLayerMetadata( name );
46  if ( !abstractMetadata )
47  {
48  QgsDebugMsg( "Failed to find symbol layer's entry in registry: " + name );
49  return false;
50  }
51  QgsSymbolLayerMetadata *metadata = dynamic_cast<QgsSymbolLayerMetadata *>( abstractMetadata );
52  if ( !metadata )
53  {
54  QgsDebugMsg( "Failed to cast symbol layer's metadata: " + name );
55  return false;
56  }
57  metadata->setWidgetFunction( f );
58  return true;
59 }
60 
61 static void _initWidgetFunctions()
62 {
63  static bool sInitialized = false;
64  if ( sInitialized )
65  return;
66 
67  _initWidgetFunction( QStringLiteral( "SimpleLine" ), QgsSimpleLineSymbolLayerWidget::create );
68  _initWidgetFunction( QStringLiteral( "MarkerLine" ), QgsMarkerLineSymbolLayerWidget::create );
69  _initWidgetFunction( QStringLiteral( "ArrowLine" ), QgsArrowSymbolLayerWidget::create );
70 
71  _initWidgetFunction( QStringLiteral( "SimpleMarker" ), QgsSimpleMarkerSymbolLayerWidget::create );
72  _initWidgetFunction( QStringLiteral( "FilledMarker" ), QgsFilledMarkerSymbolLayerWidget::create );
73  _initWidgetFunction( QStringLiteral( "SvgMarker" ), QgsSvgMarkerSymbolLayerWidget::create );
74  _initWidgetFunction( QStringLiteral( "FontMarker" ), QgsFontMarkerSymbolLayerWidget::create );
75  _initWidgetFunction( QStringLiteral( "EllipseMarker" ), QgsEllipseSymbolLayerWidget::create );
76  _initWidgetFunction( QStringLiteral( "VectorField" ), QgsVectorFieldSymbolLayerWidget::create );
77 
78  _initWidgetFunction( QStringLiteral( "SimpleFill" ), QgsSimpleFillSymbolLayerWidget::create );
79  _initWidgetFunction( QStringLiteral( "GradientFill" ), QgsGradientFillSymbolLayerWidget::create );
80  _initWidgetFunction( QStringLiteral( "ShapeburstFill" ), QgsShapeburstFillSymbolLayerWidget::create );
81  _initWidgetFunction( QStringLiteral( "RasterFill" ), QgsRasterFillSymbolLayerWidget::create );
82  _initWidgetFunction( QStringLiteral( "SVGFill" ), QgsSVGFillSymbolLayerWidget::create );
83  _initWidgetFunction( QStringLiteral( "CentroidFill" ), QgsCentroidFillSymbolLayerWidget::create );
84  _initWidgetFunction( QStringLiteral( "LinePatternFill" ), QgsLinePatternFillSymbolLayerWidget::create );
85  _initWidgetFunction( QStringLiteral( "PointPatternFill" ), QgsPointPatternFillSymbolLayerWidget::create );
86 
87  _initWidgetFunction( QStringLiteral( "GeometryGenerator" ), QgsGeometryGeneratorSymbolLayerWidget::create );
88 
89  sInitialized = true;
90 }
91 
92 
94  : QgsPanelWidget( parent )
95  , mLayer( layer )
96  , mSymbol( symbol )
97  , mVectorLayer( vl )
98 {
99 
100  setupUi( this );
101  connect( mEnabledCheckBox, &QCheckBox::toggled, this, &QgsLayerPropertiesWidget::mEnabledCheckBox_toggled );
102  // initialize the sub-widgets
103  // XXX Should this thing be here this way? Initialize all the widgets just for the sake of one layer?
104  // TODO Make this on demand creation
105  _initWidgetFunctions();
106 
107  // TODO Algorithm
108  //
109  // 3. populate the combo box with the supported layer type
110  // 4. set the present layer type
111  // 5. create the widget for the present layer type and set inn stacked widget
112  // 6. connect comboBox type changed to two things
113  // 1. emit signal that type has beed changed
114  // 2. remove the widget and place the new widget corresponding to the changed layer type
115  //
117  // update layer type combo box
118  int idx = cboLayerType->findData( mLayer->layerType() );
119  cboLayerType->setCurrentIndex( idx );
120 
121  connect( mEnabledCheckBox, &QAbstractButton::toggled, mEnabledDDBtn, &QWidget::setEnabled );
122  mEnabledCheckBox->setChecked( mLayer->enabled() );
123 
124  // set the corresponding widget
125  updateSymbolLayerWidget( layer );
126  connect( cboLayerType, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLayerPropertiesWidget::layerTypeChanged );
127 
129 
130  this->connectChildPanel( mEffectWidget );
131 
132  mEffectWidget->setPaintEffect( mLayer->paintEffect() );
133 
135 }
136 
138 {
139  mContext = context;
140 
141  QgsSymbolLayerWidget *w = dynamic_cast< QgsSymbolLayerWidget * >( stackedWidget->currentWidget() );
142  if ( w )
143  w->setContext( mContext );
144 }
145 
147 {
148  return mContext;
149 }
150 
152 {
153  QgsPanelWidget::setDockMode( dockMode );
154  mEffectWidget->setDockMode( this->dockMode() );
155 }
156 
158 {
159  QStringList symbolLayerIds = QgsApplication::symbolLayerRegistry()->symbolLayersForType( mSymbol->type() );
160 
161  Q_FOREACH ( const QString &symbolLayerId, symbolLayerIds )
162  cboLayerType->addItem( QgsApplication::symbolLayerRegistry()->symbolLayerMetadata( symbolLayerId )->visibleName(), symbolLayerId );
163 
164  if ( mSymbol->type() == QgsSymbol::Fill )
165  {
167  Q_FOREACH ( const QString &lineLayerId, lineLayerIds )
168  {
170  if ( layerInfo->type() != QgsSymbol::Hybrid )
171  {
172  QString visibleName = layerInfo->visibleName();
173  QString name = QString( tr( "Outline: %1" ) ).arg( visibleName );
174  cboLayerType->addItem( name, lineLayerId );
175  }
176  }
177  }
178 }
179 
181 {
182  if ( stackedWidget->currentWidget() != pageDummy )
183  {
184  // stop updating from the original widget
185  if ( QgsSymbolLayerWidget *w = qobject_cast< QgsSymbolLayerWidget * >( stackedWidget->currentWidget() ) )
187  stackedWidget->removeWidget( stackedWidget->currentWidget() );
188  }
189 
191 
192  QString layerType = layer->layerType();
193  QgsSymbolLayerAbstractMetadata *am = pReg->symbolLayerMetadata( layerType );
194  if ( am )
195  {
197  if ( w )
198  {
199  w->setContext( mContext );
200  w->setSymbolLayer( layer );
201  stackedWidget->addWidget( w );
202  stackedWidget->setCurrentWidget( w );
203  // start receiving updates from widget
205  connect( w, &QgsSymbolLayerWidget::symbolChanged, this, &QgsLayerPropertiesWidget::reloadLayer );
206  return;
207  }
208  }
209  // When anything is not right
210  stackedWidget->setCurrentWidget( pageDummy );
211 }
212 
214 {
215  if ( mContext.expressionContext() )
216  return *mContext.expressionContext();
217 
218  QgsExpressionContext expContext;
222 
223  if ( mContext.mapCanvas() )
224  {
227  }
228  else
229  {
231  }
232 
234 
236  if ( mLayer )
237  {
238  //cheat a bit - set the symbol color variable to match the symbol layer's color (when we should really be using the *symbols*
239  //color, but that's not accessible here). 99% of the time these will be the same anyway
241  }
242  expContext << symbolScope;
247 
248  // additional scopes
249  Q_FOREACH ( const QgsExpressionContextScope &scope, mContext.additionalExpressionContextScopes() )
250  {
251  expContext.appendScope( new QgsExpressionContextScope( scope ) );
252  }
253 
254  //TODO - show actual value
255  expContext.setOriginalValueVariable( QVariant() );
256 
261 
262  return expContext;
263 }
264 
266 {
268  connect( button, &QgsPropertyOverrideButton::changed, this, &QgsLayerPropertiesWidget::updateProperty );
269  button->registerExpressionContextGenerator( this );
270 }
271 
272 void QgsLayerPropertiesWidget::updateProperty()
273 {
274  QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
275  QgsSymbolLayer::Property key = static_cast< QgsSymbolLayer::Property >( button->propertyKey() );
276  mLayer->setDataDefinedProperty( key, button->toProperty() );
277  emit changed();
278 }
279 
281 {
282  QgsSymbolLayer *layer = mLayer;
283  if ( !layer )
284  return;
285  QString newLayerType = cboLayerType->currentData().toString();
286  if ( layer->layerType() == newLayerType )
287  return;
288 
289  // get creation function for new layer from registry
291  QgsSymbolLayerAbstractMetadata *am = pReg->symbolLayerMetadata( newLayerType );
292  if ( !am ) // check whether the metadata is assigned
293  return;
294 
295  // change layer to a new (with different type)
296  // base new layer on existing layer's properties
297  QgsSymbolLayer *newLayer = am->createSymbolLayer( layer->properties() );
298  if ( !newLayer )
299  return;
300 
301  updateSymbolLayerWidget( newLayer );
302  emit changeLayer( newLayer );
303 }
304 
306 {
307  emit changed();
308 
309  // also update paint effect preview
310  bool paintEffectToggled = false;
311  if ( mLayer->paintEffect() && mLayer->paintEffect()->enabled() )
312  {
313  mLayer->paintEffect()->setEnabled( false );
314  paintEffectToggled = true;
315  }
316  mEffectWidget->setPreviewPicture( QgsSymbolLayerUtils::symbolLayerPreviewPicture( mLayer, QgsUnitTypes::RenderMillimeters, QSize( 80, 80 ) ) );
317  if ( paintEffectToggled )
318  {
319  mLayer->paintEffect()->setEnabled( true );
320  }
321  emit widgetChanged();
322 }
323 
324 void QgsLayerPropertiesWidget::reloadLayer()
325 {
326  emit changeLayer( mLayer );
327 }
328 
329 void QgsLayerPropertiesWidget::mEnabledCheckBox_toggled( bool enabled )
330 {
331  mLayer->setEnabled( enabled );
333 }
static const QString EXPR_ORIGINAL_VALUE
Inbuilt variable name for value original value variable.
static QgsSymbolLayerRegistry * symbolLayerRegistry()
Returns the application&#39;s symbol layer registry, used for managing symbol layers. ...
static QgsExpressionContextScope * updateSymbolScope(const QgsSymbol *symbol, QgsExpressionContextScope *symbolScope=nullptr)
Updates a symbol scope related to a QgsSymbol to an expression context.
static const QString EXPR_CLUSTER_COLOR
Inbuilt variable name for cluster color variable.
Single variable definition for use within a QgsExpressionContextScope.
void connectChildPanel(QgsPanelWidget *panel)
Connect the given sub panel widgets showPanel signals to this current panels main showPanel event to ...
void symbolChanged()
Should be emitted whenever the sub symbol changed on this symbol layer configuration.
Stores metadata about one symbol layer class.
bool dockMode()
Returns the dock mode state.
static const QString EXPR_GEOMETRY_POINT_COUNT
Inbuilt variable name for point count variable.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:61
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsFilledMarkerSymbolLayerWidget.
int propertyKey() const
Returns the property key linked to the button.
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsGradientFillSymbolLayerWidget.
void setWidgetFunction(QgsSymbolLayerWidgetFunc f)
#define QgsDebugMsg(str)
Definition: qgslogger.h:38
QStringList symbolLayersForType(QgsSymbol::SymbolType type)
Returns a list of available symbol layers for a specified symbol type.
void setDockMode(bool dockMode) override
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs...
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsShapeburstFillSymbolLayerWidget.
bool enabled() const
Returns whether the effect is enabled.
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsSymbolLayerWidget.
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsSVGFillSymbolLayerWidget.
bool enabled() const
Returns true if symbol layer is enabled and will be drawn.
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.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsFontMarkerSymbolLayerWidget.
Line symbol.
Definition: qgssymbol.h:86
virtual QgsStringMap properties() const =0
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void updateSymbolLayerWidget(QgsSymbolLayer *layer)
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
QgsSymbolLayerAbstractMetadata * symbolLayerMetadata(const QString &name) const
Returns metadata for specified symbol layer. Returns NULL if not found.
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsLinePatternFillSymbolLayerWidget.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs...
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsSimpleLineSymbolLayerWidget.
The QgsMapSettings class contains configuration for rendering of the map.
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsMarkerLineSymbolLayerWidget.
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
void setEnabled(bool enabled)
Sets whether the effect is enabled.
Convenience metadata class that uses static functions to create symbol layer and its widget...
void changed()
Should be emitted whenever configuration changes happened on this symbol layer configuration.
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsPointPatternFillSymbolLayerWidget.
A button for controlling property overrides which may apply to a widget.
virtual void setSymbolLayer(QgsSymbolLayer *layer)=0
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsCentroidFillSymbolLayerWidget.
Registry of available symbol layer classes.
Contains settings which reflect the context in which a symbol (or renderer) widget is shown...
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsSvgMarkerSymbolLayerWidget.
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Will be registered as factory.
void registerExpressionContextGenerator(QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the symbol layer&#39;s property collection, used for data defined overrides...
static const QString EXPR_SYMBOL_COLOR
Inbuilt variable name for symbol color variable.
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
QgsLayerPropertiesWidget(QgsSymbolLayer *layer, const QgsSymbol *symbol, QgsVectorLayer *vl, QWidget *parent=nullptr)
Constructor for QgsLayerPropertiesWidget.
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsRasterFillSymbolLayerWidget.
Single scope for storing variables and functions for use within a QgsExpressionContext.
void setEnabled(bool enabled)
Sets whether symbol layer is enabled and should be drawn.
void widgetChanged()
Emitted when the widget state changes.
static QgsSymbolLayerWidget * create(QgsVectorLayer *layer)
Static creation method.
void registerDataDefinedButton(QgsPropertyOverrideButton *button, QgsSymbolLayer::Property key)
Registers a data defined override button.
virtual QgsSymbolLayer * createSymbolLayer(const QgsStringMap &map)=0
Create a symbol layer of this type given the map of properties.
QgsSymbolLayerWidget *(* QgsSymbolLayerWidgetFunc)(QgsVectorLayer *)
void changed()
Emitted when property definition changes.
QgsSymbol::SymbolType type() const
QgsProperty toProperty() const
Returns a QgsProperty object encapsulating the current state of the widget.
QgsSymbolWidgetContext context() const
Returns the context in which the symbol widget is shown, e.g., the associated map canvas and expressi...
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsSimpleMarkerSymbolLayerWidget.
Fill symbol.
Definition: qgssymbol.h:87
static QgsExpressionContextScope * atlasScope(QgsLayoutAtlas *atlas)
Creates a new scope which contains variables and functions relating to a QgsLayoutAtlas.
static QgsExpressionContextScope * mapSettingsScope(const QgsMapSettings &mapSettings)
Creates a new scope which contains variables and functions relating to a QgsMapSettings object...
QgsExpressionContextScope & expressionContextScope()
Returns a reference to the expression context scope for the map canvas.
Definition: qgsmapcanvas.h:560
static QPicture symbolLayerPreviewPicture(QgsSymbolLayer *layer, QgsUnitTypes::RenderUnit units, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale())
Draws a symbol layer preview to a QPicture.
void changed()
Emitted when the paint effect properties change.
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsVectorFieldSymbolLayerWidget.
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 setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the layer.
SymbolType type() const
Returns the symbol&#39;s type.
Definition: qgssymbol.h:120
void changeLayer(QgsSymbolLayer *)
static const QString EXPR_CLUSTER_SIZE
Inbuilt variable name for cluster size variable.
static const QString EXPR_GEOMETRY_POINT_NUM
Inbuilt variable name for point number variable.
static QgsSymbolLayerWidget * create(QgsVectorLayer *vl)
Creates a new QgsSimpleFillSymbolLayerWidget.
QList< QgsExpressionContextScope > additionalExpressionContextScopes() const
Returns the list of additional expression context scopes to show as available within the layer...
void setHighlightedVariables(const QStringList &variableNames)
Sets the list of variable names within the context intended to be highlighted to the user...
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.
static const QString EXPR_GEOMETRY_PART_NUM
Inbuilt variable name for geometry part number variable.
Represents a vector layer which manages a vector based data sets.
virtual QColor color() const
The fill color.
static const QString EXPR_GEOMETRY_PART_COUNT
Inbuilt variable name for geometry part count variable.
void setOriginalValueVariable(const QVariant &value)
Sets the original value variable value for the context.
void init(int propertyKey, const QgsProperty &property, const QgsPropertiesDefinition &definitions, const QgsVectorLayer *layer=nullptr, bool auxiliaryStorageEnabled=false)
Initialize a newly constructed property button (useful if button was included in a UI layout)...
Whether symbol layer is enabled.
Hybrid symbol.
Definition: qgssymbol.h:88
Property
Data definable properties.
virtual QgsSymbolLayerWidget * createSymbolLayerWidget(QgsVectorLayer *)
Create widget for symbol layer of this type. Can return NULL if there&#39;s no GUI.
virtual void setDataDefinedProperty(Property key, const QgsProperty &property)
Sets a data defined property for the layer.
virtual QString layerType() const =0
Returns a string that represents this layer type.