QGIS API Documentation  2.99.0-Master (37c43df)
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 "qgsdatadefined.h"
37 #include "qgsmapcanvas.h"
38 #include "qgsvectorlayer.h"
39 
40 static bool _initWidgetFunction( const QString& name, QgsSymbolLayerWidgetFunc f )
41 {
43 
44  QgsSymbolLayerAbstractMetadata* abstractMetadata = reg->symbolLayerMetadata( name );
45  if ( !abstractMetadata )
46  {
47  QgsDebugMsg( "Failed to find symbol layer's entry in registry: " + name );
48  return false;
49  }
50  QgsSymbolLayerMetadata* metadata = dynamic_cast<QgsSymbolLayerMetadata*>( abstractMetadata );
51  if ( !metadata )
52  {
53  QgsDebugMsg( "Failed to cast symbol layer's metadata: " + name );
54  return false;
55  }
56  metadata->setWidgetFunction( f );
57  return true;
58 }
59 
60 static void _initWidgetFunctions()
61 {
62  static bool initialized = false;
63  if ( initialized )
64  return;
65 
66  _initWidgetFunction( QStringLiteral( "SimpleLine" ), QgsSimpleLineSymbolLayerWidget::create );
67  _initWidgetFunction( QStringLiteral( "MarkerLine" ), QgsMarkerLineSymbolLayerWidget::create );
68  _initWidgetFunction( QStringLiteral( "ArrowLine" ), QgsArrowSymbolLayerWidget::create );
69 
70  _initWidgetFunction( QStringLiteral( "SimpleMarker" ), QgsSimpleMarkerSymbolLayerWidget::create );
71  _initWidgetFunction( QStringLiteral( "FilledMarker" ), QgsFilledMarkerSymbolLayerWidget::create );
72  _initWidgetFunction( QStringLiteral( "SvgMarker" ), QgsSvgMarkerSymbolLayerWidget::create );
73  _initWidgetFunction( QStringLiteral( "FontMarker" ), QgsFontMarkerSymbolLayerWidget::create );
74  _initWidgetFunction( QStringLiteral( "EllipseMarker" ), QgsEllipseSymbolLayerWidget::create );
75  _initWidgetFunction( QStringLiteral( "VectorField" ), QgsVectorFieldSymbolLayerWidget::create );
76 
77  _initWidgetFunction( QStringLiteral( "SimpleFill" ), QgsSimpleFillSymbolLayerWidget::create );
78  _initWidgetFunction( QStringLiteral( "GradientFill" ), QgsGradientFillSymbolLayerWidget::create );
79  _initWidgetFunction( QStringLiteral( "ShapeburstFill" ), QgsShapeburstFillSymbolLayerWidget::create );
80  _initWidgetFunction( QStringLiteral( "RasterFill" ), QgsRasterFillSymbolLayerWidget::create );
81  _initWidgetFunction( QStringLiteral( "SVGFill" ), QgsSVGFillSymbolLayerWidget::create );
82  _initWidgetFunction( QStringLiteral( "CentroidFill" ), QgsCentroidFillSymbolLayerWidget::create );
83  _initWidgetFunction( QStringLiteral( "LinePatternFill" ), QgsLinePatternFillSymbolLayerWidget::create );
84  _initWidgetFunction( QStringLiteral( "PointPatternFill" ), QgsPointPatternFillSymbolLayerWidget::create );
85 
86  _initWidgetFunction( QStringLiteral( "GeometryGenerator" ), QgsGeometryGeneratorSymbolLayerWidget::create );
87 
88  initialized = true;
89 }
90 
91 
93  : QgsPanelWidget( parent )
94  , mLayer( layer )
95  , mSymbol( symbol )
96  , mVectorLayer( vl )
97 {
98 
99  setupUi( this );
100  // initialize the sub-widgets
101  // XXX Should this thing be here this way? Initialize all the widgets just for the sake of one layer?
102  // TODO Make this on demand creation
104 
105  // TODO Algorithm
106  //
107  // 3. populate the combo box with the supported layer type
108  // 4. set the present layer type
109  // 5. create the widget for the present layer type and set inn stacked widget
110  // 6. connect comboBox type changed to two things
111  // 1. emit signal that type has beed changed
112  // 2. remove the widget and place the new widget corresponding to the changed layer type
113  //
115  // update layer type combo box
116  int idx = cboLayerType->findData( mLayer->layerType() );
117  cboLayerType->setCurrentIndex( idx );
118 
119  connect( mEnabledCheckBox, SIGNAL( toggled( bool ) ), mEnabledDDBtn, SLOT( setEnabled( bool ) ) );
120  mEnabledCheckBox->setChecked( mLayer->enabled() );
121 
122  // set the corresponding widget
123  updateSymbolLayerWidget( layer );
124  connect( cboLayerType, SIGNAL( currentIndexChanged( int ) ), this, SLOT( layerTypeChanged() ) );
125 
126  connect( mEffectWidget, SIGNAL( changed() ), this, SLOT( emitSignalChanged() ) );
127 
128  this->connectChildPanel( mEffectWidget );
129 
130  mEffectWidget->setPaintEffect( mLayer->paintEffect() );
131 
134  connect( mEnabledDDBtn, SIGNAL( dataDefinedChanged( const QString& ) ), this, SLOT( updateDataDefinedEnable() ) );
135  connect( mEnabledDDBtn, SIGNAL( dataDefinedActivated( bool ) ), this, SLOT( updateDataDefinedEnable() ) );
136  mEnabledDDBtn->registerExpressionContextGenerator( this );
137 }
138 
139 void QgsLayerPropertiesWidget::updateDataDefinedEnable()
140 {
142  if ( !dd )
143  {
144  dd = new QgsDataDefined();
146  }
147  mEnabledDDBtn->updateDataDefined( dd );
148 
149  emit changed();
150 }
151 
153 {
154  mContext = context;
155 
156  QgsSymbolLayerWidget* w = dynamic_cast< QgsSymbolLayerWidget* >( stackedWidget->currentWidget() );
157  if ( w )
158  w->setContext( mContext );
159 }
160 
162 {
163  return mContext;
164 }
165 
167 {
168  QgsPanelWidget::setDockMode( dockMode );
169  mEffectWidget->setDockMode( this->dockMode() );
170 }
171 
173 {
174  QStringList symbolLayerIds = QgsSymbolLayerRegistry::instance()->symbolLayersForType( mSymbol->type() );
175 
176  Q_FOREACH ( const QString& symbolLayerId, symbolLayerIds )
177  cboLayerType->addItem( QgsSymbolLayerRegistry::instance()->symbolLayerMetadata( symbolLayerId )->visibleName(), symbolLayerId );
178 
179  if ( mSymbol->type() == QgsSymbol::Fill )
180  {
182  Q_FOREACH ( const QString& lineLayerId, lineLayerIds )
183  {
185  if ( layerInfo->type() != QgsSymbol::Hybrid )
186  {
187  QString visibleName = layerInfo->visibleName();
188  QString name = QString( tr( "Outline: %1" ) ).arg( visibleName );
189  cboLayerType->addItem( name, lineLayerId );
190  }
191  }
192  }
193 }
194 
196 {
197  if ( stackedWidget->currentWidget() != pageDummy )
198  {
199  // stop updating from the original widget
200  disconnect( stackedWidget->currentWidget(), SIGNAL( changed() ), this, SLOT( emitSignalChanged() ) );
201  stackedWidget->removeWidget( stackedWidget->currentWidget() );
202  }
203 
205 
206  QString layerType = layer->layerType();
207  QgsSymbolLayerAbstractMetadata* am = pReg->symbolLayerMetadata( layerType );
208  if ( am )
209  {
211  if ( w )
212  {
213  w->setContext( mContext );
214  w->setSymbolLayer( layer );
215  stackedWidget->addWidget( w );
216  stackedWidget->setCurrentWidget( w );
217  // start receiving updates from widget
218  connect( w, SIGNAL( changed() ), this, SLOT( emitSignalChanged() ) );
219  connect( w, SIGNAL( symbolChanged() ), this, SLOT( reloadLayer() ) );
220  return;
221  }
222  }
223  // When anything is not right
224  stackedWidget->setCurrentWidget( pageDummy );
225 }
226 
228 {
229  if ( mContext.expressionContext() )
230  return *mContext.expressionContext();
231 
232  QgsExpressionContext expContext;
236 
237  if ( mContext.mapCanvas() )
238  {
241  }
242  else
243  {
245  }
246 
248 
250  if ( mLayer )
251  {
252  //cheat a bit - set the symbol color variable to match the symbol layer's color (when we should really be using the *symbols*
253  //color, but that's not accessible here). 99% of the time these will be the same anyway
255  }
256  expContext << symbolScope;
261 
262  // additional scopes
263  Q_FOREACH ( const QgsExpressionContextScope& scope, mContext.additionalExpressionContextScopes() )
264  {
265  expContext.appendScope( new QgsExpressionContextScope( scope ) );
266  }
267 
268  //TODO - show actual value
269  expContext.setOriginalValueVariable( QVariant() );
270 
275 
276  return expContext;
277 }
278 
280 {
281  QgsSymbolLayer* layer = mLayer;
282  if ( !layer )
283  return;
284  QString newLayerType = cboLayerType->currentData().toString();
285  if ( layer->layerType() == newLayerType )
286  return;
287 
288  // get creation function for new layer from registry
290  QgsSymbolLayerAbstractMetadata* am = pReg->symbolLayerMetadata( newLayerType );
291  if ( !am ) // check whether the metadata is assigned
292  return;
293 
294  // change layer to a new (with different type)
295  // base new layer on existing layer's properties
296  QgsSymbolLayer* newLayer = am->createSymbolLayer( layer->properties() );
297  if ( !newLayer )
298  return;
299 
300  updateSymbolLayerWidget( newLayer );
301  emit changeLayer( newLayer );
302 }
303 
305 {
306  emit changed();
307 
308  // also update paint effect preview
309  mEffectWidget->setPreviewPicture( QgsSymbolLayerUtils::symbolLayerPreviewPicture( mLayer, QgsUnitTypes::RenderMillimeters, QSize( 80, 80 ) ) );
310  emit widgetChanged();
311 }
312 
313 void QgsLayerPropertiesWidget::reloadLayer()
314 {
315  emit changeLayer( mLayer );
316 }
317 
318 void QgsLayerPropertiesWidget::on_mEnabledCheckBox_toggled( bool enabled )
319 {
320  mLayer->setEnabled( enabled );
322 }
static const QString EXPR_ORIGINAL_VALUE
Inbuilt variable name for value original value variable.
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.
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
Creates a new QgsFilledMarkerSymbolLayerWidget.
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 ...
Stores metadata about one symbol layer class.
bool dockMode()
Return the dock mode state.
A container class for data source field mapping or expression.
static const QString EXPR_GEOMETRY_POINT_COUNT
Inbuilt variable name for point count variable.
QgsPaintEffect * paintEffect() const
Returns the current paint effect for the layer.
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
static QgsExpressionContextScope * atlasScope(const QgsAtlasComposition *atlas)
Creates a new scope which contains variables and functions relating to a QgsAtlasComposition.
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
void setWidgetFunction(QgsSymbolLayerWidgetFunc f)
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
QgsSymbolWidgetContext context() const
Returns the context in which the symbol widget is shown, eg the associated map canvas and expression ...
QStringList symbolLayersForType(QgsSymbol::SymbolType type)
return a list of available symbol layers for a specified symbol type
virtual void setDataDefinedProperty(const QString &property, QgsDataDefined *dataDefined)
Sets a data defined property for the layer.
virtual 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(const QgsVectorLayer *vl)
virtual QgsSymbolLayerWidget * createSymbolLayerWidget(const QgsVectorLayer *)
Create widget for symbol layer of this type. Can return NULL if there&#39;s no GUI.
static bool _initWidgetFunction(const QString &name, QgsSymbolLayerWidgetFunc f)
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, eg the associated map canvas and expression con...
Line symbol.
Definition: qgssymbol.h:69
virtual QgsStringMap properties() const =0
Should be reimplemented by subclasses to return a string map that contains the configuration informat...
void updateSymbolLayerWidget(QgsSymbolLayer *layer)
void addVariable(const QgsExpressionContextScope::StaticVariable &variable)
Adds a variable into the context scope.
static void _initWidgetFunctions()
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(const QgsVectorLayer *vl)
Will be registered as factory.
The QgsMapSettings class contains configuration for rendering of the map.
QgsExpressionContextScope * lastScope()
Returns the last scope added to the context.
Convenience metadata class that uses static functions to create symbol layer and its widget...
static QgsSymbolLayerWidget * create(const QgsVectorLayer *layer)
Static creation method.
virtual void setSymbolLayer(QgsSymbolLayer *layer)=0
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
QgsSymbolLayerAbstractMetadata * symbolLayerMetadata(const QString &name) const
return metadata for specified symbol layer. Returns NULL if not found
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
Registry of available symbol layer classes.
Contains settings which reflect the context in which a symbol (or renderer) widget is shown...
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QgsSymbolLayerWidget *(* QgsSymbolLayerWidgetFunc)(const QgsVectorLayer *)
virtual QColor color() const
The fill color.
static const QString EXPR_SYMBOL_COLOR
Inbuilt variable name for symbol color variable.
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.
virtual QgsSymbolLayer * createSymbolLayer(const QgsStringMap &map)=0
Create a symbol layer of this type given the map of properties.
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
virtual QgsDataDefined * getDataDefinedProperty(const QString &property) const
Returns the data defined property corresponding to the specified property key.
QgsExpressionContext * expressionContext() const
Returns the expression context used for the widget, if set.
Fill symbol.
Definition: qgssymbol.h:70
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:417
static QPicture symbolLayerPreviewPicture(QgsSymbolLayer *layer, QgsUnitTypes::RenderUnit units, QSize size, const QgsMapUnitScale &scale=QgsMapUnitScale())
Draws a symbol layer preview to a QPicture.
bool enabled() const
Returns true if symbol layer is enabled and will be drawn.
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
SymbolType type() const
Definition: qgssymbol.h:96
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
QgsSymbol::SymbolType type() const
static QgsSymbolLayerWidget * create(const QgsVectorLayer *vl)
QgsLayerPropertiesWidget(QgsSymbolLayer *layer, const QgsSymbol *symbol, const QgsVectorLayer *vl, QWidget *parent=nullptr)
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, eg the associated map canvas and expression con...
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.
void setHighlightedVariables(const QStringList &variableNames)
Sets the list of variable names within the context intended to be highlighted to the user...
static const QString EXPR_LAYER_ENABLED
Data defined layer enabled string.
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
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.
static QgsSymbolLayerRegistry * instance()
return the single instance of this class (instantiate it if not exists)
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.
Hybrid symbol.
Definition: qgssymbol.h:71
QList< QgsExpressionContextScope > additionalExpressionContextScopes() const
Returns the list of additional expression context scopes to show as available within the layer...
const QgsVectorLayer * mVectorLayer
virtual QString layerType() const =0
Returns a string that represents this layer type.