QGIS API Documentation 3.99.0-Master (d270888f95f)
Loading...
Searching...
No Matches
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
19#include "qgsguiutils.h"
20#include "qgsmarkersymbol.h"
21#include "qgsstyle.h"
22#include "qgssymbol.h"
23#include "qgssymbollayerutils.h"
25#include "qgsvectorlayer.h"
26
27#include <QString>
28
29#include "moc_qgsfieldconditionalformatwidget.cpp"
30
31using namespace Qt::StringLiterals;
32
33//
34// QgsFieldConditionalFormatWidget
35//
36
38 : QgsPanelWidget( parent )
39{
40 setupUi( this );
41 setPanelTitle( tr( "Conditional Styles" ) );
42 connect( mFieldCombo, &QgsFieldComboBox::fieldChanged, this, &QgsFieldConditionalFormatWidget::fieldChanged );
43 connect( fieldRadio, &QAbstractButton::clicked, this, &QgsFieldConditionalFormatWidget::typeChanged );
44 connect( rowRadio, &QAbstractButton::clicked, this, &QgsFieldConditionalFormatWidget::typeChanged );
45 connect( mNewButton, &QAbstractButton::clicked, this, &QgsFieldConditionalFormatWidget::addNewRule );
46 connect( listView, &QAbstractItemView::clicked, this, &QgsFieldConditionalFormatWidget::ruleClicked );
47 mModel = new QStandardItemModel( listView );
48 listView->setModel( mModel );
49
50 connect( fieldRadio, &QRadioButton::toggled, mFieldCombo, &QWidget::setEnabled );
51
52 mPresets = defaultPresets();
53}
54
56{
57 mLayer = layer;
58 mFieldCombo->setLayer( layer );
59 mFieldCombo->setCurrentIndex( 0 );
60 fieldChanged( mFieldCombo->currentField() );
61}
62
63void QgsFieldConditionalFormatWidget::ruleClicked( const QModelIndex &index )
64{
65 const QList<QgsConditionalStyle> styles = getStyles();
66 const QgsConditionalStyle style = styles.at( index.row() );
67 editStyle( index.row(), style );
68}
69
71{
72 mEditIndex = editIndex;
73 mEditing = editIndex >= 0;
74 mPanelHandled = false;
75
77 ruleWidget->setLayer( mLayer );
78 ruleWidget->setPresets( mPresets );
79 ruleWidget->loadStyle( style );
80 ruleWidget->setDockMode( true );
81
82 if ( fieldRadio->isChecked() && style.rule().isEmpty() )
83 {
84 ruleWidget->setRule( u"@value "_s );
85 }
86
87 connect( ruleWidget, &QgsEditConditionalFormatRuleWidget::panelAccepted, this, [this, ruleWidget] {
88 if ( mPanelHandled )
89 {
90 // already handled the result of the panel, and the panel is being dismissed as a result
91 // of an already dealt with action
92 return;
93 }
94
95 QList<QgsConditionalStyle> styles = getStyles();
96 if ( mEditing )
97 {
98 styles.replace( mEditIndex, ruleWidget->currentStyle() );
99 }
100 else
101 {
102 styles.append( ruleWidget->currentStyle() );
103 }
104
105 QString fieldName;
106 if ( fieldRadio->isChecked() )
107 {
108 fieldName = mFieldCombo->currentField();
109 mLayer->conditionalStyles()->setFieldStyles( fieldName, styles );
110 }
111 else if ( rowRadio->isChecked() )
112 {
113 mLayer->conditionalStyles()->setRowStyles( styles );
114 }
115
116 reloadStyles();
117 emit rulesUpdated( fieldName );
118 } );
119
120 connect( ruleWidget, &QgsEditConditionalFormatRuleWidget::ruleSaved, this, [ruleWidget] {
121 ruleWidget->acceptPanel();
122 } );
123
124 connect( ruleWidget, &QgsEditConditionalFormatRuleWidget::canceled, this, [this, ruleWidget] {
125 mPanelHandled = true;
126 ruleWidget->acceptPanel();
127 } );
128
129 connect( ruleWidget, &QgsEditConditionalFormatRuleWidget::ruleDeleted, this, [this, ruleWidget] {
130 deleteCurrentRule();
131 mPanelHandled = true;
132 ruleWidget->acceptPanel();
133 } );
134 showPanel( ruleWidget );
135}
136
140
141QList<QgsConditionalStyle> QgsFieldConditionalFormatWidget::getStyles()
142{
143 QList<QgsConditionalStyle> styles;
144 if ( fieldRadio->isChecked() )
145 {
146 styles = mLayer->conditionalStyles()->fieldStyles( mFieldCombo->currentField() );
147 }
148 else if ( rowRadio->isChecked() )
149 {
150 styles = mLayer->conditionalStyles()->rowStyles();
151 }
152
153 return styles;
154}
155
156void QgsFieldConditionalFormatWidget::addNewRule()
157{
158 editStyle( -1, QgsConditionalStyle() );
159}
160
164
165void QgsFieldConditionalFormatWidget::setPresets( const QList<QgsConditionalStyle> &styles )
166{
167 mPresets = styles;
168}
169
171{
172 QList<QgsConditionalStyle> styles;
174 style.setBackgroundColor( QColor( 154, 216, 113 ) );
175 styles.append( style );
176 style = QgsConditionalStyle();
177 style.setBackgroundColor( QColor( 251, 193, 78 ) );
178 styles.append( style );
179 style = QgsConditionalStyle();
180 style.setBackgroundColor( QColor( 251, 154, 153 ) );
181 styles.append( style );
182 style = QgsConditionalStyle();
183 style.setTextColor( QColor( 154, 216, 113 ) );
184 styles.append( style );
185 style = QgsConditionalStyle();
186 style.setTextColor( QColor( 251, 193, 78 ) );
187 styles.append( style );
188 style = QgsConditionalStyle();
189 style.setTextColor( QColor( 251, 154, 153 ) );
190 styles.append( style );
191 return styles;
192}
193
194void QgsFieldConditionalFormatWidget::typeChanged()
195{
196 reloadStyles();
197}
198
199void QgsFieldConditionalFormatWidget::reloadStyles()
200{
201 mModel->clear();
202
203 const auto constGetStyles = getStyles();
204
205 const QSize size( Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 10, Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 2 );
206
207 listView->setIconSize( size );
208
209 for ( const QgsConditionalStyle &style : constGetStyles )
210 {
211 QStandardItem *item = new QStandardItem( style.displayText() );
212 item->setIcon( QIcon( style.renderPreview( size ) ) );
213 mModel->appendRow( item );
214 }
215}
216
217void QgsFieldConditionalFormatWidget::fieldChanged( const QString &fieldName )
218{
219 Q_UNUSED( fieldName )
220 reloadStyles();
221}
222
223void QgsFieldConditionalFormatWidget::deleteCurrentRule()
224{
225 if ( !mEditing )
226 return;
227
228 QList<QgsConditionalStyle> styles = getStyles();
229 styles.removeAt( mEditIndex );
230 QString fieldName;
231 if ( fieldRadio->isChecked() )
232 {
233 fieldName = mFieldCombo->currentField();
234 mLayer->conditionalStyles()->setFieldStyles( fieldName, styles );
235 }
236 else if ( rowRadio->isChecked() )
237 {
238 mLayer->conditionalStyles()->setRowStyles( styles );
239 }
240
241 reloadStyles();
242 emit rulesUpdated( fieldName );
243}
244
248
249
250//
251// QgsEditConditionalFormatRuleWidget
252//
253
255 : QgsPanelWidget( parent )
256{
257 setupUi( this );
258
259 setPanelTitle( tr( "Edit Rule" ) );
260
261 btnBackgroundColor->setColor( QColor() );
262 btnTextColor->setColor( QColor() );
263 checkIcon->setChecked( false );
264 btnChangeIcon->setIcon( QIcon() );
265 btnBackgroundColor->setToNoColor();
266 btnTextColor->setToNoColor();
267
268 mFontBoldBtn->setChecked( false );
269 mFontItalicBtn->setChecked( false );
270 mFontStrikethroughBtn->setChecked( false );
271 mFontUnderlineBtn->setChecked( false );
272
273 const int buttonSize = QgsGuiUtils::scaleIconSize( 24 );
274 mFontUnderlineBtn->setMinimumSize( buttonSize, buttonSize );
275 mFontUnderlineBtn->setMaximumSize( buttonSize, buttonSize );
276 mFontStrikethroughBtn->setMinimumSize( buttonSize, buttonSize );
277 mFontStrikethroughBtn->setMaximumSize( buttonSize, buttonSize );
278 mFontBoldBtn->setMinimumSize( buttonSize, buttonSize );
279 mFontBoldBtn->setMaximumSize( buttonSize, buttonSize );
280 mFontItalicBtn->setMinimumSize( buttonSize, buttonSize );
281 mFontItalicBtn->setMaximumSize( buttonSize, buttonSize );
282
283 connect( mSaveRule, &QAbstractButton::clicked, this, &QgsEditConditionalFormatRuleWidget::ruleSaved );
284 connect( mCancelButton, &QAbstractButton::clicked, this, &QgsEditConditionalFormatRuleWidget::canceled );
285 connect( mDeleteButton, &QAbstractButton::clicked, this, &QgsEditConditionalFormatRuleWidget::ruleDeleted );
286
287 connect( btnBuildExpression, &QAbstractButton::clicked, this, &QgsEditConditionalFormatRuleWidget::setExpression );
288 connect( mPresetsList, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsEditConditionalFormatRuleWidget::presetSet );
289
290 btnBackgroundColor->setAllowOpacity( true );
291 btnBackgroundColor->setShowNoColor( true );
292 btnTextColor->setAllowOpacity( true );
293 btnTextColor->setShowNoColor( true );
294 mPresetsModel = new QStandardItemModel( mPresetsList );
295 mPresetsList->setModel( mPresetsModel );
296
297 btnChangeIcon->setSymbolType( Qgis::SymbolType::Marker );
298 btnChangeIcon->setSymbol( QgsSymbol::defaultSymbol( Qgis::GeometryType::Point ) );
299 connect( checkIcon, &QCheckBox::toggled, btnChangeIcon, &QWidget::setEnabled );
300}
301
303{
304 mLayer = layer;
305}
306
308{
309 mRuleEdit->setText( style.rule() );
310 mNameEdit->setText( style.name() );
311 setFormattingFromStyle( style );
312}
313
315{
317
318 style.setRule( mRuleEdit->text() );
319 style.setName( mNameEdit->text() );
320
321 const QColor backColor = btnBackgroundColor->color();
322 const QColor fontColor = btnTextColor->color();
323
324 QFont font = mFontFamilyCmbBx->currentFont();
325 font.setBold( mFontBoldBtn->isChecked() );
326 font.setItalic( mFontItalicBtn->isChecked() );
327 font.setStrikeOut( mFontStrikethroughBtn->isChecked() );
328 font.setUnderline( mFontUnderlineBtn->isChecked() );
329 style.setFont( font );
330 style.setBackgroundColor( backColor );
331 style.setTextColor( fontColor );
332 if ( checkIcon->isChecked() )
333 {
334 style.setSymbol( btnChangeIcon->clonedSymbol<QgsMarkerSymbol>() );
335 }
336 else
337 {
338 style.setSymbol( nullptr );
339 }
340 return style;
341}
342
343void QgsEditConditionalFormatRuleWidget::setExpression()
344{
346 context.lastScope()->addVariable( QgsExpressionContextScope::StaticVariable( u"value"_s, 0, true ) );
347 context.setHighlightedVariables( QStringList() << u"value"_s );
348
349 QgsExpressionBuilderDialog dlg( mLayer, mRuleEdit->text(), this, u"generic"_s, context );
350 dlg.setWindowTitle( tr( "Conditional Style Rule Expression" ) );
351
352 if ( dlg.exec() )
353 {
354 const QString expression = dlg.expressionBuilder()->expressionText();
355 mRuleEdit->setText( expression );
356 }
357}
358
359void QgsEditConditionalFormatRuleWidget::presetSet( int index )
360{
361 if ( index == -1 || mPresets.isEmpty() )
362 return;
363
364 const int styleIndex = mPresetsList->currentData( Qt::UserRole + 1 ).toInt();
365 const QgsConditionalStyle style = mPresets.at( styleIndex );
366 setFormattingFromStyle( style );
367}
368
369void QgsEditConditionalFormatRuleWidget::setFormattingFromStyle( const QgsConditionalStyle &style )
370{
371 btnBackgroundColor->setColor( style.backgroundColor() );
372 btnTextColor->setColor( style.textColor() );
373 if ( auto *lSymbol = style.symbol() )
374 {
375 btnChangeIcon->setSymbol( lSymbol->clone() );
376 checkIcon->setChecked( true );
377 }
378 else
379 {
380 checkIcon->setChecked( false );
381 }
382 const QFont font = style.font();
383 mFontBoldBtn->setChecked( font.bold() );
384 mFontItalicBtn->setChecked( font.italic() );
385 mFontStrikethroughBtn->setChecked( font.strikeOut() );
386 mFontUnderlineBtn->setChecked( font.underline() );
387 mFontFamilyCmbBx->setCurrentFont( font );
388}
389
390void QgsEditConditionalFormatRuleWidget::setPresets( const QList<QgsConditionalStyle> &styles )
391{
392 mPresets.clear();
393 mPresetsModel->clear();
394 QStandardItem *item = new QStandardItem( QString() );
395 mPresetsModel->appendRow( item );
396 int i = 0;
397 for ( const QgsConditionalStyle &style : styles )
398 {
399 if ( style.isValid() )
400 {
401 QStandardItem *item = new QStandardItem( u"abc - 123"_s );
402 if ( style.validBackgroundColor() )
403 item->setBackground( style.backgroundColor() );
404 if ( style.validTextColor() )
405 item->setForeground( style.textColor() );
406 if ( style.symbol() )
407 item->setIcon( style.icon() );
408 item->setFont( style.font() );
409 item->setData( i, Qt::UserRole + 1 );
410 mPresetsModel->appendRow( item );
411 mPresets.append( style );
412 i++;
413 }
414 }
415 mPresetsList->setCurrentIndex( 0 );
416}
417
419{
420 mRuleEdit->setText( rule );
421}
422
423bool QgsEditConditionalFormatRuleWidget::isCustomSet()
424{
425 return ( btnBackgroundColor->color().isValid() || btnTextColor->color().isValid() || mFontButtons->checkedId() != -1 );
426}
@ Point
Points.
Definition qgis.h:366
@ Marker
Marker symbol.
Definition qgis.h:630
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition qgis.h:6499
QList< QgsConditionalStyle > fieldStyles(const QString &fieldName) const
Returns the conditional styles set for the field with matching fieldName.
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.
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.
QgsSymbol * symbol() const
The symbol used to generate the icon for the style.
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.
QgsEditConditionalFormatRuleWidget(QWidget *parent=nullptr)
Constructor for QgsFieldConditionalFormatWidget, with the specified parent widget.
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.
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=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 viewRules()
Switches the widget to the rules page.
Q_DECL_DEPRECATED void loadStyle(const QgsConditionalStyle &style)
Q_DECL_DEPRECATED void reset()
Resets the formatting options to their default state.
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.
void setLayer(QgsVectorLayer *layer)
Sets the vector layer associated with the widget.
A marker symbol type, for rendering Point and MultiPoint geometries.
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.
QgsPanelWidget(QWidget *parent=nullptr)
Base class for any widget that can be shown as an inline panel.
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(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Represents a vector layer which manages a vector based dataset.
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.