1 /*************************************************************************** 2 testqgsmaptoollabel.cpp 3 ----------------------- 4 Date : July 2019 5 Copyright : (C) 2019 by Nyall Dawson 6 Email : nyall dot dawson at gmail dot com 7 *************************************************************************** 8 * * 9 * This program is free software; you can redistribute it and/or modify * 10 * it under the terms of the GNU General Public License as published by * 11 * the Free Software Foundation; either version 2 of the License, or * 12 * (at your option) any later version. * 13 * * 14 ***************************************************************************/ 15 16 #include "qgstest.h" 17 #include <QObject> 18 #include <QString> 19 #include <QMouseEvent> 20 21 #include "qgsapplication.h" 22 #include "qgsvectorlayer.h" 23 #include "qgsvectordataprovider.h" 24 #include "qgsgeometry.h" 25 #include "qgsmapcanvas.h" 26 #include "qgsmaptoollabel.h" 27 #include "qgsfontutils.h" 28 #include "qgsvectorlayerlabelprovider.h" 29 #include "qgsvectorlayerlabeling.h" 30 #include "qgsadvanceddigitizingdockwidget.h" 31 #include "qgsexpressioncontextutils.h" 32 33 class TestQgsMapToolLabel : public QObject 34 { 35 Q_OBJECT 36 37 public: 38 TestQgsMapToolLabel() = default; 39 40 private: 41 42 private slots: 43 initTestCase()44 void initTestCase() 45 { 46 QgsApplication::init(); 47 QgsApplication::initQgis(); 48 49 } 50 cleanupTestCase()51 void cleanupTestCase() 52 { 53 QgsApplication::exitQgis(); 54 } 55 testSelectLabel()56 void testSelectLabel() 57 { 58 std::unique_ptr< QgsVectorLayer > vl1 = std::make_unique< QgsVectorLayer >( QStringLiteral( "Point?crs=epsg:3946&field=text:string" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) ); 59 QVERIFY( vl1->isValid() ); 60 QgsFeature f1; 61 f1.setAttributes( QgsAttributes() << QStringLiteral( "label" ) ); 62 f1.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( 1, 1 ) ) ); 63 QVERIFY( vl1->dataProvider()->addFeature( f1 ) ); 64 f1.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( 3, 3 ) ) ); 65 f1.setAttributes( QgsAttributes() << QStringLiteral( "l" ) ); 66 QVERIFY( vl1->dataProvider()->addFeature( f1 ) ); 67 68 std::unique_ptr< QgsVectorLayer > vl2 = std::make_unique< QgsVectorLayer >( QStringLiteral( "Point?crs=epsg:3946&field=text:string" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) ); 69 QVERIFY( vl2->isValid() ); 70 f1.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( 1, 1 ) ) ); 71 f1.setAttributes( QgsAttributes() << QStringLiteral( "label" ) ); 72 QVERIFY( vl2->dataProvider()->addFeature( f1 ) ); 73 f1.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( 3, 3 ) ) ); 74 f1.setAttributes( QgsAttributes() << QStringLiteral( "label2" ) ); 75 QVERIFY( vl2->dataProvider()->addFeature( f1 ) ); 76 f1.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( 3, 1 ) ) ); 77 f1.setAttributes( QgsAttributes() << QStringLiteral( "label3" ) ); 78 QVERIFY( vl2->dataProvider()->addFeature( f1 ) ); 79 80 std::unique_ptr< QgsMapCanvas > canvas = std::make_unique< QgsMapCanvas >(); 81 canvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3946" ) ) ); 82 canvas->setLayers( QList<QgsMapLayer *>() << vl1.get() << vl2.get() ); 83 const std::unique_ptr< QgsAdvancedDigitizingDockWidget > advancedDigitizingDockWidget = std::make_unique< QgsAdvancedDigitizingDockWidget >( canvas.get() ); 84 85 QgsMapSettings mapSettings; 86 mapSettings.setOutputSize( QSize( 500, 500 ) ); 87 mapSettings.setExtent( QgsRectangle( -1, -1, 4, 4 ) ); 88 QVERIFY( mapSettings.hasValidSettings() ); 89 90 mapSettings.setLayers( QList<QgsMapLayer *>() << vl1.get() << vl2.get() ); 91 92 canvas->setFrameStyle( QFrame::NoFrame ); 93 canvas->resize( 500, 500 ); 94 canvas->setExtent( QgsRectangle( -1, -1, 4, 4 ) ); 95 canvas->show(); // to make the canvas resize 96 canvas->hide(); 97 QCOMPARE( canvas->mapSettings().outputSize(), QSize( 500, 500 ) ); 98 QCOMPARE( canvas->mapSettings().visibleExtent(), QgsRectangle( -1, -1, 4, 4 ) ); 99 100 std::unique_ptr< QgsMapToolLabel > tool( new QgsMapToolLabel( canvas.get(), advancedDigitizingDockWidget.get() ) ); 101 102 // no labels yet 103 QgsPointXY pt; 104 pt = tool->canvas()->mapSettings().mapToPixel().transform( 1, 1 ); 105 std::unique_ptr< QMouseEvent > event( new QMouseEvent( 106 QEvent::MouseButtonPress, 107 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 108 ) ); 109 QgsLabelPosition pos; 110 QVERIFY( !tool->labelAtPosition( event.get(), pos ) ); 111 112 // add some labels 113 QgsPalLayerSettings pls1; 114 pls1.fieldName = QStringLiteral( "text" ); 115 pls1.placement = QgsPalLayerSettings::OverPoint; 116 pls1.quadOffset = QgsPalLayerSettings::QuadrantOver; 117 pls1.displayAll = true; 118 QgsTextFormat format = pls1.format(); 119 format.setFont( QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) ) ); 120 format.setSize( 12 ); 121 pls1.setFormat( format ); 122 123 vl1->setLabeling( new QgsVectorLayerSimpleLabeling( pls1 ) ); 124 vl1->setLabelsEnabled( true ); 125 126 QEventLoop loop; 127 connect( canvas.get(), &QgsMapCanvas::mapCanvasRefreshed, &loop, &QEventLoop::quit ); 128 canvas->refreshAllLayers(); 129 canvas->show(); 130 loop.exec(); 131 132 QVERIFY( canvas->labelingResults() ); 133 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 134 QCOMPARE( pos.layerID, vl1->id() ); 135 QCOMPARE( pos.labelText, QStringLiteral( "label" ) ); 136 137 pt = tool->canvas()->mapSettings().mapToPixel().transform( 3, 3 ); 138 event = std::make_unique< QMouseEvent >( 139 QEvent::MouseButtonPress, 140 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 141 ); 142 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 143 QCOMPARE( pos.layerID, vl1->id() ); 144 QCOMPARE( pos.labelText, QStringLiteral( "l" ) ); 145 146 pt = tool->canvas()->mapSettings().mapToPixel().transform( 3, 1 ); 147 event = std::make_unique< QMouseEvent >( 148 QEvent::MouseButtonPress, 149 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 150 ); 151 QVERIFY( !tool->labelAtPosition( event.get(), pos ) ); 152 153 // label second layer 154 vl2->setLabeling( new QgsVectorLayerSimpleLabeling( pls1 ) ); 155 vl2->setLabelsEnabled( true ); 156 157 canvas->refreshAllLayers(); 158 canvas->show(); 159 loop.exec(); 160 161 // should prioritize current layer 162 canvas->setCurrentLayer( vl1.get() ); 163 pt = tool->canvas()->mapSettings().mapToPixel().transform( 1, 1 ); 164 event = std::make_unique< QMouseEvent >( 165 QEvent::MouseButtonPress, 166 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 167 ); 168 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 169 QCOMPARE( pos.layerID, vl1->id() ); 170 QCOMPARE( pos.labelText, QStringLiteral( "label" ) ); 171 172 pt = tool->canvas()->mapSettings().mapToPixel().transform( 3, 3 ); 173 event = std::make_unique< QMouseEvent >( 174 QEvent::MouseButtonPress, 175 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 176 ); 177 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 178 QCOMPARE( pos.layerID, vl1->id() ); 179 QCOMPARE( pos.labelText, QStringLiteral( "l" ) ); 180 181 //... but fallback to any labels if nothing in current layer 182 pt = tool->canvas()->mapSettings().mapToPixel().transform( 3, 1 ); 183 event = std::make_unique< QMouseEvent >( 184 QEvent::MouseButtonPress, 185 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 186 ); 187 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 188 QCOMPARE( pos.layerID, vl2->id() ); 189 QCOMPARE( pos.labelText, QStringLiteral( "label3" ) ); 190 191 canvas->setCurrentLayer( vl2.get() ); 192 pt = tool->canvas()->mapSettings().mapToPixel().transform( 1, 1 ); 193 event = std::make_unique< QMouseEvent >( 194 QEvent::MouseButtonPress, 195 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 196 ); 197 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 198 QCOMPARE( pos.layerID, vl2->id() ); 199 QCOMPARE( pos.labelText, QStringLiteral( "label" ) ); 200 201 pt = tool->canvas()->mapSettings().mapToPixel().transform( 3, 3 ); 202 event = std::make_unique< QMouseEvent >( 203 QEvent::MouseButtonPress, 204 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 205 ); 206 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 207 QCOMPARE( pos.layerID, vl2->id() ); 208 QCOMPARE( pos.labelText, QStringLiteral( "label2" ) ); 209 pt = tool->canvas()->mapSettings().mapToPixel().transform( 3, 1 ); 210 event = std::make_unique< QMouseEvent >( 211 QEvent::MouseButtonPress, 212 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 213 ); 214 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 215 QCOMPARE( pos.layerID, vl2->id() ); 216 QCOMPARE( pos.labelText, QStringLiteral( "label3" ) ); 217 218 canvas->setCurrentLayer( nullptr ); 219 220 // when multiple candidates exist, pick the smallest 221 pt = tool->canvas()->mapSettings().mapToPixel().transform( 3, 3 ); 222 event = std::make_unique< QMouseEvent >( 223 QEvent::MouseButtonPress, 224 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 225 ); 226 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 227 QCOMPARE( pos.layerID, vl1->id() ); 228 QCOMPARE( pos.labelText, QStringLiteral( "l" ) ); 229 } 230 testAlignment()231 void testAlignment() 232 { 233 QgsVectorLayer *vl1 = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:3946&field=halig:string&field=valig:string" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) ); 234 QVERIFY( vl1->isValid() ); 235 QgsProject::instance()->addMapLayer( vl1 ); 236 QgsFeature f1; 237 f1.setAttributes( QgsAttributes() << QStringLiteral( "right" ) << QStringLiteral( "top" ) ); 238 f1.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( 1, 1 ) ) ); 239 QVERIFY( vl1->dataProvider()->addFeature( f1 ) ); 240 f1.setGeometry( QgsGeometry::fromPointXY( QgsPointXY( 3, 3 ) ) ); 241 f1.setAttributes( QgsAttributes() << QStringLiteral( "center" ) << QStringLiteral( "base" ) ); 242 QVERIFY( vl1->dataProvider()->addFeature( f1 ) ); 243 244 std::unique_ptr< QgsMapCanvas > canvas = std::make_unique< QgsMapCanvas >(); 245 canvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3946" ) ) ); 246 canvas->setLayers( QList<QgsMapLayer *>() << vl1 ); 247 const std::unique_ptr< QgsAdvancedDigitizingDockWidget > advancedDigitizingDockWidget = std::make_unique< QgsAdvancedDigitizingDockWidget >( canvas.get() ); 248 249 QgsMapSettings mapSettings; 250 mapSettings.setOutputSize( QSize( 500, 500 ) ); 251 mapSettings.setExtent( QgsRectangle( -1, -1, 4, 4 ) ); 252 QVERIFY( mapSettings.hasValidSettings() ); 253 254 mapSettings.setLayers( QList<QgsMapLayer *>() << vl1 ); 255 256 canvas->setFrameStyle( QFrame::NoFrame ); 257 canvas->resize( 500, 500 ); 258 canvas->setExtent( QgsRectangle( -1, -1, 4, 4 ) ); 259 canvas->show(); // to make the canvas resize 260 canvas->hide(); 261 QCOMPARE( canvas->mapSettings().outputSize(), QSize( 500, 500 ) ); 262 QCOMPARE( canvas->mapSettings().visibleExtent(), QgsRectangle( -1, -1, 4, 4 ) ); 263 264 std::unique_ptr< QgsMapToolLabel > tool( new QgsMapToolLabel( canvas.get(), advancedDigitizingDockWidget.get() ) ); 265 266 // add some labels 267 QgsPalLayerSettings pls1; 268 pls1.fieldName = QStringLiteral( "'label'" ); 269 pls1.isExpression = true; 270 pls1.placement = QgsPalLayerSettings::OverPoint; 271 pls1.quadOffset = QgsPalLayerSettings::QuadrantOver; 272 pls1.displayAll = true; 273 QgsTextFormat format = pls1.format(); 274 format.setFont( QgsFontUtils::getStandardTestFont( QStringLiteral( "Bold" ) ) ); 275 format.setSize( 12 ); 276 pls1.setFormat( format ); 277 278 vl1->setLabeling( new QgsVectorLayerSimpleLabeling( pls1 ) ); 279 vl1->setLabelsEnabled( true ); 280 281 QEventLoop loop; 282 connect( canvas.get(), &QgsMapCanvas::mapCanvasRefreshed, &loop, &QEventLoop::quit ); 283 canvas->refreshAllLayers(); 284 canvas->show(); 285 loop.exec(); 286 287 QVERIFY( canvas->labelingResults() ); 288 QgsPointXY pt; 289 pt = tool->canvas()->mapSettings().mapToPixel().transform( 1, 1 ); 290 std::unique_ptr< QMouseEvent > event( new QMouseEvent( 291 QEvent::MouseButtonPress, 292 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 293 ) ); 294 QgsLabelPosition pos; 295 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 296 QCOMPARE( pos.layerID, vl1->id() ); 297 QCOMPARE( pos.labelText, QStringLiteral( "label" ) ); 298 tool->mCurrentLabel = QgsMapToolLabel::LabelDetails( pos, canvas.get() ); 299 300 // defaults to bottom left 301 QString hali, vali; 302 tool->currentAlignment( hali, vali ); 303 QCOMPARE( hali, QStringLiteral( "Left" ) ); 304 QCOMPARE( vali, QStringLiteral( "Bottom" ) ); 305 306 // using field bound alignment 307 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::Hali, QgsProperty::fromField( QStringLiteral( "halig" ) ) ); 308 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::Vali, QgsProperty::fromField( QStringLiteral( "valig" ) ) ); 309 vl1->setLabeling( new QgsVectorLayerSimpleLabeling( pls1 ) ); 310 311 canvas->refreshAllLayers(); 312 canvas->show(); 313 loop.exec(); 314 315 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 316 QCOMPARE( pos.layerID, vl1->id() ); 317 QCOMPARE( pos.labelText, QStringLiteral( "label" ) ); 318 tool->mCurrentLabel = QgsMapToolLabel::LabelDetails( pos, canvas.get() ); 319 320 tool->currentAlignment( hali, vali ); 321 QCOMPARE( hali, QStringLiteral( "right" ) ); 322 QCOMPARE( vali, QStringLiteral( "top" ) ); 323 324 pt = tool->canvas()->mapSettings().mapToPixel().transform( 3, 3 ); 325 event = std::make_unique< QMouseEvent >( 326 QEvent::MouseButtonPress, 327 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 328 ); 329 330 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 331 QCOMPARE( pos.layerID, vl1->id() ); 332 QCOMPARE( pos.labelText, QStringLiteral( "label" ) ); 333 tool->mCurrentLabel = QgsMapToolLabel::LabelDetails( pos, canvas.get() ); 334 335 tool->currentAlignment( hali, vali ); 336 QCOMPARE( hali, QStringLiteral( "center" ) ); 337 QCOMPARE( vali, QStringLiteral( "base" ) ); 338 339 // now try with expression based alignment 340 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::Hali, QgsProperty::fromExpression( QStringLiteral( "case when $id % 2 = 0 then 'right' else 'left' end" ) ) ); 341 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::Vali, QgsProperty::fromExpression( QStringLiteral( "case when $id % 2 = 0 then 'half' else 'cap' end" ) ) ); 342 vl1->setLabeling( new QgsVectorLayerSimpleLabeling( pls1 ) ); 343 344 canvas->refreshAllLayers(); 345 canvas->show(); 346 loop.exec(); 347 348 pt = tool->canvas()->mapSettings().mapToPixel().transform( 1, 1 ); 349 event = std::make_unique< QMouseEvent >( 350 QEvent::MouseButtonPress, 351 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 352 ); 353 354 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 355 QCOMPARE( pos.layerID, vl1->id() ); 356 QCOMPARE( pos.labelText, QStringLiteral( "label" ) ); 357 tool->mCurrentLabel = QgsMapToolLabel::LabelDetails( pos, canvas.get() ); 358 359 tool->currentAlignment( hali, vali ); 360 QCOMPARE( hali, QStringLiteral( "left" ) ); 361 QCOMPARE( vali, QStringLiteral( "cap" ) ); 362 363 pt = tool->canvas()->mapSettings().mapToPixel().transform( 3, 3 ); 364 event = std::make_unique< QMouseEvent >( 365 QEvent::MouseButtonPress, 366 QPoint( std::round( pt.x() ), std::round( pt.y() ) ), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier 367 ); 368 369 QVERIFY( tool->labelAtPosition( event.get(), pos ) ); 370 QCOMPARE( pos.layerID, vl1->id() ); 371 QCOMPARE( pos.labelText, QStringLiteral( "label" ) ); 372 tool->mCurrentLabel = QgsMapToolLabel::LabelDetails( pos, canvas.get() ); 373 374 tool->currentAlignment( hali, vali ); 375 QCOMPARE( hali, QStringLiteral( "right" ) ); 376 QCOMPARE( vali, QStringLiteral( "half" ) ); 377 } 378 dataDefinedColumnName()379 void dataDefinedColumnName() 380 { 381 QgsVectorLayer *vl1 = new QgsVectorLayer( QStringLiteral( "Point?crs=epsg:3946&field=label_x_1:string&field=label_y_1:string&field=label_x_2:string&field=label_y_2:string&field=override_x_field:string" ), QStringLiteral( "vl1" ), QStringLiteral( "memory" ) ); 382 QVERIFY( vl1->isValid() ); 383 QgsProject::instance()->addMapLayer( vl1 ); 384 385 std::unique_ptr< QgsMapCanvas > canvas = std::make_unique< QgsMapCanvas >(); 386 canvas->setDestinationCrs( QgsCoordinateReferenceSystem( QStringLiteral( "EPSG:3946" ) ) ); 387 canvas->setLayers( QList<QgsMapLayer *>() << vl1 ); 388 const std::unique_ptr< QgsAdvancedDigitizingDockWidget > advancedDigitizingDockWidget = std::make_unique< QgsAdvancedDigitizingDockWidget >( canvas.get() ); 389 390 std::unique_ptr< QgsMapToolLabel > tool( new QgsMapToolLabel( canvas.get(), advancedDigitizingDockWidget.get() ) ); 391 392 QgsExpressionContextUtils::setProjectVariable( QgsProject::instance(), QStringLiteral( "var_1" ), QStringLiteral( "1" ) ); 393 394 // add some labels 395 QgsPalLayerSettings pls1; 396 pls1.fieldName = QStringLiteral( "'label'" ); 397 398 // not using a column 399 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::PositionX, QgsProperty::fromValue( 5 ) ); 400 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::PositionY, QgsProperty::fromValue( 6 ) ); 401 402 vl1->setLabeling( new QgsVectorLayerSimpleLabeling( pls1 ) ); 403 vl1->setLabelsEnabled( true ); 404 405 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::AlwaysShow, pls1, vl1 ), QString() ); 406 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionX, pls1, vl1 ), QString() ); 407 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionY, pls1, vl1 ), QString() ); 408 409 // using direct field references 410 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::PositionX, QgsProperty::fromField( QStringLiteral( "label_x_2" ) ) ); 411 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::PositionY, QgsProperty::fromField( QStringLiteral( "label_y_2" ) ) ); 412 413 vl1->setLabeling( new QgsVectorLayerSimpleLabeling( pls1 ) ); 414 vl1->setLabelsEnabled( true ); 415 416 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::AlwaysShow, pls1, vl1 ), QString() ); 417 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionX, pls1, vl1 ), QStringLiteral( "label_x_2" ) ); 418 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionY, pls1, vl1 ), QStringLiteral( "label_y_2" ) ); 419 420 // using expressions which are just field references, should still work 421 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::PositionX, QgsProperty::fromExpression( QStringLiteral( "\"label_x_1\"" ) ) ); 422 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::PositionY, QgsProperty::fromExpression( QStringLiteral( "\"label_y_1\"" ) ) ); 423 424 vl1->setLabeling( new QgsVectorLayerSimpleLabeling( pls1 ) ); 425 vl1->setLabelsEnabled( true ); 426 427 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::AlwaysShow, pls1, vl1 ), QString() ); 428 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionX, pls1, vl1 ), QStringLiteral( "label_x_1" ) ); 429 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionY, pls1, vl1 ), QStringLiteral( "label_y_1" ) ); 430 431 432 // using complex expressions which change field depending on a project level variable 433 434 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::PositionX, QgsProperty::fromExpression( QStringLiteral( "case when @var_1 = '1' then \"label_x_1\" else \"label_x_2\" end" ) ) ); 435 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::PositionY, QgsProperty::fromExpression( QStringLiteral( "case when @var_1 = '1' then \"label_y_1\" else \"label_y_2\" end" ) ) ); 436 vl1->setLabeling( new QgsVectorLayerSimpleLabeling( pls1 ) ); 437 vl1->setLabelsEnabled( true ); 438 439 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::AlwaysShow, pls1, vl1 ), QString() ); 440 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionX, pls1, vl1 ), QStringLiteral( "label_x_1" ) ); 441 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionY, pls1, vl1 ), QStringLiteral( "label_y_1" ) ); 442 443 QgsExpressionContextUtils::setProjectVariable( QgsProject::instance(), QStringLiteral( "var_1" ), QStringLiteral( "2" ) ); 444 445 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::AlwaysShow, pls1, vl1 ), QString() ); 446 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionX, pls1, vl1 ), QStringLiteral( "label_x_2" ) ); 447 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionY, pls1, vl1 ), QStringLiteral( "label_y_2" ) ); 448 449 // another smart situation -- an expression which uses coalesce to store per-feature overrides in a field, otherwise falling back to some complex expression 450 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::PositionX, QgsProperty::fromExpression( QStringLiteral( "coalesce(\"override_x_field\", $x + 10)" ) ) ); 451 pls1.dataDefinedProperties().setProperty( QgsPalLayerSettings::PositionY, QgsProperty::fromExpression( QStringLiteral( "COALESCE(case when @var_1 = '1' then \"label_y_1\" else \"label_y_2\" end, $y-20)" ) ) ); 452 vl1->setLabeling( new QgsVectorLayerSimpleLabeling( pls1 ) ); 453 vl1->setLabelsEnabled( true ); 454 455 QgsExpressionContextUtils::setProjectVariable( QgsProject::instance(), QStringLiteral( "var_1" ), QStringLiteral( "1" ) ); 456 457 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::AlwaysShow, pls1, vl1 ), QString() ); 458 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionX, pls1, vl1 ), QStringLiteral( "override_x_field" ) ); 459 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionY, pls1, vl1 ), QStringLiteral( "label_y_1" ) ); 460 461 QgsExpressionContextUtils::setProjectVariable( QgsProject::instance(), QStringLiteral( "var_1" ), QStringLiteral( "2" ) ); 462 463 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::AlwaysShow, pls1, vl1 ), QString() ); 464 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionX, pls1, vl1 ), QStringLiteral( "override_x_field" ) ); 465 QCOMPARE( tool->dataDefinedColumnName( QgsPalLayerSettings::PositionY, pls1, vl1 ), QStringLiteral( "label_y_2" ) ); 466 } 467 468 469 }; 470 471 QGSTEST_MAIN( TestQgsMapToolLabel ) 472 #include "testqgsmaptoollabel.moc" 473