Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgslayoutpagecollection.h 3 : : -------------------------- 4 : : begin : July 2017 5 : : copyright : (C) 2017 by Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : ***************************************************************************/ 8 : : /*************************************************************************** 9 : : * * 10 : : * This program is free software; you can redistribute it and/or modify * 11 : : * it under the terms of the GNU General Public License as published by * 12 : : * the Free Software Foundation; either version 2 of the License, or * 13 : : * (at your option) any later version. * 14 : : * * 15 : : ***************************************************************************/ 16 : : 17 : : #ifndef QGSLAYOUTPAGECOLLECTION_H 18 : : #define QGSLAYOUTPAGECOLLECTION_H 19 : : 20 : : #include "qgis_core.h" 21 : : #include "qgis_sip.h" 22 : : #include "qgssymbol.h" 23 : : #include "qgslayout.h" 24 : : #include "qgslayoutitempage.h" 25 : : #include "qgslayoutitem.h" 26 : : #include "qgslayoutserializableobject.h" 27 : : #include "qgslayoutpoint.h" 28 : : #include <QObject> 29 : : #include <memory> 30 : : 31 : : class QgsLayout; 32 : : class QgsLayoutGuideCollection; 33 : : 34 : : /** 35 : : * \ingroup core 36 : : * \class QgsLayoutPageCollection 37 : : * \brief A manager for a collection of pages in a layout. 38 : : * \since QGIS 3.0 39 : : */ 40 : : class CORE_EXPORT QgsLayoutPageCollection : public QObject, public QgsLayoutSerializableObject 41 : : { 42 : : 43 : 0 : Q_OBJECT 44 : : 45 : : public: 46 : : 47 : : /** 48 : : * Constructor for QgsLayoutItemPage, with the specified parent \a layout. 49 : : */ 50 : : explicit QgsLayoutPageCollection( QgsLayout *layout SIP_TRANSFERTHIS ); 51 : : 52 : : ~QgsLayoutPageCollection() override; 53 : : 54 : : QString stringType() const override { return QStringLiteral( "LayoutPageCollection" ); } 55 : : QgsLayout *layout() override; 56 : : 57 : : /** 58 : : * Returns a list of pages in the collection. 59 : : * \see page() 60 : : * \see pageCount() 61 : : */ 62 : : QList< QgsLayoutItemPage * > pages(); 63 : : 64 : : /** 65 : : * Returns the number of pages in the collection. 66 : : * \see pages() 67 : : */ 68 : : int pageCount() const; 69 : : 70 : : /** 71 : : * Returns a specific page (by \a pageNumber) from the collection. 72 : : * Internal page numbering starts at 0 - so a \a pageNumber of 0 73 : : * corresponds to the first page in the collection. 74 : : * A NULLPTR is returned if an invalid page number is specified. 75 : : * \see pages() 76 : : */ 77 : : QgsLayoutItemPage *page( int pageNumber ); 78 : : 79 : : /** 80 : : * Returns a specific page (by \a pageNumber) from the collection. 81 : : * Internal page numbering starts at 0 - so a \a pageNumber of 0 82 : : * corresponds to the first page in the collection. 83 : : * A NULLPTR is returned if an invalid page number is specified. 84 : : * \see pages() 85 : : * \note Not available in Python bindings. 86 : : */ 87 : : const QgsLayoutItemPage *page( int pageNumber ) const SIP_SKIP; 88 : : 89 : : /** 90 : : * Returns the page number for the specified \a page, or -1 if the page 91 : : * is not contained in the collection. 92 : : */ 93 : : int pageNumber( QgsLayoutItemPage *page ) const; 94 : : 95 : : /** 96 : : * Returns a list of the pages which are visible within the specified 97 : : * \a region (in layout coordinates). 98 : : * \see visiblePageNumbers() 99 : : */ 100 : : QList< QgsLayoutItemPage * > visiblePages( const QRectF ®ion ) const; 101 : : 102 : : /** 103 : : * Returns a list of the page numbers which are visible within the specified 104 : : * \a region (in layout coordinates). 105 : : * \see visiblePages() 106 : : */ 107 : : QList< int > visiblePageNumbers( const QRectF ®ion ) const; 108 : : 109 : : /** 110 : : * Returns whether a given \a page index is empty, ie, it contains no items except for the background 111 : : * paper item. 112 : : * \see shouldExportPage() 113 : : */ 114 : : bool pageIsEmpty( int page ) const; 115 : : 116 : : /** 117 : : * Returns a list of layout items on the specified \a page index. 118 : : */ 119 : : QList< QgsLayoutItem *> itemsOnPage( int page ) const; 120 : : 121 : : /** 122 : : * Returns layout items of a specific type on a specified \a page. 123 : : * \note not available in Python bindings. 124 : : */ 125 : 0 : template<class T> void itemsOnPage( QList<T *> &itemList, int page ) const SIP_SKIP 126 : : { 127 : 0 : itemList.clear(); 128 : 0 : const QList<QGraphicsItem *> graphicsItemList = mLayout->items(); 129 : 0 : for ( QGraphicsItem *graphicsItem : graphicsItemList ) 130 : : { 131 : 0 : T *item = dynamic_cast<T *>( graphicsItem ); 132 : 0 : if ( item && item->page() == page ) 133 : : { 134 : 0 : itemList.push_back( item ); 135 : 0 : } 136 : : } 137 : 0 : } 138 : : 139 : : /** 140 : : * Returns whether the specified \a page number should be included in exports of the layouts. 141 : : * 142 : : * \warning This will always return TRUE unless the layout is being currently exported -- it cannot 143 : : * be used in advance to determine whether a given page will be exported! 144 : : * 145 : : * \see pageIsEmpty() 146 : : */ 147 : : bool shouldExportPage( int page ) const; 148 : : 149 : : /** 150 : : * Adds a \a page to the collection. Ownership of the \a page is transferred 151 : : * to the collection, and the page will automatically be added to the collection's 152 : : * layout() (there is no need to manually add the page item to the layout). 153 : : * The page will be added after all pages currently contained in the collection. 154 : : * 155 : : * Calling addPage() automatically triggers a reflow() of pages. 156 : : * 157 : : * \see extendByNewPage() 158 : : * \see insertPage() 159 : : */ 160 : : void addPage( QgsLayoutItemPage *page SIP_TRANSFER ); 161 : : 162 : : /** 163 : : * Adds a new page to the end of the collection. This page will inherit the 164 : : * same size as the current final page in the collection. 165 : : * 166 : : * The newly created page will be returned. 167 : : * 168 : : * \see addPage() 169 : : * \see insertPage() 170 : : */ 171 : : QgsLayoutItemPage *extendByNewPage(); 172 : : 173 : : /** 174 : : * Inserts a \a page into a specific position in the collection. 175 : : * 176 : : * Ownership of the \a page is transferred 177 : : * to the collection, and the page will automatically be added to the collection's 178 : : * layout() (there is no need to manually add the page item to the layout). 179 : : * 180 : : * The page will be added after before the page number specified by \a beforePage. 181 : : * (Page numbers in collections begin at 0 - so a \a beforePage of 0 will insert 182 : : * the page before all existing pages). 183 : : * 184 : : * Calling insertPage() automatically triggers a reflow() of pages. 185 : : * 186 : : * \see addPage() 187 : : */ 188 : : void insertPage( QgsLayoutItemPage *page SIP_TRANSFER, int beforePage ); 189 : : 190 : : /** 191 : : * Deletes a page from the collection. The page will automatically be removed 192 : : * from the collection's layout(). 193 : : * 194 : : * Page numbers in collections begin at 0 - so a \a pageNumber of 0 will delete 195 : : * the first page in the collection. 196 : : * 197 : : * Calling deletePage() automatically triggers a reflow() of pages. 198 : : * 199 : : * \see clear() 200 : : */ 201 : : void deletePage( int pageNumber ); 202 : : 203 : : /** 204 : : * Deletes a page from the collection. The page will automatically be removed 205 : : * from the collection's layout(). 206 : : * 207 : : * Calling deletePage() automatically triggers a reflow() of pages. 208 : : * 209 : : * \see clear() 210 : : */ 211 : : void deletePage( QgsLayoutItemPage *page ); 212 : : 213 : : /** 214 : : * Removes all pages from the collection. 215 : : * \see deletePage() 216 : : */ 217 : : void clear(); 218 : : 219 : : /** 220 : : * Takes a \a page from the collection, returning ownership of the page to the caller. 221 : : */ 222 : : QgsLayoutItemPage *takePage( QgsLayoutItemPage *page ) SIP_TRANSFERBACK; 223 : : 224 : : /** 225 : : * Sets the \a symbol to use for drawing pages in the collection. 226 : : * 227 : : * Ownership is not transferred, and a copy of the symbol is created internally. 228 : : * \see pageStyleSymbol() 229 : : */ 230 : : void setPageStyleSymbol( QgsFillSymbol *symbol ); 231 : : 232 : : /** 233 : : * Returns the symbol to use for drawing pages in the collection. 234 : : * \see setPageStyleSymbol() 235 : : * 236 : : * \deprecated Use QgsLayoutItemPage::pageStyleSymbol() instead. 237 : : */ 238 : : Q_DECL_DEPRECATED const QgsFillSymbol *pageStyleSymbol() const SIP_DEPRECATED; 239 : : 240 : : /** 241 : : * Should be called before changing any page item sizes, and followed by a call to 242 : : * endPageSizeChange(). If page size changes are wrapped in these calls, then items 243 : : * will maintain their same relative position on pages after the page sizes are updated. 244 : : * \see endPageSizeChange() 245 : : */ 246 : : void beginPageSizeChange(); 247 : : 248 : : /** 249 : : * Should be called after changing any page item sizes, and preceded by a call to 250 : : * beginPageSizeChange(). If page size changes are wrapped in these calls, then items 251 : : * will maintain their same relative position on pages after the page sizes are updated. 252 : : * \see beginPageSizeChange() 253 : : */ 254 : : void endPageSizeChange(); 255 : : 256 : : /** 257 : : * Forces the page collection to reflow the arrangement of pages, e.g. to account 258 : : * for page size/orientation change. 259 : : */ 260 : : void reflow(); 261 : : 262 : : /** 263 : : * Returns the maximum width of pages in the collection. The returned value is 264 : : * in layout units. 265 : : * 266 : : * \see maximumPageSize() 267 : : */ 268 : : double maximumPageWidth() const; 269 : : 270 : : /** 271 : : * Returns the maximum size of any page in the collection, by area. The returned value 272 : : * is in layout units. 273 : : * 274 : : * \see maximumPageWidth() 275 : : */ 276 : : QSizeF maximumPageSize() const; 277 : : 278 : : /** 279 : : * Returns TRUE if the layout has uniform page sizes, e.g. all pages are the same size. 280 : : * 281 : : * This method does not consider differing units as non-uniform sizes, only the actual 282 : : * physical size of the pages. 283 : : */ 284 : : bool hasUniformPageSizes() const; 285 : : 286 : : /** 287 : : * Returns the page number corresponding to a \a point in the layout (in layout units). 288 : : * 289 : : * Page numbers in collections begin at 0 - so a page number of 0 indicates the 290 : : * first page. 291 : : * 292 : : * \note This is a relaxed check, which will always return a page number. For instance, 293 : : * it does not consider x coordinates and vertical coordinates before the first page or 294 : : * after the last page will still return the nearest page. 295 : : * 296 : : * \see predictPageNumberForPoint() 297 : : * \see pageAtPoint() 298 : : * \see positionOnPage() 299 : : */ 300 : : int pageNumberForPoint( QPointF point ) const; 301 : : 302 : : /** 303 : : * Returns the theoretical page number corresponding to a \a point in the layout (in layout units), 304 : : * assuming that enough pages exist in the layout to cover that point. 305 : : * 306 : : * If there are insufficient pages currently in the layout, this method will assume that extra 307 : : * "imaginary" pages have been added at the end of the layout until that point is reached. These 308 : : * imaginary pages will inherit the size of the existing final page in the layout. 309 : : * 310 : : * Page numbers in collections begin at 0 - so a page number of 0 indicates the 311 : : * first page. 312 : : * 313 : : * \see pageNumberForPoint() 314 : : * \see pageAtPoint() 315 : : * \see positionOnPage() 316 : : */ 317 : : int predictPageNumberForPoint( QPointF point ) const; 318 : : 319 : : /** 320 : : * Returns the page at a specified \a point (in layout coordinates). 321 : : * 322 : : * If no page exists at \a point, NULLPTR will be returned. 323 : : * 324 : : * \note Unlike pageNumberForPoint(), this method only returns pages which 325 : : * directly intersect with the specified point. 326 : : * 327 : : * \see pageNumberForPoint() 328 : : */ 329 : : QgsLayoutItemPage *pageAtPoint( QPointF point ) const; 330 : : 331 : : /** 332 : : * Converts a \a position on a \a page to an absolute position in layout coordinates.\ 333 : : * \see pagePositionToAbsolute() 334 : : */ 335 : : QPointF pagePositionToLayoutPosition( int page, const QgsLayoutPoint &position ) const; 336 : : 337 : : /** 338 : : * Converts a \a position on a \a page to an absolute position in (maintaining the units from the input \a position). 339 : : * \see pagePositionToLayoutPosition() 340 : : */ 341 : : QgsLayoutPoint pagePositionToAbsolute( int page, const QgsLayoutPoint &position ) const; 342 : : 343 : : /** 344 : : * Returns the position within a page of a \a point in the layout (in layout units). 345 : : * 346 : : * \see pageNumberForPoint() 347 : : */ 348 : : QPointF positionOnPage( QPointF point ) const; 349 : : 350 : : /** 351 : : * Returns the space between pages, in layout units. 352 : : */ 353 : : double spaceBetweenPages() const; 354 : : 355 : : /** 356 : : * Returns the size of the page shadow, in layout units. 357 : : */ 358 : : double pageShadowWidth() const; 359 : : 360 : : /** 361 : : * Resizes the layout to a single page which fits the current contents of the layout. 362 : : * 363 : : * Calling this method resets the number of pages to 1, with the size set to the 364 : : * minimum size required to fit all existing layout items. Items will also be 365 : : * repositioned so that the new top-left bounds of the layout is at the point 366 : : * (marginLeft, marginTop). An optional margin can be specified. 367 : : */ 368 : : void resizeToContents( const QgsMargins &margins, QgsUnitTypes::LayoutUnit marginUnits ); 369 : : 370 : : /** 371 : : * Stores the collection's state in a DOM element. The \a parentElement should refer to the parent layout's DOM element. 372 : : * \see readXml() 373 : : */ 374 : : bool writeXml( QDomElement &parentElement, QDomDocument &document, const QgsReadWriteContext &context ) const override; 375 : : 376 : : /** 377 : : * Sets the collection's state from a DOM element. collectionElement is the DOM node corresponding to the collection. 378 : : * \see writeXml() 379 : : */ 380 : : bool readXml( const QDomElement &collectionElement, const QDomDocument &document, const QgsReadWriteContext &context ) override; 381 : : 382 : : /** 383 : : * Returns a reference to the collection's guide collection, which manages page snap guides. 384 : : */ 385 : : QgsLayoutGuideCollection &guides(); 386 : : 387 : : /** 388 : : * Returns a reference to the collection's guide collection, which manages page snap guides. 389 : : */ 390 : : SIP_SKIP const QgsLayoutGuideCollection &guides() const; 391 : : 392 : : public slots: 393 : : 394 : : /** 395 : : * Triggers a redraw for all pages. 396 : : */ 397 : : void redraw(); 398 : : 399 : : signals: 400 : : 401 : : /** 402 : : * Emitted when pages are added or removed from the collection. 403 : : */ 404 : : void changed(); 405 : : 406 : : /** 407 : : * Emitted just before a page is removed from the collection. 408 : : * 409 : : * Page numbers in collections begin at 0 - so a page number of 0 indicates the 410 : : * first page. 411 : : */ 412 : : void pageAboutToBeRemoved( int pageNumber ); 413 : : 414 : : private: 415 : : 416 : : QgsLayout *mLayout = nullptr; 417 : : 418 : : std::unique_ptr< QgsLayoutGuideCollection > mGuideCollection; 419 : : 420 : : //! Symbol for drawing pages 421 : : std::unique_ptr< QgsFillSymbol > mPageStyleSymbol; 422 : : 423 : : QList< QgsLayoutItemPage * > mPages; 424 : : 425 : : bool mBlockUndoCommands = false; 426 : : 427 : : QMap< QString, QPair< int, QgsLayoutPoint > > mPreviousItemPositions; 428 : : 429 : : void createDefaultPageStyleSymbol(); 430 : : 431 : : friend class QgsLayoutPageCollectionUndoCommand; 432 : : }; 433 : : 434 : : #endif //QGSLAYOUTPAGECOLLECTION_H