46#include <QRandomGenerator>
48#include <QStyledItemDelegate>
50#include "moc_qgsdiagramproperties.cpp"
52using namespace Qt::StringLiterals;
56 QgsExpressionContext expContext;
59 expContext = mMapCanvas->createExpressionContext();
76 , mMapCanvas( canvas )
93 mDiagramOptionsListWidget->setAttribute( Qt::WA_MacShowFocusRect,
false );
96 mOptionsTab->setIconSize( QSize( iconSize, iconSize ) );
97 mDiagramOptionsListWidget->setIconSize( QSize( iconSize, iconSize ) );
99 mBarSpacingSpinBox->setClearValue( 0 );
104 mDiagramTypeComboBox->blockSignals(
true );
113 mDiagramTypeComboBox->blockSignals(
false );
116 mAxisLineStyleButton->setDialogTitle( tr(
"Axis Line Symbol" ) );
118 mScaleRangeWidget->setMapCanvas( mMapCanvas );
119 mSizeFieldExpressionWidget->registerExpressionContextGenerator(
this );
121 mBackgroundColorButton->setColorDialogTitle( tr(
"Select Background Color" ) );
122 mBackgroundColorButton->setAllowOpacity(
true );
123 mBackgroundColorButton->setContext( u
"symbology"_s );
124 mBackgroundColorButton->setShowNoColor(
true );
125 mBackgroundColorButton->setNoColorString( tr(
"Transparent Background" ) );
126 mDiagramPenColorButton->setColorDialogTitle( tr(
"Select Pen Color" ) );
127 mDiagramPenColorButton->setAllowOpacity(
true );
128 mDiagramPenColorButton->setContext( u
"symbology"_s );
129 mDiagramPenColorButton->setShowNoColor(
true );
130 mDiagramPenColorButton->setNoColorString( tr(
"Transparent Stroke" ) );
132 mMaxValueSpinBox->setShowClearButton(
false );
133 mSizeSpinBox->setClearValue( 5 );
135 mDiagramAttributesTreeWidget->setItemDelegateForColumn( ColumnAttributeExpression,
new EditBlockerDelegate(
this ) );
136 mDiagramAttributesTreeWidget->setItemDelegateForColumn( ColumnColor,
new QgsColorSwatchDelegate(
this ) );
138 mDiagramAttributesTreeWidget->setColumnWidth( ColumnColor,
Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance(
'X' ) * 6.6 );
149 mDiagramTypeComboBox->setEnabled(
false );
150 mOptionsTab->setEnabled(
false );
151 mDiagramFrame->setEnabled(
false );
159 stackedPlacement->setCurrentWidget( pagePoint );
160 mLinePlacementFrame->setVisible(
false );
163 stackedPlacement->setCurrentWidget( pageLine );
164 mLinePlacementFrame->setVisible(
true );
167 stackedPlacement->setCurrentWidget( pagePolygon );
168 mLinePlacementFrame->setVisible(
false );
177 mPlacePointBtnGrp =
new QButtonGroup(
this );
178 mPlacePointBtnGrp->addButton( radAroundPoint );
179 mPlacePointBtnGrp->addButton( radOverPoint );
180 mPlacePointBtnGrp->setExclusive(
true );
184 mPlaceLineBtnGrp =
new QButtonGroup(
this );
185 mPlaceLineBtnGrp->addButton( radAroundLine );
186 mPlaceLineBtnGrp->addButton( radOverLine );
187 mPlaceLineBtnGrp->setExclusive(
true );
191 mPlacePolygonBtnGrp =
new QButtonGroup(
this );
192 mPlacePolygonBtnGrp->addButton( radAroundCentroid );
193 mPlacePolygonBtnGrp->addButton( radOverCentroid );
194 mPlacePolygonBtnGrp->addButton( radPolygonPerimeter );
195 mPlacePolygonBtnGrp->addButton( radInsidePolygon );
196 mPlacePolygonBtnGrp->setExclusive(
true );
202 mScaleDependencyComboBox->addItem( tr(
"Area" ),
true );
203 mScaleDependencyComboBox->addItem( tr(
"Diameter" ),
false );
205 mAngleOffsetComboBox->addItem( tr(
"Top" ), 270 );
206 mAngleOffsetComboBox->addItem( tr(
"Right" ), 0 );
207 mAngleOffsetComboBox->addItem( tr(
"Bottom" ), 90 );
208 mAngleOffsetComboBox->addItem( tr(
"Left" ), 180 );
216 QSizePolicy policy( mDiagramOptionsListFrame->sizePolicy() );
217 policy.setHorizontalStretch( 0 );
218 mDiagramOptionsListFrame->setSizePolicy( policy );
219 if ( !settings.
contains( u
"/Windows/Diagrams/OptionsSplitState"_s ) )
222 QList<int> splitsizes;
224 mDiagramOptionsSplitter->setSizes( splitsizes );
228 mDiagramOptionsSplitter->restoreState( settings.
value( u
"Windows/Diagrams/OptionsSplitState"_s ).toByteArray() );
229 mDiagramOptionsListWidget->setCurrentRow( settings.
value( u
"Windows/Diagrams/Tab"_s, 0 ).toInt() );
232 whileBlocking( mOptionsTab )->setCurrentIndex( mDiagramStackedWidget->currentIndex() );
233 mOptionsTab->tabBar()->setUsesScrollButtons(
true );
236 mSizeFieldExpressionWidget->setLayer( mLayer );
240 mSizeFieldExpressionWidget->setGeomCalculator( myDa );
244 for (
int idx = 0; idx < layerFields.
count(); ++idx )
246 QTreeWidgetItem *newItem =
new QTreeWidgetItem( mAttributesTreeWidget );
247 const QString name = u
"\"%1\""_s.arg( layerFields.
at( idx ).
name() );
248 newItem->setText( 0, name );
249 newItem->setData( 0, RoleAttributeExpression, name );
250 newItem->setFlags( newItem->flags() & ~Qt::ItemIsDropEnabled );
254 mPaintEffect->setEnabled(
false );
267 mPaintEffectWidget->setPaintEffect( mPaintEffect.get() );
285 QList<QWidget *> widgets;
286 widgets << chkLineAbove;
287 widgets << chkLineBelow;
288 widgets << chkLineOn;
289 widgets << chkLineOrientationDependent;
290 widgets << mAngleDirectionComboBox;
291 widgets << mAngleOffsetComboBox;
292 widgets << mAttributeBasedScalingRadio;
293 widgets << mAxisLineStyleButton;
294 widgets << mBackgroundColorButton;
295 widgets << mBarSpacingSpinBox;
296 widgets << mBarSpacingUnitComboBox;
297 widgets << mBarWidthSpinBox;
298 widgets << mCheckBoxAttributeLegend;
299 widgets << mDiagramAttributesTreeWidget;
300 widgets << mDiagramDistanceSpinBox;
301 widgets << mDiagramFontButton;
302 widgets << mDiagramPenColorButton;
303 widgets << mDiagramSizeSpinBox;
304 widgets << mDiagramLineUnitComboBox;
305 widgets << mDiagramTypeComboBox;
306 widgets << mDiagramUnitComboBox;
307 widgets << mEnableDiagramCheckBox;
308 widgets << mFixedSizeRadio;
309 widgets << mIncreaseMinimumSizeSpinBox;
310 widgets << mIncreaseSmallDiagramsGroupBox;
311 widgets << mLabelPlacementComboBox;
312 widgets << mMaxValueSpinBox;
313 widgets << mPaintEffectWidget;
314 widgets << mPenWidthSpinBox;
315 widgets << mPrioritySlider;
316 widgets << mOpacityWidget;
317 widgets << mOrientationDownButton;
318 widgets << mOrientationLeftButton;
319 widgets << mOrientationRightButton;
320 widgets << mOrientationUpButton;
321 widgets << mScaleDependencyComboBox;
322 widgets << mScaleRangeWidget;
323 widgets << mScaleVisibilityGroupBox;
324 widgets << mShowAllCheckBox;
325 widgets << mShowAxisGroupBox;
326 widgets << mSizeFieldExpressionWidget;
327 widgets << mSizeSpinBox;
328 widgets << mZIndexSpinBox;
329 widgets << radAroundCentroid;
330 widgets << radAroundLine;
331 widgets << radAroundPoint;
332 widgets << radInsidePolygon;
333 widgets << radOverCentroid;
334 widgets << radOverLine;
335 widgets << radOverPoint;
336 widgets << radPolygonPerimeter;
338 connectValueChanged( widgets );
344 mOptionsTab->setVisible(
dockMode );
345 mOptionsTab->setTabToolTip( 0, tr(
"Attributes" ) );
346 mOptionsTab->setTabToolTip( 1, tr(
"Rendering" ) );
347 mOptionsTab->setTabToolTip( 2, tr(
"Size" ) );
348 mOptionsTab->setTabToolTip( 3, tr(
"Placement" ) );
349 mOptionsTab->setTabToolTip( 4, tr(
"Options" ) );
350 mOptionsTab->setTabToolTip( 5, tr(
"Legend" ) );
351 mDiagramOptionsListFrame->setVisible( !
dockMode );
356 mDiagramType = diagramType;
358 mDiagramTypeComboBox->setVisible(
false );
359 mDiagramTypeComboBox->blockSignals(
true );
360 mDiagramTypeComboBox->setCurrentIndex( mDiagramTypeComboBox->findData( mDiagramType ) );
361 mDiagramTypeComboBox->blockSignals(
false );
367void QgsDiagramProperties::insertDefaults()
369 mFixedSizeRadio->setChecked(
true );
372 mLabelPlacementComboBox->setCurrentIndex( mLabelPlacementComboBox->findText( tr(
"x-height" ) ) );
373 mDiagramSizeSpinBox->setEnabled(
true );
374 mDiagramSizeSpinBox->setValue( 15 );
375 mLinearScaleFrame->setEnabled(
false );
376 mBarWidthSpinBox->setValue( 5 );
379 mShowAllCheckBox->setChecked(
true );
380 mCheckBoxAttributeLegend->setChecked(
true );
385 radAroundPoint->setChecked(
true );
389 radAroundLine->setChecked(
true );
390 chkLineAbove->setChecked(
true );
391 chkLineBelow->setChecked(
false );
392 chkLineOn->setChecked(
false );
393 chkLineOrientationDependent->setChecked(
false );
397 radOverCentroid->setChecked(
true );
398 mDiagramDistanceLabel->setEnabled(
false );
399 mDiagramDistanceSpinBox->setEnabled(
false );
400 mDistanceDDBtn->setEnabled(
false );
407 mBackgroundColorButton->setColor( QColor( 255, 255, 255, 255 ) );
408 mDiagramPenColorButton->setColor( QColor( 0, 0, 0, 255 ) );
413void QgsDiagramProperties::updateDataDefinedButtons()
415 const QList<QgsPropertyOverrideButton *> propertyOverrideButtons { findChildren<QgsPropertyOverrideButton *>() };
416 for ( QgsPropertyOverrideButton *button : propertyOverrideButtons )
418 updateDataDefinedButton( button );
431 whileBlocking( button )->setToProperty( mDataDefinedProperties.property( key ) );
444 renderer = stackedRenderer->
renderer( 0 );
455 mDiagramAttributesTreeWidget->clear();
466 mFixedSizeRadio->setChecked(
true );
470 mAttributeBasedScalingRadio->setChecked(
true );
472 mDiagramSizeSpinBox->setEnabled( mFixedSizeRadio->isChecked() );
473 mLinearScaleFrame->setEnabled( mAttributeBasedScalingRadio->isChecked() );
478 if ( !settingList.isEmpty() )
480 setDiagramEnabled( settingList.at( 0 ).enabled );
481 mDiagramFontButton->setCurrentFont( settingList.at( 0 ).font );
482 const QSizeF size = settingList.at( 0 ).size;
483 mBackgroundColorButton->setColor( settingList.at( 0 ).backgroundColor );
484 mOpacityWidget->setOpacity( settingList.at( 0 ).opacity );
485 mDiagramPenColorButton->setColor( settingList.at( 0 ).penColor );
486 mPenWidthSpinBox->setValue( settingList.at( 0 ).penWidth );
487 mDiagramSizeSpinBox->setValue( ( size.width() + size.height() ) / 2.0 );
488 mScaleRangeWidget->setScaleRange( ( settingList.at( 0 ).minimumScale > 0 ? settingList.at( 0 ).minimumScale : mLayer->minimumScale() ), ( settingList.at( 0 ).maximumScale > 0 ? settingList.at( 0 ).maximumScale : mLayer->maximumScale() ) );
489 mScaleVisibilityGroupBox->setChecked( settingList.at( 0 ).scaleBasedVisibility );
490 mDiagramUnitComboBox->setUnit( settingList.at( 0 ).sizeType );
491 mDiagramUnitComboBox->setMapUnitScale( settingList.at( 0 ).sizeScale );
492 mDiagramLineUnitComboBox->setUnit( settingList.at( 0 ).lineSizeUnit );
493 mDiagramLineUnitComboBox->setMapUnitScale( settingList.at( 0 ).lineSizeScale );
497 mLabelPlacementComboBox->setCurrentIndex( 0 );
501 mLabelPlacementComboBox->setCurrentIndex( 1 );
504 if ( settingList.at( 0 ).paintEffect() )
505 mPaintEffect.reset( settingList.at( 0 ).paintEffect()->clone() );
507 mAngleOffsetComboBox->setCurrentIndex( mAngleOffsetComboBox->findData( settingList.at( 0 ).rotationOffset ) );
508 mAngleDirectionComboBox->setCurrentIndex( mAngleDirectionComboBox->findData( settingList.at( 0 ).direction() ) );
510 switch ( settingList.at( 0 ).diagramOrientation )
513 mOrientationLeftButton->setChecked(
true );
517 mOrientationRightButton->setChecked(
true );
521 mOrientationUpButton->setChecked(
true );
525 mOrientationDownButton->setChecked(
true );
529 mBarWidthSpinBox->setValue( settingList.at( 0 ).barWidth );
530 mBarSpacingSpinBox->setValue( settingList.at( 0 ).spacing() );
531 mBarSpacingUnitComboBox->setUnit( settingList.at( 0 ).spacingUnit() );
532 mBarSpacingUnitComboBox->setMapUnitScale( settingList.at( 0 ).spacingMapUnitScale() );
534 mShowAxisGroupBox->setChecked( settingList.at( 0 ).showAxis() );
535 if ( settingList.at( 0 ).axisLineSymbol() )
536 mAxisLineStyleButton->setSymbol( settingList.at( 0 ).axisLineSymbol()->clone() );
538 mIncreaseSmallDiagramsGroupBox->setChecked( settingList.at( 0 ).minimumSize != 0 );
539 mIncreaseMinimumSizeSpinBox->setValue( settingList.at( 0 ).minimumSize );
541 if ( settingList.at( 0 ).scaleByArea )
543 mScaleDependencyComboBox->setCurrentIndex( 0 );
547 mScaleDependencyComboBox->setCurrentIndex( 1 );
550 const QList<QColor> categoryColors = settingList.at( 0 ).categoryColors;
551 const QList<QString> categoryAttributes = settingList.at( 0 ).categoryAttributes;
552 const QList<QString> categoryLabels = settingList.at( 0 ).categoryLabels;
553 QList<QString>::const_iterator catIt = categoryAttributes.constBegin();
554 QList<QColor>::const_iterator coIt = categoryColors.constBegin();
555 QList<QString>::const_iterator labIt = categoryLabels.constBegin();
556 for ( ; catIt != categoryAttributes.constEnd(); ++catIt, ++coIt, ++labIt )
558 QTreeWidgetItem *newItem =
new QTreeWidgetItem( mDiagramAttributesTreeWidget );
559 newItem->setText( 0, *catIt );
560 newItem->setData( 0, RoleAttributeExpression, *catIt );
561 newItem->setFlags( newItem->flags() & ~Qt::ItemIsDropEnabled );
562 newItem->setData( ColumnColor, Qt::EditRole, *coIt );
563 newItem->setText( 2, *labIt );
564 newItem->setFlags( newItem->flags() | Qt::ItemIsEditable );
573 mDiagramSizeSpinBox->setEnabled(
false );
574 mLinearScaleFrame->setEnabled(
true );
575 mMaxValueSpinBox->setValue( lidr->
upperValue() );
576 mSizeSpinBox->setValue( ( lidr->
upperSize().width() + lidr->
upperSize().height() ) / 2 );
594 mDiagramTypeComboBox->blockSignals(
true );
595 mDiagramTypeComboBox->setCurrentIndex( mDiagramTypeComboBox->findData( mDiagramType ) );
596 mDiagramTypeComboBox->blockSignals(
false );
601 mPaintEffectWidget->setPaintEffect( mPaintEffect.get() );
608 mDiagramDistanceSpinBox->setValue( dls->
distance() );
609 mPrioritySlider->setValue( dls->
priority() );
610 mZIndexSpinBox->setValue( dls->
zIndex() );
615 radAroundPoint->setChecked(
true );
616 radAroundCentroid->setChecked(
true );
620 radOverPoint->setChecked(
true );
621 radOverCentroid->setChecked(
true );
625 radAroundLine->setChecked(
true );
626 radPolygonPerimeter->setChecked(
true );
630 radOverLine->setChecked(
true );
631 radInsidePolygon->setChecked(
true );
642 chkLineOrientationDependent->setChecked(
true );
648 updateDataDefinedButtons();
655 settings.
setValue( u
"Windows/Diagrams/OptionsSplitState"_s, mDiagramOptionsSplitter->saveState() );
656 settings.
setValue( u
"Windows/Diagrams/Tab"_s, mDiagramOptionsListWidget->currentRow() );
667void QgsDiagramProperties::updateProperty()
669 QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
671 mDataDefinedProperties.setProperty( key, button->
toProperty() );
677 mDiagramType = mDiagramTypeComboBox->itemData( index ).toString();
681 mTextOptionsFrame->show();
682 mBackgroundColorLabel->show();
683 mBackgroundColorButton->show();
684 mBackgroundColorDDBtn->show();
685 mDiagramFontButton->show();
689 mTextOptionsFrame->hide();
690 mBackgroundColorLabel->hide();
691 mBackgroundColorButton->hide();
692 mBackgroundColorDDBtn->hide();
693 mDiagramFontButton->hide();
698 mBarWidthLabel->show();
699 mBarWidthSpinBox->show();
700 mBarSpacingLabel->show();
701 mBarSpacingSpinBox->show();
702 mBarSpacingUnitComboBox->show();
703 mBarOptionsFrame->show();
704 mShowAxisGroupBox->show();
706 mAttributeBasedScalingRadio->setChecked(
true );
709 mLinearlyScalingLabel->setText( tr(
"Bar length: Scale linearly, so that the following value matches the specified bar length:" ) );
710 mSizeLabel->setText( tr(
"Bar length" ) );
711 mFrameIncreaseSize->setVisible(
false );
715 mBarWidthLabel->hide();
716 mBarWidthSpinBox->hide();
717 mBarSpacingLabel->hide();
718 mBarSpacingSpinBox->hide();
719 mBarSpacingUnitComboBox->hide();
720 mShowAxisGroupBox->hide();
721 mBarOptionsFrame->hide();
722 mLinearlyScalingLabel->setText( tr(
"Scale linearly between 0 and the following attribute value / diagram size:" ) );
723 mSizeLabel->setText( tr(
"Size" ) );
724 mAttributeBasedScalingRadio->setEnabled(
true );
725 mFixedSizeRadio->setEnabled(
true );
726 mDiagramSizeSpinBox->setEnabled( mFixedSizeRadio->isChecked() );
727 mFrameIncreaseSize->setVisible(
true );
732 mScaleDependencyComboBox->show();
733 mScaleDependencyLabel->show();
737 mScaleDependencyComboBox->hide();
738 mScaleDependencyLabel->hide();
743 mAngleOffsetComboBox->show();
744 mAngleDirectionComboBox->show();
745 mAngleDirectionLabel->show();
746 mAngleOffsetLabel->show();
747 mStartAngleDDBtn->show();
751 mAngleOffsetComboBox->hide();
752 mAngleDirectionComboBox->hide();
753 mAngleDirectionLabel->hide();
754 mAngleOffsetLabel->hide();
755 mStartAngleDDBtn->hide();
759QString QgsDiagramProperties::guessLegendText(
const QString &expression )
762 QString text = expression.mid( expression.startsWith(
'\"' ) ? 1 : 0 );
763 if ( text.endsWith(
'\"' ) )
770 QTreeWidgetItem *newItem =
new QTreeWidgetItem( mDiagramAttributesTreeWidget );
772 newItem->setText( 0, item->text( 0 ) );
773 newItem->setText( 2, guessLegendText( item->text( 0 ) ) );
774 newItem->setData( 0, RoleAttributeExpression, item->data( 0, RoleAttributeExpression ) );
775 newItem->setFlags( ( newItem->flags() | Qt::ItemIsEditable ) & ~Qt::ItemIsDropEnabled );
778 const int red = QRandomGenerator::global()->bounded( 1, 256 );
779 const int green = QRandomGenerator::global()->bounded( 1, 256 );
780 const int blue = QRandomGenerator::global()->bounded( 1, 256 );
781 const QColor randomColor( red, green, blue );
782 newItem->setData( ColumnColor, Qt::EditRole, randomColor );
783 mDiagramAttributesTreeWidget->addTopLevelItem( newItem );
788 const auto constSelectedItems = mAttributesTreeWidget->selectedItems();
789 for ( QTreeWidgetItem *attributeItem : constSelectedItems )
803 const auto constSelectedItems = mDiagramAttributesTreeWidget->selectedItems();
804 for ( QTreeWidgetItem *attributeItem : constSelectedItems )
806 delete attributeItem;
815 float maxValue = 0.0;
818 const QString sizeFieldNameOrExp = mSizeFieldExpressionWidget->currentField( &isExpression );
836 maxValue = std::max( maxValue, exp.
evaluate( &context ).toFloat() );
846 const int attributeNumber = mLayer->fields().lookupField( sizeFieldNameOrExp );
847 maxValue = mLayer->maximumValue( attributeNumber ).toFloat();
850 mMaxValueSpinBox->setValue( maxValue );
857 case ColumnAttributeExpression:
859 const QString currentExpression = item->data( 0, RoleAttributeExpression ).toString();
861 const QString newExpression = showExpressionBuilder( currentExpression );
862 if ( !newExpression.isEmpty() )
864 item->setData( 0, Qt::DisplayRole, newExpression );
865 item->setData( 0, RoleAttributeExpression, newExpression );
873 case ColumnLegendText:
878std::unique_ptr<QgsDiagram> QgsDiagramProperties::createDiagramObject()
880 std::unique_ptr<QgsDiagram> diagram;
884 diagram = std::make_unique<QgsTextDiagram>();
888 diagram = std::make_unique<QgsPieDiagram>();
892 diagram = std::make_unique<QgsStackedBarDiagram>();
896 diagram = std::make_unique<QgsHistogramDiagram>();
901std::unique_ptr<QgsDiagramSettings> QgsDiagramProperties::createDiagramSettings()
903 auto ds = std::make_unique<QgsDiagramSettings>();
904 ds->enabled = isDiagramEnabled();
905 ds->font = mDiagramFontButton->currentFont();
906 ds->opacity = mOpacityWidget->opacity();
908 QList<QColor> categoryColors;
909 QList<QString> categoryAttributes;
910 QList<QString> categoryLabels;
911 categoryColors.reserve( mDiagramAttributesTreeWidget->topLevelItemCount() );
912 categoryAttributes.reserve( mDiagramAttributesTreeWidget->topLevelItemCount() );
913 categoryLabels.reserve( mDiagramAttributesTreeWidget->topLevelItemCount() );
914 for (
int i = 0; i < mDiagramAttributesTreeWidget->topLevelItemCount(); ++i )
916 QColor color = mDiagramAttributesTreeWidget->topLevelItem( i )->data( ColumnColor, Qt::EditRole ).value<QColor>();
917 categoryColors.append( color );
918 categoryAttributes.append( mDiagramAttributesTreeWidget->topLevelItem( i )->data( 0, RoleAttributeExpression ).toString() );
919 categoryLabels.append( mDiagramAttributesTreeWidget->topLevelItem( i )->text( 2 ) );
921 ds->categoryColors = categoryColors;
922 ds->categoryAttributes = categoryAttributes;
923 ds->categoryLabels = categoryLabels;
924 ds->size = QSizeF( mDiagramSizeSpinBox->value(), mDiagramSizeSpinBox->value() );
925 ds->sizeType = mDiagramUnitComboBox->unit();
926 ds->sizeScale = mDiagramUnitComboBox->getMapUnitScale();
927 ds->lineSizeUnit = mDiagramLineUnitComboBox->unit();
928 ds->lineSizeScale = mDiagramLineUnitComboBox->getMapUnitScale();
932 if ( mIncreaseSmallDiagramsGroupBox->isChecked() )
934 ds->minimumSize = mIncreaseMinimumSizeSpinBox->value();
941 ds->backgroundColor = mBackgroundColorButton->color();
942 ds->penColor = mDiagramPenColorButton->color();
943 ds->penWidth = mPenWidthSpinBox->value();
944 ds->minimumScale = mScaleRangeWidget->minimumScale();
945 ds->maximumScale = mScaleRangeWidget->maximumScale();
946 ds->scaleBasedVisibility = mScaleVisibilityGroupBox->isChecked();
949 ds->rotationOffset = mAngleOffsetComboBox->currentData().toInt();
955 ds->barWidth = mBarWidthSpinBox->value();
959 ds->size.setWidth( ds->barWidth );
961 ds->size.setHeight( ds->barWidth );
964 ds->setAxisLineSymbol( mAxisLineStyleButton->clonedSymbol<QgsLineSymbol>() );
965 ds->setShowAxis( mShowAxisGroupBox->isChecked() );
967 ds->setSpacing( mBarSpacingSpinBox->value() );
968 ds->setSpacingUnit( mBarSpacingUnitComboBox->unit() );
969 ds->setSpacingMapUnitScale( mBarSpacingUnitComboBox->getMapUnitScale() );
972 ds->setPaintEffect( mPaintEffect->clone() );
974 ds->setPaintEffect(
nullptr );
979std::unique_ptr<QgsDiagramRenderer> QgsDiagramProperties::createRenderer()
981 std::unique_ptr<QgsDiagramSettings> ds = createDiagramSettings();
983 std::unique_ptr<QgsDiagramRenderer> renderer;
984 if ( mFixedSizeRadio->isChecked() )
986 auto dr = std::make_unique<QgsSingleCategoryDiagramRenderer>();
987 dr->setDiagramSettings( *ds );
988 renderer = std::move( dr );
992 auto dr = std::make_unique<QgsLinearlyInterpolatedDiagramRenderer>();
993 dr->setLowerValue( 0.0 );
994 dr->setLowerSize( QSizeF( 0.0, 0.0 ) );
995 dr->setUpperValue( mMaxValueSpinBox->value() );
996 dr->setUpperSize( QSizeF( mSizeSpinBox->value(), mSizeSpinBox->value() ) );
999 const QString sizeFieldNameOrExp = mSizeFieldExpressionWidget->currentField( &isExpression );
1000 dr->setClassificationAttributeIsExpression( isExpression );
1003 dr->setClassificationAttributeExpression( sizeFieldNameOrExp );
1007 dr->setClassificationField( sizeFieldNameOrExp );
1009 dr->setDiagramSettings( *ds );
1011 dr->setDataDefinedSizeLegend( mSizeLegend ?
new QgsDataDefinedSizeLegend( *mSizeLegend ) :
nullptr );
1013 renderer = std::move( dr );
1016 renderer->setAttributeLegend( mCheckBoxAttributeLegend->isChecked() );
1018 std::unique_ptr<QgsDiagram> diagram = createDiagramObject();
1019 renderer->setDiagram( diagram.release() );
1026 QgsDiagramLayerSettings dls;
1028 dls.
setDistance( mDiagramDistanceSpinBox->value() );
1030 dls.
setZIndex( mZIndexSpinBox->value() );
1033 QWidget *curWdgt = stackedPlacement->currentWidget();
1034 if ( ( curWdgt == pagePoint && radAroundPoint->isChecked() )
1035 || ( curWdgt == pagePolygon && radAroundCentroid->isChecked() ) )
1039 else if ( ( curWdgt == pagePoint && radOverPoint->isChecked() )
1040 || ( curWdgt == pagePolygon && radOverCentroid->isChecked() ) )
1044 else if ( ( curWdgt == pageLine && radAroundLine->isChecked() )
1045 || ( curWdgt == pagePolygon && radPolygonPerimeter->isChecked() ) )
1049 else if ( ( curWdgt == pageLine && radOverLine->isChecked() )
1050 || ( curWdgt == pagePolygon && radInsidePolygon->isChecked() ) )
1056 qFatal(
"Invalid settings" );
1060 if ( chkLineAbove->isChecked() )
1062 if ( chkLineBelow->isChecked() )
1064 if ( chkLineOn->isChecked() )
1066 if ( !chkLineOrientationDependent->isChecked() )
1077 if ( !
dockMode() || !settings.
value( u
"UI/autoApplyStyling"_s,
true ).toBool() )
1079 if ( isDiagramEnabled() && 0 == mDiagramAttributesTreeWidget->topLevelItemCount() )
1081 QMessageBox::warning(
this, tr(
"Diagrams: No attributes added." ), tr(
"You did not add any attributes to this diagram layer. Please specify the attributes to visualize on the diagrams or disable diagrams." ) );
1085 std::unique_ptr<QgsDiagramRenderer> renderer = createRenderer();
1086 mLayer->setDiagramRenderer( renderer.release() );
1089 mLayer->setDiagramLayerSettings( dls );
1093 mLayer->triggerRepaint();
1096QString QgsDiagramProperties::showExpressionBuilder(
const QString &initialExpression )
1101 dlg.setWindowTitle( tr(
"Expression Based Attribute" ) );
1106 dlg.setGeomCalculator( myDa );
1108 if ( dlg.exec() == QDialog::Accepted )
1110 return dlg.expressionText();
1121 QList<QTreeWidgetItem *> selections = mAttributesTreeWidget->selectedItems();
1122 if ( !selections.empty() )
1124 expression = selections[0]->text( 0 );
1127 const QString newExpression = showExpressionBuilder( expression );
1130 if ( !newExpression.isEmpty() )
1132 QTreeWidgetItem *newItem =
new QTreeWidgetItem( mDiagramAttributesTreeWidget );
1134 newItem->setText( 0, newExpression );
1135 newItem->setText( 2, newExpression );
1136 newItem->setData( 0, RoleAttributeExpression, newExpression );
1137 newItem->setFlags( ( newItem->flags() | Qt::ItemIsEditable ) & ~Qt::ItemIsDropEnabled );
1140 QRandomGenerator colorGenerator;
1141 const int red = colorGenerator.bounded( 1, 256 );
1142 const int green = colorGenerator.bounded( 1, 256 );
1143 const int blue = colorGenerator.bounded( 1, 256 );
1145 const QColor randomColor( red, green, blue );
1146 newItem->setData( ColumnColor, Qt::EditRole, randomColor );
1147 mDiagramAttributesTreeWidget->addTopLevelItem( newItem );
1154 mDiagramOptionsListWidget->blockSignals(
true );
1155 mDiagramOptionsListWidget->setCurrentRow( index );
1156 mDiagramOptionsListWidget->blockSignals(
false );
1161 QWidget *curWdgt = stackedPlacement->currentWidget();
1163 if ( ( curWdgt == pagePoint && radAroundPoint->isChecked() )
1164 || ( curWdgt == pageLine && radAroundLine->isChecked() )
1165 || ( curWdgt == pagePolygon && radAroundCentroid->isChecked() ) )
1167 mDiagramDistanceLabel->setEnabled(
true );
1168 mDiagramDistanceSpinBox->setEnabled(
true );
1169 mDistanceDDBtn->setEnabled(
true );
1173 mDiagramDistanceLabel->setEnabled(
false );
1174 mDiagramDistanceSpinBox->setEnabled(
false );
1175 mDistanceDDBtn->setEnabled(
false );
1178 const bool linePlacementEnabled = mLayer->geometryType() ==
Qgis::GeometryType::Line && ( curWdgt == pageLine && radAroundLine->isChecked() );
1179 chkLineAbove->setEnabled( linePlacementEnabled );
1180 chkLineBelow->setEnabled( linePlacementEnabled );
1181 chkLineOn->setEnabled( linePlacementEnabled );
1182 chkLineOrientationDependent->setEnabled( linePlacementEnabled );
1187 mButtonSizeLegendSettings->setEnabled( mAttributeBasedScalingRadio->isChecked() );
1192 mAllowedToEditDls = allowed;
1194 label_16->setVisible( allowed );
1195 mZIndexSpinBox->setVisible( allowed );
1196 mZOrderDDBtn->setVisible( allowed );
1197 mShowAllCheckBox->setVisible( allowed );
1198 mDlsLabel_1->setVisible( !allowed );
1200 mCoordinatesGrpBox->setVisible( allowed );
1201 mLinePlacementFrame->setVisible( allowed );
1202 mObstaclesGrpBox->setVisible( allowed );
1203 mPlacementFrame->setVisible( allowed );
1204 mPriorityGrpBox->setVisible( allowed );
1205 stackedPlacement->setVisible( allowed );
1206 mDlsLabel_2->setVisible( !allowed );
1211 return mAllowedToEditDls;
1218 const QString sizeFieldNameOrExp = mSizeFieldExpressionWidget->currentField( &isExpression );
1220 const bool scaleByArea = mScaleDependencyComboBox->currentData().toBool();
1226 dlg.setLayout(
new QVBoxLayout() );
1228 dlg.layout()->addWidget( panel );
1229 QDialogButtonBox *buttonBox =
new QDialogButtonBox( QDialogButtonBox::Cancel | QDialogButtonBox::Help | QDialogButtonBox::Ok );
1230 connect( buttonBox, &QDialogButtonBox::accepted, &dlg, &QDialog::accept );
1231 connect( buttonBox, &QDialogButtonBox::helpRequested,
this, &QgsDiagramProperties::showHelp );
1232 connect( buttonBox, &QDialogButtonBox::rejected, &dlg, &QDialog::reject );
1233 dlg.layout()->addWidget( buttonBox );
1238void QgsDiagramProperties::showHelp()
1243void QgsDiagramProperties::createAuxiliaryField()
1246 if ( !mLayer->auxiliaryLayer() )
1248 QgsNewAuxiliaryLayerDialog dlg( mLayer,
this );
1253 if ( !mLayer->auxiliaryLayer() )
1256 QgsPropertyOverrideButton *button = qobject_cast<QgsPropertyOverrideButton *>( sender() );
1261 if ( !mLayer->auxiliaryLayer()->exists( def ) )
1262 mLayer->auxiliaryLayer()->addAuxiliaryField( def );
1267 property.setActive(
true );
1270 mDataDefinedProperties.setProperty( key, button->
toProperty() );
1275void QgsDiagramProperties::connectValueChanged(
const QList<QWidget *> &widgets )
1277 const auto constWidgets = widgets;
1278 for ( QWidget *widget : constWidgets )
1280 if ( QgsSymbolButton *w = qobject_cast<QgsSymbolButton *>( widget ) )
1284 else if ( QgsFieldExpressionWidget *w = qobject_cast<QgsFieldExpressionWidget *>( widget ) )
1288 else if ( QgsOpacityWidget *w = qobject_cast<QgsOpacityWidget *>( widget ) )
1292 else if ( QgsUnitSelectionWidget *w = qobject_cast<QgsUnitSelectionWidget *>( widget ) )
1296 else if ( QComboBox *w = qobject_cast<QComboBox *>( widget ) )
1300 else if ( QSpinBox *w = qobject_cast<QSpinBox *>( widget ) )
1304 else if ( QDoubleSpinBox *w = qobject_cast<QDoubleSpinBox *>( widget ) )
1308 else if ( QgsColorButton *w = qobject_cast<QgsColorButton *>( widget ) )
1312 else if ( QCheckBox *w = qobject_cast<QCheckBox *>( widget ) )
1316 else if ( QRadioButton *w = qobject_cast<QRadioButton *>( widget ) )
1320 else if ( QSlider *w = qobject_cast<QSlider *>( widget ) )
1324 else if ( QGroupBox *w = qobject_cast<QGroupBox *>( widget ) )
1328 else if ( QTreeWidget *w = qobject_cast<QTreeWidget *>( widget ) )
1332 else if ( QgsScaleRangeWidget *w = qobject_cast<QgsScaleRangeWidget *>( widget ) )
1336 else if ( QgsEffectStackCompactWidget *w = qobject_cast<QgsEffectStackCompactWidget *>( widget ) )
1340 else if ( QgsFontButton *w = qobject_cast<QgsFontButton *>( widget ) )
1346 QgsLogger::warning( u
"Could not create connection for widget %1"_s.arg( widget->objectName() ) );
1351void QgsDiagramProperties::setDiagramEnabled(
bool enabled )
1353 mEnableDiagramCheckBox->setChecked( enabled );
1356bool QgsDiagramProperties::isDiagramEnabled()
const
1358 return mEnableDiagramCheckBox->isChecked();
Custom item delegate which prevents editing.
GeometryType
The geometry types are used to group Qgis::WkbType in a coarse way.
@ Millimeters
Millimeters.
@ Points
Points (e.g., for font sizes).
@ MetersInMapUnits
Meters value as Map units.
static const double UI_SCALE_FACTOR
UI scaling factor.
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.
A delegate for showing a color swatch in a list.
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.
@ StrokeColor
Stroke color.
@ BackgroundColor
Diagram background color.
@ StartAngle
Angle offset for pie diagram.
@ IsObstacle
Whether diagram features act as obstacles for other diagrams/labels.
@ StrokeWidth
Stroke width.
@ 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 scalingTypeChanged()
void setDockMode(bool dockMode) override
Sets the widget in dock mode.
void mDiagramAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)
void mAddCategoryPushButton_clicked()
bool isAllowedToEditDiagramLayerSettings() const
Returns whether this widget is allowed to edit diagram layer settings.
void mDiagramTypeComboBox_currentIndexChanged(int index)
~QgsDiagramProperties() override
void syncToLayer()
Updates the widget to reflect the layer's current diagram settings.
void mRemoveCategoryPushButton_clicked()
QgsDiagramProperties(QgsVectorLayer *layer, QWidget *parent, QgsMapCanvas *canvas)
void showSizeLegendDialog()
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 mFindMaximumValueButton_clicked()
void showAddAttributeExpressionDialog()
void syncToRenderer(const QgsDiagramRenderer *dr)
Updates the widget to reflect the diagram renderer.
void mAttributesTreeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)
void auxiliaryFieldCreated()
void updatePlacementWidgets()
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 generic dialog for building expression strings.
virtual QgsExpressionContext createExpressionContext() const =0
This method needs to be reimplemented in all classes which implement this interface and return an exp...
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.
Handles 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...
Container of fields for a vector layer.
QgsField at(int i) const
Returns the field at particular index (must be in range 0..N-1).
static void openHelp(const QString &key)
Opens help topic for the given help key using default system web browser.
static const QString DIAGRAM_NAME_HISTOGRAM
Alters the size of rendered diagrams using linear scaling.
double upperValue() const
QString classificationAttributeExpression() const
QString classificationField() const
Returns the field name used for interpolating the diagram size.
bool classificationAttributeIsExpression() const
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.
QgsCoordinateReferenceSystem crs
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.
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.
static const QString DIAGRAM_NAME_PIE
static QgsProject * instance()
Returns the QgsProject singleton instance.
void setDirty(bool b=true)
Flag the project as dirty (modified).
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.
Stores settings for use within QGIS.
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
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.
static const QString DIAGRAM_NAME_TEXT
Represents a vector layer which manages a vector based dataset.
Q_INVOKABLE Qgis::GeometryType geometryType() const
Returns point, line or polygon.
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.
#define QgsDebugMsgLevel(str, level)