Skip to content

Commit 3b3d1a7

Browse files
committed
Update labeling tools and make more undo/redo friendly
- Change QgsVectorLayer::redoEditCommand to only strip invalid QVariants, not null ones - Update undo/redo command text to start with action and end with sample of label text - Update pin/unpin labels tool to be fully undo/redo-able - Store generated label text in QgsLabelPosition (sans direction symbols) - Update change label properties dialog to show whether label text is expression
1 parent 0c2fef4 commit 3b3d1a7

15 files changed

+154
-91
lines changed

python/core/qgsmaprenderer.sip

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ class QgsLabelPosition
66
#include <qgsmaprenderer.h>
77
%End
88
public:
9-
QgsLabelPosition( int id, double r, const QVector< QgsPoint >& corners, const QgsRectangle& rect, double w, double h, const QString& layer, bool upside_down, bool diagram = false, bool pinned = false );
9+
QgsLabelPosition( int id, double r, const QVector< QgsPoint >& corners, const QgsRectangle& rect, double w, double h, const QString& layer, const QString& labeltext, bool upside_down, bool diagram = false, bool pinned = false );
1010
QgsLabelPosition();
1111
int featureId;
1212
double rotation;
@@ -15,6 +15,7 @@ class QgsLabelPosition
1515
double width;
1616
double height;
1717
QString layerID;
18+
QString labelText;
1819
bool upsideDown;
1920
bool isDiagram;
2021
bool isPinned;

src/app/qgslabelpropertydialog.cpp

+30-20
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,20 @@
2222
#include <QColorDialog>
2323
#include <QFontDialog>
2424

25-
QgsLabelPropertyDialog::QgsLabelPropertyDialog( const QString& layerId, int featureId, QgsMapRenderer* renderer, QWidget * parent, Qt::WindowFlags f ):
25+
QgsLabelPropertyDialog::QgsLabelPropertyDialog( const QString& layerId, int featureId, const QString& labelText, QgsMapRenderer* renderer, QWidget * parent, Qt::WindowFlags f ):
2626
QDialog( parent, f ), mMapRenderer( renderer ), mCurrentLabelField( -1 )
2727
{
2828
setupUi( this );
2929
fillHaliComboBox();
3030
fillValiComboBox();
31-
init( layerId, featureId );
31+
init( layerId, featureId, labelText );
3232
}
3333

3434
QgsLabelPropertyDialog::~QgsLabelPropertyDialog()
3535
{
3636
}
3737

38-
void QgsLabelPropertyDialog::init( const QString& layerId, int featureId )
38+
void QgsLabelPropertyDialog::init( const QString& layerId, int featureId, const QString& labelText )
3939
{
4040
if ( !mMapRenderer )
4141
{
@@ -65,30 +65,40 @@ void QgsLabelPropertyDialog::init( const QString& layerId, int featureId )
6565

6666
blockElementSignals( true );
6767

68+
QgsPalLayerSettings& layerSettings = lbl->layer( layerId );
69+
6870
//get label field and fill line edit
69-
QString labelFieldName = vlayer->customProperty( "labeling/fieldName" ).toString();
70-
if ( !labelFieldName.isEmpty() )
71+
if ( layerSettings.isExpression && !labelText.isNull() )
7172
{
72-
mCurrentLabelField = vlayer->fieldNameIndex( labelFieldName );
73-
mLabelTextLineEdit->setText( attributeValues[mCurrentLabelField].toString() );
74-
const QgsFieldMap& layerFields = vlayer->pendingFields();
75-
switch ( layerFields[mCurrentLabelField].type() )
73+
mLabelTextLineEdit->setText( labelText );
74+
mLabelTextLineEdit->setEnabled( false );
75+
mLabelTextLabel->setText( tr( "Expression result" ) );
76+
}
77+
else
78+
{
79+
QString labelFieldName = vlayer->customProperty( "labeling/fieldName" ).toString();
80+
if ( !labelFieldName.isEmpty() )
7681
{
77-
case QVariant::Double:
78-
mLabelTextLineEdit->setValidator( new QDoubleValidator( this ) );
79-
break;
80-
case QVariant::Int:
81-
case QVariant::UInt:
82-
case QVariant::LongLong:
83-
mLabelTextLineEdit->setValidator( new QIntValidator( this ) );
84-
break;
85-
default:
86-
break;
82+
mCurrentLabelField = vlayer->fieldNameIndex( labelFieldName );
83+
mLabelTextLineEdit->setText( attributeValues[mCurrentLabelField].toString() );
84+
const QgsFieldMap& layerFields = vlayer->pendingFields();
85+
switch ( layerFields[mCurrentLabelField].type() )
86+
{
87+
case QVariant::Double:
88+
mLabelTextLineEdit->setValidator( new QDoubleValidator( this ) );
89+
break;
90+
case QVariant::Int:
91+
case QVariant::UInt:
92+
case QVariant::LongLong:
93+
mLabelTextLineEdit->setValidator( new QIntValidator( this ) );
94+
break;
95+
default:
96+
break;
97+
}
8798
}
8899
}
89100

90101
//get attributes of the feature and fill data defined values
91-
QgsPalLayerSettings& layerSettings = lbl->layer( layerId );
92102
mLabelFont = layerSettings.textFont;
93103

94104
//set all the gui elements to the default values

src/app/qgslabelpropertydialog.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ class QgsLabelPropertyDialog: public QDialog, private Ui::QgsLabelPropertyDialog
3030
{
3131
Q_OBJECT
3232
public:
33-
QgsLabelPropertyDialog( const QString& layerId, int featureId, QgsMapRenderer* renderer, QWidget * parent = 0, Qt::WindowFlags f = 0 );
33+
QgsLabelPropertyDialog( const QString& layerId, int featureId, const QString& labelText, QgsMapRenderer* renderer, QWidget * parent = 0, Qt::WindowFlags f = 0 );
3434
~QgsLabelPropertyDialog();
3535

3636
/**Returns properties changed by the user*/
@@ -56,7 +56,7 @@ class QgsLabelPropertyDialog: public QDialog, private Ui::QgsLabelPropertyDialog
5656

5757
private:
5858
/**Sets activation / values to the gui elements depending on the label settings and feature values*/
59-
void init( const QString& layerId, int featureId );
59+
void init( const QString& layerId, int featureId, const QString& labelText );
6060
void disableGuiElements();
6161
/**Block / unblock all input element signals*/
6262
void blockElementSignals( bool block );

src/app/qgsmaptoolchangelabelproperties.cpp

+11-3
Original file line numberDiff line numberDiff line change
@@ -53,18 +53,26 @@ void QgsMapToolChangeLabelProperties::canvasReleaseEvent( QMouseEvent *e )
5353
QgsVectorLayer* vlayer = currentLayer();
5454
if ( mLabelRubberBand && mCanvas && vlayer )
5555
{
56-
QgsLabelPropertyDialog d( mCurrentLabelPos.layerID, mCurrentLabelPos.featureId, mCanvas->mapRenderer() );
56+
QString labeltext = QString(); // NULL QString signifies no expression
57+
bool settingsOk;
58+
QgsPalLayerSettings& labelSettings = currentLabelSettings( &settingsOk );
59+
if ( settingsOk && labelSettings.isExpression )
60+
{
61+
labeltext = mCurrentLabelPos.labelText;
62+
}
63+
64+
QgsLabelPropertyDialog d( mCurrentLabelPos.layerID, mCurrentLabelPos.featureId, labeltext, mCanvas->mapRenderer() );
5765
if ( d.exec() == QDialog::Accepted )
5866
{
5967
const QgsAttributeMap& changes = d.changedProperties();
6068
if ( changes.size() > 0 )
6169
{
62-
vlayer->beginEditCommand( tr( "Label properties changed" ) );
70+
vlayer->beginEditCommand( tr( "Changed properties for label" ) + QString( " '%1'" ).arg( currentLabelText( 24 ) ) );
6371

6472
QgsAttributeMap::const_iterator changeIt = changes.constBegin();
6573
for ( ; changeIt != changes.constEnd(); ++changeIt )
6674
{
67-
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, changeIt.key(), changeIt.value(), false );
75+
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, changeIt.key(), changeIt.value(), true );
6876
}
6977

7078
vlayer->endEditCommand();

src/app/qgsmaptoollabel.cpp

+36-9
Original file line numberDiff line numberDiff line change
@@ -145,22 +145,49 @@ QgsPalLayerSettings& QgsMapToolLabel::currentLabelSettings( bool* ok )
145145
return mInvalidLabelSettings;
146146
}
147147

148-
QString QgsMapToolLabel::currentLabelText()
148+
QString QgsMapToolLabel::currentLabelText( int trunc )
149149
{
150-
QgsVectorLayer* vlayer = currentLayer();
151-
if ( !vlayer )
150+
bool settingsOk;
151+
QgsPalLayerSettings& labelSettings = currentLabelSettings( &settingsOk );
152+
if ( !settingsOk )
152153
{
153154
return "";
154155
}
155156

156-
QString labelField = vlayer->customProperty( "labeling/fieldName" ).toString();
157-
if ( !labelField.isEmpty() )
157+
if ( labelSettings.isExpression )
158158
{
159-
int labelFieldId = vlayer->fieldNameIndex( labelField );
160-
QgsFeature f;
161-
if ( vlayer->featureAtId( mCurrentLabelPos.featureId, f, false, true ) )
159+
QString labelText = mCurrentLabelPos.labelText;
160+
161+
if ( trunc > 0 && labelText.length() > trunc )
162162
{
163-
return f.attributeMap()[labelFieldId].toString();
163+
labelText.truncate( trunc );
164+
labelText += "...";
165+
}
166+
return labelText;
167+
}
168+
else
169+
{
170+
QgsVectorLayer* vlayer = currentLayer();
171+
if ( !vlayer )
172+
{
173+
return "";
174+
}
175+
176+
QString labelField = vlayer->customProperty( "labeling/fieldName" ).toString();
177+
if ( !labelField.isEmpty() )
178+
{
179+
int labelFieldId = vlayer->fieldNameIndex( labelField );
180+
QgsFeature f;
181+
if ( vlayer->featureAtId( mCurrentLabelPos.featureId, f, false, true ) )
182+
{
183+
QString labelText = f.attributeMap()[labelFieldId].toString();
184+
if ( trunc > 0 && labelText.length() > trunc )
185+
{
186+
labelText.truncate( trunc );
187+
labelText += "...";
188+
}
189+
return labelText;
190+
}
164191
}
165192
}
166193
return "";

src/app/qgsmaptoollabel.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,9 @@ class QgsMapToolLabel: public QgsMapTool
8585
/**Returns layer settings of current label position*/
8686
QgsPalLayerSettings& currentLabelSettings( bool* ok );
8787

88-
QString currentLabelText();
88+
/**Returns current label's text
89+
@param trunc number of chars to truncate to, with ... added (added in 1.9)*/
90+
QString currentLabelText( int trunc = 0 );
8991

9092
void currentAlignment( QString& hali, QString& vali );
9193

src/app/qgsmaptoolmovelabel.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -149,9 +149,9 @@ void QgsMapToolMoveLabel::canvasReleaseEvent( QMouseEvent * e )
149149
}
150150
}
151151

152-
vlayer->beginEditCommand( tr( "Label moved" ) );
153-
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, xCol, xPosNew, false );
154-
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, yCol, yPosNew, false );
152+
vlayer->beginEditCommand( tr( "Moved label" ) + QString( " '%1'" ).arg( currentLabelText( 24 ) ) );
153+
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, xCol, xPosNew, true );
154+
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, yCol, yPosNew, true );
155155

156156
// set rotation to that of label, if data-defined and no rotation set yet
157157
// honor whether to preserve preexisting data on pin
@@ -167,7 +167,7 @@ void QgsMapToolMoveLabel::canvasReleaseEvent( QMouseEvent * e )
167167
if ( dataDefinedRotation( vlayer, mCurrentLabelPos.featureId, defRot, rSuccess ) )
168168
{
169169
double labelRot = mCurrentLabelPos.rotation * 180 / M_PI;
170-
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, rCol, labelRot, false );
170+
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, rCol, labelRot, true );
171171
}
172172
}
173173
vlayer->endEditCommand();

src/app/qgsmaptoolpinlabels.cpp

+30-36
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ void QgsMapToolPinLabels::updatePinnedLabels()
134134
if ( mShowPinned )
135135
{
136136
QgsDebugMsg( QString( "Updating highlighting due to layer editing mode change" ) );
137-
mCanvas->refresh();
137+
highlightPinnedLabels();
138138
}
139139
}
140140

@@ -287,11 +287,11 @@ void QgsMapToolPinLabels::pinUnpinLabels( const QgsRectangle& ext, QMouseEvent *
287287
mCurrentLabelPos = *it;
288288

289289
#ifdef QGISDEBUG
290-
QString labeltxt = currentLabelText();
291290
QString labellyr = currentLayer()->name();
291+
QString labeltxt = currentLabelText();
292292
#endif
293-
QgsDebugMsg( QString( "Label: %0" ).arg( labeltxt ) );
294293
QgsDebugMsg( QString( "Layer: %0" ).arg( labellyr ) );
294+
QgsDebugMsg( QString( "Label: %0" ).arg( labeltxt ) );
295295

296296
QgsMapLayer* layer = QgsMapLayerRegistry::instance()->mapLayer( mCurrentLabelPos.layerID );
297297
if ( !layer )
@@ -390,7 +390,8 @@ bool QgsMapToolPinLabels::pinUnpinLabel( QgsVectorLayer* vlayer,
390390
// edit attribute table
391391
int fid = labelpos.featureId;
392392

393-
QString failedWrite = QString( "Failed write to attribute table" );
393+
bool writeFailed = false;
394+
QString labelText = currentLabelText( 24 );
394395

395396
if ( pin )
396397
{
@@ -416,49 +417,42 @@ bool QgsMapToolPinLabels::pinUnpinLabel( QgsVectorLayer* vlayer,
416417
labelY = transformedPoint.y();
417418
}
418419

419-
vlayer->beginEditCommand( tr( "Label pinned" ) );
420-
if ( !vlayer->changeAttributeValue( fid, xCol, labelX, false ) )
421-
{
422-
QgsDebugMsg( failedWrite );
423-
return false;
424-
}
425-
if ( !vlayer->changeAttributeValue( fid, yCol, labelY, false ) )
426-
{
427-
QgsDebugMsg( failedWrite );
428-
return false;
429-
}
420+
vlayer->beginEditCommand( tr( "Pinned label" ) + QString( " '%1'" ).arg( labelText ) );
421+
writeFailed = !vlayer->changeAttributeValue( fid, xCol, labelX, true );
422+
writeFailed = !vlayer->changeAttributeValue( fid, yCol, labelY, true );
430423
if ( hasRCol && !preserveRot )
431424
{
432-
if ( !vlayer->changeAttributeValue( fid, rCol, labelR, false ) )
433-
{
434-
QgsDebugMsg( failedWrite );
435-
return false;
436-
}
425+
writeFailed = !vlayer->changeAttributeValue( fid, rCol, labelR, true );
437426
}
438427
vlayer->endEditCommand();
439428
}
440429
else
441430
{
442-
vlayer->beginEditCommand( tr( "Label unpinned" ) );
443-
if ( !vlayer->changeAttributeValue( fid, xCol, QVariant(), false ) )
444-
{
445-
QgsDebugMsg( failedWrite );
446-
return false;
447-
}
448-
if ( !vlayer->changeAttributeValue( fid, yCol, QVariant(), false ) )
449-
{
450-
QgsDebugMsg( failedWrite );
451-
return false;
452-
}
431+
vlayer->beginEditCommand( tr( "Unpinned label" ) + QString( " '%1'" ).arg( labelText ) );
432+
writeFailed = !vlayer->changeAttributeValue( fid, xCol, QVariant( QString::null ), true );
433+
writeFailed = !vlayer->changeAttributeValue( fid, yCol, QVariant( QString::null ), true );
453434
if ( hasRCol && !preserveRot )
454435
{
455-
if ( !vlayer->changeAttributeValue( fid, rCol, QVariant(), false ) )
456-
{
457-
QgsDebugMsg( failedWrite );
458-
return false;
459-
}
436+
writeFailed = !vlayer->changeAttributeValue( fid, rCol, QVariant( QString::null ), true );
460437
}
461438
vlayer->endEditCommand();
462439
}
440+
441+
if ( writeFailed )
442+
{
443+
QgsDebugMsg( QString( "Write to attribute table failed" ) );
444+
445+
// QgsDebugMsg( QString( "Undoing and removing failed command from layer's undo stack" ) );
446+
// int lastCmdIndx = vlayer->undoStack()->count();
447+
// const QgsUndoCommand* lastCmd = qobject_cast<const QgsUndoCommand *>( vlayer->undoStack()->command( lastCmdIndx ) );
448+
// if ( lastCmd )
449+
// {
450+
// vlayer->undoEditCommand( lastCmd );
451+
// delete vlayer->undoStack()->command( lastCmdIndx );
452+
// }
453+
454+
return false;
455+
}
456+
463457
return true;
464458
}

src/app/qgsmaptoolrotatelabel.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -171,8 +171,8 @@ void QgsMapToolRotateLabel::canvasReleaseEvent( QMouseEvent *e )
171171
return;
172172
}
173173

174-
vlayer->beginEditCommand( tr( "Label rotated" ) );
175-
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, rotationCol, rotation, false );
174+
vlayer->beginEditCommand( tr( "Rotated label" ) + QString( " '%1'" ).arg( currentLabelText( 24 ) ) );
175+
vlayer->changeAttributeValue( mCurrentLabelPos.featureId, rotationCol, rotation, true );
176176
vlayer->endEditCommand();
177177
mCanvas->refresh();
178178
}

src/app/qgsmaptoolshowhidelabels.cpp

+23-4
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,31 @@ bool QgsMapToolShowHideLabels::showHideLabel( QgsVectorLayer* vlayer,
280280
return false;
281281
}
282282

283-
// edit attribute table
284-
QString editTxt = hide ? tr( "Label hidden" ) : tr( "Label shown" );
285-
vlayer->beginEditCommand( editTxt );
286-
if ( !vlayer->changeAttributeValue( fid, showCol, ( hide ? 0 : 1 ), false ) )
283+
// check if attribute value is already the same
284+
QgsFeature f;
285+
if ( !vlayer->featureAtId( fid, f, false, true ) )
286+
{
287+
return false;
288+
}
289+
290+
int colVal = hide ? 0 : 1;
291+
QVariant fQVal = f.attributeMap()[showCol];
292+
bool convToInt;
293+
int fVal = fQVal.toInt( &convToInt );
294+
295+
if ( !convToInt || fVal == colVal )
296+
{
297+
return false;
298+
}
299+
300+
// different attribute value, edit table
301+
QString labelText = currentLabelText( 24 );
302+
QString editTxt = hide ? tr( "Hid label" ) : tr( "Showed label" );
303+
vlayer->beginEditCommand( editTxt + QString( " '%1'" ).arg( labelText ) );
304+
if ( !vlayer->changeAttributeValue( fid, showCol, colVal, true ) )
287305
{
288306
QgsDebugMsg( "Failed write to attribute table" );
307+
vlayer->endEditCommand();
289308
return false;
290309
}
291310
vlayer->endEditCommand();

0 commit comments

Comments
 (0)