QGIS API Documentation 3.40.0-Bratislava (b56115d8743)
Loading...
Searching...
No Matches
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
23
24#include "qgsproject.h"
25#include "qgsapplication.h"
29#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;
52 if ( mMapCanvas )
53 {
54 expContext = mMapCanvas->createExpressionContext();
55 }
56 else
57 {
62 }
63 expContext << QgsExpressionContextUtils::layerScope( mLayer );
64
65 return expContext;
66}
67
69 : QgsPanelWidget( parent )
70 , mLayer( layer )
71 , mMapCanvas( canvas )
72{
73 if ( !layer )
74 {
75 return;
76 }
77
78 setupUi( this );
79 connect( mDiagramTypeComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsDiagramProperties::mDiagramTypeComboBox_currentIndexChanged );
80 connect( mAddCategoryPushButton, &QPushButton::clicked, this, &QgsDiagramProperties::mAddCategoryPushButton_clicked );
81 connect( mAttributesTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QgsDiagramProperties::mAttributesTreeWidget_itemDoubleClicked );
82 connect( mFindMaximumValueButton, &QPushButton::clicked, this, &QgsDiagramProperties::mFindMaximumValueButton_clicked );
83 connect( mRemoveCategoryPushButton, &QPushButton::clicked, this, &QgsDiagramProperties::mRemoveCategoryPushButton_clicked );
84 connect( mDiagramAttributesTreeWidget, &QTreeWidget::itemDoubleClicked, this, &QgsDiagramProperties::mDiagramAttributesTreeWidget_itemDoubleClicked );
85 connect( mDiagramStackedWidget, &QStackedWidget::currentChanged, this, &QgsDiagramProperties::mDiagramStackedWidget_currentChanged );
86
87 // get rid of annoying outer focus rect on Mac
88 mDiagramOptionsListWidget->setAttribute( Qt::WA_MacShowFocusRect, false );
89
90 const int iconSize = QgsGuiUtils::scaleIconSize( 20 );
91 mOptionsTab->setIconSize( QSize( iconSize, iconSize ) );
92 mDiagramOptionsListWidget->setIconSize( QSize( iconSize, iconSize ) ) ;
93
94 mBarSpacingSpinBox->setClearValue( 0 );
95 mBarSpacingUnitComboBox->setUnits( { Qgis::RenderUnit::Millimeters,
101
102 mDiagramFontButton->setMode( QgsFontButton::ModeQFont );
103
104 mDiagramTypeComboBox->blockSignals( true );
105 QIcon icon = QgsApplication::getThemeIcon( QStringLiteral( "pie-chart.svg" ) );
106 mDiagramTypeComboBox->addItem( icon, tr( "Pie Chart" ), QgsPieDiagram::DIAGRAM_NAME_PIE );
107 icon = QgsApplication::getThemeIcon( QStringLiteral( "text.svg" ) );
108 mDiagramTypeComboBox->addItem( icon, tr( "Text Diagram" ), QgsTextDiagram::DIAGRAM_NAME_TEXT );
109 icon = QgsApplication::getThemeIcon( QStringLiteral( "histogram.svg" ) );
110 mDiagramTypeComboBox->addItem( icon, tr( "Histogram" ), QgsHistogramDiagram::DIAGRAM_NAME_HISTOGRAM );
111 icon = QgsApplication::getThemeIcon( QStringLiteral( "stacked-bar.svg" ) );
112 mDiagramTypeComboBox->addItem( icon, tr( "Stacked Bars" ), QgsStackedBarDiagram::DIAGRAM_NAME_STACKED_BAR );
113 mDiagramTypeComboBox->blockSignals( false );
114
115 mAxisLineStyleButton->setSymbolType( Qgis::SymbolType::Line );
116 mAxisLineStyleButton->setDialogTitle( tr( "Axis Line Symbol" ) );
117
118 mScaleRangeWidget->setMapCanvas( mMapCanvas );
119 mSizeFieldExpressionWidget->registerExpressionContextGenerator( this );
120
121 mBackgroundColorButton->setColorDialogTitle( tr( "Select Background Color" ) );
122 mBackgroundColorButton->setAllowOpacity( true );
123 mBackgroundColorButton->setContext( QStringLiteral( "symbology" ) );
124 mBackgroundColorButton->setShowNoColor( true );
125 mBackgroundColorButton->setNoColorString( tr( "Transparent Background" ) );
126 mDiagramPenColorButton->setColorDialogTitle( tr( "Select Pen Color" ) );
127 mDiagramPenColorButton->setAllowOpacity( true );
128 mDiagramPenColorButton->setContext( QStringLiteral( "symbology" ) );
129 mDiagramPenColorButton->setShowNoColor( true );
130 mDiagramPenColorButton->setNoColorString( tr( "Transparent Stroke" ) );
131
132 mMaxValueSpinBox->setShowClearButton( false );
133 mSizeSpinBox->setClearValue( 5 );
134
135 mDiagramAttributesTreeWidget->setItemDelegateForColumn( ColumnAttributeExpression, new EditBlockerDelegate( this ) );
136 mDiagramAttributesTreeWidget->setItemDelegateForColumn( ColumnColor, new QgsColorSwatchDelegate( this ) );
137
138 mDiagramAttributesTreeWidget->setColumnWidth( ColumnColor, Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 6.6 );
139
140 connect( mFixedSizeRadio, &QRadioButton::toggled, this, &QgsDiagramProperties::scalingTypeChanged );
141 connect( mAttributeBasedScalingRadio, &QRadioButton::toggled, this, &QgsDiagramProperties::scalingTypeChanged );
142
143 mDiagramUnitComboBox->setUnits( {Qgis::RenderUnit::Millimeters,
148 mDiagramLineUnitComboBox->setUnits( { Qgis::RenderUnit::Millimeters,
153
154 const Qgis::GeometryType layerType = layer->geometryType();
155 if ( layerType == Qgis::GeometryType::Unknown || layerType == Qgis::GeometryType::Null )
156 {
157 mDiagramTypeComboBox->setEnabled( false );
158 mOptionsTab->setEnabled( false );
159 mDiagramFrame->setEnabled( false );
160 }
161
162 // set placement methods page based on geometry type
163
164 switch ( layerType )
165 {
167 stackedPlacement->setCurrentWidget( pagePoint );
168 mLinePlacementFrame->setVisible( false );
169 break;
171 stackedPlacement->setCurrentWidget( pageLine );
172 mLinePlacementFrame->setVisible( true );
173 break;
175 stackedPlacement->setCurrentWidget( pagePolygon );
176 mLinePlacementFrame->setVisible( false );
177 break;
180 break;
181 }
182
183 //insert placement options
184 // setup point placement button group
185 mPlacePointBtnGrp = new QButtonGroup( this );
186 mPlacePointBtnGrp->addButton( radAroundPoint );
187 mPlacePointBtnGrp->addButton( radOverPoint );
188 mPlacePointBtnGrp->setExclusive( true );
189 connect( mPlacePointBtnGrp, qOverload< QAbstractButton * >( &QButtonGroup::buttonClicked ), this, &QgsDiagramProperties::updatePlacementWidgets );
190
191 // setup line placement button group
192 mPlaceLineBtnGrp = new QButtonGroup( this );
193 mPlaceLineBtnGrp->addButton( radAroundLine );
194 mPlaceLineBtnGrp->addButton( radOverLine );
195 mPlaceLineBtnGrp->setExclusive( true );
196 connect( mPlaceLineBtnGrp, qOverload< QAbstractButton * >( &QButtonGroup::buttonClicked ), this, &QgsDiagramProperties::updatePlacementWidgets );
197
198 // setup polygon placement button group
199 mPlacePolygonBtnGrp = new QButtonGroup( this );
200 mPlacePolygonBtnGrp->addButton( radAroundCentroid );
201 mPlacePolygonBtnGrp->addButton( radOverCentroid );
202 mPlacePolygonBtnGrp->addButton( radPolygonPerimeter );
203 mPlacePolygonBtnGrp->addButton( radInsidePolygon );
204 mPlacePolygonBtnGrp->setExclusive( true );
205 connect( mPlacePolygonBtnGrp, qOverload< QAbstractButton * >( &QButtonGroup::buttonClicked ), this, &QgsDiagramProperties::updatePlacementWidgets );
206
207 mLabelPlacementComboBox->addItem( tr( "Height" ), QgsDiagramSettings::Height );
208 mLabelPlacementComboBox->addItem( tr( "x-height" ), QgsDiagramSettings::XHeight );
209
210 mScaleDependencyComboBox->addItem( tr( "Area" ), true );
211 mScaleDependencyComboBox->addItem( tr( "Diameter" ), false );
212
213 mAngleOffsetComboBox->addItem( tr( "Top" ), 270 );
214 mAngleOffsetComboBox->addItem( tr( "Right" ), 0 );
215 mAngleOffsetComboBox->addItem( tr( "Bottom" ), 90 );
216 mAngleOffsetComboBox->addItem( tr( "Left" ), 180 );
217
218 mAngleDirectionComboBox->addItem( tr( "Clockwise" ), QgsDiagramSettings::Clockwise );
219 mAngleDirectionComboBox->addItem( tr( "Counter-clockwise" ), QgsDiagramSettings::Counterclockwise );
220
221 const QgsSettings settings;
222
223 // reset horiz stretch of left side of options splitter (set to 1 for previewing in Qt Designer)
224 QSizePolicy policy( mDiagramOptionsListFrame->sizePolicy() );
225 policy.setHorizontalStretch( 0 );
226 mDiagramOptionsListFrame->setSizePolicy( policy );
227 if ( !settings.contains( QStringLiteral( "/Windows/Diagrams/OptionsSplitState" ) ) )
228 {
229 // set left list widget width on initial showing
230 QList<int> splitsizes;
231 splitsizes << 115;
232 mDiagramOptionsSplitter->setSizes( splitsizes );
233 }
234
235 // restore dialog, splitters and current tab
236 mDiagramOptionsSplitter->restoreState( settings.value( QStringLiteral( "Windows/Diagrams/OptionsSplitState" ) ).toByteArray() );
237 mDiagramOptionsListWidget->setCurrentRow( settings.value( QStringLiteral( "Windows/Diagrams/Tab" ), 0 ).toInt() );
238
239 // set correct initial tab to match displayed setting page
240 whileBlocking( mOptionsTab )->setCurrentIndex( mDiagramStackedWidget->currentIndex() );
241 mOptionsTab->tabBar()->setUsesScrollButtons( true );
242
243 // field combo and expression button
244 mSizeFieldExpressionWidget->setLayer( mLayer );
245 QgsDistanceArea myDa;
247 myDa.setEllipsoid( QgsProject::instance()->ellipsoid() );
248 mSizeFieldExpressionWidget->setGeomCalculator( myDa );
249
250 //insert all attributes into the combo boxes
251 const QgsFields &layerFields = layer->fields();
252 for ( int idx = 0; idx < layerFields.count(); ++idx )
253 {
254 QTreeWidgetItem *newItem = new QTreeWidgetItem( mAttributesTreeWidget );
255 const QString name = QStringLiteral( "\"%1\"" ).arg( layerFields.at( idx ).name() );
256 newItem->setText( 0, name );
257 newItem->setData( 0, RoleAttributeExpression, name );
258 newItem->setFlags( newItem->flags() & ~Qt::ItemIsDropEnabled );
259 }
260
261 mPaintEffect.reset( QgsPaintEffectRegistry::defaultStack() );
262 mPaintEffect->setEnabled( false );
263
264 mOrientationLeftButton->setProperty( "direction", QgsDiagramSettings::Left );
265 mOrientationRightButton->setProperty( "direction", QgsDiagramSettings::Right );
266 mOrientationUpButton->setProperty( "direction", QgsDiagramSettings::Up );
267 mOrientationDownButton->setProperty( "direction", QgsDiagramSettings::Down );
268
269 // Labels to let users know some widgets are not present
270 // when editing sub diagrams in a stacked diagram.
271 mDlsLabel_1->hide();
272 mDlsLabel_2->hide();
273
274 insertDefaults();
275 mPaintEffectWidget->setPaintEffect( mPaintEffect.get() );
276
277 connect( mAddAttributeExpression, &QPushButton::clicked, this, &QgsDiagramProperties::showAddAttributeExpressionDialog );
278 registerDataDefinedButton( mBackgroundColorDDBtn, QgsDiagramLayerSettings::Property::BackgroundColor );
279 registerDataDefinedButton( mLineColorDDBtn, QgsDiagramLayerSettings::Property::StrokeColor );
280 registerDataDefinedButton( mLineWidthDDBtn, QgsDiagramLayerSettings::Property::StrokeWidth );
281 registerDataDefinedButton( mCoordXDDBtn, QgsDiagramLayerSettings::Property::PositionX );
282 registerDataDefinedButton( mCoordYDDBtn, QgsDiagramLayerSettings::Property::PositionY );
283 registerDataDefinedButton( mDistanceDDBtn, QgsDiagramLayerSettings::Property::Distance );
284 registerDataDefinedButton( mPriorityDDBtn, QgsDiagramLayerSettings::Property::Priority );
285 registerDataDefinedButton( mZOrderDDBtn, QgsDiagramLayerSettings::Property::ZIndex );
286 registerDataDefinedButton( mShowDiagramDDBtn, QgsDiagramLayerSettings::Property::Show );
287 registerDataDefinedButton( mAlwaysShowDDBtn, QgsDiagramLayerSettings::Property::AlwaysShow );
288 registerDataDefinedButton( mIsObstacleDDBtn, QgsDiagramLayerSettings::Property::IsObstacle );
289 registerDataDefinedButton( mStartAngleDDBtn, QgsDiagramLayerSettings::Property::StartAngle );
290
291 connect( mButtonSizeLegendSettings, &QPushButton::clicked, this, &QgsDiagramProperties::showSizeLegendDialog );
292
293 QList<QWidget *> widgets;
294 widgets << chkLineAbove;
295 widgets << chkLineBelow;
296 widgets << chkLineOn;
297 widgets << chkLineOrientationDependent;
298 widgets << mAngleDirectionComboBox;
299 widgets << mAngleOffsetComboBox;
300 widgets << mAttributeBasedScalingRadio;
301 widgets << mAxisLineStyleButton;
302 widgets << mBackgroundColorButton;
303 widgets << mBarSpacingSpinBox;
304 widgets << mBarSpacingUnitComboBox;
305 widgets << mBarWidthSpinBox;
306 widgets << mCheckBoxAttributeLegend;
307 widgets << mDiagramAttributesTreeWidget;
308 widgets << mDiagramDistanceSpinBox;
309 widgets << mDiagramFontButton;
310 widgets << mDiagramPenColorButton;
311 widgets << mDiagramSizeSpinBox;
312 widgets << mDiagramLineUnitComboBox;
313 widgets << mDiagramTypeComboBox;
314 widgets << mDiagramUnitComboBox;
315 widgets << mEnableDiagramCheckBox;
316 widgets << mFixedSizeRadio;
317 widgets << mIncreaseMinimumSizeSpinBox;
318 widgets << mIncreaseSmallDiagramsGroupBox;
319 widgets << mLabelPlacementComboBox;
320 widgets << mMaxValueSpinBox;
321 widgets << mPaintEffectWidget;
322 widgets << mPenWidthSpinBox;
323 widgets << mPrioritySlider;
324 widgets << mOpacityWidget;
325 widgets << mOrientationDownButton;
326 widgets << mOrientationLeftButton;
327 widgets << mOrientationRightButton;
328 widgets << mOrientationUpButton;
329 widgets << mScaleDependencyComboBox;
330 widgets << mScaleRangeWidget;
331 widgets << mScaleVisibilityGroupBox;
332 widgets << mShowAllCheckBox;
333 widgets << mShowAxisGroupBox;
334 widgets << mSizeFieldExpressionWidget;
335 widgets << mSizeSpinBox;
336 widgets << mZIndexSpinBox;
337 widgets << radAroundCentroid;
338 widgets << radAroundLine;
339 widgets << radAroundPoint;
340 widgets << radInsidePolygon;
341 widgets << radOverCentroid;
342 widgets << radOverLine;
343 widgets << radOverPoint;
344 widgets << radPolygonPerimeter;
345
346 connectValueChanged( widgets );
347}
348
350{
352 mOptionsTab->setVisible( dockMode );
353 mOptionsTab->setTabToolTip( 0, tr( "Attributes" ) );
354 mOptionsTab->setTabToolTip( 1, tr( "Rendering" ) );
355 mOptionsTab->setTabToolTip( 2, tr( "Size" ) );
356 mOptionsTab->setTabToolTip( 3, tr( "Placement" ) );
357 mOptionsTab->setTabToolTip( 4, tr( "Options" ) );
358 mOptionsTab->setTabToolTip( 5, tr( "Legend" ) );
359 mDiagramOptionsListFrame->setVisible( !dockMode );
360}
361
362void QgsDiagramProperties::setDiagramType( const QString diagramType )
363{
364 mDiagramType = diagramType;
365
366 mDiagramTypeComboBox->setVisible( false );
367 mDiagramTypeComboBox->blockSignals( true );
368 mDiagramTypeComboBox->setCurrentIndex( mDiagramTypeComboBox->findData( mDiagramType ) );
369 mDiagramTypeComboBox->blockSignals( false );
370
371 //force a refresh of widget status to match diagram type
372 mDiagramTypeComboBox_currentIndexChanged( mDiagramTypeComboBox->currentIndex() );
373}
374
375void QgsDiagramProperties::insertDefaults()
376{
377 mFixedSizeRadio->setChecked( true );
378 mDiagramUnitComboBox->setUnit( Qgis::RenderUnit::Millimeters );
379 mDiagramLineUnitComboBox->setUnit( Qgis::RenderUnit::Millimeters );
380 mLabelPlacementComboBox->setCurrentIndex( mLabelPlacementComboBox->findText( tr( "x-height" ) ) );
381 mDiagramSizeSpinBox->setEnabled( true );
382 mDiagramSizeSpinBox->setValue( 15 );
383 mLinearScaleFrame->setEnabled( false );
384 mBarWidthSpinBox->setValue( 5 );
385 mScaleVisibilityGroupBox->setChecked( mLayer->hasScaleBasedVisibility() );
386 mScaleRangeWidget->setScaleRange( mLayer->minimumScale(), mLayer->maximumScale() );
387 mShowAllCheckBox->setChecked( true );
388 mCheckBoxAttributeLegend->setChecked( true );
389
390 switch ( mLayer->geometryType() )
391 {
393 radAroundPoint->setChecked( true );
394 break;
395
397 radAroundLine->setChecked( true );
398 chkLineAbove->setChecked( true );
399 chkLineBelow->setChecked( false );
400 chkLineOn->setChecked( false );
401 chkLineOrientationDependent->setChecked( false );
402 break;
403
405 radOverCentroid->setChecked( true );
406 mDiagramDistanceLabel->setEnabled( false );
407 mDiagramDistanceSpinBox->setEnabled( false );
408 mDistanceDDBtn->setEnabled( false );
409 break;
410
413 break;
414 }
415 mBackgroundColorButton->setColor( QColor( 255, 255, 255, 255 ) );
416 mDiagramPenColorButton->setColor( QColor( 0, 0, 0, 255 ) );
417 //force a refresh of widget status to match diagram type
418 mDiagramTypeComboBox_currentIndexChanged( mDiagramTypeComboBox->currentIndex() );
419}
420
422{
423 const QgsDiagramRenderer *renderer = mLayer->diagramRenderer();
425 {
426 const QgsStackedDiagramRenderer *stackedRenderer = static_cast< const QgsStackedDiagramRenderer *>( renderer );
427 if ( stackedRenderer->rendererCount() > 0 )
428 {
429 // If layer has a stacked diagram renderer, take its first sub
430 // renderer as the basis for the new single one being created
431 renderer = stackedRenderer->renderer( 0 );
432 }
433 }
434 syncToRenderer( renderer );
435
436 const QgsDiagramLayerSettings *layerDls = mLayer->diagramLayerSettings();
437 syncToSettings( layerDls );
438}
439
441{
442 mDiagramAttributesTreeWidget->clear();
443
444 if ( !dr ) //no diagram renderer yet, insert reasonable default
445 {
446 insertDefaults();
447 }
448 else // already a diagram renderer present
449 {
450 //single category renderer or interpolated one?
452 {
453 mFixedSizeRadio->setChecked( true );
454 }
455 else
456 {
457 mAttributeBasedScalingRadio->setChecked( true );
458 }
459 mDiagramSizeSpinBox->setEnabled( mFixedSizeRadio->isChecked() );
460 mLinearScaleFrame->setEnabled( mAttributeBasedScalingRadio->isChecked() );
461 mCheckBoxAttributeLegend->setChecked( dr->attributeLegend() );
462
463 // Assume single category or linearly interpolated diagram renderer for now.
464 const QList<QgsDiagramSettings> settingList = dr->diagramSettings();
465 if ( !settingList.isEmpty() )
466 {
467 setDiagramEnabled( settingList.at( 0 ).enabled );
468 mDiagramFontButton->setCurrentFont( settingList.at( 0 ).font );
469 const QSizeF size = settingList.at( 0 ).size;
470 mBackgroundColorButton->setColor( settingList.at( 0 ).backgroundColor );
471 mOpacityWidget->setOpacity( settingList.at( 0 ).opacity );
472 mDiagramPenColorButton->setColor( settingList.at( 0 ).penColor );
473 mPenWidthSpinBox->setValue( settingList.at( 0 ).penWidth );
474 mDiagramSizeSpinBox->setValue( ( size.width() + size.height() ) / 2.0 );
475 mScaleRangeWidget->setScaleRange( ( settingList.at( 0 ).minimumScale > 0 ? settingList.at( 0 ).minimumScale : mLayer->minimumScale() ),
476 ( settingList.at( 0 ).maximumScale > 0 ? settingList.at( 0 ).maximumScale : mLayer->maximumScale() ) );
477 mScaleVisibilityGroupBox->setChecked( settingList.at( 0 ).scaleBasedVisibility );
478 mDiagramUnitComboBox->setUnit( settingList.at( 0 ).sizeType );
479 mDiagramUnitComboBox->setMapUnitScale( settingList.at( 0 ).sizeScale );
480 mDiagramLineUnitComboBox->setUnit( settingList.at( 0 ).lineSizeUnit );
481 mDiagramLineUnitComboBox->setMapUnitScale( settingList.at( 0 ).lineSizeScale );
482
483 if ( settingList.at( 0 ).labelPlacementMethod == QgsDiagramSettings::Height )
484 {
485 mLabelPlacementComboBox->setCurrentIndex( 0 );
486 }
487 else
488 {
489 mLabelPlacementComboBox->setCurrentIndex( 1 );
490 }
491
492 if ( settingList.at( 0 ).paintEffect() )
493 mPaintEffect.reset( settingList.at( 0 ).paintEffect()->clone() );
494
495 mAngleOffsetComboBox->setCurrentIndex( mAngleOffsetComboBox->findData( settingList.at( 0 ).rotationOffset ) );
496 mAngleDirectionComboBox->setCurrentIndex( mAngleDirectionComboBox->findData( settingList.at( 0 ).direction() ) );
497
498 switch ( settingList.at( 0 ).diagramOrientation )
499 {
501 mOrientationLeftButton->setChecked( true );
502 break;
503
505 mOrientationRightButton->setChecked( true );
506 break;
507
509 mOrientationUpButton->setChecked( true );
510 break;
511
513 mOrientationDownButton->setChecked( true );
514 break;
515 }
516
517 mBarWidthSpinBox->setValue( settingList.at( 0 ).barWidth );
518 mBarSpacingSpinBox->setValue( settingList.at( 0 ).spacing() );
519 mBarSpacingUnitComboBox->setUnit( settingList.at( 0 ).spacingUnit() );
520 mBarSpacingUnitComboBox->setMapUnitScale( settingList.at( 0 ).spacingMapUnitScale() );
521
522 mShowAxisGroupBox->setChecked( settingList.at( 0 ).showAxis() );
523 if ( settingList.at( 0 ).axisLineSymbol() )
524 mAxisLineStyleButton->setSymbol( settingList.at( 0 ).axisLineSymbol()->clone() );
525
526 mIncreaseSmallDiagramsGroupBox->setChecked( settingList.at( 0 ).minimumSize != 0 );
527 mIncreaseMinimumSizeSpinBox->setValue( settingList.at( 0 ).minimumSize );
528
529 if ( settingList.at( 0 ).scaleByArea )
530 {
531 mScaleDependencyComboBox->setCurrentIndex( 0 );
532 }
533 else
534 {
535 mScaleDependencyComboBox->setCurrentIndex( 1 );
536 }
537
538 const QList< QColor > categoryColors = settingList.at( 0 ).categoryColors;
539 const QList< QString > categoryAttributes = settingList.at( 0 ).categoryAttributes;
540 const QList< QString > categoryLabels = settingList.at( 0 ).categoryLabels;
541 QList< QString >::const_iterator catIt = categoryAttributes.constBegin();
542 QList< QColor >::const_iterator coIt = categoryColors.constBegin();
543 QList< QString >::const_iterator labIt = categoryLabels.constBegin();
544 for ( ; catIt != categoryAttributes.constEnd(); ++catIt, ++coIt, ++labIt )
545 {
546 QTreeWidgetItem *newItem = new QTreeWidgetItem( mDiagramAttributesTreeWidget );
547 newItem->setText( 0, *catIt );
548 newItem->setData( 0, RoleAttributeExpression, *catIt );
549 newItem->setFlags( newItem->flags() & ~Qt::ItemIsDropEnabled );
550 newItem->setData( ColumnColor, Qt::EditRole, *coIt );
551 newItem->setText( 2, *labIt );
552 newItem->setFlags( newItem->flags() | Qt::ItemIsEditable );
553 }
554 }
555
557 {
559 if ( lidr )
560 {
561 mDiagramSizeSpinBox->setEnabled( false );
562 mLinearScaleFrame->setEnabled( true );
563 mMaxValueSpinBox->setValue( lidr->upperValue() );
564 mSizeSpinBox->setValue( ( lidr->upperSize().width() + lidr->upperSize().height() ) / 2 );
566 {
567 mSizeFieldExpressionWidget->setField( lidr->classificationAttributeExpression() );
568 }
569 else
570 {
571 mSizeFieldExpressionWidget->setField( lidr->classificationField() );
572 }
573
574 mSizeLegend.reset( lidr->dataDefinedSizeLegend() ? new QgsDataDefinedSizeLegend( *lidr->dataDefinedSizeLegend() ) : nullptr );
575 }
576 }
577
578 if ( dr->diagram() )
579 {
580 mDiagramType = dr->diagram()->diagramName();
581
582 mDiagramTypeComboBox->blockSignals( true );
583 mDiagramTypeComboBox->setCurrentIndex( mDiagramTypeComboBox->findData( mDiagramType ) );
584 mDiagramTypeComboBox->blockSignals( false );
585 //force a refresh of widget status to match diagram type
586 mDiagramTypeComboBox_currentIndexChanged( mDiagramTypeComboBox->currentIndex() );
587 }
588 }
589 mPaintEffectWidget->setPaintEffect( mPaintEffect.get() );
590}
591
593{
594 if ( dls )
595 {
596 mDiagramDistanceSpinBox->setValue( dls->distance() );
597 mPrioritySlider->setValue( dls->priority() );
598 mZIndexSpinBox->setValue( dls->zIndex() );
599
600 switch ( dls->placement() )
601 {
603 radAroundPoint->setChecked( true );
604 radAroundCentroid->setChecked( true );
605 break;
606
608 radOverPoint->setChecked( true );
609 radOverCentroid->setChecked( true );
610 break;
611
613 radAroundLine->setChecked( true );
614 radPolygonPerimeter->setChecked( true );
615 break;
616
618 radOverLine->setChecked( true );
619 radInsidePolygon->setChecked( true );
620 break;
621
622 default:
623 break;
624 }
625
626 chkLineAbove->setChecked( dls->linePlacementFlags() & QgsDiagramLayerSettings::AboveLine );
627 chkLineBelow->setChecked( dls->linePlacementFlags() & QgsDiagramLayerSettings::BelowLine );
628 chkLineOn->setChecked( dls->linePlacementFlags() & QgsDiagramLayerSettings::OnLine );
630 chkLineOrientationDependent->setChecked( true );
632
633 mShowAllCheckBox->setChecked( dls->showAllDiagrams() );
634
635 mDataDefinedProperties = dls->dataDefinedProperties();
636 }
637}
638
640{
641 QgsSettings settings;
642 settings.setValue( QStringLiteral( "Windows/Diagrams/OptionsSplitState" ), mDiagramOptionsSplitter->saveState() );
643 settings.setValue( QStringLiteral( "Windows/Diagrams/Tab" ), mDiagramOptionsListWidget->currentRow() );
644}
645
646void QgsDiagramProperties::registerDataDefinedButton( QgsPropertyOverrideButton *button, QgsDiagramLayerSettings::Property key )
647{
648 button->init( static_cast< int >( key ), mDataDefinedProperties, QgsDiagramLayerSettings::propertyDefinitions(), mLayer, true );
649 connect( button, &QgsPropertyOverrideButton::changed, this, &QgsDiagramProperties::updateProperty );
650 connect( button, &QgsPropertyOverrideButton::createAuxiliaryField, this, &QgsDiagramProperties::createAuxiliaryField );
652}
653
654void QgsDiagramProperties::updateProperty()
655{
656 QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
658 mDataDefinedProperties.setProperty( key, button->toProperty() );
659 emit widgetChanged();
660}
661
663{
664 mDiagramType = mDiagramTypeComboBox->itemData( index ).toString();
665
666 if ( QgsTextDiagram::DIAGRAM_NAME_TEXT == mDiagramType )
667 {
668 mTextOptionsFrame->show();
669 mBackgroundColorLabel->show();
670 mBackgroundColorButton->show();
671 mBackgroundColorDDBtn->show();
672 mDiagramFontButton->show();
673 }
674 else
675 {
676 mTextOptionsFrame->hide();
677 mBackgroundColorLabel->hide();
678 mBackgroundColorButton->hide();
679 mBackgroundColorDDBtn->hide();
680 mDiagramFontButton->hide();
681 }
682
684 {
685 mBarWidthLabel->show();
686 mBarWidthSpinBox->show();
687 mBarSpacingLabel->show();
688 mBarSpacingSpinBox->show();
689 mBarSpacingUnitComboBox->show();
690 mBarOptionsFrame->show();
691 mShowAxisGroupBox->show();
693 mAttributeBasedScalingRadio->setChecked( true );
694 mFixedSizeRadio->setEnabled( QgsStackedBarDiagram::DIAGRAM_NAME_STACKED_BAR == mDiagramType );
695 mDiagramSizeSpinBox->setEnabled( QgsStackedBarDiagram::DIAGRAM_NAME_STACKED_BAR == mDiagramType );
696 mLinearlyScalingLabel->setText( tr( "Bar length: Scale linearly, so that the following value matches the specified bar length:" ) );
697 mSizeLabel->setText( tr( "Bar length" ) );
698 mFrameIncreaseSize->setVisible( false );
699 }
700 else
701 {
702 mBarWidthLabel->hide();
703 mBarWidthSpinBox->hide();
704 mBarSpacingLabel->hide();
705 mBarSpacingSpinBox->hide();
706 mBarSpacingUnitComboBox->hide();
707 mShowAxisGroupBox->hide();
708 mBarOptionsFrame->hide();
709 mLinearlyScalingLabel->setText( tr( "Scale linearly between 0 and the following attribute value / diagram size:" ) );
710 mSizeLabel->setText( tr( "Size" ) );
711 mAttributeBasedScalingRadio->setEnabled( true );
712 mFixedSizeRadio->setEnabled( true );
713 mDiagramSizeSpinBox->setEnabled( mFixedSizeRadio->isChecked() );
714 mFrameIncreaseSize->setVisible( true );
715 }
716
717 if ( QgsTextDiagram::DIAGRAM_NAME_TEXT == mDiagramType || QgsPieDiagram::DIAGRAM_NAME_PIE == mDiagramType )
718 {
719 mScaleDependencyComboBox->show();
720 mScaleDependencyLabel->show();
721 }
722 else
723 {
724 mScaleDependencyComboBox->hide();
725 mScaleDependencyLabel->hide();
726 }
727
728 if ( QgsPieDiagram::DIAGRAM_NAME_PIE == mDiagramType )
729 {
730 mAngleOffsetComboBox->show();
731 mAngleDirectionComboBox->show();
732 mAngleDirectionLabel->show();
733 mAngleOffsetLabel->show();
734 mStartAngleDDBtn->show();
735 }
736 else
737 {
738 mAngleOffsetComboBox->hide();
739 mAngleDirectionComboBox->hide();
740 mAngleDirectionLabel->hide();
741 mAngleOffsetLabel->hide();
742 mStartAngleDDBtn->hide();
743 }
744}
745
746QString QgsDiagramProperties::guessLegendText( const QString &expression )
747{
748 //trim unwanted characters from expression text for legend
749 QString text = expression.mid( expression.startsWith( '\"' ) ? 1 : 0 );
750 if ( text.endsWith( '\"' ) )
751 text.chop( 1 );
752 return text;
753}
754
755void QgsDiagramProperties::addAttribute( QTreeWidgetItem *item )
756{
757 QTreeWidgetItem *newItem = new QTreeWidgetItem( mDiagramAttributesTreeWidget );
758
759 newItem->setText( 0, item->text( 0 ) );
760 newItem->setText( 2, guessLegendText( item->text( 0 ) ) );
761 newItem->setData( 0, RoleAttributeExpression, item->data( 0, RoleAttributeExpression ) );
762 newItem->setFlags( ( newItem->flags() | Qt::ItemIsEditable ) & ~Qt::ItemIsDropEnabled );
763
764 //set initial color for diagram category
765 const int red = QRandomGenerator::global()->bounded( 1, 256 );
766 const int green = QRandomGenerator::global()->bounded( 1, 256 );
767 const int blue = QRandomGenerator::global()->bounded( 1, 256 );
768 const QColor randomColor( red, green, blue );
769 newItem->setData( ColumnColor, Qt::EditRole, randomColor );
770 mDiagramAttributesTreeWidget->addTopLevelItem( newItem );
771}
772
774{
775 const auto constSelectedItems = mAttributesTreeWidget->selectedItems();
776 for ( QTreeWidgetItem *attributeItem : constSelectedItems )
777 {
778 addAttribute( attributeItem );
779 }
780}
781
783{
784 Q_UNUSED( column )
785 addAttribute( item );
786}
787
789{
790 const auto constSelectedItems = mDiagramAttributesTreeWidget->selectedItems();
791 for ( QTreeWidgetItem *attributeItem : constSelectedItems )
792 {
793 delete attributeItem;
794 }
795}
796
798{
799 if ( !mLayer )
800 return;
801
802 float maxValue = 0.0;
803
804 bool isExpression;
805 const QString sizeFieldNameOrExp = mSizeFieldExpressionWidget->currentField( &isExpression );
806 if ( isExpression )
807 {
808 QgsExpression exp( sizeFieldNameOrExp );
809 QgsExpressionContext context;
814
815 exp.prepare( &context );
816 if ( !exp.hasEvalError() )
817 {
818 QgsFeature feature;
819 QgsFeatureIterator features = mLayer->getFeatures();
820 while ( features.nextFeature( *&feature ) )
821 {
822 context.setFeature( feature );
823 maxValue = std::max( maxValue, exp.evaluate( &context ).toFloat() );
824 }
825 }
826 else
827 {
828 QgsDebugMsgLevel( "Prepare error:" + exp.evalErrorString(), 4 );
829 }
830 }
831 else
832 {
833 const int attributeNumber = mLayer->fields().lookupField( sizeFieldNameOrExp );
834 maxValue = mLayer->maximumValue( attributeNumber ).toFloat();
835 }
836
837 mMaxValueSpinBox->setValue( maxValue );
838}
839
841{
842 switch ( column )
843 {
844 case ColumnAttributeExpression:
845 {
846 const QString currentExpression = item->data( 0, RoleAttributeExpression ).toString();
847
848 const QString newExpression = showExpressionBuilder( currentExpression );
849 if ( !newExpression.isEmpty() )
850 {
851 item->setData( 0, Qt::DisplayRole, newExpression );
852 item->setData( 0, RoleAttributeExpression, newExpression );
853 }
854 break;
855 }
856
857 case ColumnColor:
858 break;
859
860 case ColumnLegendText:
861 break;
862 }
863}
864
865std::unique_ptr< QgsDiagram > QgsDiagramProperties::createDiagramObject()
866{
867 std::unique_ptr< QgsDiagram > diagram;
868
869 if ( mDiagramType == QgsTextDiagram::DIAGRAM_NAME_TEXT )
870 {
871 diagram = std::make_unique< QgsTextDiagram >();
872 }
873 else if ( mDiagramType == QgsPieDiagram::DIAGRAM_NAME_PIE )
874 {
875 diagram = std::make_unique< QgsPieDiagram >();
876 }
877 else if ( mDiagramType == QgsStackedBarDiagram::DIAGRAM_NAME_STACKED_BAR )
878 {
879 diagram = std::make_unique< QgsStackedBarDiagram >();
880 }
881 else // if ( diagramType == QgsHistogramDiagram::DIAGRAM_NAME_HISTOGRAM )
882 {
883 diagram = std::make_unique< QgsHistogramDiagram >();
884 }
885 return diagram;
886}
887
888std::unique_ptr<QgsDiagramSettings> QgsDiagramProperties::createDiagramSettings()
889{
890 std::unique_ptr< QgsDiagramSettings > ds = std::make_unique< QgsDiagramSettings>();
891 ds->enabled = isDiagramEnabled();
892 ds->font = mDiagramFontButton->currentFont();
893 ds->opacity = mOpacityWidget->opacity();
894
895 QList<QColor> categoryColors;
896 QList<QString> categoryAttributes;
897 QList<QString> categoryLabels;
898 categoryColors.reserve( mDiagramAttributesTreeWidget->topLevelItemCount() );
899 categoryAttributes.reserve( mDiagramAttributesTreeWidget->topLevelItemCount() );
900 categoryLabels.reserve( mDiagramAttributesTreeWidget->topLevelItemCount() );
901 for ( int i = 0; i < mDiagramAttributesTreeWidget->topLevelItemCount(); ++i )
902 {
903 QColor color = mDiagramAttributesTreeWidget->topLevelItem( i )->data( ColumnColor, Qt::EditRole ).value<QColor>();
904 categoryColors.append( color );
905 categoryAttributes.append( mDiagramAttributesTreeWidget->topLevelItem( i )->data( 0, RoleAttributeExpression ).toString() );
906 categoryLabels.append( mDiagramAttributesTreeWidget->topLevelItem( i )->text( 2 ) );
907 }
908 ds->categoryColors = categoryColors;
909 ds->categoryAttributes = categoryAttributes;
910 ds->categoryLabels = categoryLabels;
911 ds->size = QSizeF( mDiagramSizeSpinBox->value(), mDiagramSizeSpinBox->value() );
912 ds->sizeType = mDiagramUnitComboBox->unit();
913 ds->sizeScale = mDiagramUnitComboBox->getMapUnitScale();
914 ds->lineSizeUnit = mDiagramLineUnitComboBox->unit();
915 ds->lineSizeScale = mDiagramLineUnitComboBox->getMapUnitScale();
916 ds->labelPlacementMethod = static_cast<QgsDiagramSettings::LabelPlacementMethod>( mLabelPlacementComboBox->currentData().toInt() );
917 ds->scaleByArea = ( mDiagramType == QgsStackedBarDiagram::DIAGRAM_NAME_STACKED_BAR ) ? false : mScaleDependencyComboBox->currentData().toBool();
918
919 if ( mIncreaseSmallDiagramsGroupBox->isChecked() )
920 {
921 ds->minimumSize = mIncreaseMinimumSizeSpinBox->value();
922 }
923 else
924 {
925 ds->minimumSize = 0;
926 }
927
928 ds->backgroundColor = mBackgroundColorButton->color();
929 ds->penColor = mDiagramPenColorButton->color();
930 ds->penWidth = mPenWidthSpinBox->value();
931 ds->minimumScale = mScaleRangeWidget->minimumScale();
932 ds->maximumScale = mScaleRangeWidget->maximumScale();
933 ds->scaleBasedVisibility = mScaleVisibilityGroupBox->isChecked();
934
935 // Diagram angle offset (pie)
936 ds->rotationOffset = mAngleOffsetComboBox->currentData().toInt();
937 ds->setDirection( static_cast< QgsDiagramSettings::Direction>( mAngleDirectionComboBox->currentData().toInt() ) );
938
939 // Diagram orientation (histogram)
940 ds->diagramOrientation = static_cast<QgsDiagramSettings::DiagramOrientation>( mOrientationButtonGroup->checkedButton()->property( "direction" ).toInt() );
941
942 ds->barWidth = mBarWidthSpinBox->value();
943
944 ds->setAxisLineSymbol( mAxisLineStyleButton->clonedSymbol< QgsLineSymbol >() );
945 ds->setShowAxis( mShowAxisGroupBox->isChecked() );
946
947 ds->setSpacing( mBarSpacingSpinBox->value() );
948 ds->setSpacingUnit( mBarSpacingUnitComboBox->unit() );
949 ds->setSpacingMapUnitScale( mBarSpacingUnitComboBox->getMapUnitScale() );
950
951 if ( mPaintEffect && ( !QgsPaintEffectRegistry::isDefaultStack( mPaintEffect.get() ) || mPaintEffect->enabled() ) )
952 ds->setPaintEffect( mPaintEffect->clone() );
953 else
954 ds->setPaintEffect( nullptr );
955
956 return ds;
957}
958
959std::unique_ptr<QgsDiagramRenderer> QgsDiagramProperties::createRenderer()
960{
961 std::unique_ptr< QgsDiagramSettings > ds = createDiagramSettings();
962
963 std::unique_ptr< QgsDiagramRenderer > renderer;
964 if ( mFixedSizeRadio->isChecked() )
965 {
966 std::unique_ptr< QgsSingleCategoryDiagramRenderer > dr = std::make_unique< QgsSingleCategoryDiagramRenderer >();
967 dr->setDiagramSettings( *ds );
968 renderer = std::move( dr );
969 }
970 else
971 {
972 std::unique_ptr< QgsLinearlyInterpolatedDiagramRenderer > dr = std::make_unique< QgsLinearlyInterpolatedDiagramRenderer >();
973 dr->setLowerValue( 0.0 );
974 dr->setLowerSize( QSizeF( 0.0, 0.0 ) );
975 dr->setUpperValue( mMaxValueSpinBox->value() );
976 dr->setUpperSize( QSizeF( mSizeSpinBox->value(), mSizeSpinBox->value() ) );
977
978 bool isExpression;
979 const QString sizeFieldNameOrExp = mSizeFieldExpressionWidget->currentField( &isExpression );
980 dr->setClassificationAttributeIsExpression( isExpression );
981 if ( isExpression )
982 {
983 dr->setClassificationAttributeExpression( sizeFieldNameOrExp );
984 }
985 else
986 {
987 dr->setClassificationField( sizeFieldNameOrExp );
988 }
989 dr->setDiagramSettings( *ds );
990
991 dr->setDataDefinedSizeLegend( mSizeLegend ? new QgsDataDefinedSizeLegend( *mSizeLegend ) : nullptr );
992
993 renderer = std::move( dr );
994 }
995
996 renderer->setAttributeLegend( mCheckBoxAttributeLegend->isChecked() );
997
998 std::unique_ptr< QgsDiagram > diagram = createDiagramObject();
999 renderer->setDiagram( diagram.release() );
1000
1001 return renderer;
1002}
1003
1004QgsDiagramLayerSettings QgsDiagramProperties::createDiagramLayerSettings()
1005{
1007 dls.setDataDefinedProperties( mDataDefinedProperties );
1008 dls.setDistance( mDiagramDistanceSpinBox->value() );
1009 dls.setPriority( mPrioritySlider->value() );
1010 dls.setZIndex( mZIndexSpinBox->value() );
1011 dls.setShowAllDiagrams( mShowAllCheckBox->isChecked() );
1012
1013 QWidget *curWdgt = stackedPlacement->currentWidget();
1014 if ( ( curWdgt == pagePoint && radAroundPoint->isChecked() )
1015 || ( curWdgt == pagePolygon && radAroundCentroid->isChecked() ) )
1016 {
1018 }
1019 else if ( ( curWdgt == pagePoint && radOverPoint->isChecked() )
1020 || ( curWdgt == pagePolygon && radOverCentroid->isChecked() ) )
1021 {
1023 }
1024 else if ( ( curWdgt == pageLine && radAroundLine->isChecked() )
1025 || ( curWdgt == pagePolygon && radPolygonPerimeter->isChecked() ) )
1026 {
1028 }
1029 else if ( ( curWdgt == pageLine && radOverLine->isChecked() )
1030 || ( curWdgt == pagePolygon && radInsidePolygon->isChecked() ) )
1031 {
1033 }
1034 else
1035 {
1036 qFatal( "Invalid settings" );
1037 }
1038
1040 if ( chkLineAbove->isChecked() )
1042 if ( chkLineBelow->isChecked() )
1044 if ( chkLineOn->isChecked() )
1046 if ( ! chkLineOrientationDependent->isChecked() )
1048 dls.setLinePlacementFlags( flags );
1049
1050 return dls;
1051}
1052
1054{
1055 // Avoid this messageBox when in both dock and liveUpdate mode
1056 QgsSettings settings;
1057 if ( !dockMode() || !settings.value( QStringLiteral( "UI/autoApplyStyling" ), true ).toBool() )
1058 {
1059 if ( isDiagramEnabled() && 0 == mDiagramAttributesTreeWidget->topLevelItemCount() )
1060 {
1061 QMessageBox::warning( this, tr( "Diagrams: No attributes added." ),
1062 tr( "You did not add any attributes to this diagram layer. Please specify the attributes to visualize on the diagrams or disable diagrams." ) );
1063 }
1064 }
1065
1066 std::unique_ptr< QgsDiagramRenderer > renderer = createRenderer();
1067 mLayer->setDiagramRenderer( renderer.release() );
1068
1069 QgsDiagramLayerSettings dls = createDiagramLayerSettings();
1070 mLayer->setDiagramLayerSettings( dls );
1071
1072 // refresh
1073 QgsProject::instance()->setDirty( true );
1074 mLayer->triggerRepaint();
1075}
1076
1077QString QgsDiagramProperties::showExpressionBuilder( const QString &initialExpression )
1078{
1079 QgsExpressionContext context = createExpressionContext();
1080
1081 QgsExpressionBuilderDialog dlg( mLayer, initialExpression, this, QStringLiteral( "generic" ), context );
1082 dlg.setWindowTitle( tr( "Expression Based Attribute" ) );
1083
1084 QgsDistanceArea myDa;
1085 myDa.setSourceCrs( mLayer->crs(), QgsProject::instance()->transformContext() );
1086 myDa.setEllipsoid( QgsProject::instance()->ellipsoid() );
1087 dlg.setGeomCalculator( myDa );
1088
1089 if ( dlg.exec() == QDialog::Accepted )
1090 {
1091 return dlg.expressionText();
1092 }
1093 else
1094 {
1095 return QString();
1096 }
1097}
1098
1100{
1101 QString expression;
1102 QList<QTreeWidgetItem *> selections = mAttributesTreeWidget->selectedItems();
1103 if ( !selections.empty() )
1104 {
1105 expression = selections[0]->text( 0 );
1106 }
1107
1108 const QString newExpression = showExpressionBuilder( expression );
1109
1110 //Only add the expression if the user has entered some text.
1111 if ( !newExpression.isEmpty() )
1112 {
1113 QTreeWidgetItem *newItem = new QTreeWidgetItem( mDiagramAttributesTreeWidget );
1114
1115 newItem->setText( 0, newExpression );
1116 newItem->setText( 2, newExpression );
1117 newItem->setData( 0, RoleAttributeExpression, newExpression );
1118 newItem->setFlags( ( newItem->flags() | Qt::ItemIsEditable ) & ~Qt::ItemIsDropEnabled );
1119
1120 //set initial color for diagram category
1121 QRandomGenerator colorGenerator;
1122 const int red = colorGenerator.bounded( 1, 256 );
1123 const int green = colorGenerator.bounded( 1, 256 );
1124 const int blue = colorGenerator.bounded( 1, 256 );
1125
1126 const QColor randomColor( red, green, blue );
1127 newItem->setData( ColumnColor, Qt::EditRole, randomColor );
1128 mDiagramAttributesTreeWidget->addTopLevelItem( newItem );
1129 }
1130 activateWindow(); // set focus back parent
1131}
1132
1134{
1135 mDiagramOptionsListWidget->blockSignals( true );
1136 mDiagramOptionsListWidget->setCurrentRow( index );
1137 mDiagramOptionsListWidget->blockSignals( false );
1138}
1139
1141{
1142 QWidget *curWdgt = stackedPlacement->currentWidget();
1143
1144 if ( ( curWdgt == pagePoint && radAroundPoint->isChecked() )
1145 || ( curWdgt == pageLine && radAroundLine->isChecked() )
1146 || ( curWdgt == pagePolygon && radAroundCentroid->isChecked() ) )
1147 {
1148 mDiagramDistanceLabel->setEnabled( true );
1149 mDiagramDistanceSpinBox->setEnabled( true );
1150 mDistanceDDBtn->setEnabled( true );
1151 }
1152 else
1153 {
1154 mDiagramDistanceLabel->setEnabled( false );
1155 mDiagramDistanceSpinBox->setEnabled( false );
1156 mDistanceDDBtn->setEnabled( false );
1157 }
1158
1159 const bool linePlacementEnabled = mLayer->geometryType() == Qgis::GeometryType::Line && ( curWdgt == pageLine && radAroundLine->isChecked() );
1160 chkLineAbove->setEnabled( linePlacementEnabled );
1161 chkLineBelow->setEnabled( linePlacementEnabled );
1162 chkLineOn->setEnabled( linePlacementEnabled );
1163 chkLineOrientationDependent->setEnabled( linePlacementEnabled );
1164}
1165
1167{
1168 mButtonSizeLegendSettings->setEnabled( mAttributeBasedScalingRadio->isChecked() );
1169}
1170
1172{
1173 mAllowedToEditDls = allowed;
1174
1175 label_16->setVisible( allowed );
1176 mZIndexSpinBox->setVisible( allowed );
1177 mZOrderDDBtn->setVisible( allowed );
1178 mShowAllCheckBox->setVisible( allowed );
1179 mDlsLabel_1->setVisible( !allowed );
1180
1181 mCoordinatesGrpBox->setVisible( allowed );
1182 mLinePlacementFrame->setVisible( allowed );
1183 mObstaclesGrpBox->setVisible( allowed );
1184 mPlacementFrame->setVisible( allowed );
1185 mPriorityGrpBox->setVisible( allowed );
1186 stackedPlacement->setVisible( allowed );
1187 mDlsLabel_2->setVisible( !allowed );
1188}
1189
1191{
1192 return mAllowedToEditDls;
1193}
1194
1196{
1197 // prepare size transformer
1198 bool isExpression;
1199 const QString sizeFieldNameOrExp = mSizeFieldExpressionWidget->currentField( &isExpression );
1200 QgsProperty ddSize = isExpression ? QgsProperty::fromExpression( sizeFieldNameOrExp ) : QgsProperty::fromField( sizeFieldNameOrExp );
1201 const bool scaleByArea = mScaleDependencyComboBox->currentData().toBool();
1203 0.0, mMaxValueSpinBox->value(), 0.0, mSizeSpinBox->value() ) );
1204
1205 QgsDataDefinedSizeLegendWidget *panel = new QgsDataDefinedSizeLegendWidget( mSizeLegend.get(), ddSize, nullptr, mMapCanvas );
1206
1207 QDialog dlg;
1208 dlg.setLayout( new QVBoxLayout() );
1209 dlg.setWindowTitle( panel->panelTitle() );
1210 dlg.layout()->addWidget( panel );
1211 QDialogButtonBox *buttonBox = new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
1212 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1213 connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsDiagramProperties::showHelp );
1214 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1215 dlg.layout()->addWidget( buttonBox );
1216 if ( dlg.exec() )
1217 mSizeLegend.reset( panel->dataDefinedSizeLegend() );
1218}
1219
1220void QgsDiagramProperties::showHelp()
1221{
1222 QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html#legend" ) );
1223}
1224
1225void QgsDiagramProperties::createAuxiliaryField()
1226{
1227 // try to create an auxiliary layer if not yet created
1228 if ( !mLayer->auxiliaryLayer() )
1229 {
1230 QgsNewAuxiliaryLayerDialog dlg( mLayer, this );
1231 dlg.exec();
1232 }
1233
1234 // return if still not exists
1235 if ( !mLayer->auxiliaryLayer() )
1236 return;
1237
1238 QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
1240 const QgsPropertyDefinition def = QgsDiagramLayerSettings::propertyDefinitions()[static_cast< int >( key )];
1241
1242 // create property in auxiliary storage if necessary
1243 if ( !mLayer->auxiliaryLayer()->exists( def ) )
1244 mLayer->auxiliaryLayer()->addAuxiliaryField( def );
1245
1246 // update property with join field name from auxiliary storage
1247 QgsProperty property = button->toProperty();
1248 property.setField( QgsAuxiliaryLayer::nameFromProperty( def, true ) );
1249 property.setActive( true );
1250 button->updateFieldLists();
1251 button->setToProperty( property );
1252 mDataDefinedProperties.setProperty( key, button->toProperty() );
1253
1254 emit auxiliaryFieldCreated();
1255}
1256
1257void QgsDiagramProperties::connectValueChanged( const QList<QWidget *> &widgets )
1258{
1259 const auto constWidgets = widgets;
1260 for ( QWidget *widget : constWidgets )
1261 {
1262 if ( QgsSymbolButton *w = qobject_cast<QgsSymbolButton *>( widget ) )
1263 {
1265 }
1266 else if ( QgsFieldExpressionWidget *w = qobject_cast< QgsFieldExpressionWidget *>( widget ) )
1267 {
1268 connect( w, qOverload< const QString & >( &QgsFieldExpressionWidget::fieldChanged ), this, &QgsDiagramProperties::widgetChanged );
1269 }
1270 else if ( QgsOpacityWidget *w = qobject_cast< QgsOpacityWidget *>( widget ) )
1271 {
1273 }
1274 else if ( QgsUnitSelectionWidget *w = qobject_cast<QgsUnitSelectionWidget *>( widget ) )
1275 {
1277 }
1278 else if ( QComboBox *w = qobject_cast<QComboBox *>( widget ) )
1279 {
1280 connect( w, qOverload< int >( &QComboBox::currentIndexChanged ), this, &QgsDiagramProperties::widgetChanged );
1281 }
1282 else if ( QSpinBox *w = qobject_cast<QSpinBox *>( widget ) )
1283 {
1284 connect( w, qOverload< int >( &QSpinBox::valueChanged ), this, &QgsDiagramProperties::widgetChanged );
1285 }
1286 else if ( QDoubleSpinBox *w = qobject_cast<QDoubleSpinBox *>( widget ) )
1287 {
1288 connect( w, qOverload< double >( &QDoubleSpinBox::valueChanged ), this, &QgsDiagramProperties::widgetChanged );
1289 }
1290 else if ( QgsColorButton *w = qobject_cast<QgsColorButton *>( widget ) )
1291 {
1293 }
1294 else if ( QCheckBox *w = qobject_cast<QCheckBox *>( widget ) )
1295 {
1296 connect( w, &QCheckBox::toggled, this, &QgsDiagramProperties::widgetChanged );
1297 }
1298 else if ( QRadioButton *w = qobject_cast<QRadioButton *>( widget ) )
1299 {
1300 connect( w, &QRadioButton::toggled, this, &QgsDiagramProperties::widgetChanged );
1301 }
1302 else if ( QSlider *w = qobject_cast<QSlider *>( widget ) )
1303 {
1304 connect( w, &QSlider::valueChanged, this, &QgsDiagramProperties::widgetChanged );
1305 }
1306 else if ( QGroupBox *w = qobject_cast<QGroupBox *>( widget ) )
1307 {
1308 connect( w, &QGroupBox::toggled, this, &QgsDiagramProperties::widgetChanged );
1309 }
1310 else if ( QTreeWidget *w = qobject_cast<QTreeWidget *>( widget ) )
1311 {
1312 connect( w, &QTreeWidget::itemChanged, this, &QgsDiagramProperties::widgetChanged );
1313 }
1314 else if ( QgsScaleRangeWidget *w = qobject_cast<QgsScaleRangeWidget *>( widget ) )
1315 {
1317 }
1318 else if ( QgsEffectStackCompactWidget *w = qobject_cast<QgsEffectStackCompactWidget *>( widget ) )
1319 {
1321 }
1322 else if ( QgsFontButton *w = qobject_cast<QgsFontButton *>( widget ) )
1323 {
1325 }
1326 else
1327 {
1328 QgsLogger::warning( QStringLiteral( "Could not create connection for widget %1" ).arg( widget->objectName() ) );
1329 }
1330 }
1331}
1332
1333void QgsDiagramProperties::setDiagramEnabled( bool enabled )
1334{
1335 mEnableDiagramCheckBox->setChecked( enabled );
1336}
1337
1338bool QgsDiagramProperties::isDiagramEnabled() const
1339{
1340 return mEnableDiagramCheckBox->isChecked();
1341}
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
Definition qgis.h:337
@ Polygon
Polygons.
@ Unknown
Unknown types.
@ Null
No geometry.
@ Millimeters
Millimeters.
@ Points
Points (e.g., for font sizes)
@ MapUnits
Map units.
@ MetersInMapUnits
Meters value as Map units.
@ Line
Line symbol.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition qgis.h:5627
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 cross platform button subclass for selecting colors.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
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.
QFlags< LinePlacementFlag > LinePlacementFlags
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.
Property
Data definable properties.
@ PositionX
X-coordinate data defined diagram position.
@ Distance
Distance to diagram from feature.
@ PositionY
Y-coordinate data defined diagram position.
@ Show
Whether to show the diagram.
@ Priority
Diagram priority (between 0 and 10)
@ ZIndex
Z-index for diagram ordering.
@ BackgroundColor
Diagram background color.
@ StartAngle
Angle offset for pie diagram.
@ IsObstacle
Whether diagram features act as obstacles for other diagrams/labels.
@ AlwaysShow
Whether the diagram should always be shown, even if it overlaps other diagrams/labels.
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 syncToSettings(const QgsDiagramLayerSettings *dls)
Updates the widget to reflect the diagram layer settings.
void setDockMode(bool dockMode) override
Sets the widget in dock mode.
void mDiagramAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)
bool isAllowedToEditDiagramLayerSettings() const
Returns whether this widget is allowed to edit diagram layer settings.
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 setDiagramType(const QString diagramType)
Defines the widget's diagram type and lets it know it should hide the type comboBox.
void addAttribute(QTreeWidgetItem *item)
Adds an attribute from the list of available attributes to the assigned attributes with a random colo...
void syncToRenderer(const QgsDiagramRenderer *dr)
Updates the widget to reflect the diagram renderer.
void mAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)
void setAllowedToEditDiagramLayerSettings(bool allowed)
Sets whether the widget should show diagram layer settings.
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
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.
DiagramOrientation
Orientation of histogram.
Direction
Angular directions.
@ Counterclockwise
Counter-clockwise orientation.
@ Clockwise
Clockwise orientation.
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 small widget consisting of a checkbox for enabling/disabling an effect stack and a button for openi...
void changed()
Emitted when the paint effect properties change.
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)
Fetch next feature and stores in f, returns true on success.
The feature class encapsulates a single feature including its unique ID, geometry and a list of field...
Definition qgsfeature.h:58
The QgsFieldExpressionWidget class creates a widget to choose fields and edit expressions It contains...
void fieldChanged(const QString &fieldName)
Emitted when the currently selected field changes.
QString name
Definition qgsfield.h:62
Container of fields for a vector layer.
Definition qgsfields.h:46
int count
Definition qgsfields.h:50
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
Q_INVOKABLE int lookupField(const QString &fieldName) const
Looks up field's index from the field name.
A button for customizing QgsTextFormat settings.
@ ModeQFont
Configure font settings for use with QFont objects.
void changed()
Emitted when the widget's text format settings are changed.
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
Definition qgshelp.cpp:39
static const QString DIAGRAM_NAME_HISTOGRAM
A line symbol type, for rendering LineString and MultiLineString geometries.
Alters the size of rendered diagrams using a linear scaling.
QString classificationField() const
Returns the field name used for interpolating the diagram size.
QgsDataDefinedSizeLegend * dataDefinedSizeLegend() const
Returns configuration of appearance of legend.
static const QString DIAGRAM_RENDERER_NAME_LINEARLY_INTERPOLATED
static void warning(const QString &msg)
Goes to qWarning.
Map canvas is a class for displaying all GIS data types on a canvas.
QgsExpressionContext createExpressionContext() const override
This method needs to be reimplemented in all classes which implement this interface and return an exp...
const QgsMapSettings & mapSettings() const
Gets access to properties used for map rendering.
QgsCoordinateReferenceSystem crs
Definition qgsmaplayer.h:83
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.
The QgsMapSettings class contains configuration for rendering of the map.
A dialog to create a new auxiliary layer.
A widget for setting an opacity value.
void opacityChanged(double opacity)
Emitted when the opacity is changed in the widget, where opacity ranges from 0.0 (transparent) to 1....
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.
QString panelTitle()
The title of the panel.
void widgetChanged()
Emitted when the widget state changes.
virtual void setDockMode(bool dockMode)
Set the widget in dock mode which tells the widget to emit panel widgets and not open dialogs.
bool dockMode()
Returns the dock mode state.
static const QString DIAGRAM_NAME_PIE
static QgsProject * instance()
Returns the QgsProject singleton instance.
QgsCoordinateTransformContext transformContext
Definition qgsproject.h:113
void setDirty(bool b=true)
Flag the project as dirty (modified).
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:45
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.
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.
A widget allowing entry of a range of map scales, e.g.
void rangeChanged(double min, double max)
Emitted when the scale range set in the widget is changed.
This class is a composition of two QSettings instances:
Definition qgssettings.h:64
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.
static const QString DIAGRAM_RENDERER_NAME_SINGLE_CATEGORY
QgsPropertyTransformer subclass for scaling a value into a size according to various scaling methods.
static const QString DIAGRAM_NAME_STACKED_BAR
Renders diagrams using mixed diagram render types.
static const QString DIAGRAM_RENDERER_NAME_STACKED
const QgsDiagramRenderer * renderer(const int index) const
Returns the renderer at the given index.
int rendererCount() const
Returns the number of sub renderers in the stacked diagram renderer.
A button for creating and modifying QgsSymbol settings.
void changed()
Emitted when the symbol's settings are changed.
static const QString DIAGRAM_NAME_TEXT
A widget displaying a combobox allowing the user to choose between various display units,...
void changed()
Emitted when the selected unit is changed, or the definition of the map unit scale is changed.
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.
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
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
QgsSignalBlocker< Object > whileBlocking(Object *object)
Temporarily blocks signals from a QObject while calling a single method from the object.
Definition qgis.h:5821
#define QgsDebugMsgLevel(str, level)
Definition qgslogger.h:39