1# -*- coding: utf-8 -*- 2"""QGIS Unit tests for QgsLayoutView. 3 4.. note:: This program is free software; you can redistribute it and/or modify 5it under the terms of the GNU General Public License as published by 6the Free Software Foundation; either version 2 of the License, or 7(at your option) any later version. 8""" 9__author__ = 'Nyall Dawson' 10__date__ = '05/07/2017' 11__copyright__ = 'Copyright 2017, The QGIS Project' 12 13import qgis # NOQA 14from qgis.PyQt import sip 15from qgis.core import (QgsProject, 16 QgsLayout, 17 QgsUnitTypes, 18 QgsLayoutItemPicture, 19 QgsLayoutItemLabel, 20 QgsLayoutItemHtml, 21 QgsLayoutItemRegistry, 22 QgsLayoutFrame, 23 QgsLayoutPoint, 24 QgsLayoutSize, 25 QgsLayoutAligner) 26from qgis.gui import QgsLayoutView 27from qgis.PyQt.QtCore import QRectF, QMimeData, QByteArray 28from qgis.PyQt.QtGui import QTransform 29from qgis.PyQt.QtWidgets import QApplication 30from qgis.PyQt.QtTest import QSignalSpy 31 32from qgis.testing import start_app, unittest 33 34start_app() 35 36 37class TestQgsLayoutView(unittest.TestCase): 38 39 def testScaleSafe(self): 40 """ test scaleSafe method """ 41 42 view = QgsLayoutView() 43 view.fitInView(QRectF(0, 0, 10, 10)) 44 scale = view.transform().m11() 45 view.scaleSafe(2) 46 self.assertAlmostEqual(view.transform().m11(), 2) 47 view.scaleSafe(4) 48 self.assertAlmostEqual(view.transform().m11(), 8) 49 50 # try to zoom in heaps 51 view.scaleSafe(99999999) 52 # assume we have hit the limit 53 scale = view.transform().m11() 54 view.scaleSafe(2) 55 self.assertAlmostEqual(view.transform().m11(), scale) 56 57 view.setTransform(QTransform.fromScale(1, 1)) 58 self.assertAlmostEqual(view.transform().m11(), 1) 59 # test zooming out 60 view.scaleSafe(0.5) 61 self.assertAlmostEqual(view.transform().m11(), 0.5) 62 view.scaleSafe(0.1) 63 self.assertAlmostEqual(view.transform().m11(), 0.05) 64 65 # try zooming out heaps 66 view.scaleSafe(0.000000001) 67 # assume we have hit the limit 68 scale = view.transform().m11() 69 view.scaleSafe(0.5) 70 self.assertAlmostEqual(view.transform().m11(), scale) 71 72 def testLayoutScalePixels(self): 73 p = QgsProject() 74 l = QgsLayout(p) 75 l.setUnits(QgsUnitTypes.LayoutPixels) 76 view = QgsLayoutView() 77 view.setCurrentLayout(l) 78 view.setZoomLevel(1) 79 # should be no transform, since 100% with pixel units should be pixel-pixel 80 self.assertEqual(view.transform().m11(), 1) 81 view.setZoomLevel(0.5) 82 self.assertEqual(view.transform().m11(), 0.5) 83 84 def testSelectAll(self): 85 p = QgsProject() 86 l = QgsLayout(p) 87 88 # add some items 89 item1 = QgsLayoutItemPicture(l) 90 l.addItem(item1) 91 item2 = QgsLayoutItemPicture(l) 92 l.addItem(item2) 93 item3 = QgsLayoutItemPicture(l) 94 item3.setLocked(True) 95 l.addItem(item3) 96 97 view = QgsLayoutView() 98 # no layout, no crash 99 view.selectAll() 100 101 view.setCurrentLayout(l) 102 103 focused_item_spy = QSignalSpy(view.itemFocused) 104 105 view.selectAll() 106 self.assertTrue(item1.isSelected()) 107 self.assertTrue(item2.isSelected()) 108 self.assertFalse(item3.isSelected()) # locked 109 110 self.assertEqual(len(focused_item_spy), 1) 111 112 item3.setSelected(True) # locked item selection should be cleared 113 view.selectAll() 114 self.assertTrue(item1.isSelected()) 115 self.assertTrue(item2.isSelected()) 116 self.assertFalse(item3.isSelected()) # locked 117 118 def testDeselectAll(self): 119 p = QgsProject() 120 l = QgsLayout(p) 121 122 # add some items 123 item1 = QgsLayoutItemPicture(l) 124 l.addItem(item1) 125 item2 = QgsLayoutItemPicture(l) 126 l.addItem(item2) 127 item3 = QgsLayoutItemPicture(l) 128 item3.setLocked(True) 129 l.addItem(item3) 130 131 view = QgsLayoutView() 132 # no layout, no crash 133 view.deselectAll() 134 135 view.setCurrentLayout(l) 136 137 focused_item_spy = QSignalSpy(view.itemFocused) 138 139 view.deselectAll() 140 self.assertFalse(item1.isSelected()) 141 self.assertFalse(item2.isSelected()) 142 self.assertFalse(item3.isSelected()) 143 144 self.assertEqual(len(focused_item_spy), 1) 145 146 item1.setSelected(True) 147 item2.setSelected(True) 148 item3.setSelected(True) 149 view.deselectAll() 150 self.assertFalse(item1.isSelected()) 151 self.assertFalse(item2.isSelected()) 152 self.assertFalse(item3.isSelected()) 153 154 def testInvertSelection(self): 155 p = QgsProject() 156 l = QgsLayout(p) 157 158 # add some items 159 item1 = QgsLayoutItemPicture(l) 160 l.addItem(item1) 161 item2 = QgsLayoutItemPicture(l) 162 l.addItem(item2) 163 item3 = QgsLayoutItemPicture(l) 164 item3.setLocked(True) 165 l.addItem(item3) 166 167 view = QgsLayoutView() 168 # no layout, no crash 169 view.invertSelection() 170 171 view.setCurrentLayout(l) 172 173 focused_item_spy = QSignalSpy(view.itemFocused) 174 175 view.invertSelection() 176 self.assertTrue(item1.isSelected()) 177 self.assertTrue(item2.isSelected()) 178 self.assertFalse(item3.isSelected()) # locked 179 180 self.assertEqual(len(focused_item_spy), 1) 181 182 item3.setSelected(True) # locked item selection should be cleared 183 view.invertSelection() 184 self.assertFalse(item1.isSelected()) 185 self.assertFalse(item2.isSelected()) 186 self.assertFalse(item3.isSelected()) # locked 187 188 def testSelectNextByZOrder(self): 189 p = QgsProject() 190 l = QgsLayout(p) 191 192 # add some items 193 item1 = QgsLayoutItemPicture(l) 194 l.addItem(item1) 195 item2 = QgsLayoutItemPicture(l) 196 l.addItem(item2) 197 item3 = QgsLayoutItemPicture(l) 198 item3.setLocked(True) 199 l.addItem(item3) 200 201 view = QgsLayoutView() 202 # no layout, no crash 203 view.selectNextItemAbove() 204 view.selectNextItemBelow() 205 206 view.setCurrentLayout(l) 207 208 focused_item_spy = QSignalSpy(view.itemFocused) 209 210 # no selection 211 view.selectNextItemAbove() 212 view.selectNextItemBelow() 213 self.assertEqual(len(focused_item_spy), 0) 214 215 l.setSelectedItem(item1) 216 self.assertEqual(len(focused_item_spy), 1) 217 # already bottom most 218 view.selectNextItemBelow() 219 self.assertTrue(item1.isSelected()) 220 self.assertFalse(item2.isSelected()) 221 self.assertFalse(item3.isSelected()) 222 self.assertEqual(len(focused_item_spy), 1) 223 224 view.selectNextItemAbove() 225 self.assertFalse(item1.isSelected()) 226 self.assertTrue(item2.isSelected()) 227 self.assertFalse(item3.isSelected()) 228 self.assertEqual(len(focused_item_spy), 2) 229 230 view.selectNextItemAbove() 231 self.assertFalse(item1.isSelected()) 232 self.assertFalse(item2.isSelected()) 233 self.assertTrue(item3.isSelected()) 234 self.assertEqual(len(focused_item_spy), 3) 235 236 view.selectNextItemAbove() # already top most 237 self.assertFalse(item1.isSelected()) 238 self.assertFalse(item2.isSelected()) 239 self.assertTrue(item3.isSelected()) 240 self.assertEqual(len(focused_item_spy), 3) 241 242 view.selectNextItemBelow() 243 self.assertFalse(item1.isSelected()) 244 self.assertTrue(item2.isSelected()) 245 self.assertFalse(item3.isSelected()) 246 self.assertEqual(len(focused_item_spy), 4) 247 248 view.selectNextItemBelow() 249 self.assertTrue(item1.isSelected()) 250 self.assertFalse(item2.isSelected()) 251 self.assertFalse(item3.isSelected()) 252 self.assertEqual(len(focused_item_spy), 5) 253 254 view.selectNextItemBelow() # back to bottom most 255 self.assertTrue(item1.isSelected()) 256 self.assertFalse(item2.isSelected()) 257 self.assertFalse(item3.isSelected()) 258 self.assertEqual(len(focused_item_spy), 5) 259 260 def testLockActions(self): 261 p = QgsProject() 262 l = QgsLayout(p) 263 264 view = QgsLayoutView() 265 view.setCurrentLayout(l) 266 267 # add some items 268 item1 = QgsLayoutItemPicture(l) 269 l.addItem(item1) 270 item2 = QgsLayoutItemPicture(l) 271 l.addItem(item2) 272 item3 = QgsLayoutItemPicture(l) 273 l.addItem(item3) 274 275 item1.setLocked(True) 276 item3.setLocked(True) 277 self.assertTrue(item1.isLocked()) 278 self.assertFalse(item2.isLocked()) 279 self.assertTrue(item3.isLocked()) 280 281 view.unlockAllItems() 282 self.assertFalse(item1.isLocked()) 283 self.assertFalse(item2.isLocked()) 284 self.assertFalse(item3.isLocked()) 285 self.assertTrue(item1.isSelected()) 286 self.assertFalse(item2.isSelected()) 287 self.assertTrue(item3.isSelected()) 288 289 view.lockSelectedItems() 290 self.assertTrue(item1.isLocked()) 291 self.assertFalse(item2.isLocked()) 292 self.assertTrue(item3.isLocked()) 293 self.assertFalse(item1.isSelected()) 294 self.assertFalse(item2.isSelected()) 295 self.assertFalse(item3.isSelected()) 296 297 def testStacking(self): 298 p = QgsProject() 299 l = QgsLayout(p) 300 301 # add some items 302 item1 = QgsLayoutItemPicture(l) 303 l.addLayoutItem(item1) 304 item2 = QgsLayoutItemPicture(l) 305 l.addLayoutItem(item2) 306 item3 = QgsLayoutItemPicture(l) 307 l.addLayoutItem(item3) 308 309 view = QgsLayoutView() 310 view.setCurrentLayout(l) 311 312 self.assertEqual(item1.zValue(), 1) 313 self.assertEqual(item2.zValue(), 2) 314 self.assertEqual(item3.zValue(), 3) 315 316 # no effect interactions 317 view.raiseSelectedItems() 318 view.lowerSelectedItems() 319 view.moveSelectedItemsToTop() 320 view.moveSelectedItemsToBottom() 321 322 self.assertEqual(item1.zValue(), 1) 323 self.assertEqual(item2.zValue(), 2) 324 self.assertEqual(item3.zValue(), 3) 325 326 # raising 327 item3.setSelected(True) 328 view.raiseSelectedItems() 329 self.assertEqual(item1.zValue(), 1) 330 self.assertEqual(item2.zValue(), 2) 331 self.assertEqual(item3.zValue(), 3) 332 333 item3.setSelected(False) 334 item2.setSelected(True) 335 view.raiseSelectedItems() 336 self.assertEqual(item1.zValue(), 1) 337 self.assertEqual(item2.zValue(), 3) 338 self.assertEqual(item3.zValue(), 2) 339 340 view.raiseSelectedItems() 341 self.assertEqual(item1.zValue(), 1) 342 self.assertEqual(item2.zValue(), 3) 343 self.assertEqual(item3.zValue(), 2) 344 345 item2.setSelected(False) 346 item1.setSelected(True) 347 view.raiseSelectedItems() 348 self.assertEqual(item1.zValue(), 2) 349 self.assertEqual(item2.zValue(), 3) 350 self.assertEqual(item3.zValue(), 1) 351 352 # lower 353 item1.setSelected(False) 354 item3.setSelected(True) 355 view.lowerSelectedItems() 356 self.assertEqual(item1.zValue(), 2) 357 self.assertEqual(item2.zValue(), 3) 358 self.assertEqual(item3.zValue(), 1) 359 360 item3.setSelected(False) 361 item2.setSelected(True) 362 view.lowerSelectedItems() 363 self.assertEqual(item1.zValue(), 3) 364 self.assertEqual(item2.zValue(), 2) 365 self.assertEqual(item3.zValue(), 1) 366 367 view.lowerSelectedItems() 368 self.assertEqual(item1.zValue(), 3) 369 self.assertEqual(item2.zValue(), 1) 370 self.assertEqual(item3.zValue(), 2) 371 372 # raise to top 373 item2.setSelected(False) 374 item1.setSelected(True) 375 view.moveSelectedItemsToTop() 376 self.assertEqual(item1.zValue(), 3) 377 self.assertEqual(item2.zValue(), 1) 378 self.assertEqual(item3.zValue(), 2) 379 380 item1.setSelected(False) 381 item3.setSelected(True) 382 view.moveSelectedItemsToTop() 383 self.assertEqual(item1.zValue(), 2) 384 self.assertEqual(item2.zValue(), 1) 385 self.assertEqual(item3.zValue(), 3) 386 387 item3.setSelected(False) 388 item2.setSelected(True) 389 view.moveSelectedItemsToTop() 390 self.assertEqual(item1.zValue(), 1) 391 self.assertEqual(item2.zValue(), 3) 392 self.assertEqual(item3.zValue(), 2) 393 394 # move to bottom 395 item2.setSelected(False) 396 item1.setSelected(True) 397 view.moveSelectedItemsToBottom() 398 self.assertEqual(item1.zValue(), 1) 399 self.assertEqual(item2.zValue(), 3) 400 self.assertEqual(item3.zValue(), 2) 401 402 item1.setSelected(False) 403 item3.setSelected(True) 404 view.moveSelectedItemsToBottom() 405 self.assertEqual(item1.zValue(), 2) 406 self.assertEqual(item2.zValue(), 3) 407 self.assertEqual(item3.zValue(), 1) 408 409 item3.setSelected(False) 410 item2.setSelected(True) 411 view.moveSelectedItemsToBottom() 412 self.assertEqual(item1.zValue(), 3) 413 self.assertEqual(item2.zValue(), 1) 414 self.assertEqual(item3.zValue(), 2) 415 416 def testAlign(self): 417 p = QgsProject() 418 l = QgsLayout(p) 419 420 # add some items 421 item1 = QgsLayoutItemPicture(l) 422 item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutMillimeters)) 423 item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 424 l.addItem(item1) 425 item2 = QgsLayoutItemPicture(l) 426 item2.attemptMove(QgsLayoutPoint(6, 10, QgsUnitTypes.LayoutMillimeters)) 427 item2.attemptResize(QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 428 l.addItem(item2) 429 item3 = QgsLayoutItemPicture(l) 430 item3.attemptMove(QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutCentimeters)) 431 item3.attemptResize(QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 432 l.addItem(item3) 433 434 view = QgsLayoutView() 435 view.setCurrentLayout(l) 436 437 view.alignSelectedItems(QgsLayoutAligner.AlignLeft) 438 439 item1.setSelected(True) 440 item2.setSelected(True) 441 item3.setSelected(True) 442 443 view.alignSelectedItems(QgsLayoutAligner.AlignLeft) 444 self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutMillimeters)) 445 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 446 self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(4, 10, QgsUnitTypes.LayoutMillimeters)) 447 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 448 self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(0.4, 1.2, QgsUnitTypes.LayoutCentimeters)) 449 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 450 451 view.alignSelectedItems(QgsLayoutAligner.AlignHCenter) 452 self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutMillimeters)) 453 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 454 self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(8, 10, QgsUnitTypes.LayoutMillimeters)) 455 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 456 self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(0.4, 1.2, QgsUnitTypes.LayoutCentimeters)) 457 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 458 459 view.alignSelectedItems(QgsLayoutAligner.AlignRight) 460 self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutMillimeters)) 461 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 462 self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(12, 10, QgsUnitTypes.LayoutMillimeters)) 463 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 464 self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(0.4, 1.2, QgsUnitTypes.LayoutCentimeters)) 465 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 466 467 view.alignSelectedItems(QgsLayoutAligner.AlignTop) 468 self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutMillimeters)) 469 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 470 self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(12, 8, QgsUnitTypes.LayoutMillimeters)) 471 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 472 self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(0.4, 0.8, QgsUnitTypes.LayoutCentimeters)) 473 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 474 475 view.alignSelectedItems(QgsLayoutAligner.AlignVCenter) 476 self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 10, QgsUnitTypes.LayoutMillimeters)) 477 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 478 self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(12, 11.5, QgsUnitTypes.LayoutMillimeters)) 479 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 480 self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(0.4, 0.8, QgsUnitTypes.LayoutCentimeters)) 481 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 482 483 view.alignSelectedItems(QgsLayoutAligner.AlignBottom) 484 self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 12, QgsUnitTypes.LayoutMillimeters)) 485 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 486 self.assertEqual(item2.positionWithUnits(), QgsLayoutPoint(12, 15, QgsUnitTypes.LayoutMillimeters)) 487 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 488 self.assertEqual(item3.positionWithUnits(), QgsLayoutPoint(0.4, 0.8, QgsUnitTypes.LayoutCentimeters)) 489 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 490 491 def testDistribute(self): 492 p = QgsProject() 493 l = QgsLayout(p) 494 495 # add some items 496 item1 = QgsLayoutItemPicture(l) 497 item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutMillimeters)) 498 item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 499 l.addItem(item1) 500 item2 = QgsLayoutItemPicture(l) 501 item2.attemptMove(QgsLayoutPoint(7, 10, QgsUnitTypes.LayoutMillimeters)) 502 item2.attemptResize(QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 503 l.addItem(item2) 504 item3 = QgsLayoutItemPicture(l) 505 item3.attemptMove(QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutCentimeters)) 506 item3.attemptResize(QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 507 l.addItem(item3) 508 509 view = QgsLayoutView() 510 view.setCurrentLayout(l) 511 512 view.distributeSelectedItems(QgsLayoutAligner.DistributeLeft) 513 514 item1.setSelected(True) 515 item2.setSelected(True) 516 item3.setSelected(True) 517 518 view.distributeSelectedItems(QgsLayoutAligner.DistributeLeft) 519 self.assertEqual(item1.positionWithUnits(), QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutMillimeters)) 520 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 521 self.assertAlmostEqual(item2.positionWithUnits().x(), 6.0, 3) 522 self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutMillimeters) 523 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 524 self.assertAlmostEqual(item3.positionWithUnits().x(), 0.8, 3) 525 self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutCentimeters) 526 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 527 528 view.distributeSelectedItems(QgsLayoutAligner.DistributeHCenter) 529 self.assertAlmostEqual(item1.positionWithUnits().x(), 5.0, 3) 530 self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutMillimeters) 531 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 532 self.assertAlmostEqual(item2.positionWithUnits().x(), 6.0, 3) 533 self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutMillimeters) 534 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 535 self.assertAlmostEqual(item3.positionWithUnits().x(), 0.8, 3) 536 self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutCentimeters) 537 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 538 539 view.distributeSelectedItems(QgsLayoutAligner.DistributeRight) 540 self.assertAlmostEqual(item1.positionWithUnits().x(), 3.0, 3) 541 self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutMillimeters) 542 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 543 self.assertAlmostEqual(item2.positionWithUnits().x(), 6.0, 3) 544 self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutMillimeters) 545 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 546 self.assertAlmostEqual(item3.positionWithUnits().x(), 0.8, 3) 547 self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutCentimeters) 548 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 549 550 view.distributeSelectedItems(QgsLayoutAligner.DistributeTop) 551 self.assertAlmostEqual(item1.positionWithUnits().y(), 8.0, 3) 552 self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutMillimeters) 553 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 554 self.assertAlmostEqual(item2.positionWithUnits().y(), 10.0, 3) 555 self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutMillimeters) 556 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 557 self.assertAlmostEqual(item3.positionWithUnits().y(), 1.2, 3) 558 self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutCentimeters) 559 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 560 561 view.distributeSelectedItems(QgsLayoutAligner.DistributeVCenter) 562 self.assertAlmostEqual(item1.positionWithUnits().y(), 8.0, 3) 563 self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutMillimeters) 564 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 565 self.assertAlmostEqual(item2.positionWithUnits().y(), 12.5, 3) 566 self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutMillimeters) 567 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 568 self.assertAlmostEqual(item3.positionWithUnits().y(), 1.2, 3) 569 self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutCentimeters) 570 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 571 572 view.distributeSelectedItems(QgsLayoutAligner.DistributeBottom) 573 self.assertAlmostEqual(item1.positionWithUnits().y(), 8.0, 3) 574 self.assertEqual(item1.positionWithUnits().units(), QgsUnitTypes.LayoutMillimeters) 575 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 576 self.assertAlmostEqual(item2.positionWithUnits().y(), 15.0, 3) 577 self.assertEqual(item2.positionWithUnits().units(), QgsUnitTypes.LayoutMillimeters) 578 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 579 self.assertAlmostEqual(item3.positionWithUnits().y(), 1.2, 3) 580 self.assertEqual(item3.positionWithUnits().units(), QgsUnitTypes.LayoutCentimeters) 581 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 582 583 def testResize(self): 584 p = QgsProject() 585 l = QgsLayout(p) 586 587 # add some items 588 item1 = QgsLayoutItemPicture(l) 589 item1.attemptMove(QgsLayoutPoint(4, 8, QgsUnitTypes.LayoutMillimeters)) 590 item1.attemptResize(QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 591 l.addItem(item1) 592 item2 = QgsLayoutItemPicture(l) 593 item2.attemptMove(QgsLayoutPoint(7, 10, QgsUnitTypes.LayoutMillimeters)) 594 item2.attemptResize(QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 595 l.addItem(item2) 596 item3 = QgsLayoutItemPicture(l) 597 item3.attemptMove(QgsLayoutPoint(0.8, 1.2, QgsUnitTypes.LayoutCentimeters)) 598 item3.attemptResize(QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 599 l.addItem(item3) 600 601 view = QgsLayoutView() 602 view.setCurrentLayout(l) 603 604 view.resizeSelectedItems(QgsLayoutAligner.ResizeNarrowest) 605 606 item1.setSelected(True) 607 item2.setSelected(True) 608 item3.setSelected(True) 609 610 view.resizeSelectedItems(QgsLayoutAligner.ResizeNarrowest) 611 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(10, 12, QgsUnitTypes.LayoutMillimeters)) 612 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 613 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.0, 1.6, QgsUnitTypes.LayoutCentimeters)) 614 l.undoStack().stack().undo() 615 616 view.resizeSelectedItems(QgsLayoutAligner.ResizeWidest) 617 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 12, QgsUnitTypes.LayoutMillimeters)) 618 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(18, 9, QgsUnitTypes.LayoutMillimeters)) 619 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 620 l.undoStack().stack().undo() 621 622 view.resizeSelectedItems(QgsLayoutAligner.ResizeShortest) 623 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 9, QgsUnitTypes.LayoutMillimeters)) 624 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 9, QgsUnitTypes.LayoutMillimeters)) 625 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 0.9, QgsUnitTypes.LayoutCentimeters)) 626 l.undoStack().stack().undo() 627 628 view.resizeSelectedItems(QgsLayoutAligner.ResizeTallest) 629 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 16, QgsUnitTypes.LayoutMillimeters)) 630 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(10, 16, QgsUnitTypes.LayoutMillimeters)) 631 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.6, QgsUnitTypes.LayoutCentimeters)) 632 l.undoStack().stack().undo() 633 634 item2.attemptResize(QgsLayoutSize(10, 19, QgsUnitTypes.LayoutMillimeters)) 635 view.resizeSelectedItems(QgsLayoutAligner.ResizeToSquare) 636 self.assertEqual(item1.sizeWithUnits(), QgsLayoutSize(18, 18, QgsUnitTypes.LayoutMillimeters)) 637 self.assertEqual(item2.sizeWithUnits(), QgsLayoutSize(19, 19, QgsUnitTypes.LayoutMillimeters)) 638 self.assertEqual(item3.sizeWithUnits(), QgsLayoutSize(1.8, 1.8, QgsUnitTypes.LayoutCentimeters)) 639 640 def testDeleteItems(self): 641 p = QgsProject() 642 l = QgsLayout(p) 643 644 # add some items 645 item1 = QgsLayoutItemLabel(l) 646 item1.setText('label 1') 647 l.addLayoutItem(item1) 648 item2 = QgsLayoutItemLabel(l) 649 item2.setText('label 2') 650 l.addLayoutItem(item2) 651 item3 = QgsLayoutItemLabel(l) 652 item3.setText('label 2') 653 l.addLayoutItem(item3) 654 655 view = QgsLayoutView() 656 view.setCurrentLayout(l) 657 count_before = len(l.items()) 658 view.deleteSelectedItems() 659 self.assertEqual(len(l.items()), count_before) 660 661 item2.setSelected(True) 662 view.deleteSelectedItems() 663 self.assertEqual(len(l.items()), count_before - 1) 664 self.assertIn(item1, l.items()) 665 self.assertIn(item3, l.items()) 666 view.deleteItems([item3]) 667 self.assertEqual(len(l.items()), count_before - 2) 668 self.assertIn(item1, l.items()) 669 670 def testCopyPaste(self): 671 p = QgsProject() 672 l = QgsLayout(p) 673 674 # clear clipboard 675 mime_data = QMimeData() 676 mime_data.setData("text/xml", QByteArray()) 677 clipboard = QApplication.clipboard() 678 clipboard.setMimeData(mime_data) 679 680 # add an item 681 item1 = QgsLayoutItemLabel(l) 682 item1.setText('label 1') 683 l.addLayoutItem(item1) 684 item1.setSelected(True) 685 item2 = QgsLayoutItemLabel(l) 686 item2.setText('label 2') 687 l.addLayoutItem(item2) 688 item2.setSelected(True) 689 690 # multiframes 691 multiframe1 = QgsLayoutItemHtml(l) 692 multiframe1.setHtml('mf1') 693 l.addMultiFrame(multiframe1) 694 frame1 = QgsLayoutFrame(l, multiframe1) 695 frame1.setId('frame1a') 696 multiframe1.addFrame(frame1) 697 frame1b = QgsLayoutFrame(l, multiframe1) 698 frame1b.setId('frame1b') 699 multiframe1.addFrame(frame1b) # not selected 700 frame1c = QgsLayoutFrame(l, multiframe1) 701 frame1c.setId('frame1b') 702 multiframe1.addFrame(frame1c) # not selected 703 704 multiframe2 = QgsLayoutItemHtml(l) 705 multiframe2.setHtml('mf2') 706 l.addMultiFrame(multiframe2) 707 frame2 = QgsLayoutFrame(l, multiframe2) 708 frame2.setId('frame2') 709 multiframe2.addFrame(frame2) 710 711 frame1.setSelected(True) 712 frame2.setSelected(True) 713 714 view = QgsLayoutView() 715 view.setCurrentLayout(l) 716 self.assertFalse(view.hasItemsInClipboard()) 717 718 view.copySelectedItems(QgsLayoutView.ClipboardCopy) 719 self.assertTrue(view.hasItemsInClipboard()) 720 721 pasted = view.pasteItems(QgsLayoutView.PasteModeCursor) 722 self.assertEqual(len(pasted), 4) 723 724 new_multiframes = [m for m in l.multiFrames() if m not in [multiframe1, multiframe2]] 725 self.assertEqual(len(new_multiframes), 2) 726 727 self.assertIn(pasted[0], l.items()) 728 self.assertIn(pasted[1], l.items()) 729 labels = [p for p in pasted if p.type() == QgsLayoutItemRegistry.LayoutLabel] 730 self.assertIn(sip.cast(labels[0], QgsLayoutItemLabel).text(), ('label 1', 'label 2')) 731 self.assertIn(sip.cast(labels[1], QgsLayoutItemLabel).text(), ('label 1', 'label 2')) 732 frames = [p for p in pasted if p.type() == QgsLayoutItemRegistry.LayoutFrame] 733 pasted_frame1 = sip.cast(frames[0], QgsLayoutFrame) 734 pasted_frame2 = sip.cast(frames[1], QgsLayoutFrame) 735 self.assertIn(pasted_frame1.multiFrame(), new_multiframes) 736 self.assertIn(new_multiframes[0].frames()[0].uuid(), (pasted_frame1.uuid(), pasted_frame2.uuid())) 737 self.assertIn(pasted_frame2.multiFrame(), new_multiframes) 738 self.assertIn(new_multiframes[1].frames()[0].uuid(), (pasted_frame1.uuid(), pasted_frame2.uuid())) 739 740 self.assertEqual(frame1.multiFrame(), multiframe1) 741 self.assertCountEqual(multiframe1.frames(), [frame1, frame1b, frame1c]) 742 self.assertEqual(frame1b.multiFrame(), multiframe1) 743 self.assertEqual(frame1c.multiFrame(), multiframe1) 744 self.assertEqual(frame2.multiFrame(), multiframe2) 745 self.assertCountEqual(multiframe2.frames(), [frame2]) 746 747 # copy specific item 748 view.copyItems([item2], QgsLayoutView.ClipboardCopy) 749 l2 = QgsLayout(p) 750 view2 = QgsLayoutView() 751 view2.setCurrentLayout(l2) 752 pasted = view2.pasteItems(QgsLayoutView.PasteModeCursor) 753 self.assertEqual(len(pasted), 1) 754 self.assertIn(pasted[0], l2.items()) 755 self.assertEqual(sip.cast(pasted[0], QgsLayoutItemLabel).text(), 'label 2') 756 757 def testCutPaste(self): 758 p = QgsProject() 759 l = QgsLayout(p) 760 761 # clear clipboard 762 mime_data = QMimeData() 763 mime_data.setData("text/xml", QByteArray()) 764 clipboard = QApplication.clipboard() 765 clipboard.setMimeData(mime_data) 766 767 # add an item 768 item1 = QgsLayoutItemLabel(l) 769 item1.setText('label 1') 770 l.addLayoutItem(item1) 771 item1.setSelected(True) 772 item2 = QgsLayoutItemLabel(l) 773 item2.setText('label 2') 774 l.addLayoutItem(item2) 775 item2.setSelected(True) 776 777 view = QgsLayoutView() 778 view.setCurrentLayout(l) 779 self.assertFalse(view.hasItemsInClipboard()) 780 781 len_before = len(l.items()) 782 view.copySelectedItems(QgsLayoutView.ClipboardCut) 783 self.assertTrue(view.hasItemsInClipboard()) 784 self.assertEqual(len(l.items()), len_before - 2) 785 786 pasted = view.pasteItems(QgsLayoutView.PasteModeCursor) 787 self.assertEqual(len(pasted), 2) 788 self.assertEqual(len(l.items()), len_before) 789 self.assertIn(pasted[0], l.items()) 790 self.assertIn(pasted[1], l.items()) 791 self.assertIn(sip.cast(pasted[0], QgsLayoutItemLabel).text(), ('label 1', 'label 2')) 792 self.assertIn(sip.cast(pasted[1], QgsLayoutItemLabel).text(), ('label 1', 'label 2')) 793 794 795if __name__ == '__main__': 796 unittest.main() 797