QGIS API Documentation 3.32.0-Lima (311a8cb8a6)
qgsdiagramproperties.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgsdiagramproperties.cpp
3 Adjust the properties for diagrams
4 -------------------
5 begin : August 2012
6 copyright : (C) Matthias Kuhn
7 email : matthias at opengis dot ch
8
9 ***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
22
23#include "qgsproject.h"
24#include "qgsapplication.h"
28#include "qgsdiagramrenderer.h"
30#include "qgsfeatureiterator.h"
32#include "qgsmapcanvas.h"
34#include "qgslogger.h"
35#include "qgssettings.h"
37#include "qgsauxiliarystorage.h"
41#include "qgspainteffect.h"
42#include "qgslinesymbol.h"
43
44#include <QList>
45#include <QMessageBox>
46#include <QStyledItemDelegate>
47#include <QRandomGenerator>
48
49QgsExpressionContext QgsDiagramProperties::createExpressionContext() const
50{
51 QgsExpressionContext expContext;
57
58 return expContext;
59}
60
62 : QWidget( parent )
63 , mMapCanvas( canvas )
64{
65 mLayer = layer;
66 if ( !layer )
67 {
68 return;
69 }
70
71 setupUi( this );
72 connect( mDiagramTypeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsDiagramProperties::mDiagramTypeComboBox_currentIndexChanged );
73 connect( mAddCategoryPushButton, &QPushButton::clicked, this, &QgsDiagramProperties::mAddCategoryPushButton_clicked );
74 connect( mAttributesTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QgsDiagramProperties::mAttributesTreeWidget_itemDoubleClicked );
75 connect( mFindMaximumValueButton, &QPushButton::clicked, this, &QgsDiagramProperties::mFindMaximumValueButton_clicked );
76 connect( mRemoveCategoryPushButton, &QPushButton::clicked, this, &QgsDiagramProperties::mRemoveCategoryPushButton_clicked );
77 connect( mDiagramAttributesTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QgsDiagramProperties::mDiagramAttributesTreeWidget_itemDoubleClicked );
78 connect( mEngineSettingsButton, &QPushButton::clicked, this, &QgsDiagramProperties::mEngineSettingsButton_clicked );
79 connect( mDiagramStackedWidget, &QStackedWidget::currentChanged, this, &QgsDiagramProperties::mDiagramStackedWidget_currentChanged );
80
81 // get rid of annoying outer focus rect on Mac
82 mDiagramOptionsListWidget->setAttribute( Qt::WA_MacShowFocusRect, false );
83
84 mBarSpacingSpinBox->setClearValue( 0 );
85 mBarSpacingUnitComboBox->setUnits( { Qgis::RenderUnit::Millimeters,
86 Qgis::RenderUnit::MetersInMapUnits,
87 Qgis::RenderUnit::MapUnits,
88 Qgis::RenderUnit::Pixels,
89 Qgis::RenderUnit::Points,
90 Qgis::RenderUnit::Inches } );
91
92 mDiagramFontButton->setMode( QgsFontButton::ModeQFont );
93
94 mDiagramTypeComboBox->blockSignals( true );
95 QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "diagramNone.svg" ) );
96 mDiagramTypeComboBox->addItem( icon, tr( "No Diagrams" ), "None" );
97 icon = QgsApplication::getThemeIcon( QStringLiteral( "pie-chart.svg" ) );
98 mDiagramTypeComboBox->addItem( icon, tr( "Pie Chart" ), DIAGRAM_NAME_PIE );
99 icon = QgsApplication::getThemeIcon( QStringLiteral( "text.svg" ) );
100 mDiagramTypeComboBox->addItem( icon, tr( "Text Diagram" ), DIAGRAM_NAME_TEXT );
101 icon = QgsApplication::getThemeIcon( QStringLiteral( "histogram.svg" ) );
102 mDiagramTypeComboBox->addItem( icon, tr( "Histogram" ), DIAGRAM_NAME_HISTOGRAM );
103 icon = QgsApplication::getThemeIcon( QStringLiteral( "stacked-bar.svg" ) );
104 mDiagramTypeComboBox->addItem( icon, tr( "Stacked Bars" ), DIAGRAM_NAME_STACKED );
105 mDiagramTypeComboBox->blockSignals( false );
106
107 mAxisLineStyleButton->setSymbolType( Qgis::SymbolType::Line );
108 mAxisLineStyleButton->setDialogTitle( tr( "Axis Line Symbol" ) );
109
110 mScaleRangeWidget->setMapCanvas( mMapCanvas );
111 mSizeFieldExpressionWidget->registerExpressionContextGenerator( this );
112
113 mBackgroundColorButton->setColorDialogTitle( tr( "Select Background Color" ) );
114 mBackgroundColorButton->setAllowOpacity( true );
115 mBackgroundColorButton->setContext( QStringLiteral( "symbology" ) );
116 mBackgroundColorButton->setShowNoColor( true );
117 mBackgroundColorButton->setNoColorString( tr( "Transparent Background" ) );
118 mDiagramPenColorButton->setColorDialogTitle( tr( "Select Pen Color" ) );
119 mDiagramPenColorButton->setAllowOpacity( true );
120 mDiagramPenColorButton->setContext( QStringLiteral( "symbology" ) );
121 mDiagramPenColorButton->setShowNoColor( true );
122 mDiagramPenColorButton->setNoColorString( tr( "Transparent Stroke" ) );
123
124 mMaxValueSpinBox->setShowClearButton( false );
125 mSizeSpinBox->setClearValue( 5 );
126
127 mDiagramAttributesTreeWidget->setItemDelegateForColumn( ColumnAttributeExpression, new EditBlockerDelegate( this ) );
128 mDiagramAttributesTreeWidget->setItemDelegateForColumn( ColumnColor, new QgsColorSwatchDelegate( this ) );
129
130 mDiagramAttributesTreeWidget->setColumnWidth( ColumnColor, Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 6.6 );
131
132 connect( mFixedSizeRadio, &QRadioButton::toggled, this, &QgsDiagramProperties::scalingTypeChanged );
133 connect( mAttributeBasedScalingRadio, &QRadioButton::toggled, this, &QgsDiagramProperties::scalingTypeChanged );
134
135 mDiagramUnitComboBox->setUnits( {Qgis::RenderUnit::Millimeters,
136 Qgis::RenderUnit::MapUnits,
137 Qgis::RenderUnit::Pixels,
138 Qgis::RenderUnit::Points,
139 Qgis::RenderUnit::Inches } );
140 mDiagramLineUnitComboBox->setUnits( { Qgis::RenderUnit::Millimeters,
141 Qgis::RenderUnit::MapUnits,
142 Qgis::RenderUnit::Pixels,
143 Qgis::RenderUnit::Points,
144 Qgis::RenderUnit::Inches } );
145
146 const Qgis::GeometryType layerType = layer->geometryType();
147 if ( layerType == Qgis::GeometryType::Unknown || layerType == Qgis::GeometryType::Null )
148 {
149 mDiagramTypeComboBox->setEnabled( false );
150 mDiagramFrame->setEnabled( false );
151 }
152
153 // set placement methods page based on geometry type
154
155 switch ( layerType )
156 {
157 case Qgis::GeometryType::Point:
158 stackedPlacement->setCurrentWidget( pagePoint );
159 mLinePlacementFrame->setVisible( false );
160 break;
161 case Qgis::GeometryType::Line:
162 stackedPlacement->setCurrentWidget( pageLine );
163 mLinePlacementFrame->setVisible( true );
164 break;
165 case Qgis::GeometryType::Polygon:
166 stackedPlacement->setCurrentWidget( pagePolygon );
167 mLinePlacementFrame->setVisible( false );
168 break;
169 case Qgis::GeometryType::Null:
170 case Qgis::GeometryType::Unknown:
171 break;
172 }
173
174 //insert placement options
175 // setup point placement button group
176 mPlacePointBtnGrp = new QButtonGroup( this );
177 mPlacePointBtnGrp->addButton( radAroundPoint );
178 mPlacePointBtnGrp->addButton( radOverPoint );
179 mPlacePointBtnGrp->setExclusive( true );
180 connect( mPlacePointBtnGrp, qOverload< QAbstractButton * >( &QButtonGroup::buttonClicked ), this, &QgsDiagramProperties::updatePlacementWidgets );
181
182 // setup line placement button group
183 mPlaceLineBtnGrp = new QButtonGroup( this );
184 mPlaceLineBtnGrp->addButton( radAroundLine );
185 mPlaceLineBtnGrp->addButton( radOverLine );
186 mPlaceLineBtnGrp->setExclusive( true );
187 connect( mPlaceLineBtnGrp, qOverload< QAbstractButton * >( &QButtonGroup::buttonClicked ), this, &QgsDiagramProperties::updatePlacementWidgets );
188
189 // setup polygon placement button group
190 mPlacePolygonBtnGrp = new QButtonGroup( this );
191 mPlacePolygonBtnGrp->addButton( radAroundCentroid );
192 mPlacePolygonBtnGrp->addButton( radOverCentroid );
193 mPlacePolygonBtnGrp->addButton( radPolygonPerimeter );
194 mPlacePolygonBtnGrp->addButton( radInsidePolygon );
195 mPlacePolygonBtnGrp->setExclusive( true );
196 connect( mPlacePolygonBtnGrp, qOverload< QAbstractButton * >( &QButtonGroup::buttonClicked ), this, &QgsDiagramProperties::updatePlacementWidgets );
197
198 mLabelPlacementComboBox->addItem( tr( "Height" ), QgsDiagramSettings::Height );
199 mLabelPlacementComboBox->addItem( tr( "x-height" ), QgsDiagramSettings::XHeight );
200
201 mScaleDependencyComboBox->addItem( tr( "Area" ), true );
202 mScaleDependencyComboBox->addItem( tr( "Diameter" ), false );
203
204 mAngleOffsetComboBox->addItem( tr( "Top" ), 270 );
205 mAngleOffsetComboBox->addItem( tr( "Right" ), 0 );
206 mAngleOffsetComboBox->addItem( tr( "Bottom" ), 90 );
207 mAngleOffsetComboBox->addItem( tr( "Left" ), 180 );
208
209 mAngleDirectionComboBox->addItem( tr( "Clockwise" ), QgsDiagramSettings::Clockwise );
210 mAngleDirectionComboBox->addItem( tr( "Counter-clockwise" ), QgsDiagramSettings::Counterclockwise );
211
212 const QgsSettings settings;
213
214 // reset horiz stretch of left side of options splitter (set to 1 for previewing in Qt Designer)
215 QSizePolicy policy( mDiagramOptionsListFrame->sizePolicy() );
216 policy.setHorizontalStretch( 0 );
217 mDiagramOptionsListFrame->setSizePolicy( policy );
218 if ( !settings.contains( QStringLiteral( "/Windows/Diagrams/OptionsSplitState" ) ) )
219 {
220 // set left list widget width on initial showing
221 QList<int> splitsizes;
222 splitsizes << 115;
223 mDiagramOptionsSplitter->setSizes( splitsizes );
224 }
225
226 // restore dialog, splitters and current tab
227 mDiagramOptionsSplitter->restoreState( settings.value( QStringLiteral( "Windows/Diagrams/OptionsSplitState" ) ).toByteArray() );
228 mDiagramOptionsListWidget->setCurrentRow( settings.value( QStringLiteral( "Windows/Diagrams/Tab" ), 0 ).toInt() );
229
230 // field combo and expression button
231 mSizeFieldExpressionWidget->setLayer( mLayer );
232 QgsDistanceArea myDa;
234 myDa.setEllipsoid( QgsProject::instance()->ellipsoid() );
235 mSizeFieldExpressionWidget->setGeomCalculator( myDa );
236
237 //insert all attributes into the combo boxes
238 const QgsFields &layerFields = layer->fields();
239 for ( int idx = 0; idx < layerFields.count(); ++idx )
240 {
241 QTreeWidgetItem *newItem = new QTreeWidgetItem( mAttributesTreeWidget );
242 const QString name = QStringLiteral( "\"%1\"" ).arg( layerFields.at( idx ).name() );
243 newItem->setText( 0, name );
244 newItem->setData( 0, RoleAttributeExpression, name );
245 newItem->setFlags( newItem->flags() & ~Qt::ItemIsDropEnabled );
246 }
247
248 mPaintEffect.reset( QgsPaintEffectRegistry::defaultStack() );
249 mPaintEffect->setEnabled( false );
250
251 syncToLayer();
252
253 connect( mAddAttributeExpression, &QPushButton::clicked, this, &QgsDiagramProperties::showAddAttributeExpressionDialog );
254 registerDataDefinedButton( mBackgroundColorDDBtn, QgsDiagramLayerSettings::BackgroundColor );
255 registerDataDefinedButton( mLineColorDDBtn, QgsDiagramLayerSettings::StrokeColor );
256 registerDataDefinedButton( mLineWidthDDBtn, QgsDiagramLayerSettings::StrokeWidth );
257 registerDataDefinedButton( mCoordXDDBtn, QgsDiagramLayerSettings::PositionX );
258 registerDataDefinedButton( mCoordYDDBtn, QgsDiagramLayerSettings::PositionY );
259 registerDataDefinedButton( mDistanceDDBtn, QgsDiagramLayerSettings::Distance );
260 registerDataDefinedButton( mPriorityDDBtn, QgsDiagramLayerSettings::Priority );
261 registerDataDefinedButton( mZOrderDDBtn, QgsDiagramLayerSettings::ZIndex );
262 registerDataDefinedButton( mShowDiagramDDBtn, QgsDiagramLayerSettings::Show );
263 registerDataDefinedButton( mAlwaysShowDDBtn, QgsDiagramLayerSettings::AlwaysShow );
264 registerDataDefinedButton( mIsObstacleDDBtn, QgsDiagramLayerSettings::IsObstacle );
265 registerDataDefinedButton( mStartAngleDDBtn, QgsDiagramLayerSettings::StartAngle );
266
267 connect( mButtonSizeLegendSettings, &QPushButton::clicked, this, &QgsDiagramProperties::showSizeLegendDialog );
268}
269
271{
272 mDiagramAttributesTreeWidget->clear();
273
274 const QgsDiagramRenderer *dr = mLayer->diagramRenderer();
275 if ( !dr ) //no diagram renderer yet, insert reasonable default
276 {
277 mDiagramTypeComboBox->blockSignals( true );
278 mDiagramTypeComboBox->setCurrentIndex( 0 );
279 mDiagramTypeComboBox->blockSignals( false );
280 mFixedSizeRadio->setChecked( true );
281 mDiagramUnitComboBox->setUnit( Qgis::RenderUnit::Millimeters );
282 mDiagramLineUnitComboBox->setUnit( Qgis::RenderUnit::Millimeters );
283 mLabelPlacementComboBox->setCurrentIndex( mLabelPlacementComboBox->findText( tr( "x-height" ) ) );
284 mDiagramSizeSpinBox->setEnabled( true );
285 mDiagramSizeSpinBox->setValue( 15 );
286 mLinearScaleFrame->setEnabled( false );
287 mIncreaseMinimumSizeSpinBox->setEnabled( false );
288 mIncreaseMinimumSizeLabel->setEnabled( false );
289 mBarWidthSpinBox->setValue( 5 );
290 mScaleVisibilityGroupBox->setChecked( mLayer->hasScaleBasedVisibility() );
291 mScaleRangeWidget->setScaleRange( mLayer->minimumScale(), mLayer->maximumScale() );
292 mShowAllCheckBox->setChecked( true );
293 mCheckBoxAttributeLegend->setChecked( true );
294
295 switch ( mLayer->geometryType() )
296 {
297 case Qgis::GeometryType::Point:
298 radAroundPoint->setChecked( true );
299 break;
300
301 case Qgis::GeometryType::Line:
302 radAroundLine->setChecked( true );
303 chkLineAbove->setChecked( true );
304 chkLineBelow->setChecked( false );
305 chkLineOn->setChecked( false );
306 chkLineOrientationDependent->setChecked( false );
307 break;
308
309 case Qgis::GeometryType::Polygon:
310 radOverCentroid->setChecked( true );
311 mDiagramDistanceLabel->setEnabled( false );
312 mDiagramDistanceSpinBox->setEnabled( false );
313 mDistanceDDBtn->setEnabled( false );
314 break;
315
316 case Qgis::GeometryType::Unknown:
317 case Qgis::GeometryType::Null:
318 break;
319 }
320 mBackgroundColorButton->setColor( QColor( 255, 255, 255, 255 ) );
321 //force a refresh of widget status to match diagram type
322 mDiagramTypeComboBox_currentIndexChanged( mDiagramTypeComboBox->currentIndex() );
323
324 }
325 else // already a diagram renderer present
326 {
327 //single category renderer or interpolated one?
328 if ( dr->rendererName() == QLatin1String( "SingleCategory" ) )
329 {
330 mFixedSizeRadio->setChecked( true );
331 }
332 else
333 {
334 mAttributeBasedScalingRadio->setChecked( true );
335 }
336 mDiagramSizeSpinBox->setEnabled( mFixedSizeRadio->isChecked() );
337 mLinearScaleFrame->setEnabled( mAttributeBasedScalingRadio->isChecked() );
338 mCheckBoxAttributeLegend->setChecked( dr->attributeLegend() );
339
340 //assume single category or linearly interpolated diagram renderer for now
341 const QList<QgsDiagramSettings> settingList = dr->diagramSettings();
342 if ( !settingList.isEmpty() )
343 {
344 mDiagramFrame->setEnabled( settingList.at( 0 ).enabled );
345 mDiagramFontButton->setCurrentFont( settingList.at( 0 ).font );
346 const QSizeF size = settingList.at( 0 ).size;
347 mBackgroundColorButton->setColor( settingList.at( 0 ).backgroundColor );
348 mOpacityWidget->setOpacity( settingList.at( 0 ).opacity );
349 mDiagramPenColorButton->setColor( settingList.at( 0 ).penColor );
350 mPenWidthSpinBox->setValue( settingList.at( 0 ).penWidth );
351 mDiagramSizeSpinBox->setValue( ( size.width() + size.height() ) / 2.0 );
352 mScaleRangeWidget->setScaleRange( ( settingList.at( 0 ).minimumScale > 0 ? settingList.at( 0 ).minimumScale : mLayer->minimumScale() ),
353 ( settingList.at( 0 ).maximumScale > 0 ? settingList.at( 0 ).maximumScale : mLayer->maximumScale() ) );
354 mScaleVisibilityGroupBox->setChecked( settingList.at( 0 ).scaleBasedVisibility );
355 mDiagramUnitComboBox->setUnit( settingList.at( 0 ).sizeType );
356 mDiagramUnitComboBox->setMapUnitScale( settingList.at( 0 ).sizeScale );
357 mDiagramLineUnitComboBox->setUnit( settingList.at( 0 ).lineSizeUnit );
358 mDiagramLineUnitComboBox->setMapUnitScale( settingList.at( 0 ).lineSizeScale );
359
360 if ( settingList.at( 0 ).labelPlacementMethod == QgsDiagramSettings::Height )
361 {
362 mLabelPlacementComboBox->setCurrentIndex( 0 );
363 }
364 else
365 {
366 mLabelPlacementComboBox->setCurrentIndex( 1 );
367 }
368
369 if ( settingList.at( 0 ).paintEffect() )
370 mPaintEffect.reset( settingList.at( 0 ).paintEffect()->clone() );
371
372 mAngleOffsetComboBox->setCurrentIndex( mAngleOffsetComboBox->findData( settingList.at( 0 ).rotationOffset ) );
373 mAngleDirectionComboBox->setCurrentIndex( mAngleDirectionComboBox->findData( settingList.at( 0 ).direction() ) );
374
375 mOrientationLeftButton->setProperty( "direction", QgsDiagramSettings::Left );
376 mOrientationRightButton->setProperty( "direction", QgsDiagramSettings::Right );
377 mOrientationUpButton->setProperty( "direction", QgsDiagramSettings::Up );
378 mOrientationDownButton->setProperty( "direction", QgsDiagramSettings::Down );
379 switch ( settingList.at( 0 ).diagramOrientation )
380 {
382 mOrientationLeftButton->setChecked( true );
383 break;
384
386 mOrientationRightButton->setChecked( true );
387 break;
388
390 mOrientationUpButton->setChecked( true );
391 break;
392
394 mOrientationDownButton->setChecked( true );
395 break;
396 }
397
398 mBarWidthSpinBox->setValue( settingList.at( 0 ).barWidth );
399 mBarSpacingSpinBox->setValue( settingList.at( 0 ).spacing() );
400 mBarSpacingUnitComboBox->setUnit( settingList.at( 0 ).spacingUnit() );
401 mBarSpacingUnitComboBox->setMapUnitScale( settingList.at( 0 ).spacingMapUnitScale() );
402
403 mShowAxisGroupBox->setChecked( settingList.at( 0 ).showAxis() );
404 if ( settingList.at( 0 ).axisLineSymbol() )
405 mAxisLineStyleButton->setSymbol( settingList.at( 0 ).axisLineSymbol()->clone() );
406
407 mIncreaseSmallDiagramsCheck->setChecked( settingList.at( 0 ).minimumSize != 0 );
408 mIncreaseMinimumSizeSpinBox->setEnabled( mIncreaseSmallDiagramsCheck->isChecked() );
409 mIncreaseMinimumSizeLabel->setEnabled( mIncreaseSmallDiagramsCheck->isChecked() );
410
411 mIncreaseMinimumSizeSpinBox->setValue( settingList.at( 0 ).minimumSize );
412
413 if ( settingList.at( 0 ).scaleByArea )
414 {
415 mScaleDependencyComboBox->setCurrentIndex( 0 );
416 }
417 else
418 {
419 mScaleDependencyComboBox->setCurrentIndex( 1 );
420 }
421
422 const QList< QColor > categoryColors = settingList.at( 0 ).categoryColors;
423 const QList< QString > categoryAttributes = settingList.at( 0 ).categoryAttributes;
424 const QList< QString > categoryLabels = settingList.at( 0 ).categoryLabels;
425 QList< QString >::const_iterator catIt = categoryAttributes.constBegin();
426 QList< QColor >::const_iterator coIt = categoryColors.constBegin();
427 QList< QString >::const_iterator labIt = categoryLabels.constBegin();
428 for ( ; catIt != categoryAttributes.constEnd(); ++catIt, ++coIt, ++labIt )
429 {
430 QTreeWidgetItem *newItem = new QTreeWidgetItem( mDiagramAttributesTreeWidget );
431 newItem->setText( 0, *catIt );
432 newItem->setData( 0, RoleAttributeExpression, *catIt );
433 newItem->setFlags( newItem->flags() & ~Qt::ItemIsDropEnabled );
434 newItem->setData( ColumnColor, Qt::EditRole, *coIt );
435 newItem->setText( 2, *labIt );
436 newItem->setFlags( newItem->flags() | Qt::ItemIsEditable );
437 }
438 }
439
440 if ( dr->rendererName() == QLatin1String( "LinearlyInterpolated" ) )
441 {
443 if ( lidr )
444 {
445 mDiagramSizeSpinBox->setEnabled( false );
446 mLinearScaleFrame->setEnabled( true );
447 mMaxValueSpinBox->setValue( lidr->upperValue() );
448 mSizeSpinBox->setValue( ( lidr->upperSize().width() + lidr->upperSize().height() ) / 2 );
450 {
451 mSizeFieldExpressionWidget->setField( lidr->classificationAttributeExpression() );
452 }
453 else
454 {
455 mSizeFieldExpressionWidget->setField( lidr->classificationField() );
456 }
457
458 mSizeLegend.reset( lidr->dataDefinedSizeLegend() ? new QgsDataDefinedSizeLegend( *lidr->dataDefinedSizeLegend() ) : nullptr );
459 }
460 }
461
462 const QgsDiagramLayerSettings *dls = mLayer->diagramLayerSettings();
463 if ( dls )
464 {
465 mDiagramDistanceSpinBox->setValue( dls->distance() );
466 mPrioritySlider->setValue( dls->priority() );
467 mZIndexSpinBox->setValue( dls->zIndex() );
468
469 switch ( dls->placement() )
470 {
472 radAroundPoint->setChecked( true );
473 radAroundCentroid->setChecked( true );
474 break;
475
477 radOverPoint->setChecked( true );
478 radOverCentroid->setChecked( true );
479 break;
480
482 radAroundLine->setChecked( true );
483 radPolygonPerimeter->setChecked( true );
484 break;
485
487 radOverLine->setChecked( true );
488 radInsidePolygon->setChecked( true );
489 break;
490
491 default:
492 break;
493 }
494
495 chkLineAbove->setChecked( dls->linePlacementFlags() & QgsDiagramLayerSettings::AboveLine );
496 chkLineBelow->setChecked( dls->linePlacementFlags() & QgsDiagramLayerSettings::BelowLine );
497 chkLineOn->setChecked( dls->linePlacementFlags() & QgsDiagramLayerSettings::OnLine );
499 chkLineOrientationDependent->setChecked( true );
501
502 mShowAllCheckBox->setChecked( dls->showAllDiagrams() );
503
504 mDataDefinedProperties = dls->dataDefinedProperties();
505 }
506
507 if ( dr->diagram() )
508 {
509 mDiagramType = dr->diagram()->diagramName();
510
511 mDiagramTypeComboBox->blockSignals( true );
512 mDiagramTypeComboBox->setCurrentIndex( settingList.at( 0 ).enabled ? mDiagramTypeComboBox->findData( mDiagramType ) : 0 );
513 mDiagramTypeComboBox->blockSignals( false );
514 //force a refresh of widget status to match diagram type
515 mDiagramTypeComboBox_currentIndexChanged( mDiagramTypeComboBox->currentIndex() );
516 if ( mDiagramTypeComboBox->currentIndex() == -1 )
517 {
518 QMessageBox::warning( this, tr( "Diagram Properties" ),
519 tr( "The diagram type '%1' is unknown. A default type is selected for you." ).arg( mDiagramType ), QMessageBox::Ok );
520 mDiagramTypeComboBox->setCurrentIndex( mDiagramTypeComboBox->findData( DIAGRAM_NAME_PIE ) );
521 }
522 }
523 }
524 mPaintEffectWidget->setPaintEffect( mPaintEffect.get() );
525}
526
528{
529 QgsSettings settings;
530 settings.setValue( QStringLiteral( "Windows/Diagrams/OptionsSplitState" ), mDiagramOptionsSplitter->saveState() );
531 settings.setValue( QStringLiteral( "Windows/Diagrams/Tab" ), mDiagramOptionsListWidget->currentRow() );
532}
533
534void QgsDiagramProperties::registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsDiagramLayerSettings::Property key )
535{
536 button->init( key, mDataDefinedProperties, QgsDiagramLayerSettings::propertyDefinitions(), mLayer, true );
537 connect( button, &QgsPropertyOverrideButton::changed, this, &QgsDiagramProperties::updateProperty );
538 connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsDiagramProperties::createAuxiliaryField );
540}
541
542void QgsDiagramProperties::updateProperty()
543{
544 QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
546 mDataDefinedProperties.setProperty( key, button->toProperty() );
547}
548
550{
551 if ( index == 0 )
552 {
553 mDiagramFrame->setEnabled( false );
554 }
555 else
556 {
557 mDiagramFrame->setEnabled( true );
558
559 mDiagramType = mDiagramTypeComboBox->itemData( index ).toString();
560
561 if ( DIAGRAM_NAME_TEXT == mDiagramType )
562 {
563 mTextOptionsFrame->show();
564 mBackgroundColorLabel->show();
565 mBackgroundColorButton->show();
566 mBackgroundColorDDBtn->show();
567 mDiagramFontButton->show();
568 }
569 else
570 {
571 mTextOptionsFrame->hide();
572 mBackgroundColorLabel->hide();
573 mBackgroundColorButton->hide();
574 mBackgroundColorDDBtn->hide();
575 mDiagramFontButton->hide();
576 }
577
578 if ( DIAGRAM_NAME_HISTOGRAM == mDiagramType || DIAGRAM_NAME_STACKED == mDiagramType )
579 {
580 mBarWidthLabel->show();
581 mBarWidthSpinBox->show();
582 mBarSpacingLabel->show();
583 mBarSpacingSpinBox->show();
584 mBarSpacingUnitComboBox->show();
585 mBarOptionsFrame->show();
586 mShowAxisGroupBox->show();
587 if ( DIAGRAM_NAME_HISTOGRAM == mDiagramType )
588 mAttributeBasedScalingRadio->setChecked( true );
589 mFixedSizeRadio->setEnabled( DIAGRAM_NAME_STACKED == mDiagramType );
590 mDiagramSizeSpinBox->setEnabled( DIAGRAM_NAME_STACKED == mDiagramType );
591 mLinearlyScalingLabel->setText( tr( "Bar length: Scale linearly, so that the following value matches the specified bar length:" ) );
592 mSizeLabel->setText( tr( "Bar length" ) );
593 mFrameIncreaseSize->setVisible( false );
594 }
595 else
596 {
597 mBarWidthLabel->hide();
598 mBarWidthSpinBox->hide();
599 mBarSpacingLabel->hide();
600 mBarSpacingSpinBox->hide();
601 mBarSpacingUnitComboBox->hide();
602 mShowAxisGroupBox->hide();
603 mBarOptionsFrame->hide();
604 mLinearlyScalingLabel->setText( tr( "Scale linearly between 0 and the following attribute value / diagram size:" ) );
605 mSizeLabel->setText( tr( "Size" ) );
606 mAttributeBasedScalingRadio->setEnabled( true );
607 mFixedSizeRadio->setEnabled( true );
608 mDiagramSizeSpinBox->setEnabled( mFixedSizeRadio->isChecked() );
609 mFrameIncreaseSize->setVisible( true );
610 }
611
612 if ( DIAGRAM_NAME_TEXT == mDiagramType || DIAGRAM_NAME_PIE == mDiagramType )
613 {
614 mScaleDependencyComboBox->show();
615 mScaleDependencyLabel->show();
616 }
617 else
618 {
619 mScaleDependencyComboBox->hide();
620 mScaleDependencyLabel->hide();
621 }
622
623 if ( DIAGRAM_NAME_PIE == mDiagramType )
624 {
625 mAngleOffsetComboBox->show();
626 mAngleDirectionComboBox->show();
627 mAngleDirectionLabel->show();
628 mAngleOffsetLabel->show();
629 mStartAngleDDBtn->show();
630 }
631 else
632 {
633 mAngleOffsetComboBox->hide();
634 mAngleDirectionComboBox->hide();
635 mAngleDirectionLabel->hide();
636 mAngleOffsetLabel->hide();
637 mStartAngleDDBtn->hide();
638 }
639 }
640}
641QString QgsDiagramProperties::guessLegendText( const QString &expression )
642{
643 //trim unwanted characters from expression text for legend
644 QString text = expression.mid( expression.startsWith( '\"' ) ? 1 : 0 );
645 if ( text.endsWith( '\"' ) )
646 text.chop( 1 );
647 return text;
648}
649
650void QgsDiagramProperties::addAttribute( QTreeWidgetItem *item )
651{
652 QTreeWidgetItem *newItem = new QTreeWidgetItem( mDiagramAttributesTreeWidget );
653
654 newItem->setText( 0, item->text( 0 ) );
655 newItem->setText( 2, guessLegendText( item->text( 0 ) ) );
656 newItem->setData( 0, RoleAttributeExpression, item->data( 0, RoleAttributeExpression ) );
657 newItem->setFlags( ( newItem->flags() | Qt::ItemIsEditable ) & ~Qt::ItemIsDropEnabled );
658
659 //set initial color for diagram category
660 QRandomGenerator colorGenerator;
661 const int red = colorGenerator.bounded( 1, 256 );
662 const int green = colorGenerator.bounded( 1, 256 );
663 const int blue = colorGenerator.bounded( 1, 256 );
664 const QColor randomColor( red, green, blue );
665 newItem->setData( ColumnColor, Qt::EditRole, randomColor );
666 mDiagramAttributesTreeWidget->addTopLevelItem( newItem );
667}
668
670{
671 const auto constSelectedItems = mAttributesTreeWidget->selectedItems();
672 for ( QTreeWidgetItem *attributeItem : constSelectedItems )
673 {
674 addAttribute( attributeItem );
675 }
676}
677
679{
680 Q_UNUSED( column )
681 addAttribute( item );
682}
683
685{
686 const auto constSelectedItems = mDiagramAttributesTreeWidget->selectedItems();
687 for ( QTreeWidgetItem *attributeItem : constSelectedItems )
688 {
689 delete attributeItem;
690 }
691}
692
694{
695 if ( !mLayer )
696 return;
697
698 float maxValue = 0.0;
699
700 bool isExpression;
701 const QString sizeFieldNameOrExp = mSizeFieldExpressionWidget->currentField( &isExpression );
702 if ( isExpression )
703 {
704 QgsExpression exp( sizeFieldNameOrExp );
705 QgsExpressionContext context;
710
711 exp.prepare( &context );
712 if ( !exp.hasEvalError() )
713 {
714 QgsFeature feature;
715 QgsFeatureIterator features = mLayer->getFeatures();
716 while ( features.nextFeature( *&feature ) )
717 {
718 context.setFeature( feature );
719 maxValue = std::max( maxValue, exp.evaluate( &context ).toFloat() );
720 }
721 }
722 else
723 {
724 QgsDebugMsgLevel( "Prepare error:" + exp.evalErrorString(), 4 );
725 }
726 }
727 else
728 {
729 const int attributeNumber = mLayer->fields().lookupField( sizeFieldNameOrExp );
730 maxValue = mLayer->maximumValue( attributeNumber ).toFloat();
731 }
732
733 mMaxValueSpinBox->setValue( maxValue );
734}
735
737{
738 switch ( column )
739 {
740 case ColumnAttributeExpression:
741 {
742 const QString currentExpression = item->data( 0, RoleAttributeExpression ).toString();
743
744 const QString newExpression = showExpressionBuilder( currentExpression );
745 if ( !newExpression.isEmpty() )
746 {
747 item->setData( 0, Qt::DisplayRole, newExpression );
748 item->setData( 0, RoleAttributeExpression, newExpression );
749 }
750 break;
751 }
752
753 case ColumnColor:
754 break;
755
756 case ColumnLegendText:
757 break;
758 }
759}
760
762{
764 if ( panel && panel->dockMode() )
765 {
766 QgsLabelEngineConfigWidget *widget = new QgsLabelEngineConfigWidget( mMapCanvas );
768 panel->openPanel( widget );
769 }
770 else
771 {
772 QgsLabelEngineConfigDialog dialog( mMapCanvas, this );
773 dialog.exec();
774 // reactivate button's window
775 activateWindow();
776 }
777}
778
780{
781 const int index = mDiagramTypeComboBox->currentIndex();
782 const bool diagramsEnabled = ( index != 0 );
783
784 std::unique_ptr< QgsDiagram > diagram;
785
786 if ( diagramsEnabled && 0 == mDiagramAttributesTreeWidget->topLevelItemCount() )
787 {
788 QMessageBox::warning( this, tr( "Diagrams: No attributes added." ),
789 tr( "You did not add any attributes to this diagram layer. Please specify the attributes to visualize on the diagrams or disable diagrams." ) );
790 }
791
792 if ( mDiagramType == DIAGRAM_NAME_TEXT )
793 {
794 diagram = std::make_unique< QgsTextDiagram >();
795 }
796 else if ( mDiagramType == DIAGRAM_NAME_PIE )
797 {
798 diagram = std::make_unique< QgsPieDiagram >();
799 }
800 else if ( mDiagramType == DIAGRAM_NAME_STACKED )
801 {
802 diagram = std::make_unique< QgsStackedBarDiagram >();
803 }
804 else // if ( diagramType == DIAGRAM_NAME_HISTOGRAM )
805 {
806 diagram = std::make_unique< QgsHistogramDiagram >();
807 }
808
810 ds.enabled = ( mDiagramTypeComboBox->currentIndex() != 0 );
811 ds.font = mDiagramFontButton->currentFont();
812 ds.opacity = mOpacityWidget->opacity();
813
814 QList<QColor> categoryColors;
815 QList<QString> categoryAttributes;
816 QList<QString> categoryLabels;
817 categoryColors.reserve( mDiagramAttributesTreeWidget->topLevelItemCount() );
818 categoryAttributes.reserve( mDiagramAttributesTreeWidget->topLevelItemCount() );
819 categoryLabels.reserve( mDiagramAttributesTreeWidget->topLevelItemCount() );
820 for ( int i = 0; i < mDiagramAttributesTreeWidget->topLevelItemCount(); ++i )
821 {
822 QColor color = mDiagramAttributesTreeWidget->topLevelItem( i )->data( ColumnColor, Qt::EditRole ).value<QColor>();
823 categoryColors.append( color );
824 categoryAttributes.append( mDiagramAttributesTreeWidget->topLevelItem( i )->data( 0, RoleAttributeExpression ).toString() );
825 categoryLabels.append( mDiagramAttributesTreeWidget->topLevelItem( i )->text( 2 ) );
826 }
827 ds.categoryColors = categoryColors;
828 ds.categoryAttributes = categoryAttributes;
829 ds.categoryLabels = categoryLabels;
830 ds.size = QSizeF( mDiagramSizeSpinBox->value(), mDiagramSizeSpinBox->value() );
831 ds.sizeType = mDiagramUnitComboBox->unit();
832 ds.sizeScale = mDiagramUnitComboBox->getMapUnitScale();
833 ds.lineSizeUnit = mDiagramLineUnitComboBox->unit();
834 ds.lineSizeScale = mDiagramLineUnitComboBox->getMapUnitScale();
835 ds.labelPlacementMethod = static_cast<QgsDiagramSettings::LabelPlacementMethod>( mLabelPlacementComboBox->currentData().toInt() );
836 ds.scaleByArea = ( mDiagramType == DIAGRAM_NAME_STACKED ) ? false : mScaleDependencyComboBox->currentData().toBool();
837
838 if ( mIncreaseSmallDiagramsCheck->isChecked() )
839 {
840 ds.minimumSize = mIncreaseMinimumSizeSpinBox->value();
841 }
842 else
843 {
844 ds.minimumSize = 0;
845 }
846
847 ds.backgroundColor = mBackgroundColorButton->color();
848 ds.penColor = mDiagramPenColorButton->color();
849 ds.penWidth = mPenWidthSpinBox->value();
850 ds.minimumScale = mScaleRangeWidget->minimumScale();
851 ds.maximumScale = mScaleRangeWidget->maximumScale();
852 ds.scaleBasedVisibility = mScaleVisibilityGroupBox->isChecked();
853
854 // Diagram angle offset (pie)
855 ds.rotationOffset = mAngleOffsetComboBox->currentData().toInt();
856 ds.setDirection( static_cast< QgsDiagramSettings::Direction>( mAngleDirectionComboBox->currentData().toInt() ) );
857
858 // Diagram orientation (histogram)
859 ds.diagramOrientation = static_cast<QgsDiagramSettings::DiagramOrientation>( mOrientationButtonGroup->checkedButton()->property( "direction" ).toInt() );
860
861 ds.barWidth = mBarWidthSpinBox->value();
862
863 ds.setAxisLineSymbol( mAxisLineStyleButton->clonedSymbol< QgsLineSymbol >() );
864 ds.setShowAxis( mShowAxisGroupBox->isChecked() );
865
866 ds.setSpacing( mBarSpacingSpinBox->value() );
867 ds.setSpacingUnit( mBarSpacingUnitComboBox->unit() );
868 ds.setSpacingMapUnitScale( mBarSpacingUnitComboBox->getMapUnitScale() );
869
870 if ( mPaintEffect && ( !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect.get() ) || mPaintEffect->enabled() ) )
871 ds.setPaintEffect( mPaintEffect->clone() );
872 else
873 ds.setPaintEffect( nullptr );
874
875 QgsDiagramRenderer *renderer = nullptr;
876 if ( mFixedSizeRadio->isChecked() )
877 {
879 dr->setDiagramSettings( ds );
880 renderer = dr;
881 }
882 else
883 {
885 dr->setLowerValue( 0.0 );
886 dr->setLowerSize( QSizeF( 0.0, 0.0 ) );
887 dr->setUpperValue( mMaxValueSpinBox->value() );
888 dr->setUpperSize( QSizeF( mSizeSpinBox->value(), mSizeSpinBox->value() ) );
889
890 bool isExpression;
891 const QString sizeFieldNameOrExp = mSizeFieldExpressionWidget->currentField( &isExpression );
892 dr->setClassificationAttributeIsExpression( isExpression );
893 if ( isExpression )
894 {
895 dr->setClassificationAttributeExpression( sizeFieldNameOrExp );
896 }
897 else
898 {
899 dr->setClassificationField( sizeFieldNameOrExp );
900 }
901 dr->setDiagramSettings( ds );
902
903 dr->setDataDefinedSizeLegend( mSizeLegend ? new QgsDataDefinedSizeLegend( *mSizeLegend ) : nullptr );
904
905 renderer = dr;
906 }
907 renderer->setDiagram( diagram.release() );
908 renderer->setAttributeLegend( mCheckBoxAttributeLegend->isChecked() );
909 mLayer->setDiagramRenderer( renderer );
910
912 dls.setDataDefinedProperties( mDataDefinedProperties );
913 dls.setDistance( mDiagramDistanceSpinBox->value() );
914 dls.setPriority( mPrioritySlider->value() );
915 dls.setZIndex( mZIndexSpinBox->value() );
916 dls.setShowAllDiagrams( mShowAllCheckBox->isChecked() );
917
918 QWidget *curWdgt = stackedPlacement->currentWidget();
919 if ( ( curWdgt == pagePoint && radAroundPoint->isChecked() )
920 || ( curWdgt == pagePolygon && radAroundCentroid->isChecked() ) )
921 {
923 }
924 else if ( ( curWdgt == pagePoint && radOverPoint->isChecked() )
925 || ( curWdgt == pagePolygon && radOverCentroid->isChecked() ) )
926 {
928 }
929 else if ( ( curWdgt == pageLine && radAroundLine->isChecked() )
930 || ( curWdgt == pagePolygon && radPolygonPerimeter->isChecked() ) )
931 {
933 }
934 else if ( ( curWdgt == pageLine && radOverLine->isChecked() )
935 || ( curWdgt == pagePolygon && radInsidePolygon->isChecked() ) )
936 {
938 }
939 else
940 {
941 qFatal( "Invalid settings" );
942 }
943
944 QgsDiagramLayerSettings::LinePlacementFlags flags = QgsDiagramLayerSettings::LinePlacementFlags();
945 if ( chkLineAbove->isChecked() )
947 if ( chkLineBelow->isChecked() )
949 if ( chkLineOn->isChecked() )
951 if ( ! chkLineOrientationDependent->isChecked() )
953 dls.setLinePlacementFlags( flags );
954
955 mLayer->setDiagramLayerSettings( dls );
956
957 // refresh
959 mLayer->triggerRepaint();
960}
961
962QString QgsDiagramProperties::showExpressionBuilder( const QString &initialExpression )
963{
964 QgsExpressionContext context;
970
971 QgsExpressionBuilderDialog dlg( mLayer, initialExpression, this, QStringLiteral( "generic" ), context );
972 dlg.setWindowTitle( tr( "Expression Based Attribute" ) );
973
974 QgsDistanceArea myDa;
976 myDa.setEllipsoid( QgsProject::instance()->ellipsoid() );
977 dlg.setGeomCalculator( myDa );
978
979 if ( dlg.exec() == QDialog::Accepted )
980 {
981 return dlg.expressionText();
982 }
983 else
984 {
985 return QString();
986 }
987}
988
990{
991 QString expression;
992 QList<QTreeWidgetItem *> selections = mAttributesTreeWidget->selectedItems();
993 if ( !selections.empty() )
994 {
995 expression = selections[0]->text( 0 );
996 }
997
998 const QString newExpression = showExpressionBuilder( expression );
999
1000 //Only add the expression if the user has entered some text.
1001 if ( !newExpression.isEmpty() )
1002 {
1003 QTreeWidgetItem *newItem = new QTreeWidgetItem( mDiagramAttributesTreeWidget );
1004
1005 newItem->setText( 0, newExpression );
1006 newItem->setText( 2, newExpression );
1007 newItem->setData( 0, RoleAttributeExpression, newExpression );
1008 newItem->setFlags( ( newItem->flags() | Qt::ItemIsEditable ) & ~Qt::ItemIsDropEnabled );
1009
1010 //set initial color for diagram category
1011 QRandomGenerator colorGenerator;
1012 const int red = colorGenerator.bounded( 1, 256 );
1013 const int green = colorGenerator.bounded( 1, 256 );
1014 const int blue = colorGenerator.bounded( 1, 256 );
1015
1016 const QColor randomColor( red, green, blue );
1017 newItem->setData( ColumnColor, Qt::EditRole, randomColor );
1018 mDiagramAttributesTreeWidget->addTopLevelItem( newItem );
1019 }
1020 activateWindow(); // set focus back parent
1021}
1022
1024{
1025 mDiagramOptionsListWidget->blockSignals( true );
1026 mDiagramOptionsListWidget->setCurrentRow( index );
1027 mDiagramOptionsListWidget->blockSignals( false );
1028}
1029
1031{
1032 QWidget *curWdgt = stackedPlacement->currentWidget();
1033
1034 if ( ( curWdgt == pagePoint && radAroundPoint->isChecked() )
1035 || ( curWdgt == pageLine && radAroundLine->isChecked() )
1036 || ( curWdgt == pagePolygon && radAroundCentroid->isChecked() ) )
1037 {
1038 mDiagramDistanceLabel->setEnabled( true );
1039 mDiagramDistanceSpinBox->setEnabled( true );
1040 mDistanceDDBtn->setEnabled( true );
1041 }
1042 else
1043 {
1044 mDiagramDistanceLabel->setEnabled( false );
1045 mDiagramDistanceSpinBox->setEnabled( false );
1046 mDistanceDDBtn->setEnabled( false );
1047 }
1048
1049 const bool linePlacementEnabled = mLayer->geometryType() == Qgis::GeometryType::Line && ( curWdgt == pageLine && radAroundLine->isChecked() );
1050 chkLineAbove->setEnabled( linePlacementEnabled );
1051 chkLineBelow->setEnabled( linePlacementEnabled );
1052 chkLineOn->setEnabled( linePlacementEnabled );
1053 chkLineOrientationDependent->setEnabled( linePlacementEnabled );
1054}
1055
1057{
1058 mButtonSizeLegendSettings->setEnabled( mAttributeBasedScalingRadio->isChecked() );
1059}
1060
1062{
1063 // prepare size transformer
1064 bool isExpression;
1065 const QString sizeFieldNameOrExp = mSizeFieldExpressionWidget->currentField( &isExpression );
1066 QgsProperty ddSize = isExpression ? QgsProperty::fromExpression( sizeFieldNameOrExp ) : QgsProperty::fromField( sizeFieldNameOrExp );
1067 const bool scaleByArea = mScaleDependencyComboBox->currentData().toBool();
1069 0.0, mMaxValueSpinBox->value(), 0.0, mSizeSpinBox->value() ) );
1070
1071 QgsDataDefinedSizeLegendWidget *panel = new QgsDataDefinedSizeLegendWidget( mSizeLegend.get(), ddSize, nullptr, mMapCanvas );
1072
1073 QDialog dlg;
1074 dlg.setLayout( new QVBoxLayout() );
1075 dlg.setWindowTitle( panel->panelTitle() );
1076 dlg.layout()->addWidget( panel );
1077 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
1078 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1079 connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsDiagramProperties::showHelp );
1080 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1081 dlg.layout()->addWidget( buttonBox );
1082 if ( dlg.exec() )
1083 mSizeLegend.reset( panel->dataDefinedSizeLegend() );
1084}
1085
1086void QgsDiagramProperties::showHelp()
1087{
1088 QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html#legend" ) );
1089}
1090
1091void QgsDiagramProperties::createAuxiliaryField()
1092{
1093 // try to create an auxiliary layer if not yet created
1094 if ( !mLayer->auxiliaryLayer() )
1095 {
1096 QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
1097 dlg.exec();
1098 }
1099
1100 // return if still not exists
1101 if ( !mLayer->auxiliaryLayer() )
1102 return;
1103
1104 QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
1107
1108 // create property in auxiliary storage if necessary
1109 if ( !mLayer->auxiliaryLayer()->exists( def ) )
1110 mLayer->auxiliaryLayer()->addAuxiliaryField( def );
1111
1112 // update property with join field name from auxiliary storage
1113 QgsProperty property = button->toProperty();
1114 property.setField( QgsAuxiliaryLayer::nameFromProperty( def, true ) );
1115 property.setActive( true );
1116 button->updateFieldLists();
1117 button->setToProperty( property );
1118 mDataDefinedProperties.setProperty( key, button->toProperty() );
1119
1120 emit auxiliaryFieldCreated();
1121}
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition: qgis.h:227
@ Line
Line symbol.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:3749
static QIcon getThemeIcon(const QString &name, const QColor &fillColor=QColor(), const QColor &strokeColor=QColor())
Helper to get a theme icon.
static QString nameFromProperty(const QgsPropertyDefinition &def, bool joined=false)
Returns the name of the auxiliary field for a property definition.
bool addAuxiliaryField(const QgsPropertyDefinition &definition)
Adds an auxiliary field for the given property.
bool exists(const QgsPropertyDefinition &definition) const
Returns true if the property is stored in the layer already, false otherwise.
A delegate for showing a color swatch in a list.
Widget for configuration of appearance of legend for marker symbols with data-defined size.
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration as set up in the dialog (may be nullptr). Ownership is passed to the caller.
Object that keeps configuration of appearance of marker symbol's data-defined size in legend.
Stores the settings for rendering of all diagrams for a layer.
void setZIndex(double index)
Sets the diagram z-index.
Placement placement() const
Returns the diagram placement.
Property
Data definable properties.
@ StartAngle
Angle offset for pie diagram.
@ Distance
Distance to diagram from feature.
@ IsObstacle
Whether diagram features act as obstacles for other diagrams/labels.
@ PositionX
X-coordinate data defined diagram position.
@ Priority
Diagram priority (between 0 and 10)
@ AlwaysShow
Whether the diagram should always be shown, even if it overlaps other diagrams/labels.
@ Show
Whether to show the diagram.
@ ZIndex
Z-index for diagram ordering.
@ BackgroundColor
Diagram background color.
@ PositionY
Y-coordinate data defined diagram position.
bool showAllDiagrams() const
Returns whether the layer should show all diagrams, including overlapping diagrams.
QgsPropertyCollection & dataDefinedProperties()
Returns a reference to the diagram's property collection, used for data defined overrides.
LinePlacementFlags linePlacementFlags() const
Returns the diagram placement flags.
void setShowAllDiagrams(bool showAllDiagrams)
Sets whether the layer should show all diagrams, including overlapping diagrams.
void setDistance(double distance)
Sets the distance between the diagram and the feature.
static const QgsPropertiesDefinition & propertyDefinitions()
Returns the diagram property definitions.
void setPriority(int value)
Sets the diagram priority.
int priority() const
Returns the diagram priority.
void setPlacement(Placement value)
Sets the diagram placement.
void setLinePlacementFlags(LinePlacementFlags flags)
Sets the the diagram placement flags.
void setDataDefinedProperties(const QgsPropertyCollection &collection)
Sets the diagram's property collection, used for data defined overrides.
double zIndex() const
Returns the diagram z-index.
double distance() const
Returns the distance between the diagram and the feature (in mm).
void mDiagramAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)
void mDiagramTypeComboBox_currentIndexChanged(int index)
void syncToLayer()
Updates the widget to reflect the layer's current diagram settings.
QgsDiagramProperties(QgsVectorLayer *layer, QWidget *parent, QgsMapCanvas *canvas)
void addAttribute(QTreeWidgetItem *item)
Adds an attribute from the list of available attributes to the assigned attributes with a random colo...
void mAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)
void mDiagramStackedWidget_currentChanged(int index)
Evaluates and returns the diagram settings relating to a diagram for a specific feature.
virtual QString rendererName() const =0
QgsDiagram * diagram() const
void setAttributeLegend(bool enabled)
Sets whether the renderer will show legend items for diagram attributes.
virtual QList< QgsDiagramSettings > diagramSettings() const =0
Returns list with all diagram settings in the renderer.
bool attributeLegend() const
Returns true if renderer will show legend items for diagram attributes.
void setDiagram(QgsDiagram *d)
Stores the settings for rendering a single diagram.
void setDirection(Direction direction)
Sets the chart's angular direction.
DiagramOrientation
Orientation of histogram.
LabelPlacementMethod labelPlacementMethod
double opacity
Opacity, from 0 (transparent) to 1.0 (opaque)
Qgis::RenderUnit sizeType
Diagram size unit.
void setSpacingUnit(Qgis::RenderUnit unit)
Sets the unit for the content spacing.
QList< QString > categoryAttributes
QList< QString > categoryLabels
DiagramOrientation diagramOrientation
QgsMapUnitScale lineSizeScale
Line unit scale.
QList< QColor > categoryColors
double rotationOffset
Rotation offset, in degrees clockwise from horizontal.
QgsMapUnitScale sizeScale
Diagram size unit scale.
double minimumScale
The minimum map scale (i.e.
void setSpacing(double spacing)
Sets the spacing between diagram contents.
double maximumScale
The maximum map scale (i.e.
void setAxisLineSymbol(QgsLineSymbol *symbol)
Sets the line symbol to use for rendering axis in diagrams.
void setSpacingMapUnitScale(const QgsMapUnitScale &scale)
Sets the map unit scale for the content spacing.
Qgis::RenderUnit lineSizeUnit
Line unit index.
double minimumSize
Scale diagrams smaller than mMinimumSize to mMinimumSize.
Direction
Angular directions.
@ Counterclockwise
Counter-clockwise orientation.
@ Clockwise
Clockwise orientation.
void setShowAxis(bool showAxis)
Sets whether the diagram axis should be shown.
void setPaintEffect(QgsPaintEffect *effect)
Sets the paint effect to use while rendering diagrams.
virtual QString diagramName() const =0
Gets a descriptive name for this diagram type.
A general purpose distance and area calculator, capable of performing ellipsoid based calculations.
void setSourceCrs(const QgsCoordinateReferenceSystem &crs, const QgsCoordinateTransformContext &context)
Sets source spatial reference system crs.
bool setEllipsoid(const QString &ellipsoid)
Sets the ellipsoid by its acronym.
A generic dialog for building expression strings.
static QgsExpressionContextScope * projectScope(const QgsProject *project)
Creates a new scope which contains variables and functions relating to a QGIS project.
static QgsExpressionContextScope * atlasScope(const 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.
static QgsExpressionContextScope * layerScope(const QgsMapLayer *layer)
Creates a new scope which contains variables and functions relating to a QgsMapLayer.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void setFeature(const QgsFeature &feature)
Convenience function for setting a feature for the context.
Class for parsing and evaluation of expressions (formerly called "search strings").
bool prepare(const QgsExpressionContext *context)
Gets the expression ready for evaluation - find out column indexes.
QString evalErrorString() const
Returns evaluation error.
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
QVariant evaluate()
Evaluate the feature and return the result.
Wrapper for iterator of features from vector data provider or vector layer.
bool nextFeature(QgsFeature &f)
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition: qgsfeature.h:56
QString name
Definition: qgsfield.h:62
Container of fields for a vector layer.
Definition: qgsfields.h:45
int count() const
Returns number of items.
Definition: qgsfields.cpp:133
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Definition: qgsfields.cpp:163
int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
Definition: qgsfields.cpp:359
@ ModeQFont
Configure font settings for use with QFont objects.
Definition: qgsfontbutton.h:63
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition: qgshelp.cpp:38
Dialog for configuring the labeling engine.
Widget for configuring the labeling engine.
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:30
void setDiagramSettings(const QgsDiagramSettings &s)
void setDataDefinedSizeLegend(QgsDataDefinedSizeLegend *settings)
Configures appearance of legend.
QString classificationField() const
Returns the field name used for interpolating the diagram size.
void setClassificationAttributeExpression(const QString &expression)
void setClassificationField(const QString &field)
Sets the field name used for interpolating the diagram size.
void setClassificationAttributeIsExpression(bool isExpression)
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:90
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsCoordinateReferenceSystem crs
Definition: qgsmaplayer.h:79
void triggerRepaint(bool deferredUpdate=false)
Will advise the map canvas (and any other interested party) that this layer requires to be repainted.
bool hasScaleBasedVisibility() const
Returns whether scale based visibility is enabled for the layer.
double minimumScale() const
Returns the minimum map scale (i.e.
double maximumScale() const
Returns the maximum map scale (i.e.
A dialog to create a new auxiliary layer.
static QgsPaintEffect * defaultStack()
Returns a new effect stack consisting of a sensible selection of default effects.
static bool isDefaultStack(QgsPaintEffect *effect)
Tests whether a paint effect matches the default effects stack.
Base class for any widget that can be shown as a inline panel.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
QString panelTitle()
The title of the panel.
void widgetChanged()
Emitted when the widget state changes.
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
bool dockMode()
Returns the dock mode state.
static QgsProject * instance()
Returns the QgsProject singleton instance.
Definition: qgsproject.cpp:484
QgsCoordinateTransformContext transformContext
Definition: qgsproject.h:113
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:603
void setProperty(int key, const QgsProperty &property)
Adds a property to the collection and takes ownership of it.
Definition for a property.
Definition: qgsproperty.h:46
A button for controlling property overrides which may apply to a widget.
QgsProperty toProperty() const
Returns a QgsProperty object encapsulating the current state of the widget.
void updateFieldLists()
Updates list of fields.
void changed()
Emitted when property definition changes.
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).
void registerExpressionContextGenerator(QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
int propertyKey() const
Returns the property key linked to the button.
void setToProperty(const QgsProperty &property)
Sets the widget to reflect the current state of a QgsProperty.
void createAuxiliaryField()
Emitted when creating a new auxiliary field.
A store for object properties.
Definition: qgsproperty.h:230
void setTransformer(QgsPropertyTransformer *transformer)
Sets an optional transformer to use for manipulating the calculated values for the property.
static QgsProperty fromExpression(const QString &expression, bool isActive=true)
Returns a new ExpressionBasedProperty created from the specified expression.
void setField(const QString &field)
Sets the field name the property references.
static QgsProperty fromField(const QString &fieldName, bool isActive=true)
Returns a new FieldBasedProperty created from the specified field name.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:63
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
bool contains(const QString &key, QgsSettings::Section section=QgsSettings::NoSection) const
Returns true if there exists a setting called key; returns false otherwise.
void setValue(const QString &key, const QVariant &value, QgsSettings::Section section=QgsSettings::NoSection)
Sets the value of setting key to value.
Renders the diagrams for all features with the same settings.
void setDiagramSettings(const QgsDiagramSettings &s)
QgsPropertyTransformer subclass for scaling a value into a size according to various scaling methods.
Represents a vector layer which manages a vector based data sets.
QVariant maximumValue(int index) const FINAL
Returns the maximum value for an attribute column or an invalid variant in case of error.
const QgsDiagramLayerSettings * diagramLayerSettings() const
QgsFeatureIterator getFeatures(const QgsFeatureRequest &request=QgsFeatureRequest()) const FINAL
Queries the layer for features specified in request.
QgsFields fields() const FINAL
Returns the list of fields of this layer.
QgsAuxiliaryLayer * auxiliaryLayer()
Returns the current auxiliary layer.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
void setDiagramLayerSettings(const QgsDiagramLayerSettings &s)
void setDiagramRenderer(QgsDiagramRenderer *r)
Sets diagram rendering object (takes ownership)
const QgsDiagramRenderer * diagramRenderer() const
#define DIAGRAM_NAME_HISTOGRAM
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:39
#define DIAGRAM_NAME_PIE
Definition: qgspiediagram.h:18
#define DIAGRAM_NAME_STACKED
#define DIAGRAM_NAME_TEXT