1 /***************************************************************************
2                           qgslabelpropertydialog.cpp
3                           --------------------------
4     begin                : 2010-11-12
5     copyright            : (C) 2010 by Marco Hugentobler
6     email                : marco dot hugentobler at sourcepole dot ch
7 ***************************************************************************/
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 
18 #include "qgslabelpropertydialog.h"
19 #include "qgsfontutils.h"
20 #include "qgslogger.h"
21 #include "qgsfeatureiterator.h"
22 #include "qgsproject.h"
23 #include "qgsvectorlayer.h"
24 #include "qgisapp.h"
25 #include "qgsmapcanvas.h"
26 #include "qgsvectorlayerlabeling.h"
27 #include "qgsproperty.h"
28 #include "qgssettings.h"
29 #include "qgsexpressioncontextutils.h"
30 #include "qgsgui.h"
31 #include "qgshelp.h"
32 
33 #include <QColorDialog>
34 #include <QFontDatabase>
35 #include <QDialogButtonBox>
36 
37 
QgsLabelPropertyDialog(const QString & layerId,const QString & providerId,QgsFeatureId featureId,const QFont & labelFont,const QString & labelText,bool isPinned,const QgsPalLayerSettings & layerSettings,QWidget * parent,Qt::WindowFlags f)38 QgsLabelPropertyDialog::QgsLabelPropertyDialog( const QString &layerId, const QString &providerId, QgsFeatureId featureId, const QFont &labelFont, const QString &labelText, bool isPinned, const QgsPalLayerSettings &layerSettings, QWidget *parent, Qt::WindowFlags f )
39   : QDialog( parent, f )
40   , mLabelFont( labelFont )
41   , mIsPinned( isPinned )
42 {
43   setupUi( this );
44   QgsGui::instance()->enableAutoGeometryRestore( this );
45 
46   // set defaults to layer defaults
47   mLabelAllPartsCheckBox->setChecked( layerSettings.labelPerPart );
48 
49   connect( buttonBox, &QDialogButtonBox::clicked, this, &QgsLabelPropertyDialog::buttonBox_clicked );
50   connect( buttonBox, &QDialogButtonBox::helpRequested, this, &QgsLabelPropertyDialog::showHelp );
51   connect( mShowLabelChkbx, &QCheckBox::toggled, this, &QgsLabelPropertyDialog::mShowLabelChkbx_toggled );
52   connect( mAlwaysShowChkbx, &QCheckBox::toggled, this, &QgsLabelPropertyDialog::mAlwaysShowChkbx_toggled );
53   connect( mShowCalloutChkbx, &QCheckBox::toggled, this, &QgsLabelPropertyDialog::showCalloutToggled );
54   connect( mBufferDrawChkbx, &QCheckBox::toggled, this, &QgsLabelPropertyDialog::bufferDrawToggled );
55   connect( mLabelDistanceSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLabelPropertyDialog::mLabelDistanceSpinBox_valueChanged );
56   connect( mXCoordSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLabelPropertyDialog::mXCoordSpinBox_valueChanged );
57   connect( mYCoordSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLabelPropertyDialog::mYCoordSpinBox_valueChanged );
58   connect( mFontFamilyCmbBx, &QFontComboBox::currentFontChanged, this, &QgsLabelPropertyDialog::mFontFamilyCmbBx_currentFontChanged );
59   connect( mFontStyleCmbBx, &QComboBox::currentTextChanged, this, &QgsLabelPropertyDialog::mFontStyleCmbBx_currentIndexChanged );
60   connect( mFontUnderlineBtn, &QToolButton::toggled, this, &QgsLabelPropertyDialog::mFontUnderlineBtn_toggled );
61   connect( mFontStrikethroughBtn, &QToolButton::toggled, this, &QgsLabelPropertyDialog::mFontStrikethroughBtn_toggled );
62   connect( mFontBoldBtn, &QToolButton::toggled, this, &QgsLabelPropertyDialog::mFontBoldBtn_toggled );
63   connect( mFontItalicBtn, &QToolButton::toggled, this, &QgsLabelPropertyDialog::mFontItalicBtn_toggled );
64   connect( mFontSizeSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLabelPropertyDialog::mFontSizeSpinBox_valueChanged );
65   connect( mBufferSizeSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLabelPropertyDialog::mBufferSizeSpinBox_valueChanged );
66   connect( mRotationSpinBox, static_cast < void ( QDoubleSpinBox::* )( double ) > ( &QDoubleSpinBox::valueChanged ), this, &QgsLabelPropertyDialog::mRotationSpinBox_valueChanged );
67   connect( mFontColorButton, &QgsColorButton::colorChanged, this, &QgsLabelPropertyDialog::mFontColorButton_colorChanged );
68   connect( mBufferColorButton, &QgsColorButton::colorChanged, this, &QgsLabelPropertyDialog::mBufferColorButton_colorChanged );
69   connect( mMultiLineAlignComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLabelPropertyDialog::mMultiLineAlignComboBox_currentIndexChanged );
70   connect( mHaliComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLabelPropertyDialog::mHaliComboBox_currentIndexChanged );
71   connect( mValiComboBox, static_cast<void ( QComboBox::* )( int )>( &QComboBox::currentIndexChanged ), this, &QgsLabelPropertyDialog::mValiComboBox_currentIndexChanged );
72   connect( mLabelTextLineEdit, &QLineEdit::textChanged, this, &QgsLabelPropertyDialog::mLabelTextLineEdit_textChanged );
73   connect( mLabelAllPartsCheckBox, &QCheckBox::toggled, this, &QgsLabelPropertyDialog::labelAllPartsToggled );
74 
75   mRotationSpinBox->setClearValue( 0 );
76   fillMultiLineAlignComboBox();
77   fillHaliComboBox();
78   fillValiComboBox();
79 
80   init( layerId, providerId, featureId, labelText );
81 
82   connect( mMinScaleWidget, &QgsScaleWidget::scaleChanged, this, &QgsLabelPropertyDialog::minScaleChanged );
83   connect( mMaxScaleWidget, &QgsScaleWidget::scaleChanged, this, &QgsLabelPropertyDialog::maxScaleChanged );
84 }
85 
setMapCanvas(QgsMapCanvas * canvas)86 void QgsLabelPropertyDialog::setMapCanvas( QgsMapCanvas *canvas )
87 {
88   mMinScaleWidget->setMapCanvas( canvas );
89   mMinScaleWidget->setShowCurrentScaleButton( true );
90   mMaxScaleWidget->setMapCanvas( canvas );
91   mMaxScaleWidget->setShowCurrentScaleButton( true );
92 }
93 
buttonBox_clicked(QAbstractButton * button)94 void QgsLabelPropertyDialog::buttonBox_clicked( QAbstractButton *button )
95 {
96   if ( buttonBox->buttonRole( button ) == QDialogButtonBox::ApplyRole )
97   {
98     emit applied();
99   }
100 }
101 
init(const QString & layerId,const QString & providerId,QgsFeatureId featureId,const QString & labelText)102 void QgsLabelPropertyDialog::init( const QString &layerId, const QString &providerId, QgsFeatureId featureId, const QString &labelText )
103 {
104   //get feature attributes
105   QgsVectorLayer *vlayer = QgsProject::instance()->mapLayer<QgsVectorLayer *>( layerId );
106   if ( !vlayer )
107   {
108     return;
109   }
110   if ( !vlayer->labeling() )
111   {
112     return;
113   }
114 
115   if ( !vlayer->getFeatures( QgsFeatureRequest().setFilterFid( featureId ).setFlags( QgsFeatureRequest::NoGeometry ) ).nextFeature( mCurLabelFeat ) )
116   {
117     return;
118   }
119   QgsAttributes attributeValues = mCurLabelFeat.attributes();
120 
121   //get layerproperties. Problem: only for pallabeling...
122 
123   blockElementSignals( true );
124 
125   QgsPalLayerSettings layerSettings = vlayer->labeling()->settings( providerId );
126 
127   //get label field and fill line edit
128   if ( layerSettings.isExpression && !labelText.isNull() )
129   {
130     mLabelTextLineEdit->setText( labelText );
131     mLabelTextLineEdit->setEnabled( false );
132     mLabelTextLabel->setText( tr( "Expression result" ) );
133   }
134   else
135   {
136     QString labelFieldName = layerSettings.fieldName;
137     if ( !labelFieldName.isEmpty() )
138     {
139       mCurLabelField = vlayer->fields().lookupField( labelFieldName );
140       if ( mCurLabelField >= 0 )
141       {
142         mLabelTextLineEdit->setText( attributeValues.at( mCurLabelField ).toString() );
143 
144         if ( vlayer->isEditable() )
145           mLabelTextLineEdit->setEnabled( true );
146         else
147           mLabelTextLineEdit->setEnabled( false );
148 
149         const QgsFields &layerFields = vlayer->fields();
150         switch ( layerFields.at( mCurLabelField ).type() )
151         {
152           case QVariant::Double:
153             mLabelTextLineEdit->setValidator( new QDoubleValidator( this ) );
154             break;
155           case QVariant::Int:
156           case QVariant::UInt:
157           case QVariant::LongLong:
158             mLabelTextLineEdit->setValidator( new QIntValidator( this ) );
159             break;
160           default:
161             break;
162         }
163       }
164       else
165       {
166         mLabelTextLineEdit->setEnabled( false );
167       }
168     }
169   }
170 
171   //get attributes of the feature and fill data defined values
172 
173   // font is set directly from QgsLabelPosition
174   updateFont( mLabelFont, false );
175 
176   QgsTextFormat format = layerSettings.format();
177   QgsTextBufferSettings buffer = format.buffer();
178 
179   //set all the gui elements to the default layer-level values
180   mLabelDistanceSpinBox->clear();
181   mLabelDistanceSpinBox->setSpecialValueText( tr( "Layer default (%1)" ).arg( QString::number( layerSettings.dist, 'f', mLabelDistanceSpinBox->decimals() ) ) );
182   mBufferSizeSpinBox->clear();
183   mBufferSizeSpinBox->setSpecialValueText( tr( "Layer default (%1)" ).arg( QString::number( buffer.size(), 'f', mBufferSizeSpinBox->decimals() ) ) );
184   mRotationSpinBox->clear();
185   mXCoordSpinBox->clear();
186   mYCoordSpinBox->clear();
187 
188   mShowLabelChkbx->setChecked( true );
189   mBufferDrawChkbx->setChecked( buffer.enabled() );
190   mFontColorButton->setColor( format.color() );
191   mBufferColorButton->setColor( buffer.color() );
192   mMinScaleWidget->setScale( layerSettings.minimumScale );
193   mMaxScaleWidget->setScale( layerSettings.maximumScale );
194 
195   QString defaultMultilineAlign;
196   switch ( layerSettings.multilineAlign )
197   {
198     case QgsPalLayerSettings::MultiLeft:
199       defaultMultilineAlign = QStringLiteral( "left" );
200       break;
201     case QgsPalLayerSettings::MultiCenter:
202       defaultMultilineAlign = QStringLiteral( "center" );
203       break;
204     case QgsPalLayerSettings::MultiRight:
205       defaultMultilineAlign = QStringLiteral( "right" );
206       break;
207     case QgsPalLayerSettings::MultiJustify:
208       defaultMultilineAlign = QStringLiteral( "justify" );
209       break;
210     case QgsPalLayerSettings::MultiFollowPlacement:
211       defaultMultilineAlign = QStringLiteral( "follow label placement" );
212       break;
213   }
214   mMultiLineAlignComboBox->setItemText( mMultiLineAlignComboBox->findData( "" ), tr( "Layer default (%1)" ).arg( defaultMultilineAlign ) );
215   mMultiLineAlignComboBox->setCurrentIndex( mMultiLineAlignComboBox->findData( "" ) );
216 
217   mHaliComboBox->setCurrentIndex( mHaliComboBox->findData( "left", Qt::UserRole, Qt::MatchFixedString ) );
218   mValiComboBox->setCurrentIndex( mValiComboBox->findData( "bottom", Qt::UserRole, Qt::MatchFixedString ) );
219   mFontColorButton->setColorDialogTitle( tr( "Font Color" ) );
220   mBufferColorButton->setColorDialogTitle( tr( "Buffer Color" ) );
221 
222   disableGuiElements();
223 
224   mDataDefinedProperties = layerSettings.dataDefinedProperties();
225 
226   //set widget values from data defined results
227   setDataDefinedValues( vlayer );
228   //enable widgets connected to data defined fields
229   enableDataDefinedWidgets( vlayer );
230 
231   blockElementSignals( false );
232 }
233 
disableGuiElements()234 void QgsLabelPropertyDialog::disableGuiElements()
235 {
236   mShowLabelChkbx->setEnabled( false );
237   mAlwaysShowChkbx->setEnabled( false );
238   mShowCalloutChkbx->setEnabled( false );
239   mMinScaleWidget->setEnabled( false );
240   mMaxScaleWidget->setEnabled( false );
241   mFontFamilyCmbBx->setEnabled( false );
242   mFontStyleCmbBx->setEnabled( false );
243   mFontUnderlineBtn->setEnabled( false );
244   mFontStrikethroughBtn->setEnabled( false );
245   mFontBoldBtn->setEnabled( false );
246   mFontItalicBtn->setEnabled( false );
247   mFontSizeSpinBox->setEnabled( false );
248   mBufferSizeSpinBox->setEnabled( false );
249   mFontColorButton->setEnabled( false );
250   mBufferColorButton->setEnabled( false );
251   mBufferDrawChkbx->setEnabled( false );
252   mLabelDistanceSpinBox->setEnabled( false );
253   mXCoordSpinBox->setEnabled( false );
254   mYCoordSpinBox->setEnabled( false );
255   mMultiLineAlignComboBox->setEnabled( false );
256   mHaliComboBox->setEnabled( false );
257   mValiComboBox->setEnabled( false );
258   mRotationSpinBox->setEnabled( false );
259   mLabelAllPartsCheckBox->setEnabled( false );
260 }
261 
blockElementSignals(bool block)262 void QgsLabelPropertyDialog::blockElementSignals( bool block )
263 {
264   mShowLabelChkbx->blockSignals( block );
265   mAlwaysShowChkbx->blockSignals( block );
266   mShowCalloutChkbx->blockSignals( block );
267   mMinScaleWidget->blockSignals( block );
268   mMaxScaleWidget->blockSignals( block );
269   mFontFamilyCmbBx->blockSignals( block );
270   mFontStyleCmbBx->blockSignals( block );
271   mFontUnderlineBtn->blockSignals( block );
272   mFontStrikethroughBtn->blockSignals( block );
273   mFontBoldBtn->blockSignals( block );
274   mFontItalicBtn->blockSignals( block );
275   mFontSizeSpinBox->blockSignals( block );
276   mBufferSizeSpinBox->blockSignals( block );
277   mFontColorButton->blockSignals( block );
278   mBufferColorButton->blockSignals( block );
279   mBufferDrawChkbx->blockSignals( block );
280   mLabelDistanceSpinBox->blockSignals( block );
281   mXCoordSpinBox->blockSignals( block );
282   mYCoordSpinBox->blockSignals( block );
283   mMultiLineAlignComboBox->blockSignals( block );
284   mHaliComboBox->blockSignals( block );
285   mValiComboBox->blockSignals( block );
286   mRotationSpinBox->blockSignals( block );
287   mLabelAllPartsCheckBox->blockSignals( block );
288 }
289 
setDataDefinedValues(QgsVectorLayer * vlayer)290 void QgsLabelPropertyDialog::setDataDefinedValues( QgsVectorLayer *vlayer )
291 {
292   //loop through data defined properties and set all the GUI widget values. We can do this
293   //even if the data defined property is set to an expression, as it's useful to show
294   //users what the evaluated property is...
295 
296   QgsExpressionContext context;
297   context << QgsExpressionContextUtils::globalScope()
298           << QgsExpressionContextUtils::projectScope( QgsProject::instance() )
299           << QgsExpressionContextUtils::atlasScope( nullptr )
300           << QgsExpressionContextUtils::mapSettingsScope( QgisApp::instance()->mapCanvas()->mapSettings() )
301           << QgsExpressionContextUtils::layerScope( vlayer );
302   context.setFeature( mCurLabelFeat );
303 
304   const auto constPropertyKeys = mDataDefinedProperties.propertyKeys();
305   for ( int key : constPropertyKeys )
306   {
307     if ( !mDataDefinedProperties.isActive( key ) )
308       continue;
309 
310     //TODO - pass expression context
311     QVariant result = mDataDefinedProperties.value( key, context );
312     if ( !result.isValid() || result.isNull() )
313     {
314       //could not evaluate data defined value
315       continue;
316     }
317 
318     bool ok = false;
319     switch ( key )
320     {
321       case QgsPalLayerSettings::Show:
322       {
323         int showLabel = result.toInt( &ok );
324         mShowLabelChkbx->setChecked( !ok || showLabel != 0 );
325         break;
326       }
327       case QgsPalLayerSettings::AlwaysShow:
328         mAlwaysShowChkbx->setChecked( result.toBool() );
329         break;
330 
331       case QgsPalLayerSettings::CalloutDraw:
332         mShowCalloutChkbx->setChecked( result.toBool() );
333         break;
334 
335       case QgsPalLayerSettings::LabelAllParts:
336         mLabelAllPartsCheckBox->setChecked( result.toBool() );
337         break;
338 
339       case QgsPalLayerSettings::MinimumScale:
340       {
341         double minScale = result.toDouble( &ok );
342         if ( ok )
343         {
344           mMinScaleWidget->setScale( minScale );
345         }
346         break;
347       }
348       case QgsPalLayerSettings::MaximumScale:
349       {
350         double maxScale = result.toDouble( &ok );
351         if ( ok )
352         {
353           mMaxScaleWidget->setScale( maxScale );
354         }
355         break;
356       }
357       case QgsPalLayerSettings::BufferSize:
358       {
359         double bufferSize = result.toDouble( &ok );
360         if ( ok )
361         {
362           mBufferSizeSpinBox->setValue( bufferSize );
363         }
364         break;
365       }
366       case QgsPalLayerSettings::PositionX:
367       {
368         double posX = result.toDouble( &ok );
369         if ( ok )
370         {
371           mXCoordSpinBox->setValue( posX );
372         }
373         break;
374       }
375       case QgsPalLayerSettings::PositionY:
376       {
377         double posY = result.toDouble( &ok );
378         if ( ok )
379         {
380           mYCoordSpinBox->setValue( posY );
381         }
382         break;
383       }
384       case QgsPalLayerSettings::LabelDistance:
385       {
386         double labelDist = result.toDouble( &ok );
387         if ( ok )
388         {
389           mLabelDistanceSpinBox->setValue( labelDist );
390         }
391         break;
392       }
393       case QgsPalLayerSettings::MultiLineAlignment:
394         mMultiLineAlignComboBox->setCurrentIndex( mMultiLineAlignComboBox->findData( result.toString(), Qt::UserRole, Qt::MatchFixedString ) );
395         break;
396       case QgsPalLayerSettings::Hali:
397         mHaliComboBox->setCurrentIndex( mHaliComboBox->findData( result.toString(), Qt::UserRole, Qt::MatchFixedString ) );
398         break;
399       case QgsPalLayerSettings::Vali:
400         mValiComboBox->setCurrentIndex( mValiComboBox->findData( result.toString(), Qt::UserRole, Qt::MatchFixedString ) );
401         break;
402       case QgsPalLayerSettings::BufferColor:
403         mBufferColorButton->setColor( QColor( result.toString() ) );
404         break;
405 
406       case QgsPalLayerSettings::BufferDraw:
407         mBufferDrawChkbx->setChecked( result.toBool() );
408         break;
409 
410       case QgsPalLayerSettings::Color:
411         mFontColorButton->setColor( QColor( result.toString() ) );
412         break;
413       case QgsPalLayerSettings::LabelRotation:
414       {
415         double rot = result.toDouble( &ok );
416         if ( ok )
417         {
418           mRotationSpinBox->setValue( rot );
419         }
420         break;
421       }
422 
423       case QgsPalLayerSettings::Size:
424       {
425         double size = result.toDouble( &ok );
426         if ( ok )
427         {
428           mFontSizeSpinBox->setValue( size );
429         }
430         else
431         {
432           mFontSizeSpinBox->setValue( 0 );
433         }
434         break;
435       }
436       default:
437         break;
438     }
439   }
440   enableWidgetsForPinnedLabels();
441 }
442 
enableDataDefinedWidgets(QgsVectorLayer * vlayer)443 void QgsLabelPropertyDialog::enableDataDefinedWidgets( QgsVectorLayer *vlayer )
444 {
445   //loop through data defined properties, this time setting whether or not the widgets are enabled
446   //this can only be done for properties which are assigned to fields
447   const auto constPropertyKeys = mDataDefinedProperties.propertyKeys();
448   for ( int key : constPropertyKeys )
449   {
450     QgsProperty prop = mDataDefinedProperties.property( key );
451     if ( !prop || !prop.isActive() || prop.propertyType() != QgsProperty::FieldBasedProperty )
452     {
453       continue; // can only modify attributes with an active data definition of a mapped field
454     }
455 
456     QString ddField = prop.field();
457     if ( ddField.isEmpty() )
458     {
459       continue;
460     }
461 
462     int ddIndx = vlayer->fields().lookupField( ddField );
463     if ( ddIndx == -1 )
464     {
465       continue;
466     }
467 
468     QgsDebugMsg( QStringLiteral( "ddField: %1" ).arg( ddField ) );
469 
470     switch ( key )
471     {
472       case QgsPalLayerSettings::Show:
473         mShowLabelChkbx->setEnabled( true );
474         break;
475       case QgsPalLayerSettings::AlwaysShow:
476         mAlwaysShowChkbx->setEnabled( true );
477         break;
478       case QgsPalLayerSettings::MinimumScale:
479         mMinScaleWidget->setEnabled( true );
480         break;
481       case QgsPalLayerSettings::MaximumScale:
482         mMaxScaleWidget->setEnabled( true );
483         break;
484       case QgsPalLayerSettings::BufferSize:
485         mBufferSizeSpinBox->setEnabled( true );
486         break;
487       case QgsPalLayerSettings::PositionX:
488         mXCoordSpinBox->setEnabled( true );
489         break;
490       case QgsPalLayerSettings::PositionY:
491         mYCoordSpinBox->setEnabled( true );
492         break;
493       case QgsPalLayerSettings::LabelDistance:
494         mLabelDistanceSpinBox->setEnabled( true );
495         break;
496       case QgsPalLayerSettings::MultiLineAlignment:
497         mMultiLineAlignComboBox->setEnabled( true );
498         break;
499       case QgsPalLayerSettings::Hali:
500         mCanSetHAlignment = true;
501         mHaliComboBox->setEnabled( mIsPinned );
502         break;
503       case QgsPalLayerSettings::Vali:
504         mCanSetVAlignment = true;
505         mValiComboBox->setEnabled( mIsPinned );
506         break;
507       case QgsPalLayerSettings::BufferColor:
508         mBufferColorButton->setEnabled( true );
509         break;
510       case QgsPalLayerSettings::BufferDraw:
511         mBufferDrawChkbx->setEnabled( true );
512         break;
513       case QgsPalLayerSettings::Color:
514         mFontColorButton->setEnabled( true );
515         break;
516       case QgsPalLayerSettings::LabelRotation:
517         mRotationSpinBox->setEnabled( true );
518         break;
519       //font related properties
520       case QgsPalLayerSettings::Family:
521         mFontFamilyCmbBx->setEnabled( true );
522         break;
523       case QgsPalLayerSettings::FontStyle:
524         mFontStyleCmbBx->setEnabled( true );
525         break;
526       case QgsPalLayerSettings::Underline:
527         mFontUnderlineBtn->setEnabled( true );
528         break;
529       case QgsPalLayerSettings::Strikeout:
530         mFontStrikethroughBtn->setEnabled( true );
531         break;
532       case QgsPalLayerSettings::Bold:
533         mFontBoldBtn->setEnabled( true );
534         break;
535       case QgsPalLayerSettings::Italic:
536         mFontItalicBtn->setEnabled( true );
537         break;
538       case QgsPalLayerSettings::Size:
539         mFontSizeSpinBox->setEnabled( true );
540         break;
541       case QgsPalLayerSettings::CalloutDraw:
542         mShowCalloutChkbx->setEnabled( true );
543         break;
544       case QgsPalLayerSettings::LabelAllParts:
545         mLabelAllPartsCheckBox->setEnabled( true );
546         break;
547       default:
548         break;
549     }
550   }
551 }
552 
updateFont(const QFont & font,bool block)553 void QgsLabelPropertyDialog::updateFont( const QFont &font, bool block )
554 {
555   // update background reference font
556   if ( font != mLabelFont )
557   {
558     mLabelFont = font;
559   }
560 
561   if ( block )
562     blockElementSignals( true );
563 
564   mFontFamilyCmbBx->setCurrentFont( mLabelFont );
565   populateFontStyleComboBox();
566   mFontUnderlineBtn->setChecked( mLabelFont.underline() );
567   mFontStrikethroughBtn->setChecked( mLabelFont.strikeOut() );
568   mFontBoldBtn->setChecked( mLabelFont.bold() );
569   mFontItalicBtn->setChecked( mLabelFont.italic() );
570   if ( block )
571     blockElementSignals( false );
572 }
573 
populateFontStyleComboBox()574 void QgsLabelPropertyDialog::populateFontStyleComboBox()
575 {
576   mFontStyleCmbBx->clear();
577   const auto constFamily = mFontDB.styles( mLabelFont.family() );
578   for ( const QString &style : constFamily )
579   {
580     mFontStyleCmbBx->addItem( style );
581   }
582 
583   int curIndx = 0;
584   int stylIndx = mFontStyleCmbBx->findText( mFontDB.styleString( mLabelFont ) );
585   if ( stylIndx > -1 )
586   {
587     curIndx = stylIndx;
588   }
589 
590   mFontStyleCmbBx->setCurrentIndex( curIndx );
591 }
592 
fillMultiLineAlignComboBox()593 void QgsLabelPropertyDialog::fillMultiLineAlignComboBox()
594 {
595   mMultiLineAlignComboBox->addItem( tr( "Layer Default" ), "" );
596   mMultiLineAlignComboBox->addItem( tr( "Left" ), "Left" );
597   mMultiLineAlignComboBox->addItem( tr( "Center" ), "Center" );
598   mMultiLineAlignComboBox->addItem( tr( "Right" ), "Right" );
599   mMultiLineAlignComboBox->addItem( tr( "Justify" ), "Justify" );
600 }
601 
fillHaliComboBox()602 void QgsLabelPropertyDialog::fillHaliComboBox()
603 {
604   mHaliComboBox->addItem( tr( "Left" ), "Left" );
605   mHaliComboBox->addItem( tr( "Center" ), "Center" );
606   mHaliComboBox->addItem( tr( "Right" ), "Right" );
607 }
608 
fillValiComboBox()609 void QgsLabelPropertyDialog::fillValiComboBox()
610 {
611   mValiComboBox->addItem( tr( "Bottom" ), "Bottom" );
612   mValiComboBox->addItem( tr( "Base" ), "Base" );
613   mValiComboBox->addItem( tr( "Half" ), "Half" );
614   mValiComboBox->addItem( tr( "Cap" ), "Cap" );
615   mValiComboBox->addItem( tr( "Top" ), "Top" );
616 }
617 
mShowLabelChkbx_toggled(bool chkd)618 void QgsLabelPropertyDialog::mShowLabelChkbx_toggled( bool chkd )
619 {
620   insertChangedValue( QgsPalLayerSettings::Show, ( chkd ? 1 : 0 ) );
621 }
622 
mAlwaysShowChkbx_toggled(bool chkd)623 void QgsLabelPropertyDialog::mAlwaysShowChkbx_toggled( bool chkd )
624 {
625   insertChangedValue( QgsPalLayerSettings::AlwaysShow, ( chkd ? 1 : 0 ) );
626 }
627 
labelAllPartsToggled(bool checked)628 void QgsLabelPropertyDialog::labelAllPartsToggled( bool checked )
629 {
630   insertChangedValue( QgsPalLayerSettings::LabelAllParts, ( checked ? 1 : 0 ) );
631 }
632 
showCalloutToggled(bool chkd)633 void QgsLabelPropertyDialog::showCalloutToggled( bool chkd )
634 {
635   insertChangedValue( QgsPalLayerSettings::CalloutDraw, ( chkd ? 1 : 0 ) );
636 }
637 
bufferDrawToggled(bool chkd)638 void QgsLabelPropertyDialog::bufferDrawToggled( bool chkd )
639 {
640   insertChangedValue( QgsPalLayerSettings::BufferDraw, ( chkd ? 1 : 0 ) );
641 }
642 
minScaleChanged(double scale)643 void QgsLabelPropertyDialog::minScaleChanged( double scale )
644 {
645   insertChangedValue( QgsPalLayerSettings::MinimumScale, scale );
646 }
647 
maxScaleChanged(double scale)648 void QgsLabelPropertyDialog::maxScaleChanged( double scale )
649 {
650   insertChangedValue( QgsPalLayerSettings::MaximumScale, scale );
651 }
652 
mLabelDistanceSpinBox_valueChanged(double d)653 void QgsLabelPropertyDialog::mLabelDistanceSpinBox_valueChanged( double d )
654 {
655   QVariant distance( d );
656   if ( d < 0 )
657   {
658     //null value so that distance is reset to default
659     distance.clear();
660   }
661   insertChangedValue( QgsPalLayerSettings::LabelDistance, distance );
662 }
663 
mXCoordSpinBox_valueChanged(double d)664 void QgsLabelPropertyDialog::mXCoordSpinBox_valueChanged( double d )
665 {
666   QVariant x( d );
667   if ( d < mXCoordSpinBox->minimum() + mXCoordSpinBox->singleStep() )
668   {
669     //null value
670     x.clear();
671   }
672 
673   insertChangedValue( QgsPalLayerSettings::PositionX, x );
674   enableWidgetsForPinnedLabels();
675 }
676 
mYCoordSpinBox_valueChanged(double d)677 void QgsLabelPropertyDialog::mYCoordSpinBox_valueChanged( double d )
678 {
679   QVariant y( d );
680   if ( d < mYCoordSpinBox->minimum() + mYCoordSpinBox->singleStep() )
681   {
682     //null value
683     y.clear();
684   }
685   insertChangedValue( QgsPalLayerSettings::PositionY, y );
686   enableWidgetsForPinnedLabels();
687 }
688 
mFontFamilyCmbBx_currentFontChanged(const QFont & f)689 void QgsLabelPropertyDialog::mFontFamilyCmbBx_currentFontChanged( const QFont &f )
690 {
691   mLabelFont.setFamily( f.family() );
692   updateFont( mLabelFont );
693   insertChangedValue( QgsPalLayerSettings::Family, f.family() );
694 }
695 
mFontStyleCmbBx_currentIndexChanged(const QString & text)696 void QgsLabelPropertyDialog::mFontStyleCmbBx_currentIndexChanged( const QString &text )
697 {
698   QgsFontUtils::updateFontViaStyle( mLabelFont, text );
699   updateFont( mLabelFont );
700   insertChangedValue( QgsPalLayerSettings::FontStyle, text );
701 }
702 
mFontUnderlineBtn_toggled(bool ckd)703 void QgsLabelPropertyDialog::mFontUnderlineBtn_toggled( bool ckd )
704 {
705   mLabelFont.setUnderline( ckd );
706   updateFont( mLabelFont );
707   insertChangedValue( QgsPalLayerSettings::Underline, ckd );
708 }
709 
mFontStrikethroughBtn_toggled(bool ckd)710 void QgsLabelPropertyDialog::mFontStrikethroughBtn_toggled( bool ckd )
711 {
712   mLabelFont.setStrikeOut( ckd );
713   updateFont( mLabelFont );
714   insertChangedValue( QgsPalLayerSettings::Strikeout, ckd );
715 }
716 
mFontBoldBtn_toggled(bool ckd)717 void QgsLabelPropertyDialog::mFontBoldBtn_toggled( bool ckd )
718 {
719   mLabelFont.setBold( ckd );
720   updateFont( mLabelFont );
721   insertChangedValue( QgsPalLayerSettings::Bold, ckd );
722 }
723 
mFontItalicBtn_toggled(bool ckd)724 void QgsLabelPropertyDialog::mFontItalicBtn_toggled( bool ckd )
725 {
726   mLabelFont.setItalic( ckd );
727   updateFont( mLabelFont );
728   insertChangedValue( QgsPalLayerSettings::Italic, ckd );
729 }
730 
mFontSizeSpinBox_valueChanged(double d)731 void QgsLabelPropertyDialog::mFontSizeSpinBox_valueChanged( double d )
732 {
733   QVariant size( d );
734   if ( d <= 0 )
735   {
736     //null value so that font size is reset to default
737     size.clear();
738   }
739   insertChangedValue( QgsPalLayerSettings::Size, size );
740 }
741 
mBufferSizeSpinBox_valueChanged(double d)742 void QgsLabelPropertyDialog::mBufferSizeSpinBox_valueChanged( double d )
743 {
744   QVariant size( d );
745   if ( d < 0 )
746   {
747     //null value so that size is reset to default
748     size.clear();
749   }
750   insertChangedValue( QgsPalLayerSettings::BufferSize, size );
751 }
752 
mRotationSpinBox_valueChanged(double d)753 void QgsLabelPropertyDialog::mRotationSpinBox_valueChanged( double d )
754 {
755   QVariant rotation( d );
756   if ( d < 0 )
757   {
758     //null value so that size is reset to default
759     rotation.clear();
760   }
761   insertChangedValue( QgsPalLayerSettings::LabelRotation, rotation );
762 }
763 
mFontColorButton_colorChanged(const QColor & color)764 void QgsLabelPropertyDialog::mFontColorButton_colorChanged( const QColor &color )
765 {
766   insertChangedValue( QgsPalLayerSettings::Color, color.name() );
767 }
768 
mBufferColorButton_colorChanged(const QColor & color)769 void QgsLabelPropertyDialog::mBufferColorButton_colorChanged( const QColor &color )
770 {
771   insertChangedValue( QgsPalLayerSettings::BufferColor, color.name() );
772 }
773 
mMultiLineAlignComboBox_currentIndexChanged(const int index)774 void QgsLabelPropertyDialog::mMultiLineAlignComboBox_currentIndexChanged( const int index )
775 {
776   insertChangedValue( QgsPalLayerSettings::MultiLineAlignment, mMultiLineAlignComboBox->itemData( index ) );
777 }
778 
mHaliComboBox_currentIndexChanged(const int index)779 void QgsLabelPropertyDialog::mHaliComboBox_currentIndexChanged( const int index )
780 {
781   insertChangedValue( QgsPalLayerSettings::Hali, mHaliComboBox->itemData( index ) );
782 }
783 
mValiComboBox_currentIndexChanged(const int index)784 void QgsLabelPropertyDialog::mValiComboBox_currentIndexChanged( const int index )
785 {
786   insertChangedValue( QgsPalLayerSettings::Vali, mValiComboBox->itemData( index ) );
787 }
788 
mLabelTextLineEdit_textChanged(const QString & text)789 void QgsLabelPropertyDialog::mLabelTextLineEdit_textChanged( const QString &text )
790 {
791   if ( mCurLabelField != -1 )
792   {
793     mChangedProperties.insert( mCurLabelField, text );
794   }
795 }
796 
insertChangedValue(QgsPalLayerSettings::Property p,const QVariant & value)797 void QgsLabelPropertyDialog::insertChangedValue( QgsPalLayerSettings::Property p, const QVariant &value )
798 {
799   if ( mDataDefinedProperties.isActive( p ) )
800   {
801     QgsProperty prop = mDataDefinedProperties.property( p );
802     if ( prop.propertyType() == QgsProperty::FieldBasedProperty )
803     {
804       mChangedProperties.insert( mCurLabelFeat.fieldNameIndex( prop.field() ), value );
805     }
806   }
807 }
808 
enableWidgetsForPinnedLabels()809 void QgsLabelPropertyDialog::enableWidgetsForPinnedLabels()
810 {
811   const bool pinned = mXCoordSpinBox->value() >= ( mXCoordSpinBox->minimum() + mXCoordSpinBox->singleStep() ) &&
812                       mYCoordSpinBox->value() >= ( mYCoordSpinBox->minimum() + mYCoordSpinBox->singleStep() );
813 
814   mHaliComboBox->setEnabled( pinned && mCanSetHAlignment );
815   mValiComboBox->setEnabled( pinned && mCanSetVAlignment );
816 
817   if ( !pinned )
818   {
819     mHaliComboBox->setToolTip( tr( "Alignment can only be set for pinned labels" ) );
820     mValiComboBox->setToolTip( tr( "Alignment can only be set for pinned labels" ) );
821   }
822   else
823   {
824     mHaliComboBox->setToolTip( QString() );
825     mValiComboBox->setToolTip( QString() );
826   }
827 }
828 
showHelp()829 void QgsLabelPropertyDialog::showHelp()
830 {
831   QgsHelp::openHelp( QStringLiteral( "working_with_vector/vector_properties.html#the-label-toolbar" ) );
832 }
833