QGIS API Documentation  3.22.4-Białowieża (ce8e65e95e)
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 <QMenu>
42 #include <QClipboard>
43 #include <QMimeData>
44 #include <QWindow>
45 #include <QScreen>
46 
47 #define MIN_VIEW_SCALE 0.05
48 #define MAX_VIEW_SCALE 1000.0
49 
50 QgsLayoutView::QgsLayoutView( QWidget *parent )
51  : QGraphicsView( parent )
52 {
53  setResizeAnchor( QGraphicsView::AnchorViewCenter );
54  setMouseTracking( true );
55  viewport()->setMouseTracking( true );
56 
57  // set the "scene" background on the view using stylesheets
58  // we don't want to use QGraphicsScene::setBackgroundBrush because we want to keep
59  // a transparent background for exports, and it's only a cosmetic thing for the view only
60  // ALSO - only set it on the viewport - we don't want scrollbars/etc affected by this
61  viewport()->setStyleSheet( QStringLiteral( "background-color:#d7d7d7;" ) );
62 
63  mSpacePanTool = new QgsLayoutViewToolTemporaryKeyPan( this );
64  mMidMouseButtonPanTool = new QgsLayoutViewToolTemporaryMousePan( this );
65  mSpaceZoomTool = new QgsLayoutViewToolTemporaryKeyZoom( this );
66 
67  mPreviewEffect = new QgsPreviewEffect( this );
68  viewport()->setGraphicsEffect( mPreviewEffect );
69 
70  connect( this, &QgsLayoutView::zoomLevelChanged, this, &QgsLayoutView::invalidateCachedRenders );
71 }
72 
74 {
75  emit willBeDeleted();
76 }
77 
79 {
80  return qobject_cast<QgsLayout *>( scene() );
81 }
82 
84 {
85  return qobject_cast<const QgsLayout *>( scene() );
86 }
87 
89 {
90  setScene( layout );
91 
94 
95  viewChanged();
96 
97  // IMPORTANT!
98  // previous snap markers, snap lines are owned by previous layout - so don't delete them here!
99  mSnapMarker = new QgsLayoutViewSnapMarker();
100  mSnapMarker->hide();
101  layout->addItem( mSnapMarker );
102  mHorizontalSnapLine = createSnapLine();
103  mHorizontalSnapLine->hide();
104  layout->addItem( mHorizontalSnapLine );
105  mVerticalSnapLine = createSnapLine();
106  mVerticalSnapLine->hide();
107  layout->addItem( mVerticalSnapLine );
108  mSectionLabel = nullptr;
109 
110  if ( mHorizontalRuler )
111  {
112  connect( &layout->guides(), &QAbstractItemModel::dataChanged, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
113  connect( &layout->guides(), &QAbstractItemModel::rowsInserted, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
114  connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
115  connect( &layout->guides(), &QAbstractItemModel::modelReset, mHorizontalRuler, [ = ] { mHorizontalRuler->update(); } );
116  }
117  if ( mVerticalRuler )
118  {
119  connect( &layout->guides(), &QAbstractItemModel::dataChanged, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
120  connect( &layout->guides(), &QAbstractItemModel::rowsInserted, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
121  connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
122  connect( &layout->guides(), &QAbstractItemModel::modelReset, mVerticalRuler, [ = ] { mVerticalRuler->update(); } );
123  }
124 
125  //emit layoutSet, so that designer dialogs can update for the new layout
126  emit layoutSet( layout );
127 }
128 
130 {
131  return mTool;
132 }
133 
135 {
136  if ( !tool )
137  return;
138 
139  if ( mTool )
140  {
141  mTool->deactivate();
142  disconnect( mTool, &QgsLayoutViewTool::itemFocused, this, &QgsLayoutView::itemFocused );
143  }
144 
145  if ( mSnapMarker )
146  mSnapMarker->hide();
147  if ( mHorizontalSnapLine )
148  mHorizontalSnapLine->hide();
149  if ( mVerticalSnapLine )
150  mVerticalSnapLine->hide();
151 
152  // activate new tool before setting it - gives tools a chance
153  // to respond to whatever the current tool is
154  tool->activate();
155  mTool = tool;
157  emit toolSet( mTool );
158 }
159 
161 {
162  if ( mTool && mTool == tool )
163  {
164  mTool->deactivate();
165  emit toolSet( nullptr );
166  setCursor( Qt::ArrowCursor );
167  }
168 }
169 
171 {
172  mPreviewEffect->setEnabled( enabled );
173 }
174 
176 {
177  return mPreviewEffect->isEnabled();
178 }
179 
181 {
182  mPreviewEffect->setMode( mode );
183 }
184 
186 {
187  return mPreviewEffect->mode();
188 }
189 
190 void QgsLayoutView::scaleSafe( double scale )
191 {
192  double currentScale = transform().m11();
193  scale *= currentScale;
194  scale = std::clamp( scale, MIN_VIEW_SCALE, MAX_VIEW_SCALE );
195  setTransform( QTransform::fromScale( scale, scale ) );
196  emit zoomLevelChanged();
197  viewChanged();
198 }
199 
200 void QgsLayoutView::setZoomLevel( double level )
201 {
202  if ( !currentLayout() )
203  return;
204 
205  if ( currentLayout()->units() == QgsUnitTypes::LayoutPixels )
206  {
207  setTransform( QTransform::fromScale( level, level ) );
208  }
209  else
210  {
211  double dpi = mScreenDpi;
212  //monitor dpi is not always correct - so make sure the value is sane
213  if ( ( dpi < 60 ) || ( dpi > 1200 ) )
214  dpi = 72;
215 
216  //desired pixel width for 1mm on screen
217  level = std::clamp( level, MIN_VIEW_SCALE, MAX_VIEW_SCALE );
218  double mmLevel = currentLayout()->convertFromLayoutUnits( level, QgsUnitTypes::LayoutMillimeters ).length() * dpi / 25.4;
219  setTransform( QTransform::fromScale( mmLevel, mmLevel ) );
220  }
221  emit zoomLevelChanged();
222  viewChanged();
223 }
224 
226 {
227  mHorizontalRuler = ruler;
228  ruler->setLayoutView( this );
229  if ( QgsLayout *layout = currentLayout() )
230  {
231  connect( &layout->guides(), &QAbstractItemModel::dataChanged, ruler, [ = ] { mHorizontalRuler->update(); } );
232  connect( &layout->guides(), &QAbstractItemModel::rowsInserted, ruler, [ = ] { mHorizontalRuler->update(); } );
233  connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, ruler, [ = ] { mHorizontalRuler->update(); } );
234  connect( &layout->guides(), &QAbstractItemModel::modelReset, ruler, [ = ] { mHorizontalRuler->update(); } );
235  }
236  viewChanged();
237 }
238 
240 {
241  mVerticalRuler = ruler;
242  ruler->setLayoutView( this );
243  if ( QgsLayout *layout = currentLayout() )
244  {
245  connect( &layout->guides(), &QAbstractItemModel::dataChanged, ruler, [ = ] { mVerticalRuler->update(); } );
246  connect( &layout->guides(), &QAbstractItemModel::rowsInserted, ruler, [ = ] { mVerticalRuler->update(); } );
247  connect( &layout->guides(), &QAbstractItemModel::rowsRemoved, ruler, [ = ] { mVerticalRuler->update(); } );
248  connect( &layout->guides(), &QAbstractItemModel::modelReset, ruler, [ = ] { mVerticalRuler->update(); } );
249  }
250  viewChanged();
251 }
252 
254 {
255  mMenuProvider.reset( provider );
256 }
257 
259 {
260  return mMenuProvider.get();
261 }
262 
263 QList<QgsLayoutItemPage *> QgsLayoutView::visiblePages() const
264 {
265  if ( !currentLayout() )
266  return QList< QgsLayoutItemPage *>();
267 
268  //get current visible part of scene
269  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
270  QRectF visibleRect = mapToScene( viewportRect ).boundingRect();
271  return currentLayout()->pageCollection()->visiblePages( visibleRect );
272 }
273 
275 {
276  if ( !currentLayout() )
277  return QList< int >();
278 
279  //get current visible part of scene
280  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
281  QRectF visibleRect = mapToScene( viewportRect ).boundingRect();
282  return currentLayout()->pageCollection()->visiblePageNumbers( visibleRect );
283 }
284 
286 {
287  if ( !currentLayout() )
288  return;
289 
290  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
291  QgsLayoutAligner::alignItems( currentLayout(), selectedItems, alignment );
292 }
293 
295 {
296  if ( !currentLayout() )
297  return;
298 
299  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
300  QgsLayoutAligner::distributeItems( currentLayout(), selectedItems, distribution );
301 }
302 
304 {
305  if ( !currentLayout() )
306  return;
307 
308  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
309  QgsLayoutAligner::resizeItems( currentLayout(), selectedItems, resize );
310 }
311 
313 {
314  copyItems( currentLayout()->selectedLayoutItems(), operation );
315 }
316 
317 void QgsLayoutView::copyItems( const QList<QgsLayoutItem *> &items, QgsLayoutView::ClipboardOperation operation )
318 {
319  if ( !currentLayout() )
320  return;
321 
322  QgsReadWriteContext context;
323  QDomDocument doc;
324  QDomElement documentElement = doc.createElement( QStringLiteral( "LayoutItemClipboard" ) );
325  if ( operation == ClipboardCut )
326  currentLayout()->undoStack()->beginMacro( tr( "Cut Items" ) );
327 
328  QSet< QgsLayoutMultiFrame * > copiedMultiFrames;
329 
330  for ( QgsLayoutItem *item : items )
331  {
332  // copy every child from a group
333  if ( QgsLayoutItemGroup *itemGroup = qobject_cast<QgsLayoutItemGroup *>( item ) )
334  {
335  const QList<QgsLayoutItem *> groupedItems = itemGroup->items();
336  for ( const QgsLayoutItem *groupedItem : groupedItems )
337  {
338  groupedItem->writeXml( documentElement, doc, context );
339  }
340  }
341  else if ( QgsLayoutFrame *frame = qobject_cast<QgsLayoutFrame *>( item ) )
342  {
343  // copy multiframe too
344  if ( frame->multiFrame() && !copiedMultiFrames.contains( frame->multiFrame() ) )
345  {
346  frame->multiFrame()->writeXml( documentElement, doc, context );
347  copiedMultiFrames.insert( frame->multiFrame() );
348  }
349  }
350  item->writeXml( documentElement, doc, context );
351  if ( operation == ClipboardCut )
352  currentLayout()->removeLayoutItem( item );
353  }
354  doc.appendChild( documentElement );
355  if ( operation == ClipboardCut )
356  {
358  currentLayout()->update();
359  }
360 
361  //remove the UUIDs since we don't want any duplicate UUID
362  QDomNodeList itemsNodes = doc.elementsByTagName( QStringLiteral( "LayoutItem" ) );
363  for ( int i = 0; i < itemsNodes.count(); ++i )
364  {
365  QDomNode itemNode = itemsNodes.at( i );
366  if ( itemNode.isElement() )
367  {
368  itemNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
369  itemNode.toElement().removeAttribute( QStringLiteral( "groupUuid" ) );
370  }
371  }
372  QDomNodeList multiFrameNodes = doc.elementsByTagName( QStringLiteral( "LayoutMultiFrame" ) );
373  for ( int i = 0; i < multiFrameNodes.count(); ++i )
374  {
375  QDomNode multiFrameNode = multiFrameNodes.at( i );
376  if ( multiFrameNode.isElement() )
377  {
378  multiFrameNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
379  QDomNodeList frameNodes = multiFrameNode.toElement().elementsByTagName( QStringLiteral( "childFrame" ) );
380  for ( int j = 0; j < frameNodes.count(); ++j )
381  {
382  QDomNode itemNode = frameNodes.at( j );
383  if ( itemNode.isElement() )
384  {
385  itemNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
386  }
387  }
388  }
389  }
390 
391  QMimeData *mimeData = new QMimeData;
392  mimeData->setData( QStringLiteral( "text/xml" ), doc.toByteArray() );
393  QClipboard *clipboard = QApplication::clipboard();
394  clipboard->setMimeData( mimeData );
395 }
396 
397 QList< QgsLayoutItem * > QgsLayoutView::pasteItems( QgsLayoutView::PasteMode mode )
398 {
399  if ( !currentLayout() )
400  return QList< QgsLayoutItem * >();
401 
402  QList< QgsLayoutItem * > pastedItems;
403  QDomDocument doc;
404  QClipboard *clipboard = QApplication::clipboard();
405  if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral( "text/xml" ) ) ) )
406  {
407  QDomElement docElem = doc.documentElement();
408  if ( docElem.tagName() == QLatin1String( "LayoutItemClipboard" ) )
409  {
410  QPointF pt;
411  switch ( mode )
412  {
413  case PasteModeCursor:
414  case PasteModeInPlace:
415  {
416  // place items at cursor position
417  pt = mapToScene( mapFromGlobal( QCursor::pos() ) );
418  break;
419  }
420  case PasteModeCenter:
421  {
422  // place items in center of viewport
423  pt = mapToScene( viewport()->rect().center() );
424  break;
425  }
426  }
427  bool pasteInPlace = ( mode == PasteModeInPlace );
428  currentLayout()->undoStack()->beginMacro( tr( "Paste Items" ) );
429  currentLayout()->undoStack()->beginCommand( currentLayout(), tr( "Paste Items" ) );
430  pastedItems = currentLayout()->addItemsFromXml( docElem, doc, QgsReadWriteContext(), &pt, pasteInPlace );
433  }
434  }
435  return pastedItems;
436 }
437 
438 QList<QgsLayoutItem *> QgsLayoutView::pasteItems( QPointF layoutPoint )
439 {
440  if ( !currentLayout() )
441  return QList<QgsLayoutItem *>();
442 
443  QList< QgsLayoutItem * > pastedItems;
444  QDomDocument doc;
445  QClipboard *clipboard = QApplication::clipboard();
446  if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral( "text/xml" ) ) ) )
447  {
448  QDomElement docElem = doc.documentElement();
449  if ( docElem.tagName() == QLatin1String( "LayoutItemClipboard" ) )
450  {
451  currentLayout()->undoStack()->beginMacro( tr( "Paste Items" ) );
452  currentLayout()->undoStack()->beginCommand( currentLayout(), tr( "Paste Items" ) );
453  pastedItems = currentLayout()->addItemsFromXml( docElem, doc, QgsReadWriteContext(), &layoutPoint, false );
456  }
457  }
458  return pastedItems;
459 }
460 
462 {
463  QDomDocument doc;
464  QClipboard *clipboard = QApplication::clipboard();
465  if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral( "text/xml" ) ) ) )
466  {
467  QDomElement docElem = doc.documentElement();
468  if ( docElem.tagName() == QLatin1String( "LayoutItemClipboard" ) )
469  return true;
470  }
471  return false;
472 }
473 
474 QPointF QgsLayoutView::deltaForKeyEvent( QKeyEvent *event )
475 {
476  // increment used for cursor key item movement
477  double increment = 1.0;
478  if ( event->modifiers() & Qt::ShiftModifier )
479  {
480  //holding shift while pressing cursor keys results in a big step
481  increment = 10.0;
482  }
483  else if ( event->modifiers() & Qt::AltModifier )
484  {
485  //holding alt while pressing cursor keys results in a 1 pixel step
486  double viewScale = transform().m11();
487  if ( viewScale > 0 )
488  {
489  increment = 1 / viewScale;
490  }
491  }
492 
493  double deltaX = 0;
494  double deltaY = 0;
495  switch ( event->key() )
496  {
497  case Qt::Key_Left:
498  deltaX = -increment;
499  break;
500  case Qt::Key_Right:
501  deltaX = increment;
502  break;
503  case Qt::Key_Up:
504  deltaY = -increment;
505  break;
506  case Qt::Key_Down:
507  deltaY = increment;
508  break;
509  default:
510  break;
511  }
512 
513  return QPointF( deltaX, deltaY );
514 }
515 
517 {
518  mPaintingEnabled = enabled;
519  if ( enabled )
520  update();
521 }
522 
523 void QgsLayoutView::setSectionLabel( const QString &label )
524 {
525  if ( !currentLayout() )
526  return;
527 
528  if ( !mSectionLabel )
529  {
530  mSectionLabel = new QgsLayoutReportSectionLabel( currentLayout(), this );
531  currentLayout()->addItem( mSectionLabel );
532  mSectionLabel->setRect( 0, -200, 1000, 200 );
533  mSectionLabel->setZValue( -1 );
534  }
535  mSectionLabel->setLabel( label );
536 }
537 
539 {
540  if ( !scene() )
541  return;
542 
543  fitInView( scene()->sceneRect(), Qt::KeepAspectRatio );
544  viewChanged();
545  emit zoomLevelChanged();
546 }
547 
549 {
550  if ( !scene() )
551  return;
552 
553  //get current visible part of scene
554  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
555  QRectF visibleRect = mapToScene( viewportRect ).boundingRect();
556 
557  double verticalCenter = ( visibleRect.top() + visibleRect.bottom() ) / 2.0;
558  // expand out visible rect to include left/right edges of scene
559  // centered on current visible vertical center
560  // note that we can't have a 0 height rect - fitInView doesn't handle that
561  // so we just set a very small height instead.
562  const double tinyHeight = 0.01;
563  QRectF targetRect( scene()->sceneRect().left(),
564  verticalCenter - tinyHeight,
565  scene()->sceneRect().width(),
566  tinyHeight * 2 );
567 
568  fitInView( targetRect, Qt::KeepAspectRatio );
569  emit zoomLevelChanged();
570  viewChanged();
571 }
572 
574 {
575  scaleSafe( 2 );
576 }
577 
579 {
580  scaleSafe( 0.5 );
581 }
582 
584 {
585  setZoomLevel( 1.0 );
586 }
587 
589 {
590  emit zoomLevelChanged();
591 }
592 
594 {
595  if ( !currentLayout() )
596  {
597  return;
598  }
599 
600  //select all items in layout
601  QgsLayoutItem *focusedItem = nullptr;
602  const QList<QGraphicsItem *> itemList = currentLayout()->items();
603  for ( QGraphicsItem *graphicsItem : itemList )
604  {
605  QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
606  QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( graphicsItem );
607  if ( item && !paperItem )
608  {
609  if ( !item->isLocked() )
610  {
611  item->setSelected( true );
612  if ( !focusedItem )
613  focusedItem = item;
614  }
615  else
616  {
617  //deselect all locked items
618  item->setSelected( false );
619  }
620  }
621  }
622  emit itemFocused( focusedItem );
623 }
624 
626 {
627  if ( !currentLayout() )
628  {
629  return;
630  }
631 
633 }
634 
636 {
637  if ( !currentLayout() )
638  {
639  return;
640  }
641 
642  QgsLayoutItem *focusedItem = nullptr;
643  //check all items in layout
644  const QList<QGraphicsItem *> itemList = currentLayout()->items();
645  for ( QGraphicsItem *graphicsItem : itemList )
646  {
647  QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicsItem );
648  QgsLayoutItemPage *paperItem = dynamic_cast<QgsLayoutItemPage *>( graphicsItem );
649  if ( item && !paperItem )
650  {
651  //flip selected state for items (and deselect any locked items)
652  if ( item->isSelected() || item->isLocked() )
653  {
654  item->setSelected( false );
655  }
656  else
657  {
658  item->setSelected( true );
659  if ( !focusedItem )
660  focusedItem = item;
661  }
662  }
663  }
664  if ( focusedItem )
665  emit itemFocused( focusedItem );
666 }
667 
668 
669 void selectNextByZOrder( QgsLayout *layout, bool above )
670 {
671  if ( !layout )
672  return;
673 
674  QgsLayoutItem *previousSelectedItem = nullptr;
675  const QList<QgsLayoutItem *> selectedItems = layout->selectedLayoutItems();
676  if ( !selectedItems.isEmpty() )
677  {
678  previousSelectedItem = selectedItems.at( 0 );
679  }
680 
681  if ( !previousSelectedItem )
682  {
683  return;
684  }
685 
686  //select item with target z value
687  QgsLayoutItem *selectedItem = nullptr;
688  if ( !above )
689  selectedItem = layout->itemsModel()->findItemBelow( previousSelectedItem );
690  else
691  selectedItem = layout->itemsModel()->findItemAbove( previousSelectedItem );
692 
693  if ( !selectedItem )
694  {
695  return;
696  }
697 
698  //OK, found a good target item
699  layout->setSelectedItem( selectedItem );
700 }
701 
703 {
705 }
706 
708 {
709  selectNextByZOrder( currentLayout(), false );
710 }
711 
713 {
714  if ( !currentLayout() )
715  return;
716 
717  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
718  bool itemsRaised = false;
719  for ( QgsLayoutItem *item : selectedItems )
720  {
721  itemsRaised = itemsRaised | currentLayout()->raiseItem( item, true );
722  }
723 
724  if ( !itemsRaised )
725  {
726  //no change
727  return;
728  }
729 
730  //update all positions
732  currentLayout()->update();
733 }
734 
736 {
737  if ( !currentLayout() )
738  return;
739 
740  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
741  bool itemsLowered = false;
742  for ( QgsLayoutItem *item : selectedItems )
743  {
744  itemsLowered = itemsLowered | currentLayout()->lowerItem( item, true );
745  }
746 
747  if ( !itemsLowered )
748  {
749  //no change
750  return;
751  }
752 
753  //update all positions
755  currentLayout()->update();
756 }
757 
759 {
760  if ( !currentLayout() )
761  return;
762 
763  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
764  bool itemsRaised = false;
765  for ( QgsLayoutItem *item : selectedItems )
766  {
767  itemsRaised = itemsRaised | currentLayout()->moveItemToTop( item, true );
768  }
769 
770  if ( !itemsRaised )
771  {
772  //no change
773  return;
774  }
775 
776  //update all positions
778  currentLayout()->update();
779 }
780 
782 {
783  if ( !currentLayout() )
784  return;
785 
786  const QList<QgsLayoutItem *> selectedItems = currentLayout()->selectedLayoutItems();
787  bool itemsLowered = false;
788  for ( QgsLayoutItem *item : selectedItems )
789  {
790  itemsLowered = itemsLowered | currentLayout()->moveItemToBottom( item, true );
791  }
792 
793  if ( !itemsLowered )
794  {
795  //no change
796  return;
797  }
798 
799  //update all positions
801  currentLayout()->update();
802 }
803 
805 {
806  if ( !currentLayout() )
807  return;
808 
809  currentLayout()->undoStack()->beginMacro( tr( "Lock Items" ) );
810  const QList<QgsLayoutItem *> selectionList = currentLayout()->selectedLayoutItems();
811  for ( QgsLayoutItem *item : selectionList )
812  {
813  item->setLocked( true );
814  }
815 
818 }
819 
821 {
822  if ( !currentLayout() )
823  return;
824 
825  //unlock all items in layout
826  currentLayout()->undoStack()->beginMacro( tr( "Unlock Items" ) );
827 
828  //first, clear the selection
830 
831  QgsLayoutItem *focusItem = nullptr;
832 
833  const QList<QGraphicsItem *> itemList = currentLayout()->items();
834  for ( QGraphicsItem *graphicItem : itemList )
835  {
836  QgsLayoutItem *item = dynamic_cast<QgsLayoutItem *>( graphicItem );
837  if ( item && item->isLocked() )
838  {
839  focusItem = item;
840  item->setLocked( false );
841  //select unlocked items, same behavior as illustrator
842  item->setSelected( true );
843  }
844  }
846 
847  emit itemFocused( focusItem );
848 }
849 
851 {
852  if ( !currentLayout() )
853  return;
854 
855  deleteItems( currentLayout()->selectedLayoutItems() );
856 }
857 
858 void QgsLayoutView::deleteItems( const QList<QgsLayoutItem *> &items )
859 {
860  if ( !currentLayout() )
861  return;
862 
863  if ( items.empty() )
864  return;
865 
866  currentLayout()->undoStack()->beginMacro( tr( "Delete Items" ) );
867  //delete selected items
868  for ( QgsLayoutItem *item : items )
869  {
870  currentLayout()->removeLayoutItem( item );
871  }
873  currentLayout()->project()->setDirty( true );
874 }
875 
877 {
878  if ( !currentLayout() )
879  {
880  return;
881  }
882 
883  //group selected items
884  const QList<QgsLayoutItem *> selectionList = currentLayout()->selectedLayoutItems();
885  QgsLayoutItemGroup *itemGroup = currentLayout()->groupItems( selectionList );
886 
887  if ( !itemGroup )
888  {
889  //group could not be created
890  return;
891  }
892 
893  for ( QgsLayoutItem *item : selectionList )
894  {
895  item->setSelected( false );
896  }
897 
898  currentLayout()->setSelectedItem( itemGroup );
899 }
900 
902 {
903  if ( !currentLayout() )
904  {
905  return;
906  }
907 
908  QList< QgsLayoutItem * > ungroupedItems;
909  //hunt through selection for any groups, and ungroup them
910  const QList<QgsLayoutItem *> selectionList = currentLayout()->selectedLayoutItems();
911  for ( QgsLayoutItem *item : selectionList )
912  {
913  if ( item->type() == QgsLayoutItemRegistry::LayoutGroup )
914  {
915  QgsLayoutItemGroup *itemGroup = static_cast<QgsLayoutItemGroup *>( item );
916  ungroupedItems.append( currentLayout()->ungroupItems( itemGroup ) );
917  }
918  }
919 
920  if ( !ungroupedItems.empty() )
921  {
922  for ( QgsLayoutItem *item : std::as_const( ungroupedItems ) )
923  {
924  item->setSelected( true );
925  }
926  emit itemFocused( ungroupedItems.at( 0 ) );
927  }
928 }
929 
930 void QgsLayoutView::mousePressEvent( QMouseEvent *event )
931 {
932  if ( !currentLayout() )
933  return;
934 
935  if ( mSnapMarker )
936  mSnapMarker->setVisible( false );
937 
938  if ( mTool )
939  {
940  std::unique_ptr<QgsLayoutViewMouseEvent> me( new QgsLayoutViewMouseEvent( this, event, mTool->flags() & QgsLayoutViewTool::FlagSnaps ) );
941  mTool->layoutPressEvent( me.get() );
942  event->setAccepted( me->isAccepted() );
943  }
944 
945  if ( !mTool || !event->isAccepted() )
946  {
947  if ( event->button() == Qt::MiddleButton )
948  {
949  // Pan layout with middle mouse button
950  setTool( mMidMouseButtonPanTool );
951  event->accept();
952  }
953  else if ( event->button() == Qt::RightButton && mMenuProvider )
954  {
955  QMenu *menu = mMenuProvider->createContextMenu( this, currentLayout(), mapToScene( event->pos() ) );
956  if ( menu )
957  {
958  menu->exec( event->globalPos() );
959  delete menu;
960  }
961  }
962  else
963  {
964  QGraphicsView::mousePressEvent( event );
965  }
966  }
967 }
968 
969 void QgsLayoutView::mouseReleaseEvent( QMouseEvent *event )
970 {
971  if ( !currentLayout() )
972  return;
973 
974  if ( mTool )
975  {
976  std::unique_ptr<QgsLayoutViewMouseEvent> me( new QgsLayoutViewMouseEvent( this, event, mTool->flags() & QgsLayoutViewTool::FlagSnaps ) );
977  mTool->layoutReleaseEvent( me.get() );
978  event->setAccepted( me->isAccepted() );
979  }
980 
981  if ( !mTool || !event->isAccepted() )
982  QGraphicsView::mouseReleaseEvent( event );
983 }
984 
985 void QgsLayoutView::mouseMoveEvent( QMouseEvent *event )
986 {
987  if ( !currentLayout() )
988  return;
989 
990  mMouseCurrentXY = event->pos();
991 
992  QPointF cursorPos = mapToScene( mMouseCurrentXY );
993  if ( mTool )
994  {
995  std::unique_ptr<QgsLayoutViewMouseEvent> me( new QgsLayoutViewMouseEvent( this, event, false ) );
996  if ( mTool->flags() & QgsLayoutViewTool::FlagSnaps )
997  {
998  me->snapPoint( mHorizontalSnapLine, mVerticalSnapLine, mTool->ignoredSnapItems() );
999  }
1000  if ( mTool->flags() & QgsLayoutViewTool::FlagSnaps )
1001  {
1002  //draw snapping point indicator
1003  if ( me->isSnapped() )
1004  {
1005  cursorPos = me->snappedPoint();
1006  if ( mSnapMarker )
1007  {
1008  mSnapMarker->setPos( me->snappedPoint() );
1009  mSnapMarker->setVisible( true );
1010  }
1011  }
1012  else if ( mSnapMarker )
1013  {
1014  mSnapMarker->setVisible( false );
1015  }
1016  }
1017  mTool->layoutMoveEvent( me.get() );
1018  event->setAccepted( me->isAccepted() );
1019  }
1020 
1021  //update cursor position in status bar
1022  emit cursorPosChanged( cursorPos );
1023 
1024  if ( !mTool || !event->isAccepted() )
1025  QGraphicsView::mouseMoveEvent( event );
1026 }
1027 
1028 void QgsLayoutView::mouseDoubleClickEvent( QMouseEvent *event )
1029 {
1030  if ( !currentLayout() )
1031  return;
1032 
1033  if ( mTool )
1034  {
1035  std::unique_ptr<QgsLayoutViewMouseEvent> me( new QgsLayoutViewMouseEvent( this, event, mTool->flags() & QgsLayoutViewTool::FlagSnaps ) );
1036  mTool->layoutDoubleClickEvent( me.get() );
1037  event->setAccepted( me->isAccepted() );
1038  }
1039 
1040  if ( !mTool || !event->isAccepted() )
1041  QGraphicsView::mouseDoubleClickEvent( event );
1042 }
1043 
1044 void QgsLayoutView::wheelEvent( QWheelEvent *event )
1045 {
1046  if ( !currentLayout() )
1047  return;
1048 
1049  if ( mTool )
1050  {
1051  mTool->wheelEvent( event );
1052  }
1053 
1054  if ( !mTool || !event->isAccepted() )
1055  {
1056  event->accept();
1057  wheelZoom( event );
1058  }
1059 }
1060 
1061 void QgsLayoutView::keyPressEvent( QKeyEvent *event )
1062 {
1063  if ( !currentLayout() )
1064  return;
1065 
1066  if ( mTool )
1067  {
1068  mTool->keyPressEvent( event );
1069  }
1070 
1071  if ( mTool && event->isAccepted() )
1072  return;
1073 
1074  if ( event->key() == Qt::Key_Space && ! event->isAutoRepeat() )
1075  {
1076  if ( !( event->modifiers() & Qt::ControlModifier ) )
1077  {
1078  // Pan layout with space bar
1079  setTool( mSpacePanTool );
1080  }
1081  else
1082  {
1083  //ctrl+space pressed, so switch to temporary keyboard based zoom tool
1084  setTool( mSpaceZoomTool );
1085  }
1086  event->accept();
1087  }
1088  else if ( event->key() == Qt::Key_Left
1089  || event->key() == Qt::Key_Right
1090  || event->key() == Qt::Key_Up
1091  || event->key() == Qt::Key_Down )
1092  {
1093  QgsLayout *l = currentLayout();
1094  const QList<QgsLayoutItem *> layoutItemList = l->selectedLayoutItems();
1095 
1096  QPointF delta = deltaForKeyEvent( event );
1097 
1098  l->undoStack()->beginMacro( tr( "Move Item" ) );
1099  for ( QgsLayoutItem *item : layoutItemList )
1100  {
1101  l->undoStack()->beginCommand( item, tr( "Move Item" ), QgsLayoutItem::UndoIncrementalMove );
1102  item->attemptMoveBy( delta.x(), delta.y() );
1103  l->undoStack()->endCommand();
1104  }
1105  l->undoStack()->endMacro();
1106  event->accept();
1107  }
1108 }
1109 
1110 void QgsLayoutView::keyReleaseEvent( QKeyEvent *event )
1111 {
1112  if ( !currentLayout() )
1113  return;
1114 
1115  if ( mTool )
1116  {
1117  mTool->keyReleaseEvent( event );
1118  }
1119 
1120  if ( !mTool || !event->isAccepted() )
1121  QGraphicsView::keyReleaseEvent( event );
1122 }
1123 
1124 void QgsLayoutView::resizeEvent( QResizeEvent *event )
1125 {
1126  QGraphicsView::resizeEvent( event );
1127  emit zoomLevelChanged();
1128  viewChanged();
1129 }
1130 
1131 void QgsLayoutView::scrollContentsBy( int dx, int dy )
1132 {
1133  QGraphicsView::scrollContentsBy( dx, dy );
1134  viewChanged();
1135 }
1136 
1137 void QgsLayoutView::dragEnterEvent( QDragEnterEvent *e )
1138 {
1139  // By default graphics view delegates the drag events to graphics items.
1140  // But we do not want that and by ignoring the drag enter we let the
1141  // parent (e.g. QgsLayoutDesignerDialog) to handle drops of files.
1142  e->ignore();
1143 }
1144 
1145 void QgsLayoutView::paintEvent( QPaintEvent *event )
1146 {
1147  if ( mPaintingEnabled )
1148  {
1149  QGraphicsView::paintEvent( event );
1150  event->accept();
1151  }
1152  else
1153  {
1154  event->ignore();
1155  }
1156 }
1157 
1158 void QgsLayoutView::showEvent( QShowEvent *event )
1159 {
1160  QGraphicsView::showEvent( event );
1161 
1162  updateDevicePixelFromScreen();
1163  // keep device pixel ratio up to date on screen or resolution change
1164  if ( window()->windowHandle() )
1165  {
1166  connect( window()->windowHandle(), &QWindow::screenChanged, this, [ = ]( QScreen * )
1167  {
1168  disconnect( mScreenDpiChangedConnection );
1169  mScreenDpiChangedConnection = connect( window()->windowHandle()->screen(), &QScreen::physicalDotsPerInchChanged, this, &QgsLayoutView::updateDevicePixelFromScreen );
1170  updateDevicePixelFromScreen();
1171  } );
1172 
1173  mScreenDpiChangedConnection = connect( window()->windowHandle()->screen(), &QScreen::physicalDotsPerInchChanged, this, &QgsLayoutView::updateDevicePixelFromScreen );
1174  }
1175 }
1176 
1177 void QgsLayoutView::invalidateCachedRenders()
1178 {
1179  if ( !currentLayout() )
1180  return;
1181 
1182  //redraw cached map items
1183  QList< QgsLayoutItem *> items;
1184  currentLayout()->layoutItems( items );
1185 
1186  for ( QgsLayoutItem *item : std::as_const( items ) )
1187  {
1188  item->invalidateCache();
1189  }
1190 }
1191 
1192 void QgsLayoutView::updateDevicePixelFromScreen()
1193 {
1194  if ( window()->windowHandle() )
1195  mScreenDpi = window()->windowHandle()->screen()->physicalDotsPerInch();
1196 }
1197 
1199 {
1200  if ( mHorizontalRuler )
1201  {
1202  mHorizontalRuler->setSceneTransform( viewportTransform() );
1203  }
1204  if ( mVerticalRuler )
1205  {
1206  mVerticalRuler->setSceneTransform( viewportTransform() );
1207  }
1208 
1209  // determine page at center of view
1210  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
1211  QRectF visibleRect = mapToScene( viewportRect ).boundingRect();
1212  QPointF centerVisible = visibleRect.center();
1213 
1214  if ( currentLayout() && currentLayout()->pageCollection() )
1215  {
1216  int newPage = currentLayout()->pageCollection()->pageNumberForPoint( centerVisible );
1217  if ( newPage != mCurrentPage )
1218  {
1219  mCurrentPage = newPage;
1220  emit pageChanged( mCurrentPage );
1221  }
1222  }
1223 }
1224 
1225 void QgsLayoutView::pushStatusMessage( const QString &message )
1226 {
1227  emit statusMessage( message );
1228 }
1229 
1230 void QgsLayoutView::wheelZoom( QWheelEvent *event )
1231 {
1232  //get mouse wheel zoom behavior settings
1233  QgsSettings settings;
1234  double zoomFactor = settings.value( QStringLiteral( "qgis/zoom_factor" ), 2 ).toDouble();
1235 
1236  // "Normal" mouse have an angle delta of 120, precision mouses provide data faster, in smaller steps
1237  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 120.0 * std::fabs( event->angleDelta().y() );
1238 
1239  if ( event->modifiers() & Qt::ControlModifier )
1240  {
1241  //holding ctrl while wheel zooming results in a finer zoom
1242  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
1243  }
1244 
1245  //calculate zoom scale factor
1246  bool zoomIn = event->angleDelta().y() > 0;
1247  double scaleFactor = ( zoomIn ? 1 / zoomFactor : zoomFactor );
1248 
1249  //get current visible part of scene
1250  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
1251  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
1252 
1253  //transform the mouse pos to scene coordinates
1254 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
1255  QPointF scenePoint = mapToScene( event->pos() );
1256 #else
1257  QPointF scenePoint = mapToScene( event->position().x(), event->position().y() );
1258 #endif
1259 
1260  //adjust view center
1261  QgsPointXY oldCenter( visibleRect.center() );
1262  QgsPointXY newCenter( scenePoint.x() + ( ( oldCenter.x() - scenePoint.x() ) * scaleFactor ),
1263  scenePoint.y() + ( ( oldCenter.y() - scenePoint.y() ) * scaleFactor ) );
1264  centerOn( newCenter.x(), newCenter.y() );
1265 
1266  //zoom layout
1267  if ( zoomIn )
1268  {
1269  scaleSafe( zoomFactor );
1270  }
1271  else
1272  {
1273  scaleSafe( 1 / zoomFactor );
1274  }
1275 }
1276 
1277 QGraphicsLineItem *QgsLayoutView::createSnapLine() const
1278 {
1279  std::unique_ptr< QGraphicsLineItem> item( new QGraphicsLineItem( nullptr ) );
1280  QPen pen = QPen( QColor( Qt::blue ) );
1281  pen.setStyle( Qt::DotLine );
1282  pen.setWidthF( 0.0 );
1283  item->setPen( pen );
1284  item->setZValue( QgsLayout::ZSmartGuide );
1285  return item.release();
1286 }
1287 
1288 //
1289 // QgsLayoutViewSnapMarker
1290 //
1291 
1293 QgsLayoutViewSnapMarker::QgsLayoutViewSnapMarker()
1294  : QGraphicsRectItem( QRectF( 0, 0, 0, 0 ) )
1295 {
1296  QFont f;
1297  QFontMetrics fm( f );
1298  mSize = fm.horizontalAdvance( 'X' );
1299  setPen( QPen( Qt::transparent, mSize ) );
1300 
1301  setFlags( flags() | QGraphicsItem::ItemIgnoresTransformations );
1302  setZValue( QgsLayout::ZSnapIndicator );
1303 }
1304 
1305 void QgsLayoutViewSnapMarker::paint( QPainter *p, const QStyleOptionGraphicsItem *, QWidget * )
1306 {
1307  QPen pen( QColor( 255, 0, 0 ) );
1308  pen.setWidth( 0 );
1309  p->setPen( pen );
1310  p->setBrush( Qt::NoBrush );
1311 
1312  double halfSize = mSize / 2.0;
1313  p->drawLine( QLineF( -halfSize, -halfSize, halfSize, halfSize ) );
1314  p->drawLine( QLineF( -halfSize, halfSize, halfSize, -halfSize ) );
1315 }
1316 
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 showEvent(QShowEvent *event) override
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
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
@ 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