QGIS API Documentation  3.20.0-Odense (decaadbb31)
qgslayoutview.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgslayoutview.cpp
3  -----------------
4  Date : July 2017
5  Copyright : (C) 2017 Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include "qgslayoutview.h"
19 #include "qgslayout.h"
20 #include "qgslayoutframe.h"
21 #include "qgslayoutmultiframe.h"
22 #include "qgslayoutviewtool.h"
27 #include "qgslayoutmousehandles.h"
28 #include "qgslayoutruler.h"
29 #include "qgslayoutmodel.h"
30 #include "qgssettings.h"
31 #include "qgsrectangle.h"
32 #include "qgsapplication.h"
34 #include "qgsproject.h"
35 #include "qgslayoutitemgroup.h"
37 #include "qgslayoutundostack.h"
39 #include "qgsreadwritecontext.h"
40 #include <memory>
41 #include <QDesktopWidget>
42 #include <QMenu>
43 #include <QClipboard>
44 #include <QMimeData>
45 
46 #define MIN_VIEW_SCALE 0.05
47 #define MAX_VIEW_SCALE 1000.0
48 
49 QgsLayoutView::QgsLayoutView( QWidget *parent )
50  : QGraphicsView( parent )
51 {
52  setResizeAnchor( QGraphicsView::AnchorViewCenter );
53  setMouseTracking( true );
54  viewport()->setMouseTracking( true );
55 
56  // set the "scene" background on the view using stylesheets
57  // we don't want to use QGraphicsScene::setBackgroundBrush because we want to keep
58  // a transparent background for exports, and it's only a cosmetic thing for the view only
59  // ALSO - only set it on the viewport - we don't want scrollbars/etc affected by this
60  viewport()->setStyleSheet( QStringLiteral( "background-color:#d7d7d7;" ) );
61 
62  mSpacePanTool = new QgsLayoutViewToolTemporaryKeyPan( this );
63  mMidMouseButtonPanTool = new QgsLayoutViewToolTemporaryMousePan( this );
64  mSpaceZoomTool = new QgsLayoutViewToolTemporaryKeyZoom( this );
65 
66  mPreviewEffect = new QgsPreviewEffect( this );
67  viewport()->setGraphicsEffect( mPreviewEffect );
68 
69  connect( this, &QgsLayoutView::zoomLevelChanged, this, &QgsLayoutView::invalidateCachedRenders );
70 }
71 
73 {
74  emit willBeDeleted();
75 }
76 
78 {
79  return qobject_cast<QgsLayout *>( scene() );
80 }
81 
83 {
84  return qobject_cast<const QgsLayout *>( scene() );
85 }
86 
88 {
89  setScene( layout );
90 
93 
94  viewChanged();
95 
96  // IMPORTANT!
97  // previous snap markers, snap lines are owned by previous layout - so don't delete them here!
98  mSnapMarker = new QgsLayoutViewSnapMarker();
99  mSnapMarker->hide();
100  layout->addItem( mSnapMarker );
101  mHorizontalSnapLine = createSnapLine();
102  mHorizontalSnapLine->hide();
103  layout->addItem( mHorizontalSnapLine );
104  mVerticalSnapLine = createSnapLine();
105  mVerticalSnapLine->hide();
106  layout->addItem( mVerticalSnapLine );
107  mSectionLabel = nullptr;
108 
109  if ( mHorizontalRuler )
110  {
111  connect( &layout->guides(), &QAbstractItemModel::dataChanged, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
112  connect( &layout->guides(), &QAbstractItemModel::rowsInserted, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
113  connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
114  connect( &layout->guides(), &QAbstractItemModel::modelReset, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
115  }
116  if ( mVerticalRuler )
117  {
118  connect( &layout->guides(), &QAbstractItemModel::dataChanged, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
119  connect( &layout->guides(), &QAbstractItemModel::rowsInserted, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
120  connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
121  connect( &layout->guides(), &QAbstractItemModel::modelReset, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
122  }
123 
124  //emit layoutSet, so that designer dialogs can update for the new layout
125  emit layoutSet( layout );
126 }
127 
129 {
130  return mTool;
131 }
132 
134 {
135  if ( !tool )
136  return;
137 
138  if ( mTool )
139  {
140  mTool->deactivate();
141  disconnect( mTool, &QgsLayoutViewTool::itemFocused, this, &QgsLayoutView::itemFocused );
142  }
143 
144  if ( mSnapMarker )
145  mSnapMarker->hide();
146  if ( mHorizontalSnapLine )
147  mHorizontalSnapLine->hide();
148  if ( mVerticalSnapLine )
149  mVerticalSnapLine->hide();
150 
151  // activate new tool before setting it - gives tools a chance
152  // to respond to whatever the current tool is
153  tool->activate();
154  mTool = tool;
156  emit toolSet( mTool );
157 }
158 
160 {
161  if ( mTool && mTool == tool )
162  {
163  mTool->deactivate();
164  emit toolSet( nullptr );
165  setCursor( Qt::ArrowCursor );
166  }
167 }
168 
170 {
171  mPreviewEffect->setEnabled( enabled );
172 }
173 
175 {
176  return mPreviewEffect->isEnabled();
177 }
178 
180 {
181  mPreviewEffect->setMode( mode );
182 }
183 
185 {
186  return mPreviewEffect->mode();
187 }
188 
189 void QgsLayoutView::scaleSafe( double scale )
190 {
191  double currentScale = transform().m11();
192  scale *= currentScale;
193  scale = std::clamp( scale, MIN_VIEW_SCALE, MAX_VIEW_SCALE );
194  setTransform( QTransform::fromScale( scale, scale ) );
195  emit zoomLevelChanged();
196  viewChanged();
197 }
198 
199 void QgsLayoutView::setZoomLevel( double level )
200 {
201  if ( !currentLayout() )
202  return;
203 
204  if ( currentLayout()->units() == QgsUnitTypes::LayoutPixels )
205  {
206  setTransform( QTransform::fromScale( level, level ) );
207  }
208  else
209  {
210  double dpi = QgsApplication::desktop()->logicalDpiX();
211  //monitor dpi is not always correct - so make sure the value is sane
212  if ( ( dpi < 60 ) || ( dpi > 1200 ) )
213  dpi = 72;
214 
215  //desired pixel width for 1mm on screen
216  level = std::clamp( level, MIN_VIEW_SCALE, MAX_VIEW_SCALE );
217  double mmLevel = currentLayout()->convertFromLayoutUnits( level, QgsUnitTypes::LayoutMillimeters ).length() * dpi / 25.4;
218  setTransform( QTransform::fromScale( mmLevel, mmLevel ) );
219  }
220  emit zoomLevelChanged();
221  viewChanged();
222 }
223 
225 {
226  mHorizontalRuler = ruler;
227  ruler->setLayoutView( this );
228  if ( QgsLayout *layout = currentLayout() )
229  {
230  connect( &layout->guides(), &QAbstractItemModel::dataChanged, ruler, [ = ] { mHorizontalRuler->update(); } );
231  connect( &layout->guides(), &QAbstractItemModel::rowsInserted, ruler, [ = ] { mHorizontalRuler->update(); } );
232  connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, ruler, [ = ] { mHorizontalRuler->update(); } );
233  connect( &layout->guides(), &QAbstractItemModel::modelReset, ruler, [ = ] { mHorizontalRuler->update(); } );
234  }
235  viewChanged();
236 }
237 
239 {
240  mVerticalRuler = ruler;
241  ruler->setLayoutView( this );
242  if ( QgsLayout *layout = currentLayout() )
243  {
244  connect( &layout->guides(), &QAbstractItemModel::dataChanged, ruler, [ = ] { mVerticalRuler->update(); } );
245  connect( &layout->guides(), &QAbstractItemModel::rowsInserted, ruler, [ = ] { mVerticalRuler->update(); } );
246  connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, ruler, [ = ] { mVerticalRuler->update(); } );
247  connect( &layout->guides(), &QAbstractItemModel::modelReset, ruler, [ = ] { mVerticalRuler->update(); } );
248  }
249  viewChanged();
250 }
251 
253 {
254  mMenuProvider.reset( provider );
255 }
256 
258 {
259  return mMenuProvider.get();
260 }
261 
262 QList<QgsLayoutItemPage *> QgsLayoutView::visiblePages() const
263 {
264  if ( !currentLayout() )
265  return QList< QgsLayoutItemPage *>();
266 
267  //get current visible part of scene
268  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
269  QRectF visibleRect = mapToScene( viewportRect ).boundingRect();
270  return currentLayout()->pageCollection()->visiblePages( visibleRect );
271 }
272 
274 {
275  if ( !currentLayout() )
276  return QList< int >();
277 
278  //get current visible part of scene
279  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
280  QRectF visibleRect = mapToScene( viewportRect ).boundingRect();
281  return currentLayout()->pageCollection()->visiblePageNumbers( visibleRect );
282 }
283 
285 {
286  if ( !currentLayout() )
287  return;
288 
289  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
290  QgsLayoutAligner::alignItems( currentLayout(), selectedItems, alignment );
291 }
292 
294 {
295  if ( !currentLayout() )
296  return;
297 
298  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
299  QgsLayoutAligner::distributeItems( currentLayout(), selectedItems, distribution );
300 }
301 
303 {
304  if ( !currentLayout() )
305  return;
306 
307  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
308  QgsLayoutAligner::resizeItems( currentLayout(), selectedItems, resize );
309 }
310 
312 {
313  copyItems( currentLayout()->selectedLayoutItems(), operation );
314 }
315 
316 void QgsLayoutView::copyItems( const QList<QgsLayoutItem *> &items, QgsLayoutView::ClipboardOperation operation )
317 {
318  if ( !currentLayout() )
319  return;
320 
321  QgsReadWriteContext context;
322  QDomDocument doc;
323  QDomElement documentElement = doc.createElement( QStringLiteral( "LayoutItemClipboard" ) );
324  if ( operation == ClipboardCut )
325  currentLayout()->undoStack()->beginMacro( tr( "Cut Items" ) );
326 
327  QSet< QgsLayoutMultiFrame * > copiedMultiFrames;
328 
329  for ( QgsLayoutItem *item : items )
330  {
331  // copy every child from a group
332  if ( QgsLayoutItemGroup *itemGroup = qobject_cast<QgsLayoutItemGroup *>( item ) )
333  {
334  const QList<QgsLayoutItem *> groupedItems = itemGroup->items();
335  for ( const QgsLayoutItem *groupedItem : groupedItems )
336  {
337  groupedItem->writeXml( documentElement, doc, context );
338  }
339  }
340  else if ( QgsLayoutFrame *frame = qobject_cast<QgsLayoutFrame *>( item ) )
341  {
342  // copy multiframe too
343  if ( frame->multiFrame() && !copiedMultiFrames.contains( frame->multiFrame() ) )
344  {
345  frame->multiFrame()->writeXml( documentElement, doc, context );
346  copiedMultiFrames.insert( frame->multiFrame() );
347  }
348  }
349  item->writeXml( documentElement, doc, context );
350  if ( operation == ClipboardCut )
351  currentLayout()->removeLayoutItem( item );
352  }
353  doc.appendChild( documentElement );
354  if ( operation == ClipboardCut )
355  {
357  currentLayout()->update();
358  }
359 
360  //remove the UUIDs since we don't want any duplicate UUID
361  QDomNodeList itemsNodes = doc.elementsByTagName( QStringLiteral( "LayoutItem" ) );
362  for ( int i = 0; i < itemsNodes.count(); ++i )
363  {
364  QDomNode itemNode = itemsNodes.at( i );
365  if ( itemNode.isElement() )
366  {
367  itemNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
368  itemNode.toElement().removeAttribute( QStringLiteral( "groupUuid" ) );
369  }
370  }
371  QDomNodeList multiFrameNodes = doc.elementsByTagName( QStringLiteral( "LayoutMultiFrame" ) );
372  for ( int i = 0; i < multiFrameNodes.count(); ++i )
373  {
374  QDomNode multiFrameNode = multiFrameNodes.at( i );
375  if ( multiFrameNode.isElement() )
376  {
377  multiFrameNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
378  QDomNodeList frameNodes = multiFrameNode.toElement().elementsByTagName( QStringLiteral( "childFrame" ) );
379  for ( int j = 0; j < frameNodes.count(); ++j )
380  {
381  QDomNode itemNode = frameNodes.at( j );
382  if ( itemNode.isElement() )
383  {
384  itemNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
385  }
386  }
387  }
388  }
389 
390  QMimeData *mimeData = new QMimeData;
391  mimeData->setData( QStringLiteral( "text/xml" ), doc.toByteArray() );
392  QClipboard *clipboard = QApplication::clipboard();
393  clipboard->setMimeData( mimeData );
394 }
395 
396 QList< QgsLayoutItem * > QgsLayoutView::pasteItems( QgsLayoutView::PasteMode mode )
397 {
398  if ( !currentLayout() )
399  return QList< QgsLayoutItem * >();
400 
401  QList< QgsLayoutItem * > pastedItems;
402  QDomDocument doc;
403  QClipboard *clipboard = QApplication::clipboard();
404  if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral( "text/xml" ) ) ) )
405  {
406  QDomElement docElem = doc.documentElement();
407  if ( docElem.tagName() == QLatin1String( "LayoutItemClipboard" ) )
408  {
409  QPointF pt;
410  switch ( mode )
411  {
412  case PasteModeCursor:
413  case PasteModeInPlace:
414  {
415  // place items at cursor position
416  pt = mapToScene( mapFromGlobal( QCursor::pos() ) );
417  break;
418  }
419  case PasteModeCenter:
420  {
421  // place items in center of viewport
422  pt = mapToScene( viewport()->rect().center() );
423  break;
424  }
425  }
426  bool pasteInPlace = ( mode == PasteModeInPlace );
427  currentLayout()->undoStack()->beginMacro( tr( "Paste Items" ) );
428  currentLayout()->undoStack()->beginCommand( currentLayout(), tr( "Paste Items" ) );
429  pastedItems = currentLayout()->addItemsFromXml( docElem, doc, QgsReadWriteContext(), &pt, pasteInPlace );
432  }
433  }
434  return pastedItems;
435 }
436 
437 QList<QgsLayoutItem *> QgsLayoutView::pasteItems( QPointF layoutPoint )
438 {
439  if ( !currentLayout() )
440  return QList<QgsLayoutItem *>();
441 
442  QList< QgsLayoutItem * > pastedItems;
443  QDomDocument doc;
444  QClipboard *clipboard = QApplication::clipboard();
445  if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral( "text/xml" ) ) ) )
446  {
447  QDomElement docElem = doc.documentElement();
448  if ( docElem.tagName() == QLatin1String( "LayoutItemClipboard" ) )
449  {
450  currentLayout()->undoStack()->beginMacro( tr( "Paste Items" ) );
451  currentLayout()->undoStack()->beginCommand( currentLayout(), tr( "Paste Items" ) );
452  pastedItems = currentLayout()->addItemsFromXml( docElem, doc, QgsReadWriteContext(), &layoutPoint, false );
455  }
456  }
457  return pastedItems;
458 }
459 
461 {
462  QDomDocument doc;
463  QClipboard *clipboard = QApplication::clipboard();
464  if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral( "text/xml" ) ) ) )
465  {
466  QDomElement docElem = doc.documentElement();
467  if ( docElem.tagName() == QLatin1String( "LayoutItemClipboard" ) )
468  return true;
469  }
470  return false;
471 }
472 
473 QPointF QgsLayoutView::deltaForKeyEvent( QKeyEvent *event )
474 {
475  // increment used for cursor key item movement
476  double increment = 1.0;
477  if ( event->modifiers() & Qt::ShiftModifier )
478  {
479  //holding shift while pressing cursor keys results in a big step
480  increment = 10.0;
481  }
482  else if ( event->modifiers() & Qt::AltModifier )
483  {
484  //holding alt while pressing cursor keys results in a 1 pixel step
485  double viewScale = transform().m11();
486  if ( viewScale > 0 )
487  {
488  increment = 1 / viewScale;
489  }
490  }
491 
492  double deltaX = 0;
493  double deltaY = 0;
494  switch ( event->key() )
495  {
496  case Qt::Key_Left:
497  deltaX = -increment;
498  break;
499  case Qt::Key_Right:
500  deltaX = increment;
501  break;
502  case Qt::Key_Up:
503  deltaY = -increment;
504  break;
505  case Qt::Key_Down:
506  deltaY = increment;
507  break;
508  default:
509  break;
510  }
511 
512  return QPointF( deltaX, deltaY );
513 }
514 
516 {
517  mPaintingEnabled = enabled;
518  if ( enabled )
519  update();
520 }
521 
522 void QgsLayoutView::setSectionLabel( const QString &label )
523 {
524  if ( !currentLayout() )
525  return;
526 
527  if ( !mSectionLabel )
528  {
529  mSectionLabel = new QgsLayoutReportSectionLabel( currentLayout(), this );
530  currentLayout()->addItem( mSectionLabel );
531  mSectionLabel->setRect( 0, -200, 1000, 200 );
532  mSectionLabel->setZValue( -1 );
533  }
534  mSectionLabel->setLabel( label );
535 }
536 
538 {
539  if ( !scene() )
540  return;
541 
542  fitInView( scene()->sceneRect(), Qt::KeepAspectRatio );
543  viewChanged();
544  emit zoomLevelChanged();
545 }
546 
548 {
549  if ( !scene() )
550  return;
551 
552  //get current visible part of scene
553  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
554  QRectF visibleRect = mapToScene( viewportRect ).boundingRect();
555 
556  double verticalCenter = ( visibleRect.top() + visibleRect.bottom() ) / 2.0;
557  // expand out visible rect to include left/right edges of scene
558  // centered on current visible vertical center
559  // note that we can't have a 0 height rect - fitInView doesn't handle that
560  // so we just set a very small height instead.
561  const double tinyHeight = 0.01;
562  QRectF targetRect( scene()->sceneRect().left(),
563  verticalCenter - tinyHeight,
564  scene()->sceneRect().width(),
565  tinyHeight * 2 );
566 
567  fitInView( targetRect, Qt::KeepAspectRatio );
568  emit zoomLevelChanged();
569  viewChanged();
570 }
571 
573 {
574  scaleSafe( 2 );
575 }
576 
578 {
579  scaleSafe( 0.5 );
580 }
581 
583 {
584  setZoomLevel( 1.0 );
585 }
586 
588 {
589  emit zoomLevelChanged();
590 }
591 
593 {
594  if ( !currentLayout() )
595  {
596  return;
597  }
598 
599  //select all items in layout
600  QgsLayoutItem *focusedItem = nullptr;
601  const QList<QGraphicsItem *> itemList = currentLayout()->items();
602  for ( QGraphicsItem *graphicsItem : itemList )
603  {
604  QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
605  QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( graphicsItem );
606  if ( item && !paperItem )
607  {
608  if ( !item->isLocked() )
609  {
610  item->setSelected( true );
611  if ( !focusedItem )
612  focusedItem = item;
613  }
614  else
615  {
616  //deselect all locked items
617  item->setSelected( false );
618  }
619  }
620  }
621  emit itemFocused( focusedItem );
622 }
623 
625 {
626  if ( !currentLayout() )
627  {
628  return;
629  }
630 
632 }
633 
635 {
636  if ( !currentLayout() )
637  {
638  return;
639  }
640 
641  QgsLayoutItem *focusedItem = nullptr;
642  //check all items in layout
643  const QList<QGraphicsItem *> itemList = currentLayout()->items();
644  for ( QGraphicsItem *graphicsItem : itemList )
645  {
646  QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
647  QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( graphicsItem );
648  if ( item && !paperItem )
649  {
650  //flip selected state for items (and deselect any locked items)
651  if ( item->isSelected() || item->isLocked() )
652  {
653  item->setSelected( false );
654  }
655  else
656  {
657  item->setSelected( true );
658  if ( !focusedItem )
659  focusedItem = item;
660  }
661  }
662  }
663  if ( focusedItem )
664  emit itemFocused( focusedItem );
665 }
666 
667 
668 void selectNextByZOrder( QgsLayout *layout, bool above )
669 {
670  if ( !layout )
671  return;
672 
673  QgsLayoutItem *previousSelectedItem = nullptr;
674  const QList<QgsLayoutItem *> selectedItems = layout->selectedLayoutItems();
675  if ( !selectedItems.isEmpty() )
676  {
677  previousSelectedItem = selectedItems.at( 0 );
678  }
679 
680  if ( !previousSelectedItem )
681  {
682  return;
683  }
684 
685  //select item with target z value
686  QgsLayoutItem *selectedItem = nullptr;
687  if ( !above )
688  selectedItem = layout->itemsModel()->findItemBelow( previousSelectedItem );
689  else
690  selectedItem = layout->itemsModel()->findItemAbove( previousSelectedItem );
691 
692  if ( !selectedItem )
693  {
694  return;
695  }
696 
697  //OK, found a good target item
698  layout->setSelectedItem( selectedItem );
699 }
700 
702 {
704 }
705 
707 {
708  selectNextByZOrder( currentLayout(), false );
709 }
710 
712 {
713  if ( !currentLayout() )
714  return;
715 
716  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
717  bool itemsRaised = false;
718  for ( QgsLayoutItem *item : selectedItems )
719  {
720  itemsRaised = itemsRaised | currentLayout()->raiseItem( item, true );
721  }
722 
723  if ( !itemsRaised )
724  {
725  //no change
726  return;
727  }
728 
729  //update all positions
731  currentLayout()->update();
732 }
733 
735 {
736  if ( !currentLayout() )
737  return;
738 
739  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
740  bool itemsLowered = false;
741  for ( QgsLayoutItem *item : selectedItems )
742  {
743  itemsLowered = itemsLowered | currentLayout()->lowerItem( item, true );
744  }
745 
746  if ( !itemsLowered )
747  {
748  //no change
749  return;
750  }
751 
752  //update all positions
754  currentLayout()->update();
755 }
756 
758 {
759  if ( !currentLayout() )
760  return;
761 
762  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
763  bool itemsRaised = false;
764  for ( QgsLayoutItem *item : selectedItems )
765  {
766  itemsRaised = itemsRaised | currentLayout()->moveItemToTop( item, true );
767  }
768 
769  if ( !itemsRaised )
770  {
771  //no change
772  return;
773  }
774 
775  //update all positions
777  currentLayout()->update();
778 }
779 
781 {
782  if ( !currentLayout() )
783  return;
784 
785  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
786  bool itemsLowered = false;
787  for ( QgsLayoutItem *item : selectedItems )
788  {
789  itemsLowered = itemsLowered | currentLayout()->moveItemToBottom( item, true );
790  }
791 
792  if ( !itemsLowered )
793  {
794  //no change
795  return;
796  }
797 
798  //update all positions
800  currentLayout()->update();
801 }
802 
804 {
805  if ( !currentLayout() )
806  return;
807 
808  currentLayout()->undoStack()->beginMacro( tr( "Lock Items" ) );
809  const QList<QgsLayoutItem *> selectionList = currentLayout()->selectedLayoutItems();
810  for ( QgsLayoutItem *item : selectionList )
811  {
812  item->setLocked( true );
813  }
814 
817 }
818 
820 {
821  if ( !currentLayout() )
822  return;
823 
824  //unlock all items in layout
825  currentLayout()->undoStack()->beginMacro( tr( "Unlock Items" ) );
826 
827  //first, clear the selection
829 
830  QgsLayoutItem *focusItem = nullptr;
831 
832  const QList<QGraphicsItem *> itemList = currentLayout()->items();
833  for ( QGraphicsItem *graphicItem : itemList )
834  {
835  QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicItem );
836  if ( item && item->isLocked() )
837  {
838  focusItem = item;
839  item->setLocked( false );
840  //select unlocked items, same behavior as illustrator
841  item->setSelected( true );
842  }
843  }
845 
846  emit itemFocused( focusItem );
847 }
848 
850 {
851  if ( !currentLayout() )
852  return;
853 
854  deleteItems( currentLayout()->selectedLayoutItems() );
855 }
856 
857 void QgsLayoutView::deleteItems( const QList<QgsLayoutItem *> &items )
858 {
859  if ( !currentLayout() )
860  return;
861 
862  if ( items.empty() )
863  return;
864 
865  currentLayout()->undoStack()->beginMacro( tr( "Delete Items" ) );
866  //delete selected items
867  for ( QgsLayoutItem *item : items )
868  {
869  currentLayout()->removeLayoutItem( item );
870  }
872  currentLayout()->project()->setDirty( true );
873 }
874 
876 {
877  if ( !currentLayout() )
878  {
879  return;
880  }
881 
882  //group selected items
883  const QList<QgsLayoutItem *> selectionList = currentLayout()->selectedLayoutItems();
884  QgsLayoutItemGroup *itemGroup = currentLayout()->groupItems( selectionList );
885 
886  if ( !itemGroup )
887  {
888  //group could not be created
889  return;
890  }
891 
892  for ( QgsLayoutItem *item : selectionList )
893  {
894  item->setSelected( false );
895  }
896 
897  currentLayout()->setSelectedItem( itemGroup );
898 }
899 
901 {
902  if ( !currentLayout() )
903  {
904  return;
905  }
906 
907  QList< QgsLayoutItem * > ungroupedItems;
908  //hunt through selection for any groups, and ungroup them
909  const QList<QgsLayoutItem *> selectionList = currentLayout()->selectedLayoutItems();
910  for ( QgsLayoutItem *item : selectionList )
911  {
912  if ( item->type() == QgsLayoutItemRegistry::LayoutGroup )
913  {
914  QgsLayoutItemGroup *itemGroup = static_cast<QgsLayoutItemGroup *>( item );
915  ungroupedItems.append( currentLayout()->ungroupItems( itemGroup ) );
916  }
917  }
918 
919  if ( !ungroupedItems.empty() )
920  {
921  for ( QgsLayoutItem *item : std::as_const( ungroupedItems ) )
922  {
923  item->setSelected( true );
924  }
925  emit itemFocused( ungroupedItems.at( 0 ) );
926  }
927 }
928 
929 void QgsLayoutView::mousePressEvent( QMouseEvent *event )
930 {
931  if ( !currentLayout() )
932  return;
933 
934  if ( mSnapMarker )
935  mSnapMarker->setVisible( false );
936 
937  if ( mTool )
938  {
939  std::unique_ptr<QgsLayoutViewMouseEvent> me( new QgsLayoutViewMouseEvent( this, event, mTool->flags() & QgsLayoutViewTool::FlagSnaps ) );
940  mTool->layoutPressEvent( me.get() );
941  event->setAccepted( me->isAccepted() );
942  }
943 
944  if ( !mTool || !event->isAccepted() )
945  {
946  if ( event->button() == Qt::MiddleButton )
947  {
948  // Pan layout with middle mouse button
949  setTool( mMidMouseButtonPanTool );
950  event->accept();
951  }
952  else if ( event->button() == Qt::RightButton && mMenuProvider )
953  {
954  QMenu *menu = mMenuProvider->createContextMenu( this, currentLayout(), mapToScene( event->pos() ) );
955  if ( menu )
956  {
957  menu->exec( event->globalPos() );
958  delete menu;
959  }
960  }
961  else
962  {
963  QGraphicsView::mousePressEvent( event );
964  }
965  }
966 }
967 
968 void QgsLayoutView::mouseReleaseEvent( QMouseEvent *event )
969 {
970  if ( !currentLayout() )
971  return;
972 
973  if ( mTool )
974  {
975  std::unique_ptr<QgsLayoutViewMouseEvent> me( new QgsLayoutViewMouseEvent( this, event, mTool->flags() & QgsLayoutViewTool::FlagSnaps ) );
976  mTool->layoutReleaseEvent( me.get() );
977  event->setAccepted( me->isAccepted() );
978  }
979 
980  if ( !mTool || !event->isAccepted() )
981  QGraphicsView::mouseReleaseEvent( event );
982 }
983 
984 void QgsLayoutView::mouseMoveEvent( QMouseEvent *event )
985 {
986  if ( !currentLayout() )
987  return;
988 
989  mMouseCurrentXY = event->pos();
990 
991  QPointF cursorPos = mapToScene( mMouseCurrentXY );
992  if ( mTool )
993  {
994  std::unique_ptr<QgsLayoutViewMouseEvent> me( new QgsLayoutViewMouseEvent( this, event, false ) );
995  if ( mTool->flags() & QgsLayoutViewTool::FlagSnaps )
996  {
997  me->snapPoint( mHorizontalSnapLine, mVerticalSnapLine, mTool->ignoredSnapItems() );
998  }
999  if ( mTool->flags() & QgsLayoutViewTool::FlagSnaps )
1000  {
1001  //draw snapping point indicator
1002  if ( me->isSnapped() )
1003  {
1004  cursorPos = me->snappedPoint();
1005  if ( mSnapMarker )
1006  {
1007  mSnapMarker->setPos( me->snappedPoint() );
1008  mSnapMarker->setVisible( true );
1009  }
1010  }
1011  else if ( mSnapMarker )
1012  {
1013  mSnapMarker->setVisible( false );
1014  }
1015  }
1016  mTool->layoutMoveEvent( me.get() );
1017  event->setAccepted( me->isAccepted() );
1018  }
1019 
1020  //update cursor position in status bar
1021  emit cursorPosChanged( cursorPos );
1022 
1023  if ( !mTool || !event->isAccepted() )
1024  QGraphicsView::mouseMoveEvent( event );
1025 }
1026 
1027 void QgsLayoutView::mouseDoubleClickEvent( QMouseEvent *event )
1028 {
1029  if ( !currentLayout() )
1030  return;
1031 
1032  if ( mTool )
1033  {
1034  std::unique_ptr<QgsLayoutViewMouseEvent> me( new QgsLayoutViewMouseEvent( this, event, mTool->flags() & QgsLayoutViewTool::FlagSnaps ) );
1035  mTool->layoutDoubleClickEvent( me.get() );
1036  event->setAccepted( me->isAccepted() );
1037  }
1038 
1039  if ( !mTool || !event->isAccepted() )
1040  QGraphicsView::mouseDoubleClickEvent( event );
1041 }
1042 
1043 void QgsLayoutView::wheelEvent( QWheelEvent *event )
1044 {
1045  if ( !currentLayout() )
1046  return;
1047 
1048  if ( mTool )
1049  {
1050  mTool->wheelEvent( event );
1051  }
1052 
1053  if ( !mTool || !event->isAccepted() )
1054  {
1055  event->accept();
1056  wheelZoom( event );
1057  }
1058 }
1059 
1060 void QgsLayoutView::keyPressEvent( QKeyEvent *event )
1061 {
1062  if ( !currentLayout() )
1063  return;
1064 
1065  if ( mTool )
1066  {
1067  mTool->keyPressEvent( event );
1068  }
1069 
1070  if ( mTool && event->isAccepted() )
1071  return;
1072 
1073  if ( event->key() == Qt::Key_Space && ! event->isAutoRepeat() )
1074  {
1075  if ( !( event->modifiers() & Qt::ControlModifier ) )
1076  {
1077  // Pan layout with space bar
1078  setTool( mSpacePanTool );
1079  }
1080  else
1081  {
1082  //ctrl+space pressed, so switch to temporary keyboard based zoom tool
1083  setTool( mSpaceZoomTool );
1084  }
1085  event->accept();
1086  }
1087  else if ( event->key() == Qt::Key_Left
1088  || event->key() == Qt::Key_Right
1089  || event->key() == Qt::Key_Up
1090  || event->key() == Qt::Key_Down )
1091  {
1092  QgsLayout *l = currentLayout();
1093  const QList<QgsLayoutItem *> layoutItemList = l->selectedLayoutItems();
1094 
1095  QPointF delta = deltaForKeyEvent( event );
1096 
1097  l->undoStack()->beginMacro( tr( "Move Item" ) );
1098  for ( QgsLayoutItem *item : layoutItemList )
1099  {
1100  l->undoStack()->beginCommand( item, tr( "Move Item" ), QgsLayoutItem::UndoIncrementalMove );
1101  item->attemptMoveBy( delta.x(), delta.y() );
1102  l->undoStack()->endCommand();
1103  }
1104  l->undoStack()->endMacro();
1105  event->accept();
1106  }
1107 }
1108 
1109 void QgsLayoutView::keyReleaseEvent( QKeyEvent *event )
1110 {
1111  if ( !currentLayout() )
1112  return;
1113 
1114  if ( mTool )
1115  {
1116  mTool->keyReleaseEvent( event );
1117  }
1118 
1119  if ( !mTool || !event->isAccepted() )
1120  QGraphicsView::keyReleaseEvent( event );
1121 }
1122 
1123 void QgsLayoutView::resizeEvent( QResizeEvent *event )
1124 {
1125  QGraphicsView::resizeEvent( event );
1126  emit zoomLevelChanged();
1127  viewChanged();
1128 }
1129 
1130 void QgsLayoutView::scrollContentsBy( int dx, int dy )
1131 {
1132  QGraphicsView::scrollContentsBy( dx, dy );
1133  viewChanged();
1134 }
1135 
1136 void QgsLayoutView::dragEnterEvent( QDragEnterEvent *e )
1137 {
1138  // By default graphics view delegates the drag events to graphics items.
1139  // But we do not want that and by ignoring the drag enter we let the
1140  // parent (e.g. QgsLayoutDesignerDialog) to handle drops of files.
1141  e->ignore();
1142 }
1143 
1144 void QgsLayoutView::paintEvent( QPaintEvent *event )
1145 {
1146  if ( mPaintingEnabled )
1147  {
1148  QGraphicsView::paintEvent( event );
1149  event->accept();
1150  }
1151  else
1152  {
1153  event->ignore();
1154  }
1155 }
1156 
1157 void QgsLayoutView::invalidateCachedRenders()
1158 {
1159  if ( !currentLayout() )
1160  return;
1161 
1162  //redraw cached map items
1163  QList< QgsLayoutItem *> items;
1164  currentLayout()->layoutItems( items );
1165 
1166  for ( QgsLayoutItem *item : std::as_const( items ) )
1167  {
1168  item->invalidateCache();
1169  }
1170 }
1171 
1173 {
1174  if ( mHorizontalRuler )
1175  {
1176  mHorizontalRuler->setSceneTransform( viewportTransform() );
1177  }
1178  if ( mVerticalRuler )
1179  {
1180  mVerticalRuler->setSceneTransform( viewportTransform() );
1181  }
1182 
1183  // determine page at center of view
1184  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
1185  QRectF visibleRect = mapToScene( viewportRect ).boundingRect();
1186  QPointF centerVisible = visibleRect.center();
1187 
1188  if ( currentLayout() && currentLayout()->pageCollection() )
1189  {
1190  int newPage = currentLayout()->pageCollection()->pageNumberForPoint( centerVisible );
1191  if ( newPage != mCurrentPage )
1192  {
1193  mCurrentPage = newPage;
1194  emit pageChanged( mCurrentPage );
1195  }
1196  }
1197 }
1198 
1199 void QgsLayoutView::pushStatusMessage( const QString &message )
1200 {
1201  emit statusMessage( message );
1202 }
1203 
1204 void QgsLayoutView::wheelZoom( QWheelEvent *event )
1205 {
1206  //get mouse wheel zoom behavior settings
1207  QgsSettings settings;
1208  double zoomFactor = settings.value( QStringLiteral( "qgis/zoom_factor" ), 2 ).toDouble();
1209 
1210  // "Normal" mouse have an angle delta of 120, precision mouses provide data faster, in smaller steps
1211  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 120.0 * std::fabs( event->angleDelta().y() );
1212 
1213  if ( event->modifiers() & Qt::ControlModifier )
1214  {
1215  //holding ctrl while wheel zooming results in a finer zoom
1216  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
1217  }
1218 
1219  //calculate zoom scale factor
1220  bool zoomIn = event->angleDelta().y() > 0;
1221  double scaleFactor = ( zoomIn ? 1 / zoomFactor : zoomFactor );
1222 
1223  //get current visible part of scene
1224  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
1225  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
1226 
1227  //transform the mouse pos to scene coordinates
1228  QPointF scenePoint = mapToScene( event->pos() );
1229 
1230  //adjust view center
1231  QgsPointXY oldCenter( visibleRect.center() );
1232  QgsPointXY newCenter( scenePoint.x() + ( ( oldCenter.x() - scenePoint.x() ) * scaleFactor ),
1233  scenePoint.y() + ( ( oldCenter.y() - scenePoint.y() ) * scaleFactor ) );
1234  centerOn( newCenter.x(), newCenter.y() );
1235 
1236  //zoom layout
1237  if ( zoomIn )
1238  {
1239  scaleSafe( zoomFactor );
1240  }
1241  else
1242  {
1243  scaleSafe( 1 / zoomFactor );
1244  }
1245 }
1246 
1247 QGraphicsLineItem *QgsLayoutView::createSnapLine() const
1248 {
1249  std::unique_ptr< QGraphicsLineItem> item( new QGraphicsLineItem( nullptr ) );
1250  QPen pen = QPen( QColor( Qt::blue ) );
1251  pen.setStyle( Qt::DotLine );
1252  pen.setWidthF( 0.0 );
1253  item->setPen( pen );
1254  item->setZValue( QgsLayout::ZSmartGuide );
1255  return item.release();
1256 }
1257 
1258 //
1259 // QgsLayoutViewSnapMarker
1260 //
1261 
1263 QgsLayoutViewSnapMarker::QgsLayoutViewSnapMarker()
1264  : QGraphicsRectItem( QRectF( 0, 0, 0, 0 ) )
1265 {
1266  QFont f;
1267  QFontMetrics fm( f );
1268  mSize = fm.horizontalAdvance( 'X' );
1269  setPen( QPen( Qt::transparent, mSize ) );
1270 
1271  setFlags( flags() | QGraphicsItem::ItemIgnoresTransformations );
1272  setZValue( QgsLayout::ZSnapIndicator );
1273 }
1274 
1275 void QgsLayoutViewSnapMarker::paint( QPainter *p, const QStyleOptionGraphicsItem *, QWidget * )
1276 {
1277  QPen pen( QColor( 255, 0, 0 ) );
1278  pen.setWidth( 0 );
1279  p->setPen( pen );
1280  p->setBrush( Qt::NoBrush );
1281 
1282  double halfSize = mSize / 2.0;
1283  p->drawLine( QLineF( -halfSize, -halfSize, halfSize, halfSize ) );
1284  p->drawLine( QLineF( -halfSize, halfSize, halfSize, -halfSize ) );
1285 }
1286 
Alignment
Alignment options.
Resize
Resize options.
static void alignItems(QgsLayout *layout, const QList< QgsLayoutItem * > &items, Alignment alignment)
Aligns a set of items from a layout in place.
static void distributeItems(QgsLayout *layout, const QList< QgsLayoutItem * > &items, Distribution distribution)
Distributes a set of items from a layout in place.
static void resizeItems(QgsLayout *layout, const QList< QgsLayoutItem * > &items, Resize resize)
Resizes a set of items from a layout in place.
Distribution
Distribution options.
Base class for frame items, which form a layout multiframe item.
A container for grouping several QgsLayoutItems.
Item representing the paper in a layout.
Base class for graphical items within a QgsLayout.
@ UndoIncrementalMove
Layout item incremental movement, e.g. as a result of a keypress.
virtual void setSelected(bool selected)
Sets whether the item should be selected.
bool isLocked() const
Returns true if the item is locked, and cannot be interacted with using the mouse.
void setLocked(bool locked)
Sets whether the item is locked, preventing mouse interactions with the item.
double length() const
Returns the length of the measurement.
QList< int > visiblePageNumbers(const QRectF &region) const
Returns a list of the page numbers which are visible within the specified region (in layout coordinat...
void changed()
Emitted when pages are added or removed from the collection.
int pageNumberForPoint(QPointF point) const
Returns the page number corresponding to a point in the layout (in layout units).
QList< QgsLayoutItemPage * > visiblePages(const QRectF &region) const
Returns a list of the pages which are visible within the specified region (in layout coordinates).
A custom ruler widget for use with QgsLayoutView, displaying the current zoom and position of the vis...
void setSceneTransform(const QTransform &transform)
Sets the current scene transform.
void setLayoutView(QgsLayoutView *view)
Sets the current layout view to synchronize the ruler with.
void endCommand()
Saves final state of an object and pushes the active command to the undo history.
void beginMacro(const QString &commandText)
Starts a macro command, with the given descriptive commandText.
void beginCommand(QgsLayoutUndoObjectInterface *object, const QString &commandText, int id=0)
Begins a new undo command for the specified object.
void endMacro()
Ends a macro command.
Interface for a QgsLayoutView context menu.
A QgsLayoutViewMouseEvent is the result of a user interaction with the mouse on a QgsLayoutView.
Layout view tool for temporarily panning a layout while a key is depressed.
Layout view tool for temporarily zooming a layout while a key is depressed.
Layout view tool for temporarily panning a layout while a mouse button is depressed.
Abstract base class for all layout view tools.
@ FlagSnaps
Tool utilizes snapped coordinates.
virtual void activate()
Called when tool is set as the currently active layout tool.
void itemFocused(QgsLayoutItem *item)
Emitted when an item is "focused" by the tool, i.e.
void alignSelectedItems(QgsLayoutAligner::Alignment alignment)
Aligns all selected items using the specified alignment.
void zoomFull()
Zooms the view to the full extent of the layout.
void selectNextItemBelow()
Selects the next item below the existing selection, by item z order.
QgsLayoutView(QWidget *parent=nullptr)
Constructor for QgsLayoutView.
void moveSelectedItemsToBottom()
Lowers the selected items to the bottom of the z-order.
void pushStatusMessage(const QString &message)
Pushes a new status bar message to the view.
void viewChanged()
Updates associated rulers and other widgets after view extent or zoom has changed.
void cursorPosChanged(QPointF layoutPoint)
Emitted when the mouse cursor coordinates change within the view.
PasteMode
Paste modes.
Definition: qgslayoutview.h:77
@ PasteModeCenter
Paste items in center of view.
Definition: qgslayoutview.h:79
@ PasteModeInPlace
Paste items in place.
Definition: qgslayoutview.h:80
@ PasteModeCursor
Paste items at cursor position.
Definition: qgslayoutview.h:78
void unlockAllItems()
Unlocks all locked items in the layout.
void deleteSelectedItems()
Deletes all selected items.
void mouseMoveEvent(QMouseEvent *event) override
QgsLayout * currentLayout
Definition: qgslayoutview.h:63
void setMenuProvider(QgsLayoutViewMenuProvider *provider)
Sets a provider for context menus.
void dragEnterEvent(QDragEnterEvent *e) override
void resizeEvent(QResizeEvent *event) override
void lowerSelectedItems()
Lowers the selected items down the z-order.
void setPaintingEnabled(bool enabled)
Sets whether widget repainting should be allowed for the view.
void mouseReleaseEvent(QMouseEvent *event) override
QgsPreviewEffect::PreviewMode previewMode() const
Returns the preview mode which may be used to modify the view's appearance.
void lockSelectedItems()
Locks any selected items, preventing them from being interacted with by mouse interactions.
void setSectionLabel(const QString &label)
Sets a section label, to display above the first page shown in the view.
void resizeSelectedItems(QgsLayoutAligner::Resize resize)
Resizes all selected items using the specified resize mode.
void setTool(QgsLayoutViewTool *tool)
Sets the tool currently being used in the view.
void zoomLevelChanged()
Emitted whenever the zoom level of the view is changed.
void deleteItems(const QList< QgsLayoutItem * > &items)
Delete the specified items.
void selectAll()
Selects all items in the view.
QList< QgsLayoutItem * > pasteItems(PasteMode mode)
Pastes items from clipboard, using the specified mode.
void willBeDeleted()
Emitted in the destructor when the view is about to be deleted, but is still in a perfectly valid sta...
QPointF deltaForKeyEvent(QKeyEvent *event)
Returns the delta (in layout coordinates) by which to move items for the given key event.
void setHorizontalRuler(QgsLayoutRuler *ruler)
Sets a horizontal ruler to synchronize with the view state.
~QgsLayoutView() override
void setPreviewMode(QgsPreviewEffect::PreviewMode mode)
Sets the preview mode which should be used to modify the view's appearance.
void deselectAll()
Deselects all items in the view.
void keyPressEvent(QKeyEvent *event) override
void zoomWidth()
Zooms the view to the full width of the layout.
void raiseSelectedItems()
Raises the selected items up the z-order.
void statusMessage(const QString &message)
Emitted when the view has a message for display in a parent window's status bar.
void itemFocused(QgsLayoutItem *item)
Emitted when an item is "focused" in the view, i.e.
void selectNextItemAbove()
Selects the next item above the existing selection, by item z order.
void moveSelectedItemsToTop()
Raises the selected items to the top of the z-order.
bool hasItemsInClipboard() const
Returns true if the current clipboard contains layout items.
void zoomActual()
Zooms to the actual size of the layout.
void setPreviewModeEnabled(bool enabled)
Sets whether a preview effect should be used to alter the view's appearance.
void layoutSet(QgsLayout *layout)
Emitted when a layout is set for the view.
void setCurrentLayout(QgsLayout *layout)
Sets the current layout to edit in the view.
void wheelEvent(QWheelEvent *event) override
ClipboardOperation
Clipboard operations.
Definition: qgslayoutview.h:70
@ ClipboardCut
Cut items.
Definition: qgslayoutview.h:71
void ungroupSelectedItems()
Ungroups all selected items.
void emitZoomLevelChanged()
Emits the zoomLevelChanged() signal.
bool previewModeEnabled() const
Returns true if a preview effect is being used to alter the view's appearance.
void zoomOut()
Zooms out of the view by a preset amount.
void setVerticalRuler(QgsLayoutRuler *ruler)
Sets a vertical ruler to synchronize with the view state.
QList< QgsLayoutItemPage * > visiblePages() const
Returns a list of page items which are currently visible in the view.
void copyItems(const QList< QgsLayoutItem * > &items, ClipboardOperation operation)
Cuts or copies the a list of items, respecting the specified operation.
void setZoomLevel(double level)
Sets the zoom level for the view, where a zoom level of 1.0 corresponds to 100%.
QgsLayoutViewTool * tool
Definition: qgslayoutview.h:64
void distributeSelectedItems(QgsLayoutAligner::Distribution distribution)
Distributes all selected items using the specified distribution.
void unsetTool(QgsLayoutViewTool *tool)
Unsets the current view tool, if it matches the specified tool.
void invertSelection()
Inverts the current selection, selecting deselected items and deselecting and selected items.
void toolSet(QgsLayoutViewTool *tool)
Emitted when the current tool is changed.
void mouseDoubleClickEvent(QMouseEvent *event) override
void scaleSafe(double scale)
Scales the view in a safe way, by limiting the acceptable range of the scale applied.
void pageChanged(int page)
Emitted when the page visible in the view is changed.
void scrollContentsBy(int dx, int dy) override
void copySelectedItems(ClipboardOperation operation)
Cuts or copies the selected items, respecting the specified operation.
void zoomIn()
Zooms in to the view by a preset amount.
void paintEvent(QPaintEvent *event) override
void keyReleaseEvent(QKeyEvent *event) override
QgsLayoutViewMenuProvider * menuProvider() const
Returns the provider for context menus.
QList< int > visiblePageNumbers() const
Returns a list of page numbers for pages which are currently visible in the view.
void groupSelectedItems()
Groups all selected items.
void mousePressEvent(QMouseEvent *event) override
Base class for layouts, which can contain items such as maps, labels, scalebars, etc.
Definition: qgslayout.h:51
QgsLayoutModel * itemsModel()
Returns the items model attached to the layout.
Definition: qgslayout.cpp:137
QgsLayoutPageCollection * pageCollection()
Returns a pointer to the layout's page collection, which stores and manages page items in the layout.
Definition: qgslayout.cpp:459
void layoutItems(QList< T * > &itemList) const
Returns a list of layout items of a specific type.
Definition: qgslayout.h:122
QgsLayoutGuideCollection & guides()
Returns a reference to the layout's guide collection, which manages page snap guides.
Definition: qgslayout.cpp:385
QList< QgsLayoutItem * > ungroupItems(QgsLayoutItemGroup *group)
Ungroups items by removing them from an item group and removing the group from the layout.
Definition: qgslayout.cpp:764
bool moveItemToTop(QgsLayoutItem *item, bool deferUpdate=false)
Raises an item up to the top of the z-order.
Definition: qgslayout.cpp:212
bool moveItemToBottom(QgsLayoutItem *item, bool deferUpdate=false)
Lowers an item down to the bottom of the z-order.
Definition: qgslayout.cpp:225
QgsLayoutItemGroup * groupItems(const QList< QgsLayoutItem * > &items)
Creates a new group from a list of layout items and adds the group to the layout.
Definition: qgslayout.cpp:738
QList< QgsLayoutItem * > addItemsFromXml(const QDomElement &parentElement, const QDomDocument &document, const QgsReadWriteContext &context, QPointF *position=nullptr, bool pasteInPlace=false)
Add items from an XML representation to the layout.
Definition: qgslayout.cpp:989
bool lowerItem(QgsLayoutItem *item, bool deferUpdate=false)
Lowers an item down the z-order.
Definition: qgslayout.cpp:199
bool raiseItem(QgsLayoutItem *item, bool deferUpdate=false)
Raises an item up the z-order.
Definition: qgslayout.cpp:186
QList< QgsLayoutItem * > selectedLayoutItems(bool includeLockedItems=true)
Returns list of selected layout items.
Definition: qgslayout.cpp:142
void selectedItemChanged(QgsLayoutItem *selected)
Emitted whenever the selected item changes.
void deselectAll()
Clears any selected items in the layout.
Definition: qgslayout.cpp:169
void setSelectedItem(QgsLayoutItem *item)
Clears any selected items and sets item as the current selection.
Definition: qgslayout.cpp:159
void removeLayoutItem(QgsLayoutItem *item)
Removes an item from the layout.
Definition: qgslayout.cpp:556
QgsLayoutMeasurement convertFromLayoutUnits(double length, QgsUnitTypes::LayoutUnit unit) const
Converts a length measurement from the layout's native units to a specified target unit.
Definition: qgslayout.cpp:344
void updateZValues(bool addUndoCommands=true)
Resets the z-values of items based on their position in the internal z order list.
Definition: qgslayout.cpp:919
@ ZSmartGuide
Z-value for smart (item bounds based) guides.
Definition: qgslayout.h:63
@ ZSnapIndicator
Z-value for snapping indicator.
Definition: qgslayout.h:66
QgsProject * project() const
The project associated with the layout.
Definition: qgslayout.cpp:132
QgsLayoutUndoStack * undoStack()
Returns a pointer to the layout's undo stack, which manages undo/redo states for the layout and it's ...
Definition: qgslayout.cpp:686
A class to represent a 2D point.
Definition: qgspointxy.h:59
A graphics effect which can be applied to a widget to simulate various printing and color blindness m...
void setMode(PreviewMode mode)
Sets the mode for the preview effect, which controls how the effect modifies a widgets appearance.
PreviewMode mode() const
Returns the mode used for the preview effect.
void setDirty(bool b=true)
Flag the project as dirty (modified).
Definition: qgsproject.cpp:518
The class is used as a container of context for various read/write operations on other objects.
A rectangle specified with double values.
Definition: qgsrectangle.h:42
QgsPointXY center() const SIP_HOLDGIL
Returns the center point of the rectangle.
Definition: qgsrectangle.h:251
@ LayoutMillimeters
Millimeters.
Definition: qgsunittypes.h:183
@ LayoutPixels
Pixels.
Definition: qgsunittypes.h:190
void selectNextByZOrder(QgsLayout *layout, bool above)
#define MAX_VIEW_SCALE
#define MIN_VIEW_SCALE