QGIS API Documentation  3.18.1-Zürich (202f1bf7e5)
qgsfieldconditionalformatwidget.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsfieldconditionalformatwidget.cpp
3  ---------------------
4  begin : August 2015
5  copyright : (C) 2015 by Nathan Woodrow
6  email : woodrow dot nathan 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  ***************************************************************************/
16 
18 #include "qgssymbol.h"
20 #include "qgssymbollayerutils.h"
21 #include "qgsstyle.h"
22 #include "qgsvectorlayer.h"
24 #include "qgsguiutils.h"
25 
26 //
27 // QgsFieldConditionalFormatWidget
28 //
29 
31  : QgsPanelWidget( parent )
32 {
33  setupUi( this );
34  setPanelTitle( tr( "Conditional Styles" ) );
35  connect( mFieldCombo, &QgsFieldComboBox::fieldChanged, this, &QgsFieldConditionalFormatWidget::fieldChanged );
36  connect( fieldRadio, &QAbstractButton::clicked, this, &QgsFieldConditionalFormatWidget::reloadStyles );
37  connect( rowRadio, &QAbstractButton::clicked, this, &QgsFieldConditionalFormatWidget::reloadStyles );
38  connect( mNewButton, &QAbstractButton::clicked, this, &QgsFieldConditionalFormatWidget::addNewRule );
39  connect( listView, &QAbstractItemView::clicked, this, &QgsFieldConditionalFormatWidget::ruleClicked );
40  mModel = new QStandardItemModel( listView );
41  listView->setModel( mModel );
42 
43  connect( fieldRadio, &QRadioButton::toggled, mFieldCombo, &QWidget::setEnabled );
44 
45  mPresets = defaultPresets();
46 }
47 
49 {
50  mLayer = layer;
51  mFieldCombo->setLayer( layer );
52  mFieldCombo->setCurrentIndex( 0 );
53  fieldChanged( mFieldCombo->currentField() );
54 }
55 
56 void QgsFieldConditionalFormatWidget::ruleClicked( const QModelIndex &index )
57 {
58  QList<QgsConditionalStyle> styles = getStyles();
59  QgsConditionalStyle style = styles.at( index.row() );
60  editStyle( index.row(), style );
61 }
62 
64 {
65  mEditIndex = editIndex;
66  mEditing = editIndex >= 0;
67  mPanelHandled = false;
68 
70  ruleWidget->setLayer( mLayer );
71  ruleWidget->setPresets( mPresets );
72  ruleWidget->loadStyle( style );
73  ruleWidget->setDockMode( true );
74 
75  if ( fieldRadio->isChecked() && style.rule().isEmpty() )
76  {
77  ruleWidget->setRule( QStringLiteral( "@value " ) );
78  }
79 
80  connect( ruleWidget, &QgsEditConditionalFormatRuleWidget::panelAccepted, this, [ = ]
81  {
82  if ( mPanelHandled )
83  {
84  // already handled the result of the panel, and the panel is being dismissed as a result
85  // of an already dealt with action
86  return;
87  }
88 
89  QList<QgsConditionalStyle> styles = getStyles();
90  if ( mEditing )
91  {
92  styles.replace( mEditIndex, ruleWidget->currentStyle() );
93  }
94  else
95  {
96  styles.append( ruleWidget->currentStyle() );
97  }
98 
99  QString fieldName;
100  if ( fieldRadio->isChecked() )
101  {
102  fieldName = mFieldCombo->currentField();
103  mLayer->conditionalStyles()->setFieldStyles( fieldName, styles );
104  }
105  if ( rowRadio->isChecked() )
106  {
107  mLayer->conditionalStyles()->setRowStyles( styles );
108  }
109  reloadStyles();
110  emit rulesUpdated( fieldName );
111  } );
112 
113  connect( ruleWidget, &QgsEditConditionalFormatRuleWidget::ruleSaved, this, [ = ]
114  {
115  ruleWidget->acceptPanel();
116  } );
117 
118  connect( ruleWidget, &QgsEditConditionalFormatRuleWidget::canceled, this, [ = ]
119  {
120  mPanelHandled = true;
121  ruleWidget->acceptPanel();
122  } );
123 
124  connect( ruleWidget, &QgsEditConditionalFormatRuleWidget::ruleDeleted, this, [ = ]
125  {
126  deleteCurrentRule();
127  mPanelHandled = true;
128  ruleWidget->acceptPanel();
129  } );
130  showPanel( ruleWidget );
131 }
132 
134 {
135 }
136 
137 QList<QgsConditionalStyle> QgsFieldConditionalFormatWidget::getStyles()
138 {
139  QList<QgsConditionalStyle> styles;
140  if ( fieldRadio->isChecked() )
141  {
142  styles = mLayer->conditionalStyles()->fieldStyles( mFieldCombo->currentField() );
143  }
144  if ( rowRadio->isChecked() )
145  {
146  styles = mLayer->conditionalStyles()->rowStyles();
147  }
148  return styles;
149 }
150 
151 void QgsFieldConditionalFormatWidget::addNewRule()
152 {
154 }
155 
157 {
158 }
159 
160 void QgsFieldConditionalFormatWidget::setPresets( const QList<QgsConditionalStyle> &styles )
161 {
162  mPresets = styles;
163 }
164 
166 {
167  QList<QgsConditionalStyle> styles;
169  style.setBackgroundColor( QColor( 154, 216, 113 ) );
170  styles.append( style );
171  style = QgsConditionalStyle();
172  style.setBackgroundColor( QColor( 251, 193, 78 ) );
173  styles.append( style );
174  style = QgsConditionalStyle();
175  style.setBackgroundColor( QColor( 251, 154, 153 ) );
176  styles.append( style );
177  style = QgsConditionalStyle();
178  style.setTextColor( QColor( 154, 216, 113 ) );
179  styles.append( style );
180  style = QgsConditionalStyle();
181  style.setTextColor( QColor( 251, 193, 78 ) );
182  styles.append( style );
183  style = QgsConditionalStyle();
184  style.setTextColor( QColor( 251, 154, 153 ) );
185  styles.append( style );
186  return styles;
187 }
188 
189 void QgsFieldConditionalFormatWidget::reloadStyles()
190 {
191  mModel->clear();
192 
193  const auto constGetStyles = getStyles();
194 
195 #if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
196  const QSize size( Qgis::UI_SCALE_FACTOR * fontMetrics().width( 'X' ) * 10, Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 2 );
197 #else
198  const QSize size( Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 10, Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 2 );
199 #endif
200 
201  listView->setIconSize( size );
202 
203  for ( const QgsConditionalStyle &style : constGetStyles )
204  {
205  QStandardItem *item = new QStandardItem( style.displayText() );
206  item->setIcon( QIcon( style.renderPreview( size ) ) );
207  mModel->appendRow( item );
208  }
209 }
210 
211 void QgsFieldConditionalFormatWidget::fieldChanged( const QString &fieldName )
212 {
213  Q_UNUSED( fieldName )
214  reloadStyles();
215 }
216 
217 void QgsFieldConditionalFormatWidget::deleteCurrentRule()
218 {
219  if ( !mEditing )
220  return;
221 
222  QList<QgsConditionalStyle> styles = getStyles();
223  styles.removeAt( mEditIndex );
224  QString fieldName;
225  if ( fieldRadio->isChecked() )
226  {
227  fieldName = mFieldCombo->currentField();
228  mLayer->conditionalStyles()->setFieldStyles( fieldName, styles );
229  }
230  if ( rowRadio->isChecked() )
231  {
232  mLayer->conditionalStyles()->setRowStyles( styles );
233  }
234 
235  reloadStyles();
236  emit rulesUpdated( fieldName );
237 }
238 
240 {
241 }
242 
243 
244 //
245 // QgsEditConditionalFormatRuleWidget
246 //
247 
249  : QgsPanelWidget( parent )
250 {
251  setupUi( this );
252 
253  setPanelTitle( tr( "Edit Rule" ) );
254 
255  btnBackgroundColor->setColor( QColor() );
256  btnTextColor->setColor( QColor() );
257  checkIcon->setChecked( false );
258  btnChangeIcon->setIcon( QIcon() );
259  btnBackgroundColor->setToNoColor();
260  btnTextColor->setToNoColor();
261 
262  mFontBoldBtn->setChecked( false );
263  mFontItalicBtn->setChecked( false );
264  mFontStrikethroughBtn->setChecked( false );
265  mFontUnderlineBtn->setChecked( false );
266 
267  const int buttonSize = QgsGuiUtils::scaleIconSize( 24 );
268  mFontUnderlineBtn->setMinimumSize( buttonSize, buttonSize );
269  mFontUnderlineBtn->setMaximumSize( buttonSize, buttonSize );
270  mFontStrikethroughBtn->setMinimumSize( buttonSize, buttonSize );
271  mFontStrikethroughBtn->setMaximumSize( buttonSize, buttonSize );
272  mFontBoldBtn->setMinimumSize( buttonSize, buttonSize );
273  mFontBoldBtn->setMaximumSize( buttonSize, buttonSize );
274  mFontItalicBtn->setMinimumSize( buttonSize, buttonSize );
275  mFontItalicBtn->setMaximumSize( buttonSize, buttonSize );
276 
277  connect( mSaveRule, &QAbstractButton::clicked, this, &QgsEditConditionalFormatRuleWidget::ruleSaved );
278  connect( mCancelButton, &QAbstractButton::clicked, this, &QgsEditConditionalFormatRuleWidget::canceled );
279  connect( mDeleteButton, &QAbstractButton::clicked, this, &QgsEditConditionalFormatRuleWidget::ruleDeleted );
280 
281  connect( btnBuildExpression, &QAbstractButton::clicked, this, &QgsEditConditionalFormatRuleWidget::setExpression );
282  connect( mPresetsList, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsEditConditionalFormatRuleWidget::presetSet );
283 
284  btnBackgroundColor->setAllowOpacity( true );
285  btnBackgroundColor->setShowNoColor( true );
286  btnTextColor->setAllowOpacity( true );
287  btnTextColor->setShowNoColor( true );
288  mPresetsModel = new QStandardItemModel( mPresetsList );
289  mPresetsList->setModel( mPresetsModel );
290 
291  btnChangeIcon->setSymbolType( QgsSymbol::Marker );
292  btnChangeIcon->setSymbol( QgsSymbol::defaultSymbol( QgsWkbTypes::PointGeometry ) );
293  connect( checkIcon, &QCheckBox::toggled, btnChangeIcon, &QWidget::setEnabled );
294 }
295 
297 {
298  mLayer = layer;
299 }
300 
302 {
303  mRuleEdit->setText( style.rule() );
304  mNameEdit->setText( style.name() );
305  setFormattingFromStyle( style );
306 }
307 
309 {
310  QgsConditionalStyle style;
311 
312  style.setRule( mRuleEdit->text() );
313  style.setName( mNameEdit->text() );
314 
315  QColor backColor = btnBackgroundColor->color();
316  QColor fontColor = btnTextColor->color();
317 
318  QFont font = mFontFamilyCmbBx->currentFont();
319  font.setBold( mFontBoldBtn->isChecked() );
320  font.setItalic( mFontItalicBtn->isChecked() );
321  font.setStrikeOut( mFontStrikethroughBtn->isChecked() );
322  font.setUnderline( mFontUnderlineBtn->isChecked() );
323  style.setFont( font );
324  style.setBackgroundColor( backColor );
325  style.setTextColor( fontColor );
326  if ( checkIcon->isChecked() )
327  {
328  style.setSymbol( btnChangeIcon->clonedSymbol< QgsMarkerSymbol >() );
329  }
330  else
331  {
332  style.setSymbol( nullptr );
333  }
334  return style;
335 }
336 
337 void QgsEditConditionalFormatRuleWidget::setExpression()
338 {
340  context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( QStringLiteral( "value" ), 0, true ) );
341  context.setHighlightedVariables( QStringList() << QStringLiteral( "value" ) );
342 
343  QgsExpressionBuilderDialog dlg( mLayer, mRuleEdit->text(), this, QStringLiteral( "generic" ), context );
344  dlg.setWindowTitle( tr( "Conditional Style Rule Expression" ) );
345 
346  if ( dlg.exec() )
347  {
348  QString expression = dlg.expressionBuilder()->expressionText();
349  mRuleEdit->setText( expression );
350  }
351 }
352 
353 void QgsEditConditionalFormatRuleWidget::presetSet( int index )
354 {
355  if ( index == -1 || mPresets.isEmpty() )
356  return;
357 
358  const int styleIndex = mPresetsList->currentData( Qt::UserRole + 1 ).toInt();
359  QgsConditionalStyle style = mPresets.at( styleIndex );
360  setFormattingFromStyle( style );
361 }
362 
363 void QgsEditConditionalFormatRuleWidget::setFormattingFromStyle( const QgsConditionalStyle &style )
364 {
365  btnBackgroundColor->setColor( style.backgroundColor() );
366  btnTextColor->setColor( style.textColor() );
367  if ( auto *lSymbol = style.symbol() )
368  {
369  btnChangeIcon->setSymbol( lSymbol->clone() );
370  checkIcon->setChecked( true );
371  }
372  else
373  {
374  checkIcon->setChecked( false );
375  }
376  QFont font = style.font();
377  mFontBoldBtn->setChecked( font.bold() );
378  mFontItalicBtn->setChecked( font.italic() );
379  mFontStrikethroughBtn->setChecked( font.strikeOut() );
380  mFontUnderlineBtn->setChecked( font.underline() );
381  mFontFamilyCmbBx->setCurrentFont( font );
382 }
383 
384 void QgsEditConditionalFormatRuleWidget::setPresets( const QList<QgsConditionalStyle> &styles )
385 {
386  mPresets.clear();
387  mPresetsModel->clear();
388  QStandardItem *item = new QStandardItem( QString() );
389  mPresetsModel->appendRow( item );
390  int i = 0;
391  for ( const QgsConditionalStyle &style : styles )
392  {
393  if ( style.isValid() )
394  {
395  QStandardItem *item = new QStandardItem( QStringLiteral( "abc - 123" ) );
396  if ( style.validBackgroundColor() )
397  item->setBackground( style.backgroundColor() );
398  if ( style.validTextColor() )
399  item->setForeground( style.textColor() );
400  if ( style.symbol() )
401  item->setIcon( style.icon() );
402  item->setFont( style.font() );
403  item->setData( i, Qt::UserRole + 1 );
404  mPresetsModel->appendRow( item );
405  mPresets.append( style );
406  i++;
407  }
408  }
409  mPresetsList->setCurrentIndex( 0 );
410 }
411 
413 {
414  mRuleEdit->setText( rule );
415 }
416 
417 bool QgsEditConditionalFormatRuleWidget::isCustomSet()
418 {
419  return ( btnBackgroundColor->color().isValid()
420  || btnTextColor->color().isValid()
421  || mFontButtons->checkedId() != -1 );
422 }
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:183
QgsConditionalStyles rowStyles() const
Returns a list of row styles associated with the layer.
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName) const
Returns the conditional styles set for the field with matching fieldName.
void setFieldStyles(const QString &fieldName, const QList< QgsConditionalStyle > &styles)
Set the conditional styles for a field, with the specified fieldName.
void setRowStyles(const QgsConditionalStyles &styles)
Sets the conditional styles that apply to full rows of data in the attribute table.
Conditional styling for a rule.
QString displayText() const
The name of the style.
QString name() const
The name of the style.
void setSymbol(QgsSymbol *value)
Set the icon for the style.
void setName(const QString &value)
Set the name of the style.
QPixmap renderPreview(const QSize &size=QSize()) const
Render a preview icon of the rule, at the specified size.
QgsSymbol * symbol() const
The symbol used to generate the icon for the style.
void setTextColor(const QColor &value)
Set the text color for the style.
void setRule(const QString &value)
Set the rule for the style.
void setBackgroundColor(const QColor &value)
Set the background color for the style.
void setFont(const QFont &value)
Set the font for the style.
QColor backgroundColor() const
The background color for style.
QColor textColor() const
The text color set for style.
QString rule() const
The condition rule set for the style.
QFont font() const
The font for the style.
bool validTextColor() const
Check if the text color is valid for render.
bool isValid() const
isValid Check if this rule is valid.
QPixmap icon() const
The icon set for style generated from the set symbol.
bool validBackgroundColor() const
Check if the background color is valid for render.
A widget for customizing an individual conditional formatting rule.
void setPresets(const QList< QgsConditionalStyle > &styles)
Sets the preset styles that can be used for quick pick.
void loadStyle(const QgsConditionalStyle &style)
Sets the widget to match the settings from the specified style.
QgsEditConditionalFormatRuleWidget(QWidget *parent SIP_TRANSFERTHIS=nullptr)
Constructor for QgsFieldConditionalFormatWidget, with the specified parent widget.
void setLayer(QgsVectorLayer *layer)
Sets the vector layer associated with the widget.
void setRule(const QString &rule)
Sets the current expression rule to show in the widget.
QgsConditionalStyle currentStyle() const
Returns the current style defined by the widget.
void canceled()
Emitted when a user has opted to cancel the rule modification.
void ruleDeleted()
Emitted when a user has opted to deleted the current rule.
void ruleSaved()
Emitted when a user has opted to save the current rule.
A generic dialog for building expression strings.
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
QgsFieldConditionalFormatWidget(QWidget *parent SIP_TRANSFERTHIS=nullptr)
Constructor for QgsFieldConditionalFormatWidget.
void rulesUpdated(const QString &fieldName)
Emitted when the conditional styling rules are updated.
static QList< QgsConditionalStyle > defaultPresets()
Returns a list of the default presets.
Q_DECL_DEPRECATED void reset() SIP_DEPRECATED
Resets the formatting options to their default state.
Q_DECL_DEPRECATED void viewRules() SIP_DEPRECATED
Switches the widget to the rules page.
void editStyle(int index, const QgsConditionalStyle &style)
Switches the widget to the edit style mode for the specified style, where index is the index of the c...
void setPresets(const QList< QgsConditionalStyle > &styles)
Sets the preset styles that can be used for quick pick.
Q_DECL_DEPRECATED void loadStyle(const QgsConditionalStyle &style) SIP_DEPRECATED
void setLayer(QgsVectorLayer *layer)
Sets the vector layer associated with the widget.
A marker symbol type, for rendering Point and MultiPoint geometries.
Definition: qgssymbol.h:1004
Base class for any widget that can be shown as a inline panel.
void showPanel(QgsPanelWidget *panel)
Emit when you require a panel to be show in the interface.
void panelAccepted(QgsPanelWidget *panel)
Emitted when the panel is accepted by the user.
void acceptPanel()
Accept the panel.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:346
@ Marker
Marker symbol.
Definition: qgssymbol.h:88
Represents a vector layer which manages a vector based data sets.
QgsConditionalLayerStyles * conditionalStyles() const
Returns the conditional styles that are set for this layer.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
Single variable definition for use within a QgsExpressionContextScope.