Skip to content

Commit 6cfb060

Browse files
committed
Option to preserve existing rotation values during freeze/thaw label operations
- PAL layer setting for preserving existing rotation values - Clean up field-mapping checks
1 parent 55628dd commit 6cfb060

8 files changed

+105
-76
lines changed

src/app/qgslabelinggui.cpp

+11
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ QgsLabelingGui::QgsLabelingGui( QgsPalLabeling* lbl, QgsVectorLayer* layer, QgsM
140140
mMinSizeSpinBox->setValue( lyr.minFeatureSize );
141141
chkAddDirectionSymbol->setChecked( lyr.addDirectionSymbol );
142142
wrapCharacterEdit->setText( lyr.wrapChar );
143+
chkPreserveRotation->setChecked( lyr.preserveRotation );
143144

144145
bool scaleBased = ( lyr.scaleMin != 0 && lyr.scaleMax != 0 );
145146
chkScaleBasedVisibility->setChecked( scaleBased );
@@ -323,6 +324,14 @@ QgsPalLayerSettings QgsLabelingGui::layerSettings()
323324
lyr.minFeatureSize = mMinSizeSpinBox->value();
324325
lyr.fontSizeInMapUnits = ( mFontSizeUnitComboBox->currentIndex() == 1 );
325326
lyr.wrapChar = wrapCharacterEdit->text();
327+
if ( chkPreserveRotation->isChecked() )
328+
{
329+
lyr.preserveRotation = true;
330+
}
331+
else
332+
{
333+
lyr.preserveRotation = false;
334+
}
326335

327336
//data defined labeling
328337
setDataDefinedProperty( mSizeAttributeComboBox, QgsPalLayerSettings::Size, lyr );
@@ -600,11 +609,13 @@ void QgsLabelingGui::disableDataDefinedAlignment()
600609
mVerticalAlignmentComboBox->setEnabled( false );
601610
mRotationComboBox->setCurrentIndex( mRotationComboBox->findText( "" ) );
602611
mRotationComboBox->setEnabled( false );
612+
chkPreserveRotation->setEnabled( false );
603613
}
604614

605615
void QgsLabelingGui::enableDataDefinedAlignment()
606616
{
607617
mHorizontalAlignmentComboBox->setEnabled( true );
608618
mVerticalAlignmentComboBox->setEnabled( true );
609619
mRotationComboBox->setEnabled( true );
620+
chkPreserveRotation->setEnabled( true );
610621
}

src/app/qgsmaptoolfreezelabels.cpp

+18-40
Original file line numberDiff line numberDiff line change
@@ -379,50 +379,28 @@ bool QgsMapToolFreezeLabels::freezeThawLabel( QgsVectorLayer* vlayer,
379379
QgsDebugMsg( QString( "Label is diagram, skipping" ) );
380380
return false;
381381
}
382-
// verify attribute table has proper fields setup
383-
bool xColOk, yColOk, rColOk;
384-
int xCol, yCol, rCol;
385382

386-
QVariant xColumn = vlayer->customProperty( "labeling/dataDefinedProperty9" );
387-
if ( !xColumn.isValid() )
388-
{
389-
QgsDebugMsg( QString( "X column not set" ) );
390-
return false;
391-
}
392-
xCol = xColumn.toInt( &xColOk );
393-
if ( !xColOk )
394-
{
395-
QgsDebugMsg( QString( "X column not convertible to integer" ) );
396-
return false;
397-
}
383+
// verify attribute table has x, y fields mapped
384+
int xCol, yCol;
385+
double xPosOrig, yPosOrig;
386+
bool xSuccess, ySuccess;
398387

399-
QVariant yColumn = vlayer->customProperty( "labeling/dataDefinedProperty10" );
400-
if ( !yColumn.isValid() )
401-
{
402-
QgsDebugMsg( QString( "Y column not set" ) );
403-
return false;
404-
}
405-
yCol = yColumn.toInt( &yColOk );
406-
if ( !yColOk )
388+
if ( !dataDefinedPosition( vlayer, mCurrentLabelPos.featureId, xPosOrig, xSuccess, yPosOrig, ySuccess, xCol, yCol ) )
407389
{
408-
QgsDebugMsg( QString( "Y column not convertible to integer" ) );
390+
QgsDebugMsg( QString( "Label X or Y column not mapped, skipping" ) );
409391
return false;
410392
}
411393

412-
// rotation field is optional, but will be used if available
413-
bool hasRCol = true;
414-
QVariant rColumn = vlayer->customProperty( "labeling/dataDefinedProperty14" );
415-
if ( !rColumn.isValid() )
416-
{
417-
QgsDebugMsg( QString( "Rotation column not set" ) );
418-
hasRCol = false;
419-
}
420-
rCol = rColumn.toInt( &rColOk );
421-
if ( !rColOk )
422-
{
423-
QgsDebugMsg( QString( "Rotation column not convertible to integer" ) );
424-
hasRCol = false;
425-
}
394+
// rotation field is optional, but will be used if available, unless data exists
395+
int rCol;
396+
bool rSuccess = false;
397+
double defRot;
398+
399+
bool hasRCol = ( layerIsRotatable( vlayer, rCol )
400+
&& dataDefinedRotation( vlayer, mCurrentLabelPos.featureId, defRot, rSuccess, true ) );
401+
402+
// get whether to preserve predefined rotation data during label freeze/thaw operations
403+
bool preserveRot = preserveRotation();
426404

427405
// edit attribute table
428406
int fid = labelpos.featureId;
@@ -464,7 +442,7 @@ bool QgsMapToolFreezeLabels::freezeThawLabel( QgsVectorLayer* vlayer,
464442
QgsDebugMsg( failedWrite );
465443
return false;
466444
}
467-
if ( hasRCol )
445+
if ( hasRCol && !preserveRot )
468446
{
469447
if ( !vlayer->changeAttributeValue( fid, rCol, labelR, false ) )
470448
{
@@ -487,7 +465,7 @@ bool QgsMapToolFreezeLabels::freezeThawLabel( QgsVectorLayer* vlayer,
487465
QgsDebugMsg( failedWrite );
488466
return false;
489467
}
490-
if ( hasRCol )
468+
if ( hasRCol && !preserveRot )
491469
{
492470
if ( !vlayer->changeAttributeValue( fid, rCol, QVariant(), false ) )
493471
{

src/app/qgsmaptoollabel.cpp

+22-6
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,19 @@ QFont QgsMapToolLabel::labelFontCurrentFeature()
280280
return font;
281281
}
282282

283+
bool QgsMapToolLabel::preserveRotation()
284+
{
285+
bool labelSettingsOk;
286+
QgsPalLayerSettings& layerSettings = currentLabelSettings( &labelSettingsOk );
287+
288+
if ( labelSettingsOk )
289+
{
290+
return layerSettings.preserveRotation;
291+
}
292+
293+
return true; // default, so there is no accidental data loss
294+
}
295+
283296
bool QgsMapToolLabel::rotationPoint( QgsPoint& pos, bool ignoreUpsideDown )
284297
{
285298
QVector<QgsPoint> cornerPoints = mCurrentLabelPos.cornerPoints;
@@ -429,7 +442,7 @@ bool QgsMapToolLabel::layerIsRotatable( const QgsMapLayer* layer, int& rotationC
429442
return true;
430443
}
431444

432-
bool QgsMapToolLabel::dataDefinedRotation( QgsVectorLayer* vlayer, int featureId, double& rotation, bool& rotationSuccess )
445+
bool QgsMapToolLabel::dataDefinedRotation( QgsVectorLayer* vlayer, int featureId, double& rotation, bool& rotationSuccess, bool ignoreXY )
433446
{
434447
rotationSuccess = false;
435448
if ( !vlayer )
@@ -452,12 +465,15 @@ bool QgsMapToolLabel::dataDefinedRotation( QgsVectorLayer* vlayer, int featureId
452465
QgsAttributeMap attributes = f.attributeMap();
453466

454467
//test, if data defined x- and y- values are not null. Otherwise, the position is determined by PAL and the rotation cannot be fixed
455-
int xCol, yCol;
456-
double x, y;
457-
bool xSuccess, ySuccess;
458-
if ( !dataDefinedPosition( vlayer, featureId, x, xSuccess, y, ySuccess, xCol, yCol ) || !xSuccess || !ySuccess )
468+
if ( !ignoreXY )
459469
{
460-
return false;
470+
int xCol, yCol;
471+
double x, y;
472+
bool xSuccess, ySuccess;
473+
if ( !dataDefinedPosition( vlayer, featureId, x, xSuccess, y, ySuccess, xCol, yCol ) || !xSuccess || !ySuccess )
474+
{
475+
return false;
476+
}
461477
}
462478

463479
rotation = attributes[rotationCol].toDouble( &rotationSuccess );

src/app/qgsmaptoollabel.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ class QgsMapToolLabel: public QgsMapTool
9393
/**Returns the font for the current feature (considering default font and data defined properties*/
9494
QFont labelFontCurrentFeature();
9595

96+
/**Returns whether to preserve predefined rotation data during label freeze/thaw operations*/
97+
bool preserveRotation();
98+
9699
/**Get data defined position of a feature
97100
@param vlayer vector layer
98101
@param featureId feature identification integer
@@ -110,9 +113,10 @@ class QgsMapToolLabel: public QgsMapTool
110113
@param featureId feature identification integer
111114
@param rotation out: rotation value
112115
@param rotationSuccess out: false if rotation value is NULL
116+
@param ignoreXY ignore that x and y are required to be data-defined
113117
@return true if data defined rotation is enabled on the layer
114118
*/
115-
bool dataDefinedRotation( QgsVectorLayer* vlayer, int featureId, double& rotation, bool& rotationSuccess );
119+
bool dataDefinedRotation( QgsVectorLayer* vlayer, int featureId, double& rotation, bool& rotationSuccess, bool ignoreXY = false );
116120

117121
private:
118122
QgsPalLayerSettings mInvalidLabelSettings;

src/app/qgsmaptoolmovelabel.cpp

+6-8
Original file line numberDiff line numberDiff line change
@@ -154,22 +154,20 @@ void QgsMapToolMoveLabel::canvasReleaseEvent( QMouseEvent * e )
154154
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, yCol, yPosNew, false );
155155

156156
// set rotation to that of label, if data-defined and no rotation set yet
157-
// handle case of initially set rotation column fields of 0 instead of NULL
157+
// honor whether to preserve preexisting data on freeze
158158
// must come after setting x and y positions
159159
int rCol;
160-
if ( !mCurrentLabelPos.isDiagram && !mCurrentLabelPos.isFrozen
160+
if ( !mCurrentLabelPos.isDiagram
161+
&& !mCurrentLabelPos.isFrozen
162+
&& !preserveRotation()
161163
&& layerIsRotatable( vlayer, rCol ) )
162164
{
163-
double labelRot = 0;
164165
double defRot;
165166
bool rSuccess;
166167
if ( dataDefinedRotation( vlayer, mCurrentLabelPos.featureId, defRot, rSuccess ) )
167168
{
168-
labelRot = mCurrentLabelPos.rotation * 180 / M_PI;
169-
if ( !rSuccess || ( rSuccess && defRot != labelRot ) )
170-
{
171-
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, rCol, labelRot, false );
172-
}
169+
double labelRot = mCurrentLabelPos.rotation * 180 / M_PI;
170+
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, rCol, labelRot, false );
173171
}
174172
}
175173
vlayer->endEditCommand();

src/core/qgspallabeling.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ QgsPalLayerSettings::QgsPalLayerSettings()
163163
fontSizeInMapUnits = false;
164164
distInMapUnits = false;
165165
wrapChar = "";
166+
preserveRotation = true;
166167
}
167168

168169
QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
@@ -194,6 +195,7 @@ QgsPalLayerSettings::QgsPalLayerSettings( const QgsPalLayerSettings& s )
194195
fontSizeInMapUnits = s.fontSizeInMapUnits;
195196
distInMapUnits = s.distInMapUnits;
196197
wrapChar = s.wrapChar;
198+
preserveRotation = s.preserveRotation;
197199

198200
dataDefinedProperties = s.dataDefinedProperties;
199201
fontMetrics = NULL;
@@ -337,6 +339,7 @@ void QgsPalLayerSettings::readFromLayer( QgsVectorLayer* layer )
337339
fontSizeInMapUnits = layer->customProperty( "labeling/fontSizeInMapUnits" ).toBool();
338340
distInMapUnits = layer->customProperty( "labeling/distInMapUnits" ).toBool();
339341
wrapChar = layer->customProperty( "labeling/wrapChar" ).toString();
342+
preserveRotation = layer->customProperty( "labeling/preserveRotation", QVariant( true ) ).toBool();
340343
_readDataDefinedPropertyMap( layer, dataDefinedProperties );
341344
}
342345

@@ -376,6 +379,7 @@ void QgsPalLayerSettings::writeToLayer( QgsVectorLayer* layer )
376379
layer->setCustomProperty( "labeling/fontSizeInMapUnits", fontSizeInMapUnits );
377380
layer->setCustomProperty( "labeling/distInMapUnits", distInMapUnits );
378381
layer->setCustomProperty( "labeling/wrapChar", wrapChar );
382+
layer->setCustomProperty( "labeling/preserveRotation", preserveRotation );
379383
_writeDataDefinedPropertyMap( layer, dataDefinedProperties );
380384
}
381385

src/core/qgspallabeling.h

+2
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ class CORE_EXPORT QgsPalLayerSettings
161161
/**Stores field indices for data defined layer properties*/
162162
QMap< DataDefinedProperties, int > dataDefinedProperties;
163163

164+
bool preserveRotation; // preserve predefined rotation data during label freeze/thaw operations
165+
164166
/**Calculates pixel size (considering output size should be in pixel or map units, scale factors and oversampling)
165167
@param size size to convert
166168
@param c rendercontext

src/ui/qgslabelingguibase.ui

+37-21
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<x>0</x>
88
<y>0</y>
99
<width>703</width>
10-
<height>469</height>
10+
<height>482</height>
1111
</rect>
1212
</property>
1313
<property name="windowTitle">
@@ -463,8 +463,8 @@
463463
<rect>
464464
<x>0</x>
465465
<y>0</y>
466-
<width>647</width>
467-
<height>435</height>
466+
<width>621</width>
467+
<height>479</height>
468468
</rect>
469469
</property>
470470
<layout class="QGridLayout" name="gridLayout_13">
@@ -924,9 +924,9 @@
924924
<property name="geometry">
925925
<rect>
926926
<x>0</x>
927-
<y>0</y>
928-
<width>647</width>
929-
<height>507</height>
927+
<y>-289</y>
928+
<width>618</width>
929+
<height>599</height>
930930
</rect>
931931
</property>
932932
<layout class="QGridLayout" name="gridLayout_11">
@@ -1050,6 +1050,26 @@
10501050
<string>Position</string>
10511051
</property>
10521052
<layout class="QGridLayout" name="gridLayout_4">
1053+
<item row="5" column="1">
1054+
<widget class="QComboBox" name="mRotationComboBox"/>
1055+
</item>
1056+
<item row="5" column="0">
1057+
<widget class="QLabel" name="mRotationLabel">
1058+
<property name="text">
1059+
<string>Rotation</string>
1060+
</property>
1061+
</widget>
1062+
</item>
1063+
<item row="0" column="1">
1064+
<widget class="QComboBox" name="mLabelDistanceComboBox"/>
1065+
</item>
1066+
<item row="0" column="0">
1067+
<widget class="QLabel" name="mLabelDistanceLabel">
1068+
<property name="text">
1069+
<string>Label distance</string>
1070+
</property>
1071+
</widget>
1072+
</item>
10531073
<item row="1" column="0">
10541074
<widget class="QLabel" name="mXCoordinateLabel">
10551075
<property name="text">
@@ -1090,23 +1110,19 @@
10901110
<item row="4" column="1">
10911111
<widget class="QComboBox" name="mVerticalAlignmentComboBox"/>
10921112
</item>
1093-
<item row="5" column="1">
1094-
<widget class="QComboBox" name="mRotationComboBox"/>
1095-
</item>
1096-
<item row="5" column="0">
1097-
<widget class="QLabel" name="mRotationLabel">
1098-
<property name="text">
1099-
<string>Rotation</string>
1113+
<item row="6" column="0" colspan="2">
1114+
<widget class="QCheckBox" name="chkPreserveRotation">
1115+
<property name="toolTip">
1116+
<string>Uncheck to write labeling engine derived rotation on freeze and NULL on thaw</string>
1117+
</property>
1118+
<property name="styleSheet">
1119+
<string notr="true">margin-left: 12px;</string>
11001120
</property>
1101-
</widget>
1102-
</item>
1103-
<item row="0" column="1">
1104-
<widget class="QComboBox" name="mLabelDistanceComboBox"/>
1105-
</item>
1106-
<item row="0" column="0">
1107-
<widget class="QLabel" name="mLabelDistanceLabel">
11081121
<property name="text">
1109-
<string>Label distance</string>
1122+
<string>Preserve existing rotation values during label freeze/thaw operations</string>
1123+
</property>
1124+
<property name="checked">
1125+
<bool>true</bool>
11101126
</property>
11111127
</widget>
11121128
</item>

0 commit comments

Comments
 (0)