QGIS API Documentation  2.99.0-Master (19b062c)
qgscomposerview.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposerview.cpp
3  -------------------
4  begin : January 2005
5  copyright : (C) 2005 by Radim Blazek
6  email : blazek@itc.it
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 <QApplication>
19 #include <QMainWindow>
20 #include <QMouseEvent>
21 #include <QKeyEvent>
22 #include <QClipboard>
23 #include <QMimeData>
24 #include <QGridLayout>
25 #include <QScrollBar>
26 #include <QDesktopWidget>
27 
28 #include "qgsapplication.h"
29 #include "qgscomposerview.h"
30 #include "qgscomposerarrow.h"
31 #include "qgscomposerframe.h"
32 #include "qgscomposerpolygon.h"
33 #include "qgscomposerpolyline.h"
34 #include "qgscomposerhtml.h"
35 #include "qgscomposerlabel.h"
36 #include "qgscomposerlegend.h"
37 #include "qgscomposermap.h"
39 #include "qgscomposeritemgroup.h"
40 #include "qgscomposerpicture.h"
41 #include "qgscomposerruler.h"
42 #include "qgscomposerscalebar.h"
43 #include "qgscomposershape.h"
46 #include "qgspaperitem.h"
47 #include "qgsmapcanvas.h"
48 #include "qgscomposerutils.h"
49 #include "qgssettings.h"
50 
51 #define MIN_VIEW_SCALE 0.05
52 #define MAX_VIEW_SCALE 1000.0
53 
54 QgsComposerView::QgsComposerView( QWidget *parent, const char *name, Qt::WindowFlags f )
55  : QGraphicsView( parent )
56 {
57  Q_UNUSED( f );
58  Q_UNUSED( name );
59 
60  setResizeAnchor( QGraphicsView::AnchorViewCenter );
61  setMouseTracking( true );
62  viewport()->setMouseTracking( true );
63  setFrameShape( QFrame::NoFrame );
64 
65  mPreviewEffect = new QgsPreviewEffect( this );
66  viewport()->setGraphicsEffect( mPreviewEffect );
67 }
68 
70 {
71  mCurrentTool = t;
72 
73  //update mouse cursor for current tool
74  if ( !composition() )
75  {
76  return;
77  }
78 
79  // do not display points of NodesItem by default
80  mNodesItemIndex = -1;
81  mNodesItem = nullptr;
82  mPolygonItem.reset();
83  mPolylineItem.reset();
84  displayNodes( false );
85  deselectNode();
86 
87  switch ( t )
88  {
90  {
91  //lock cursor to prevent composer items changing it
93  viewport()->setCursor( defaultCursorForTool( Pan ) );
94  break;
95  }
97  {
98  //lock cursor to prevent composer items changing it
100  //set the cursor to zoom in
101  viewport()->setCursor( defaultCursorForTool( Zoom ) );
102  break;
103  }
118  {
119  //using a drawing tool
120  //lock cursor to prevent composer items changing it
122  viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
123  break;
124  }
125 
127  {
129  viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
130 
131  displayNodes();
132 
133  break;
134  }
135  default:
136  {
137  //not using pan tool, composer items can change cursor
139  viewport()->setCursor( Qt::ArrowCursor );
140  }
141  }
142 }
143 
144 void QgsComposerView::mousePressEvent( QMouseEvent *e )
145 {
146  if ( !composition() )
147  {
148  return;
149  }
150 
151  if ( mRubberBandItem || mRubberBandLineItem || mKeyPanning || mMousePanning || mToolPanning || mMovingItemContent )
152  {
153  //ignore clicks during certain operations
154  return;
155  }
156 
157  if ( composition()->selectionHandles()->isDragging() || composition()->selectionHandles()->isResizing() )
158  {
159  //ignore clicks while dragging/resizing items
160  return;
161  }
162 
163  QPointF scenePoint = mapToScene( e->pos() );
164  QPointF snappedScenePoint = composition()->snapPointToGrid( scenePoint );
165  mMousePressStartPos = e->pos();
166 
167  if ( e->button() == Qt::RightButton )
168  {
169  //ignore right clicks for now
170  //TODO - show context menu
171  return;
172  }
173  else if ( e->button() == Qt::MidButton )
174  {
175  //pan composer with middle button
176  mMousePanning = true;
177  mMouseLastXY = e->pos();
178  if ( composition() )
179  {
180  //lock cursor to closed hand cursor
182  }
183  viewport()->setCursor( Qt::ClosedHandCursor );
184  return;
185  }
186 
187  switch ( mCurrentTool )
188  {
189  //select/deselect items and pass mouse event further
190  case Select:
191  {
192  //check if we are clicking on a selection handle
193  if ( composition()->selectionHandles()->isVisible() )
194  {
195  //selection handles are being shown, get mouse action for current cursor position
197 
199  {
200  //mouse is over a resize handle, so propagate event onward
201  QGraphicsView::mousePressEvent( e );
202  return;
203  }
204  }
205 
206  QgsComposerItem *selectedItem = nullptr;
207  QgsComposerItem *previousSelectedItem = nullptr;
208 
209  if ( e->modifiers() & Qt::ControlModifier )
210  {
211  //CTRL modifier, so we are trying to select the next item below the current one
212  //first, find currently selected item
213  QList<QgsComposerItem *> selectedItems = composition()->selectedComposerItems();
214  if ( !selectedItems.isEmpty() )
215  {
216  previousSelectedItem = selectedItems.at( 0 );
217  }
218  }
219 
220  if ( previousSelectedItem )
221  {
222  //select highest item just below previously selected item at position of event
223  selectedItem = composition()->composerItemAt( scenePoint, previousSelectedItem, true );
224 
225  //if we didn't find a lower item we'll use the top-most as fall-back
226  //this duplicates mapinfo/illustrator/etc behavior where ctrl-clicks are "cyclic"
227  if ( !selectedItem )
228  {
229  selectedItem = composition()->composerItemAt( scenePoint, true );
230  }
231  }
232  else
233  {
234  //select topmost item at position of event
235  selectedItem = composition()->composerItemAt( scenePoint, true );
236  }
237 
238  if ( !selectedItem )
239  {
240  //not clicking over an item, so start marquee selection
241  startMarqueeSelect( scenePoint );
242  break;
243  }
244 
245  if ( ( !selectedItem->selected() ) && //keep selection if an already selected item pressed
246  !( e->modifiers() & Qt::ShiftModifier ) ) //keep selection if shift key pressed
247  {
249  }
250 
251  if ( ( e->modifiers() & Qt::ShiftModifier ) && ( selectedItem->selected() ) )
252  {
253  //SHIFT-clicking a selected item deselects it
254  selectedItem->setSelected( false );
255 
256  //Check if we have any remaining selected items, and if so, update the item panel
257  QList<QgsComposerItem *> selectedItems = composition()->selectedComposerItems();
258  if ( !selectedItems.isEmpty() )
259  {
260  emit selectedItemChanged( selectedItems.at( 0 ) );
261  }
262  }
263  else
264  {
265  selectedItem->setSelected( true );
266  QGraphicsView::mousePressEvent( e );
267  emit selectedItemChanged( selectedItem );
268  }
269  break;
270  }
271 
272  case Zoom:
273  {
274  if ( !( e->modifiers() & Qt::AltModifier ) )
275  {
276  //zoom in action
277  startMarqueeZoom( scenePoint );
278  }
279  else
280  {
281  //zoom out action, so zoom out and recenter on clicked point
282  double scaleFactor = 2;
283  //get current visible part of scene
284  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
285  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
286 
287  //transform the mouse pos to scene coordinates
288  QPointF scenePoint = mapToScene( e->pos() );
289 
290  visibleRect.scale( scaleFactor, scenePoint.x(), scenePoint.y() );
291  QRectF boundsRect = visibleRect.toRectF();
292 
293  //zoom view to fit desired bounds
294  fitInView( boundsRect, Qt::KeepAspectRatio );
295  }
296  break;
297  }
298 
299  case Pan:
300  {
301  //pan action
302  mToolPanning = true;
303  mMouseLastXY = e->pos();
304  viewport()->setCursor( Qt::ClosedHandCursor );
305  break;
306  }
307 
308  case MoveItemContent:
309  {
310  //get a list of items at clicked position
311  QList<QGraphicsItem *> itemsAtCursorPos = items( e->pos() );
312  if ( itemsAtCursorPos.isEmpty() )
313  {
314  //no items at clicked position
315  return;
316  }
317 
318  //find highest non-locked QgsComposerItem at clicked position
319  //(other graphics items may be higher, e.g., selection handles)
320  QList<QGraphicsItem *>::iterator itemIter = itemsAtCursorPos.begin();
321  for ( ; itemIter != itemsAtCursorPos.end(); ++itemIter )
322  {
323  QgsComposerItem *item = dynamic_cast<QgsComposerItem *>( ( *itemIter ) );
324  if ( item && !item->positionLock() )
325  {
326  //we've found the highest QgsComposerItem
327  mMoveContentStartPos = scenePoint;
328  mMoveContentItem = item;
329  mMovingItemContent = true;
330  break;
331  }
332  }
333 
334  //no QgsComposerItem at clicked position
335  return;
336  }
337 
338  case EditNodesItem:
339  {
340  QList<QGraphicsItem *> itemsAtCursorPos = items( e->pos().x(), e->pos().y(),
341  mMoveContentSearchRadius,
342  mMoveContentSearchRadius );
343  if ( itemsAtCursorPos.isEmpty() )
344  return;
345 
346  mNodesItemIndex = -1;
347  mNodesItem = nullptr;
348 
349  QList<QGraphicsItem *>::iterator itemIter = itemsAtCursorPos.begin();
350  for ( ; itemIter != itemsAtCursorPos.end(); ++itemIter )
351  {
352  QgsComposerItem *item = dynamic_cast<QgsComposerItem *>( ( *itemIter ) );
353 
354  if ( item && !item->positionLock() )
355  {
356  if ( ( item->type() == QgsComposerItem::ComposerPolygon
357  || item->type() == QgsComposerItem::ComposerPolyline ) )
358  {
359  QgsComposerNodesItem *itemP = static_cast<QgsComposerNodesItem *>( item );
360  int index = itemP->nodeAtPosition( scenePoint );
361  if ( index != -1 )
362  {
363  mNodesItemIndex = index;
364  mNodesItem = itemP;
365  mMoveContentStartPos = scenePoint;
366  }
367  }
368  }
369 
370  if ( mNodesItemIndex != -1 )
371  {
372  composition()->beginCommand( mNodesItem, tr( "Move item node" ) );
373  setSelectedNode( mNodesItem, mNodesItemIndex );
374  break;
375  }
376  }
377 
378  break;
379  }
380 
381  //create rubber band for adding line items
382  case AddArrow:
383  {
384  mRubberBandStartPos = QPointF( snappedScenePoint.x(), snappedScenePoint.y() );
385  mRubberBandLineItem = new QGraphicsLineItem( snappedScenePoint.x(), snappedScenePoint.y(), snappedScenePoint.x(), snappedScenePoint.y() );
386  mRubberBandLineItem->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
387  mRubberBandLineItem->setZValue( 1000 );
388  scene()->addItem( mRubberBandLineItem );
389  scene()->update();
390  break;
391  }
392 
393  //create rubber band for adding rectangular items
394  case AddMap:
395  case AddRectangle:
396  case AddTriangle:
397  case AddEllipse:
398  case AddHtml:
399  case AddPicture:
400  case AddLabel:
401  case AddLegend:
402  case AddTable:
403  case AddAttributeTable:
404  {
405  QTransform t;
406  mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
407  mRubberBandItem->setBrush( Qt::NoBrush );
408  mRubberBandItem->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
409  mRubberBandStartPos = QPointF( snappedScenePoint.x(), snappedScenePoint.y() );
410  t.translate( snappedScenePoint.x(), snappedScenePoint.y() );
411  mRubberBandItem->setTransform( t );
412  mRubberBandItem->setZValue( 1000 );
413  scene()->addItem( mRubberBandItem );
414  scene()->update();
415  }
416  break;
417 
418  case AddScalebar:
419  if ( composition() )
420  {
421  QgsComposerScaleBar *newScaleBar = new QgsComposerScaleBar( composition() );
422  newScaleBar->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), 20, 20 ) );
423  composition()->addComposerScaleBar( newScaleBar );
424  QList<const QgsComposerMap *> mapItemList = composition()->composerMapItems();
425  if ( !mapItemList.isEmpty() )
426  {
427  newScaleBar->setComposerMap( const_cast< QgsComposerMap *>( mapItemList.at( 0 ) ) );
428  }
429  newScaleBar->applyDefaultSize(); //4 segments, 1/5 of composer map width
430 
432  newScaleBar->setSelected( true );
433  emit selectedItemChanged( newScaleBar );
434 
435  emit actionFinished();
436  composition()->pushAddRemoveCommand( newScaleBar, tr( "Scale bar added" ) );
437  }
438  break;
439 
440  case AddPolygon:
441  {
442  if ( !mPolygonItem )
443  {
444  mPolygonItem.reset( new QGraphicsPolygonItem() );
445  mPolygonItem->setBrush( Qt::NoBrush );
446  mPolygonItem->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
447  mPolygonItem->setZValue( 1000 );
448 
449  scene()->addItem( mPolygonItem.get() );
450  scene()->update();
451  }
452 
453  break;
454  }
455 
456  case AddPolyline:
457  {
458  if ( !mPolylineItem && !mPolygonItem )
459  {
460  mPolygonItem.reset( new QGraphicsPolygonItem() );
461 
462  mPolylineItem.reset( new QGraphicsPathItem() );
463  mPolylineItem->setPen( QPen( QBrush( QColor( 227, 22, 22, 200 ) ), 0 ) );
464  mPolylineItem->setZValue( 1000 );
465  }
466 
467  break;
468  }
469 
470  default:
471  break;
472  }
473 }
474 
475 QCursor QgsComposerView::defaultCursorForTool( Tool currentTool )
476 {
477  switch ( currentTool )
478  {
479  case Select:
480  return Qt::ArrowCursor;
481 
482  // Use custom QGIS cursor for ZoomIn
483  case Zoom:
484  return QgsApplication::getThemeCursor( QgsApplication::Cursor::ZoomIn );
485 
486  case Pan:
487  return Qt::OpenHandCursor;
488 
489  case MoveItemContent:
490  return Qt::ArrowCursor;
491 
492  // Use QGIS custom cursor for the following
493  case EditNodesItem:
494  case AddPolyline:
495  case AddArrow:
496  case AddMap:
497  case AddRectangle:
498  case AddTriangle:
499  case AddEllipse:
500  case AddPolygon:
501  case AddHtml:
502  case AddLabel:
503  case AddScalebar:
504  case AddLegend:
505  case AddPicture:
506  case AddTable:
507  case AddAttributeTable:
508  return QgsApplication::getThemeCursor( QgsApplication::Cursor::CrossHair );
509  }
510  return Qt::ArrowCursor;
511 }
512 
513 void QgsComposerView::addShape( Tool currentTool )
514 {
516 
517  if ( currentTool == AddRectangle )
519  else if ( currentTool == AddTriangle )
521 
522  if ( !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
523  {
524  removeRubberBand();
525  return;
526  }
527  if ( composition() )
528  {
529  QgsComposerShape *composerShape = new QgsComposerShape( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height(), composition() );
530  composerShape->setShapeType( shape );
531  //new shapes use symbol v2 by default
532  composerShape->setUseSymbol( true );
533  composition()->addComposerShape( composerShape );
534  removeRubberBand();
535 
537  composerShape->setSelected( true );
538  emit selectedItemChanged( composerShape );
539 
540  emit actionFinished();
541  composition()->pushAddRemoveCommand( composerShape, tr( "Shape added" ) );
542  }
543 }
544 
546 {
547  if ( mHorizontalRuler )
548  {
549  mHorizontalRuler->setSceneTransform( viewportTransform() );
550  }
551  if ( mVerticalRuler )
552  {
553  mVerticalRuler->setSceneTransform( viewportTransform() );
554  }
555 }
556 
557 void QgsComposerView::removeRubberBand()
558 {
559  if ( mRubberBandItem )
560  {
561  scene()->removeItem( mRubberBandItem );
562  delete mRubberBandItem;
563  mRubberBandItem = nullptr;
564  }
565 }
566 
567 void QgsComposerView::startMarqueeSelect( QPointF &scenePoint )
568 {
569  mMarqueeSelect = true;
570 
571  QTransform t;
572  mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
573  mRubberBandItem->setBrush( QBrush( QColor( 224, 178, 76, 63 ) ) );
574  mRubberBandItem->setPen( QPen( QBrush( QColor( 254, 58, 29, 100 ) ), 0, Qt::DotLine ) );
575  mRubberBandStartPos = QPointF( scenePoint.x(), scenePoint.y() );
576  t.translate( scenePoint.x(), scenePoint.y() );
577  mRubberBandItem->setTransform( t );
578  mRubberBandItem->setZValue( 1000 );
579  scene()->addItem( mRubberBandItem );
580  scene()->update();
581 }
582 
583 void QgsComposerView::endMarqueeSelect( QMouseEvent *e )
584 {
585  mMarqueeSelect = false;
586 
587  bool subtractingSelection = false;
588  if ( e->modifiers() & Qt::ShiftModifier )
589  {
590  //shift modifer means adding to selection, nothing required here
591  }
592  else if ( e->modifiers() & Qt::ControlModifier )
593  {
594  //control modifier means subtract from current selection
595  subtractingSelection = true;
596  }
597  else
598  {
599  //not adding to or removing from selection, so clear current selection
601  }
602 
603  if ( !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
604  {
605  //just a click, do nothing
606  removeRubberBand();
607  return;
608  }
609 
610  QRectF boundsRect = QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(),
611  mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
612 
613  //determine item selection mode, default to intersection
614  Qt::ItemSelectionMode selectionMode = Qt::IntersectsItemShape;
615  if ( e->modifiers() & Qt::AltModifier )
616  {
617  //alt modifier switches to contains selection mode
618  selectionMode = Qt::ContainsItemShape;
619  }
620 
621  //find all items in rubber band
622  QList<QGraphicsItem *> itemList = composition()->items( boundsRect, selectionMode );
623  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
624  for ( ; itemIt != itemList.end(); ++itemIt )
625  {
626  QgsComposerItem *mypItem = dynamic_cast<QgsComposerItem *>( *itemIt );
627  QgsPaperItem *paperItem = dynamic_cast<QgsPaperItem *>( *itemIt );
628  if ( mypItem && !paperItem )
629  {
630  if ( !mypItem->positionLock() )
631  {
632  if ( subtractingSelection )
633  {
634  mypItem->setSelected( false );
635  }
636  else
637  {
638  mypItem->setSelected( true );
639  }
640  }
641  }
642  }
643  removeRubberBand();
644 
645  //update item panel
646  QList<QgsComposerItem *> selectedItemList = composition()->selectedComposerItems();
647  if ( !selectedItemList.isEmpty() )
648  {
649  emit selectedItemChanged( selectedItemList[0] );
650  }
651 }
652 
653 void QgsComposerView::startMarqueeZoom( QPointF &scenePoint )
654 {
655  mMarqueeZoom = true;
656 
657  QTransform t;
658  mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
659  mRubberBandItem->setBrush( QBrush( QColor( 70, 50, 255, 25 ) ) );
660  mRubberBandItem->setPen( QPen( QColor( 70, 50, 255, 100 ) ) );
661  mRubberBandStartPos = QPointF( scenePoint.x(), scenePoint.y() );
662  t.translate( scenePoint.x(), scenePoint.y() );
663  mRubberBandItem->setTransform( t );
664  mRubberBandItem->setZValue( 1000 );
665  scene()->addItem( mRubberBandItem );
666  scene()->update();
667 }
668 
669 void QgsComposerView::endMarqueeZoom( QMouseEvent *e )
670 {
671  mMarqueeZoom = false;
672 
673  QRectF boundsRect;
674 
675  if ( !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
676  {
677  //just a click, so zoom to clicked point and recenter
678  double scaleFactor = 0.5;
679  //get current visible part of scene
680  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
681  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
682 
683  //transform the mouse pos to scene coordinates
684  QPointF scenePoint = mapToScene( e->pos() );
685 
686  visibleRect.scale( scaleFactor, scenePoint.x(), scenePoint.y() );
687  boundsRect = visibleRect.toRectF();
688  }
689  else
690  {
691  //marquee zoom
692  //zoom bounds are size marquee object
693  boundsRect = QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(),
694  mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
695  }
696 
697  removeRubberBand();
698  //zoom view to fit desired bounds
699  fitInView( boundsRect, Qt::KeepAspectRatio );
700 
701  if ( mTemporaryZoomStatus == QgsComposerView::ActiveUntilMouseRelease )
702  {
703  //user was using the temporary keyboard activated zoom tool
704  //and the control or space key was released before mouse button, so end temporary zoom
705  mTemporaryZoomStatus = QgsComposerView::Inactive;
706  setCurrentTool( mPreviousTool );
707  }
708 }
709 
711 {
712  if ( !composition() )
713  {
714  return;
715  }
716 
717  if ( e->button() != Qt::LeftButton &&
719  {
720  //ignore clicks while dragging/resizing items
721  return;
722  }
723 
724  QPoint mousePressStopPoint = e->pos();
725  int diffX = mousePressStopPoint.x() - mMousePressStartPos.x();
726  int diffY = mousePressStopPoint.y() - mMousePressStartPos.y();
727 
728  //was this just a click? or a click and drag?
729  bool clickOnly = false;
730  if ( std::fabs( diffX ) < 2 && std::fabs( diffY ) < 2 )
731  {
732  clickOnly = true;
733  }
734 
735  QPointF scenePoint = mapToScene( e->pos() );
736 
737  if ( mMousePanning || mToolPanning )
738  {
739  mMousePanning = false;
740  mToolPanning = false;
741 
742  if ( clickOnly && e->button() == Qt::MidButton )
743  {
744  //middle mouse button click = recenter on point
745 
746  //get current visible part of scene
747  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
748  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
749  visibleRect.scale( 1, scenePoint.x(), scenePoint.y() );
750  QRectF boundsRect = visibleRect.toRectF();
751 
752  //zoom view to fit desired bounds
753  fitInView( boundsRect, Qt::KeepAspectRatio );
754  }
755 
756  //set new cursor
757  if ( mCurrentTool != Pan )
758  {
759  if ( composition() )
760  {
761  //allow composer items to change cursor
763  }
764  }
765  viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
766  }
767 
768  if ( e->button() == Qt::RightButton )
769  {
770  switch ( mCurrentTool )
771  {
772  case AddPolygon:
773  {
774  if ( mPolygonItem )
775  {
776  QPolygonF poly = mPolygonItem->polygon();
777 
778  // last (temporary) point is removed
779  poly.remove( poly.count() - 1 );
780  if ( poly.size() >= 3 )
781  {
782  mPolygonItem->setPolygon( poly );
783 
784  // add polygon in composition
785  QgsComposerPolygon *composerPolygon = new QgsComposerPolygon( mPolygonItem->polygon(), composition() );
786  composition()->addComposerPolygon( composerPolygon );
787 
788  // select the polygon
790  composerPolygon->setSelected( true );
791  emit selectedItemChanged( composerPolygon );
792 
793  composition()->pushAddRemoveCommand( composerPolygon, tr( "Polygon added" ) );
794  }
795 
796  // clean
797  scene()->removeItem( mPolygonItem.get() );
798  mPolygonItem.reset();
799  emit actionFinished();
800  }
801  break;
802  }
803 
804  case AddPolyline:
805  {
806  if ( mPolygonItem && mPolylineItem )
807  {
808  // ignore the last point due to release event before doubleClick event # spellok
809  QPolygonF poly = mPolygonItem->polygon();
810 
811  // last (temporary) point is removed
812  poly.remove( poly.count() - 1 );
813  if ( poly.size() >= 2 )
814  {
815  mPolygonItem->setPolygon( poly );
816 
817  // add polygon in composition
818  QgsComposerPolyline *composerPolyline = new QgsComposerPolyline( mPolygonItem->polygon(), composition() );
819  composition()->addComposerPolyline( composerPolyline );
820 
821  // select the polygon
823  composerPolyline->setSelected( true );
824  emit selectedItemChanged( composerPolyline );
825 
826  composition()->pushAddRemoveCommand( composerPolyline, tr( "Polyline added" ) );
827  }
828 
829  // clean
830  scene()->removeItem( mPolylineItem.get() );
831  mPolygonItem.reset();
832  mPolylineItem.reset();
833  emit actionFinished();
834  }
835 
836  break;
837  }
838 
839  default:
840  e->ignore();
841  }
842  }
843 
844  //for every other tool, ignore clicks of non-left button
845  if ( e->button() != Qt::LeftButton )
846  {
847  return;
848  }
849 
850  if ( mMarqueeSelect )
851  {
852  endMarqueeSelect( e );
853  return;
854  }
855 
856  switch ( mCurrentTool )
857  {
858  case Select:
859  {
860  QGraphicsView::mouseReleaseEvent( e );
861  break;
862  }
863 
864  case Zoom:
865  {
866  if ( mMarqueeZoom )
867  {
868  endMarqueeZoom( e );
869  }
870  break;
871  }
872 
873  case MoveItemContent:
874  {
875  if ( mMoveContentItem )
876  {
877  //update map preview if composer map
878  QgsComposerMap *composerMap = dynamic_cast<QgsComposerMap *>( mMoveContentItem );
879  if ( composerMap )
880  {
881  composerMap->setOffset( 0, 0 );
882  }
883 
884  double moveX = scenePoint.x() - mMoveContentStartPos.x();
885  double moveY = scenePoint.y() - mMoveContentStartPos.y();
886 
887  composition()->beginCommand( mMoveContentItem, tr( "Move item content" ) );
888  mMoveContentItem->moveContent( -moveX, -moveY );
889  composition()->endCommand();
890  mMoveContentItem = nullptr;
891  mMovingItemContent = false;
892  }
893  break;
894  }
895 
896  case EditNodesItem:
897  {
898  if ( mNodesItemIndex != -1 )
899  {
900  if ( scenePoint != mMoveContentStartPos )
901  composition()->endCommand();
902  else
904  }
905 
906  break;
907  }
908 
909  case AddArrow:
910  if ( !composition() || !mRubberBandLineItem )
911  {
912  scene()->removeItem( mRubberBandLineItem );
913  delete mRubberBandLineItem;
914  mRubberBandLineItem = nullptr;
915  return;
916  }
917  else
918  {
919  QgsComposerArrow *composerArrow = new QgsComposerArrow( mRubberBandLineItem->line().p1(), mRubberBandLineItem->line().p2(), composition() );
920  composition()->addComposerArrow( composerArrow );
921 
923  composerArrow->setSelected( true );
924  emit selectedItemChanged( composerArrow );
925 
926  scene()->removeItem( mRubberBandLineItem );
927  delete mRubberBandLineItem;
928  mRubberBandLineItem = nullptr;
929  emit actionFinished();
930  composition()->pushAddRemoveCommand( composerArrow, tr( "Arrow added" ) );
931  }
932  break;
933 
934  case AddRectangle:
935  case AddTriangle:
936  case AddEllipse:
937  addShape( mCurrentTool );
938  break;
939 
940  case AddPolygon:
941  {
942  if ( mPolygonItem )
943  addPolygonNode( scenePoint );
944 
945  break;
946  }
947 
948  case AddPolyline:
949  {
950  if ( mPolygonItem && mPolylineItem )
951  {
952  addPolygonNode( scenePoint );
953 
954  // rebuild a new qpainter path
955  QPainterPath path;
956  path.addPolygon( mPolygonItem->polygon() );
957  mPolylineItem->setPath( path );
958 
959  // add it to the scene
960  scene()->addItem( mPolylineItem.get() );
961  scene()->update();
962  }
963  break;
964  }
965 
966  case AddMap:
967  if ( !composition() || !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
968  {
969  removeRubberBand();
970  return;
971  }
972  else
973  {
974  QgsComposerMap *composerMap = new QgsComposerMap( composition(), mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
975  composition()->addComposerMap( composerMap );
976  if ( mCanvas )
977  {
978  composerMap->zoomToExtent( mCanvas->mapSettings().visibleExtent() );
979  }
980 
982  composerMap->setSelected( true );
983  emit selectedItemChanged( composerMap );
984 
985  removeRubberBand();
986  emit actionFinished();
987  composition()->pushAddRemoveCommand( composerMap, tr( "Map added" ) );
988  }
989  break;
990 
991  case AddPicture:
992  if ( !composition() || !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
993  {
994  removeRubberBand();
995  return;
996  }
997  else
998  {
999  QgsComposerPicture *newPicture = new QgsComposerPicture( composition() );
1000  newPicture->setSceneRect( QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height() ) );
1001  composition()->addComposerPicture( newPicture );
1002 
1004  newPicture->setSelected( true );
1005  emit selectedItemChanged( newPicture );
1006 
1007  removeRubberBand();
1008  emit actionFinished();
1009  composition()->pushAddRemoveCommand( newPicture, tr( "Picture added" ) );
1010  }
1011  break;
1012 
1013  case AddLabel:
1014  if ( !composition() || !mRubberBandItem )
1015  {
1016  removeRubberBand();
1017  return;
1018  }
1019  else
1020  {
1021  QgsComposerLabel *newLabelItem = new QgsComposerLabel( composition() );
1022  newLabelItem->setText( tr( "QGIS" ) );
1023  newLabelItem->adjustSizeToText();
1024 
1025  //make sure label size is sufficient to fit text
1026  double labelWidth = std::max( mRubberBandItem->rect().width(), newLabelItem->rect().width() );
1027  double labelHeight = std::max( mRubberBandItem->rect().height(), newLabelItem->rect().height() );
1028  newLabelItem->setSceneRect( QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), labelWidth, labelHeight ) );
1029 
1030  composition()->addComposerLabel( newLabelItem );
1031 
1033  newLabelItem->setSelected( true );
1034  emit selectedItemChanged( newLabelItem );
1035 
1036  removeRubberBand();
1037  emit actionFinished();
1038  composition()->pushAddRemoveCommand( newLabelItem, tr( "Label added" ) );
1039  }
1040  break;
1041 
1042  case AddLegend:
1043  if ( !composition() || !mRubberBandItem )
1044  {
1045  removeRubberBand();
1046  return;
1047  }
1048  else
1049  {
1050  QgsComposerLegend *newLegend = new QgsComposerLegend( composition() );
1051  QList<const QgsComposerMap *> mapItemList = composition()->composerMapItems();
1052  if ( !mapItemList.isEmpty() )
1053  {
1054  newLegend->setComposerMap( mapItemList.at( 0 ) );
1055  }
1056  newLegend->setSceneRect( QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height() ) );
1057  composition()->addComposerLegend( newLegend );
1058  newLegend->updateLegend();
1059 
1061  newLegend->setSelected( true );
1062  emit selectedItemChanged( newLegend );
1063 
1064  removeRubberBand();
1065  emit actionFinished();
1066  composition()->pushAddRemoveCommand( newLegend, tr( "Legend added" ) );
1067  }
1068  break;
1069 
1070  case AddAttributeTable:
1071  if ( !composition() || !mRubberBandItem )
1072  {
1073  removeRubberBand();
1074  return;
1075  }
1076  else
1077  {
1079  QList<const QgsComposerMap *> mapItemList = composition()->composerMapItems();
1080  if ( !mapItemList.isEmpty() )
1081  {
1082  newTable->setComposerMap( mapItemList.at( 0 ) );
1083  }
1085  newTable, composition(), tr( "Attribute table added" ) );
1086  composition()->undoStack()->push( command );
1087  QgsComposerFrame *frame = new QgsComposerFrame( composition(), newTable, mRubberBandItem->transform().dx(),
1088  mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(),
1089  mRubberBandItem->rect().height() );
1090  composition()->beginMultiFrameCommand( newTable, tr( "Attribute table frame added" ) );
1091  newTable->addFrame( frame );
1093 
1095  frame->setSelected( true );
1096  emit selectedItemChanged( frame );
1097 
1098  removeRubberBand();
1099  emit actionFinished();
1100  }
1101  break;
1102 
1103  case AddHtml:
1104  if ( !composition() || !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
1105  {
1106  removeRubberBand();
1107  return;
1108  }
1109  else
1110  {
1111  QgsComposerHtml *composerHtml = new QgsComposerHtml( composition(), true );
1113  composerHtml, composition(), tr( "HTML item added" ) );
1114  composition()->undoStack()->push( command );
1115  QgsComposerFrame *frame = new QgsComposerFrame( composition(), composerHtml, mRubberBandItem->transform().dx(),
1116  mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(),
1117  mRubberBandItem->rect().height() );
1118  composition()->beginMultiFrameCommand( composerHtml, tr( "HTML frame added" ) );
1119  composerHtml->addFrame( frame );
1121 
1123  frame->setSelected( true );
1124  emit selectedItemChanged( frame );
1125 
1126  removeRubberBand();
1127  emit actionFinished();
1128  }
1129  break;
1130  default:
1131  break;
1132  }
1133 }
1134 
1135 void QgsComposerView::mouseMoveEvent( QMouseEvent *e )
1136 {
1137  if ( !composition() )
1138  {
1139  return;
1140  }
1141 
1142  bool shiftModifier = false;
1143  bool altModifier = false;
1144  if ( e->modifiers() & Qt::ShiftModifier )
1145  {
1146  //shift key depressed
1147  shiftModifier = true;
1148  }
1149  if ( e->modifiers() & Qt::AltModifier )
1150  {
1151  //alt key depressed
1152  altModifier = true;
1153  }
1154 
1155  mMouseCurrentXY = e->pos();
1156  //update cursor position in composer status bar
1157  emit cursorPosChanged( mapToScene( e->pos() ) );
1158 
1159  updateRulers();
1160  if ( mHorizontalRuler )
1161  {
1162  mHorizontalRuler->updateMarker( e->posF() );
1163  }
1164  if ( mVerticalRuler )
1165  {
1166  mVerticalRuler->updateMarker( e->posF() );
1167  }
1168 
1169  if ( mToolPanning || mMousePanning || mKeyPanning )
1170  {
1171  //panning, so scroll view
1172  horizontalScrollBar()->setValue( horizontalScrollBar()->value() - ( e->x() - mMouseLastXY.x() ) );
1173  verticalScrollBar()->setValue( verticalScrollBar()->value() - ( e->y() - mMouseLastXY.y() ) );
1174  mMouseLastXY = e->pos();
1175  return;
1176  }
1177  else if ( ( e->buttons() == Qt::NoButton ) && ( !mPolygonItem ) )
1178  {
1179  if ( mCurrentTool == Select )
1180  {
1181  QGraphicsView::mouseMoveEvent( e );
1182  }
1183  }
1184  else
1185  {
1186  QPointF scenePoint = mapToScene( e->pos() );
1187 
1188  if ( mMarqueeSelect || mMarqueeZoom )
1189  {
1190  updateRubberBandRect( scenePoint );
1191  return;
1192  }
1193 
1194  switch ( mCurrentTool )
1195  {
1196  case Select:
1197  QGraphicsView::mouseMoveEvent( e );
1198  break;
1199 
1200  case AddArrow:
1201  {
1202  updateRubberBandLine( scenePoint, shiftModifier );
1203  break;
1204  }
1205 
1206  case AddMap:
1207  case AddRectangle:
1208  case AddTriangle:
1209  case AddEllipse:
1210  case AddHtml:
1211  case AddPicture:
1212  case AddLabel:
1213  case AddLegend:
1214  case AddTable:
1215  case AddAttributeTable:
1216  //adjust rubber band item
1217  {
1218  updateRubberBandRect( scenePoint, shiftModifier, altModifier );
1219  break;
1220  }
1221 
1222  case AddPolygon:
1223  {
1224  if ( mPolygonItem )
1225  movePolygonNode( scenePoint, shiftModifier );
1226 
1227  break;
1228  }
1229 
1230  case AddPolyline:
1231  {
1232  if ( mPolygonItem && mPolylineItem )
1233  {
1234  movePolygonNode( scenePoint, shiftModifier );
1235 
1236  // rebuild a new qpainter path
1237  QPainterPath path;
1238  path.addPolygon( mPolygonItem->polygon() );
1239  mPolylineItem->setPath( path );
1240  }
1241 
1242  break;
1243  }
1244 
1245  case MoveItemContent:
1246  {
1247  //update map preview if composer map
1248  QgsComposerMap *composerMap = dynamic_cast<QgsComposerMap *>( mMoveContentItem );
1249  if ( composerMap )
1250  {
1251  composerMap->setOffset( scenePoint.x() - mMoveContentStartPos.x(), scenePoint.y() - mMoveContentStartPos.y() );
1252  composerMap->update();
1253  }
1254  break;
1255  }
1256 
1257  case EditNodesItem:
1258  {
1259  if ( mNodesItemIndex != -1 )
1260  {
1261  QPointF scenePoint = mapToScene( e->pos() );
1262  mNodesItem->moveNode( mNodesItemIndex, scenePoint );
1263  scene()->update();
1264  }
1265 
1266  break;
1267  }
1268 
1269  default:
1270  break;
1271  }
1272  }
1273 }
1274 
1275 void QgsComposerView::updateRubberBandRect( QPointF &pos, const bool constrainSquare, const bool fromCenter )
1276 {
1277  if ( !mRubberBandItem )
1278  {
1279  return;
1280  }
1281 
1282  double x = 0;
1283  double y = 0;
1284  double width = 0;
1285  double height = 0;
1286 
1287  double dx = pos.x() - mRubberBandStartPos.x();
1288  double dy = pos.y() - mRubberBandStartPos.y();
1289 
1290  if ( constrainSquare )
1291  {
1292  if ( std::fabs( dx ) > std::fabs( dy ) )
1293  {
1294  width = std::fabs( dx );
1295  height = width;
1296  }
1297  else
1298  {
1299  height = std::fabs( dy );
1300  width = height;
1301  }
1302 
1303  x = mRubberBandStartPos.x() - ( ( dx < 0 ) ? width : 0 );
1304  y = mRubberBandStartPos.y() - ( ( dy < 0 ) ? height : 0 );
1305  }
1306  else
1307  {
1308  //not constraining
1309  if ( dx < 0 )
1310  {
1311  x = pos.x();
1312  width = -dx;
1313  }
1314  else
1315  {
1316  x = mRubberBandStartPos.x();
1317  width = dx;
1318  }
1319 
1320  if ( dy < 0 )
1321  {
1322  y = pos.y();
1323  height = -dy;
1324  }
1325  else
1326  {
1327  y = mRubberBandStartPos.y();
1328  height = dy;
1329  }
1330  }
1331 
1332  if ( fromCenter )
1333  {
1334  x = mRubberBandStartPos.x() - width;
1335  y = mRubberBandStartPos.y() - height;
1336  width *= 2.0;
1337  height *= 2.0;
1338  }
1339 
1340  mRubberBandItem->setRect( 0, 0, width, height );
1341  QTransform t;
1342  t.translate( x, y );
1343  mRubberBandItem->setTransform( t );
1344 }
1345 
1346 void QgsComposerView::updateRubberBandLine( QPointF pos, const bool constrainAngles )
1347 {
1348  if ( !mRubberBandLineItem )
1349  {
1350  return;
1351  }
1352 
1353  //snap to grid
1354  QPointF snappedScenePoint = composition()->snapPointToGrid( pos );
1355 
1356  QLineF newLine = QLineF( mRubberBandStartPos, snappedScenePoint );
1357 
1358  if ( constrainAngles )
1359  {
1360  //movement is contrained to 45 degree angles
1361  double angle = QgsComposerUtils::snappedAngle( newLine.angle() );
1362  newLine.setAngle( angle );
1363  }
1364 
1365  mRubberBandLineItem->setLine( newLine );
1366 }
1367 
1369 {
1370  QPointF scenePoint = mapToScene( e->pos() );
1371 
1372  switch ( mCurrentTool )
1373  {
1374  case EditNodesItem:
1375  {
1376  // erase status previously set by the mousePressEvent method
1377  if ( mNodesItemIndex != -1 )
1378  {
1379  mNodesItem = nullptr;
1380  mNodesItemIndex = -1;
1381  deselectNode();
1382  }
1383 
1384  // search items in composer
1385  QList<QGraphicsItem *> itemsAtCursorPos = items( e->pos().x(), e->pos().y(),
1386  mMoveContentSearchRadius,
1387  mMoveContentSearchRadius );
1388  if ( itemsAtCursorPos.isEmpty() )
1389  return;
1390 
1391  bool rc = false;
1392  QList<QGraphicsItem *>::iterator itemIter = itemsAtCursorPos.begin();
1393  for ( ; itemIter != itemsAtCursorPos.end(); ++itemIter )
1394  {
1395  QgsComposerItem *item = dynamic_cast<QgsComposerItem *>( ( *itemIter ) );
1396 
1397  if ( item && !item->positionLock() )
1398  {
1399  if ( ( item->type() == QgsComposerItem::ComposerPolygon
1400  || item->type() == QgsComposerItem::ComposerPolyline ) )
1401  {
1402  QgsComposerNodesItem *itemP = dynamic_cast<QgsComposerNodesItem *>( item );
1403 
1404  composition()->beginCommand( itemP, tr( "Add item node" ) );
1405  rc = itemP->addNode( scenePoint );
1406 
1407  if ( rc )
1408  {
1409  composition()->endCommand();
1410  mNodesItem = itemP;
1411  mNodesItemIndex = mNodesItem->nodeAtPosition( scenePoint );
1412  }
1413  else
1415  }
1416  }
1417 
1418  if ( rc )
1419  break;
1420  }
1421 
1422  if ( rc )
1423  {
1424  setSelectedNode( mNodesItem, mNodesItemIndex );
1425  scene()->update();
1426  }
1427 
1428  break;
1429  }
1430 
1431  default:
1432  break;
1433  }
1434 }
1435 
1437 {
1438  if ( !composition() )
1439  {
1440  return;
1441  }
1442 
1443  QList<QgsComposerItem *> composerItemList = composition()->selectedComposerItems();
1444  QList<QgsComposerItem *>::iterator itemIt = composerItemList.begin();
1445 
1446  QDomDocument doc;
1447  QDomElement documentElement = doc.createElement( QStringLiteral( "ComposerItemClipboard" ) );
1448  for ( ; itemIt != composerItemList.end(); ++itemIt )
1449  {
1450  // copy each item in a group
1451  QgsComposerItemGroup *itemGroup = dynamic_cast<QgsComposerItemGroup *>( *itemIt );
1452  if ( itemGroup && composition() )
1453  {
1454  QSet<QgsComposerItem *> groupedItems = itemGroup->items();
1455  QSet<QgsComposerItem *>::iterator it = groupedItems.begin();
1456  for ( ; it != groupedItems.end(); ++it )
1457  {
1458  ( *it )->writeXml( documentElement, doc );
1459  }
1460  }
1461  ( *itemIt )->writeXml( documentElement, doc );
1462  if ( mode == ClipboardModeCut )
1463  {
1464  composition()->removeComposerItem( *itemIt );
1465  }
1466  }
1467  doc.appendChild( documentElement );
1468 
1469  //if it's a copy, we have to remove the UUIDs since we don't want any duplicate UUID
1470  if ( mode == ClipboardModeCopy )
1471  {
1472  // remove all uuid attributes
1473  QDomNodeList composerItemsNodes = doc.elementsByTagName( QStringLiteral( "ComposerItem" ) );
1474  for ( int i = 0; i < composerItemsNodes.count(); ++i )
1475  {
1476  QDomNode composerItemNode = composerItemsNodes.at( i );
1477  if ( composerItemNode.isElement() )
1478  {
1479  composerItemNode.toElement().removeAttribute( QStringLiteral( "uuid" ) );
1480  }
1481  }
1482  }
1483 
1484  QMimeData *mimeData = new QMimeData;
1485  mimeData->setData( QStringLiteral( "text/xml" ), doc.toByteArray() );
1486  QClipboard *clipboard = QApplication::clipboard();
1487  clipboard->setMimeData( mimeData );
1488 }
1489 
1491 {
1492  if ( !composition() )
1493  {
1494  return;
1495  }
1496 
1497  QDomDocument doc;
1498  QClipboard *clipboard = QApplication::clipboard();
1499  if ( doc.setContent( clipboard->mimeData()->data( QStringLiteral( "text/xml" ) ) ) )
1500  {
1501  QDomElement docElem = doc.documentElement();
1502  if ( docElem.tagName() == QLatin1String( "ComposerItemClipboard" ) )
1503  {
1504  if ( composition() )
1505  {
1506  QPointF pt;
1508  {
1509  // place items at cursor position
1510  pt = mapToScene( mapFromGlobal( QCursor::pos() ) );
1511  }
1512  else
1513  {
1514  // place items in center of viewport
1515  pt = mapToScene( viewport()->rect().center() );
1516  }
1517  bool pasteInPlace = ( mode == PasteModeInPlace );
1518  composition()->addItemsFromXml( docElem, doc, true, &pt, pasteInPlace );
1519  }
1520  }
1521  }
1522 
1523  //switch back to select tool so that pasted items can be moved/resized (#8958)
1525 }
1526 
1528 {
1529  if ( !composition() )
1530  {
1531  return;
1532  }
1533 
1534  if ( mCurrentTool == QgsComposerView::EditNodesItem )
1535  {
1536  if ( mNodesItemIndex != -1 )
1537  {
1538  composition()->beginCommand( mNodesItem, tr( "Remove item node" ) );
1539  if ( mNodesItem->removeNode( mNodesItemIndex ) )
1540  {
1541  composition()->endCommand();
1542  if ( mNodesItem->nodesSize() > 0 )
1543  {
1544  mNodesItemIndex = mNodesItem->selectedNode();
1545  // setSelectedNode( mNodesItem, mNodesItemIndex );
1546  }
1547  else
1548  {
1549  mNodesItemIndex = -1;
1550  mNodesItem = nullptr;
1551  }
1552  scene()->update();
1553  }
1554  else
1555  {
1557  }
1558  }
1559  }
1560  else
1561  {
1562  QList<QgsComposerItem *> composerItemList = composition()->selectedComposerItems();
1563  QList<QgsComposerItem *>::iterator itemIt = composerItemList.begin();
1564 
1565  //delete selected items
1566  for ( ; itemIt != composerItemList.end(); ++itemIt )
1567  {
1568  if ( composition() )
1569  {
1570  composition()->removeComposerItem( *itemIt );
1571  }
1572  }
1573  }
1574 }
1575 
1577 {
1578  if ( !composition() )
1579  {
1580  return;
1581  }
1582 
1583  //select all items in composer
1584  QList<QGraphicsItem *> itemList = composition()->items();
1585  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1586  for ( ; itemIt != itemList.end(); ++itemIt )
1587  {
1588  QgsComposerItem *mypItem = dynamic_cast<QgsComposerItem *>( *itemIt );
1589  QgsPaperItem *paperItem = dynamic_cast<QgsPaperItem *>( *itemIt );
1590  if ( mypItem && !paperItem )
1591  {
1592  if ( !mypItem->positionLock() )
1593  {
1594  mypItem->setSelected( true );
1595  }
1596  else
1597  {
1598  //deselect all locked items
1599  mypItem->setSelected( false );
1600  }
1601  emit selectedItemChanged( mypItem );
1602  }
1603  }
1604 }
1605 
1607 {
1608  if ( !composition() )
1609  {
1610  return;
1611  }
1612 
1614 }
1615 
1617 {
1618  if ( !composition() )
1619  {
1620  return;
1621  }
1622 
1623  //check all items in composer
1624  QList<QGraphicsItem *> itemList = composition()->items();
1625  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1626  for ( ; itemIt != itemList.end(); ++itemIt )
1627  {
1628  QgsComposerItem *mypItem = dynamic_cast<QgsComposerItem *>( *itemIt );
1629  QgsPaperItem *paperItem = dynamic_cast<QgsPaperItem *>( *itemIt );
1630  if ( mypItem && !paperItem )
1631  {
1632  //flip selected state for items (and deselect any locked items)
1633  if ( mypItem->selected() || mypItem->positionLock() )
1634  {
1635 
1636  mypItem->setSelected( false );
1637  }
1638  else
1639  {
1640  mypItem->setSelected( true );
1641  emit selectedItemChanged( mypItem );
1642  }
1643  }
1644  }
1645 }
1646 
1648 {
1649  if ( !composition() )
1650  {
1651  return;
1652  }
1653 
1654  if ( mKeyPanning || mMousePanning || mToolPanning || mMovingItemContent ||
1655  composition()->selectionHandles()->isDragging() || composition()->selectionHandles()->isResizing() )
1656  {
1657  return;
1658  }
1659 
1660  if ( mTemporaryZoomStatus != QgsComposerView::Inactive )
1661  {
1662  //temporary keyboard based zoom is active
1663  if ( e->isAutoRepeat() )
1664  {
1665  return;
1666  }
1667 
1668  //respond to changes in ctrl key status
1669  if ( !( e->modifiers() & Qt::ControlModifier ) && !mMarqueeZoom )
1670  {
1671  //space pressed, but control key was released, end of temporary zoom tool
1672  mTemporaryZoomStatus = QgsComposerView::Inactive;
1673  setCurrentTool( mPreviousTool );
1674  }
1675  else if ( !( e->modifiers() & Qt::ControlModifier ) && mMarqueeZoom )
1676  {
1677  //control key released, but user is mid-way through a marquee zoom
1678  //so end temporary zoom when user releases the mouse button
1679  mTemporaryZoomStatus = QgsComposerView::ActiveUntilMouseRelease;
1680  }
1681  else
1682  {
1683  //both control and space pressed
1684  viewport()->setCursor( ( e->modifiers() & Qt::AltModifier ) ?
1685  QgsApplication::getThemeCursor( QgsApplication::Cursor::ZoomOut ) :
1686  QgsApplication::getThemeCursor( QgsApplication::Cursor::ZoomIn ) );
1687  }
1688  return;
1689  }
1690 
1691  if ( mCurrentTool != QgsComposerView::Zoom && ( mRubberBandItem || mRubberBandLineItem ) )
1692  {
1693  //disable keystrokes while drawing a box
1694  return;
1695  }
1696 
1697  if ( e->key() == Qt::Key_Space && ! e->isAutoRepeat() )
1698  {
1699  if ( !( e->modifiers() & Qt::ControlModifier ) )
1700  {
1701  // Pan composer with space bar
1702  mKeyPanning = true;
1703  mMouseLastXY = mMouseCurrentXY;
1704  if ( composition() )
1705  {
1706  //prevent cursor changes while panning
1708  }
1709  viewport()->setCursor( Qt::ClosedHandCursor );
1710  return;
1711  }
1712  else
1713  {
1714  //ctrl+space pressed, so switch to temporary keyboard based zoom tool
1715  mTemporaryZoomStatus = QgsComposerView::Active;
1716  mPreviousTool = mCurrentTool;
1717  setCurrentTool( Zoom );
1718  //set cursor to zoom in/out depending on alt key status
1719  viewport()->setCursor( ( e->modifiers() & Qt::AltModifier ) ?
1720  QgsApplication::getThemeCursor( QgsApplication::Cursor::ZoomOut ) :
1721  QgsApplication::getThemeCursor( QgsApplication::Cursor::ZoomIn ) );
1722  return;
1723  }
1724  }
1725 
1726  if ( mCurrentTool == QgsComposerView::Zoom )
1727  {
1728  //using the zoom tool, respond to changes in alt key status and update mouse cursor accordingly
1729  if ( ! e->isAutoRepeat() )
1730  {
1731  viewport()->setCursor( ( e->modifiers() & Qt::AltModifier ) ?
1732  QgsApplication::getThemeCursor( QgsApplication::Cursor::ZoomOut ) :
1733  QgsApplication::getThemeCursor( QgsApplication::Cursor::ZoomIn ) );
1734  }
1735  return;
1736  }
1737 
1738  QList<QgsComposerItem *> composerItemList = composition()->selectedComposerItems();
1739  QList<QgsComposerItem *>::iterator itemIt = composerItemList.begin();
1740 
1741  // increment used for cursor key item movement
1742  double increment = 1.0;
1743  if ( e->modifiers() & Qt::ShiftModifier )
1744  {
1745  //holding shift while pressing cursor keys results in a big step
1746  increment = 10.0;
1747  }
1748  else if ( e->modifiers() & Qt::AltModifier )
1749  {
1750  //holding alt while pressing cursor keys results in a 1 pixel step
1751  double viewScale = transform().m11();
1752  if ( viewScale > 0 )
1753  {
1754  increment = 1 / viewScale;
1755  }
1756  }
1757 
1758  if ( e->key() == Qt::Key_Left )
1759  {
1760  if ( mCurrentTool == EditNodesItem )
1761  {
1762  if ( mNodesItemIndex != -1 )
1763  {
1764  QPointF currentPos;
1765 
1766  if ( mNodesItem->nodePosition( mNodesItemIndex, currentPos ) )
1767  {
1768  currentPos.setX( currentPos.x() - increment );
1769 
1770  composition()->beginCommand( mNodesItem, tr( "Move item node" ) );
1771  mNodesItem->moveNode( mNodesItemIndex, currentPos );
1772  composition()->endCommand();
1773 
1774  scene()->update();
1775  }
1776  }
1777  }
1778  else
1779  {
1780  for ( ; itemIt != composerItemList.end(); ++itemIt )
1781  {
1782  ( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
1783  ( *itemIt )->move( -1 * increment, 0.0 );
1784  ( *itemIt )->endCommand();
1785  }
1786  }
1787  }
1788  else if ( e->key() == Qt::Key_Right )
1789  {
1790  if ( mCurrentTool == EditNodesItem )
1791  {
1792  if ( mNodesItemIndex != -1 )
1793  {
1794  QPointF currentPos;
1795 
1796  if ( mNodesItem->nodePosition( mNodesItemIndex, currentPos ) )
1797  {
1798  currentPos.setX( currentPos.x() + increment );
1799 
1800  composition()->beginCommand( mNodesItem, tr( "Move item node" ) );
1801  mNodesItem->moveNode( mNodesItemIndex, currentPos );
1802  composition()->endCommand();
1803 
1804  scene()->update();
1805  }
1806  }
1807  }
1808  else
1809  {
1810  for ( ; itemIt != composerItemList.end(); ++itemIt )
1811  {
1812  ( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
1813  ( *itemIt )->move( increment, 0.0 );
1814  ( *itemIt )->endCommand();
1815  }
1816  }
1817  }
1818  else if ( e->key() == Qt::Key_Down )
1819  {
1820  if ( mCurrentTool == EditNodesItem )
1821  {
1822  if ( mNodesItemIndex != -1 )
1823  {
1824  QPointF currentPos;
1825 
1826  if ( mNodesItem->nodePosition( mNodesItemIndex, currentPos ) )
1827  {
1828  currentPos.setY( currentPos.y() + increment );
1829 
1830  composition()->beginCommand( mNodesItem, tr( "Move item node" ) );
1831  mNodesItem->moveNode( mNodesItemIndex, currentPos );
1832  composition()->endCommand();
1833 
1834  scene()->update();
1835  }
1836  }
1837  }
1838  else
1839  {
1840  for ( ; itemIt != composerItemList.end(); ++itemIt )
1841  {
1842  ( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
1843  ( *itemIt )->move( 0.0, increment );
1844  ( *itemIt )->endCommand();
1845  }
1846  }
1847  }
1848  else if ( e->key() == Qt::Key_Up )
1849  {
1850  if ( mCurrentTool == EditNodesItem )
1851  {
1852  if ( mNodesItemIndex != -1 )
1853  {
1854  QPointF currentPos;
1855 
1856  if ( mNodesItem->nodePosition( mNodesItemIndex, currentPos ) )
1857  {
1858  currentPos.setY( currentPos.y() - increment );
1859 
1860  composition()->beginCommand( mNodesItem, tr( "Move item node" ) );
1861  mNodesItem->moveNode( mNodesItemIndex, currentPos );
1862  composition()->endCommand();
1863 
1864  scene()->update();
1865  }
1866  }
1867  }
1868  else
1869  {
1870  for ( ; itemIt != composerItemList.end(); ++itemIt )
1871  {
1872  ( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
1873  ( *itemIt )->move( 0.0, -1 * increment );
1874  ( *itemIt )->endCommand();
1875  }
1876  }
1877  }
1878 }
1879 
1881 {
1882  if ( e->key() == Qt::Key_Space && !e->isAutoRepeat() && mKeyPanning )
1883  {
1884  //end of panning with space key
1885  mKeyPanning = false;
1886 
1887  //reset cursor
1888  if ( mCurrentTool != Pan )
1889  {
1890  if ( composition() )
1891  {
1892  //allow cursor changes again
1893  composition()->setPreventCursorChange( false );
1894  }
1895  }
1896  viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
1897  return;
1898  }
1899  else if ( e->key() == Qt::Key_Space && !e->isAutoRepeat() && mTemporaryZoomStatus != QgsComposerView::Inactive )
1900  {
1901  //temporary keyboard-based zoom tool is active and space key has been released
1902  if ( mMarqueeZoom )
1903  {
1904  //currently in the middle of a marquee operation, so don't switch tool back immediately
1905  //instead, wait until mouse button has been released before switching tool back
1906  mTemporaryZoomStatus = QgsComposerView::ActiveUntilMouseRelease;
1907  }
1908  else
1909  {
1910  //switch tool back
1911  mTemporaryZoomStatus = QgsComposerView::Inactive;
1912  setCurrentTool( mPreviousTool );
1913  }
1914  }
1915  else if ( mCurrentTool == QgsComposerView::Zoom )
1916  {
1917  //if zoom tool is active, respond to changes in the alt key status and update cursor accordingly
1918  if ( ! e->isAutoRepeat() )
1919  {
1920  viewport()->setCursor( ( e->modifiers() & Qt::AltModifier ) ?
1921  QgsApplication::getThemeCursor( QgsApplication::Cursor::ZoomOut ) :
1922  QgsApplication::getThemeCursor( QgsApplication::Cursor::ZoomIn ) );
1923  }
1924  return;
1925  }
1926 }
1927 
1928 void QgsComposerView::wheelEvent( QWheelEvent *event )
1929 {
1930  if ( mRubberBandItem || mRubberBandLineItem )
1931  {
1932  //ignore wheel events while marquee operations are active (e.g., creating new item)
1933  return;
1934  }
1935 
1936  if ( composition()->selectionHandles()->isDragging() || composition()->selectionHandles()->isResizing() )
1937  {
1938  //ignore wheel events while dragging/resizing items
1939  return;
1940  }
1941 
1942  if ( currentTool() == MoveItemContent )
1943  {
1944  //move item content tool, so scroll events get handled by the selected composer item
1945 
1946  QPointF scenePoint = mapToScene( event->pos() );
1947  //select topmost item at position of event
1948  QgsComposerItem *item = composition()->composerItemAt( scenePoint, true );
1949  if ( item )
1950  {
1951  if ( item->isSelected() )
1952  {
1953  QgsSettings settings;
1954  //read zoom mode
1955  QgsComposerItem::ZoomMode zoomMode = ( QgsComposerItem::ZoomMode )settings.value( QStringLiteral( "qgis/wheel_action" ), 2 ).toInt();
1956  if ( zoomMode == QgsComposerItem::NoZoom )
1957  {
1958  //do nothing
1959  return;
1960  }
1961 
1962  double zoomFactor = settings.value( QStringLiteral( "qgis/zoom_factor" ), 2.0 ).toDouble();
1963  if ( event->modifiers() & Qt::ControlModifier )
1964  {
1965  //holding ctrl while wheel zooming results in a finer zoom
1966  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
1967  }
1968  zoomFactor = event->delta() > 0 ? zoomFactor : 1 / zoomFactor;
1969 
1970  QPointF itemPoint = item->mapFromScene( scenePoint );
1971  item->beginCommand( tr( "Zoom item content" ), QgsComposerMergeCommand::ItemZoomContent );
1972  item->zoomContent( zoomFactor, itemPoint, zoomMode );
1973  item->endCommand();
1974  }
1975  }
1976  }
1977  else
1978  {
1979  //not using move item content tool, so zoom whole composition
1980  wheelZoom( event );
1981  }
1982 }
1983 
1984 void QgsComposerView::wheelZoom( QWheelEvent *event )
1985 {
1986  //get mouse wheel zoom behavior settings
1987  QgsSettings mySettings;
1988  double zoomFactor = mySettings.value( QStringLiteral( "qgis/zoom_factor" ), 2 ).toDouble();
1989 
1990  // "Normal" mouse have an angle delta of 120, precision mouses provide data faster, in smaller steps
1991  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 120.0 * std::fabs( event->angleDelta().y() );
1992 
1993  if ( event->modifiers() & Qt::ControlModifier )
1994  {
1995  //holding ctrl while wheel zooming results in a finer zoom
1996  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 20.0;
1997  }
1998 
1999  //calculate zoom scale factor
2000  bool zoomIn = event->angleDelta().y() > 0;
2001  double scaleFactor = ( zoomIn ? 1 / zoomFactor : zoomFactor );
2002 
2003  //get current visible part of scene
2004  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
2005  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
2006 
2007  //transform the mouse pos to scene coordinates
2008  QPointF scenePoint = mapToScene( event->pos() );
2009 
2010  //adjust view center
2011  QgsPointXY oldCenter( visibleRect.center() );
2012  QgsPointXY newCenter( scenePoint.x() + ( ( oldCenter.x() - scenePoint.x() ) * scaleFactor ),
2013  scenePoint.y() + ( ( oldCenter.y() - scenePoint.y() ) * scaleFactor ) );
2014  centerOn( newCenter.x(), newCenter.y() );
2015 
2016  //zoom composition
2017  if ( zoomIn )
2018  {
2019  scaleSafe( zoomFactor );
2020  }
2021  else
2022  {
2023  scaleSafe( 1 / zoomFactor );
2024  }
2025 
2026  //update composition for new zoom
2027  emit zoomLevelChanged();
2028  updateRulers();
2029  update();
2030 }
2031 
2032 void QgsComposerView::setZoomLevel( double zoomLevel )
2033 {
2034  double dpi = QgsApplication::desktop()->logicalDpiX();
2035  //monitor dpi is not always correct - so make sure the value is sane
2036  if ( ( dpi < 60 ) || ( dpi > 250 ) )
2037  dpi = 72;
2038 
2039  //desired pixel width for 1mm on screen
2040  double scale = qBound( MIN_VIEW_SCALE, zoomLevel * dpi / 25.4, MAX_VIEW_SCALE );
2041  setTransform( QTransform::fromScale( scale, scale ) );
2042 
2043  updateRulers();
2044  update();
2045  emit zoomLevelChanged();
2046 }
2047 
2048 void QgsComposerView::scaleSafe( double scale )
2049 {
2050  double currentScale = transform().m11();
2051  scale *= currentScale;
2052  scale = qBound( MIN_VIEW_SCALE, scale, MAX_VIEW_SCALE );
2053  setTransform( QTransform::fromScale( scale, scale ) );
2054 }
2055 
2057 {
2058  if ( !mPreviewEffect )
2059  {
2060  return;
2061  }
2062 
2063  mPreviewEffect->setEnabled( enabled );
2064 }
2065 
2067 {
2068  if ( !mPreviewEffect )
2069  {
2070  return;
2071  }
2072 
2073  mPreviewEffect->setMode( mode );
2074 }
2075 
2077 {
2078  mCanvas = canvas;
2079 }
2080 
2082 {
2083  return mCanvas;
2084 }
2085 
2086 void QgsComposerView::paintEvent( QPaintEvent *event )
2087 {
2088  if ( mPaintingEnabled )
2089  {
2090  QGraphicsView::paintEvent( event );
2091  event->accept();
2092  }
2093  else
2094  {
2095  event->ignore();
2096  }
2097 }
2098 
2099 void QgsComposerView::hideEvent( QHideEvent *e )
2100 {
2101  emit composerViewHide( this );
2102  e->ignore();
2103 }
2104 
2105 void QgsComposerView::showEvent( QShowEvent *e )
2106 {
2107  emit composerViewShow( this );
2108  e->ignore();
2109 }
2110 
2111 void QgsComposerView::resizeEvent( QResizeEvent *event )
2112 {
2113  QGraphicsView::resizeEvent( event );
2114  emit zoomLevelChanged();
2115  updateRulers();
2116 }
2117 
2119 {
2120  QGraphicsView::scrollContentsBy( dx, dy );
2121  updateRulers();
2122 }
2123 
2125 {
2126  setScene( c );
2127  if ( mHorizontalRuler )
2128  {
2129  mHorizontalRuler->setComposition( c );
2130  }
2131  if ( mVerticalRuler )
2132  {
2133  mVerticalRuler->setComposition( c );
2134  }
2135 
2136  //emit compositionSet, so that composer windows can update for the new composition
2137  emit compositionSet( c );
2138 }
2139 
2141 {
2142  if ( scene() )
2143  {
2144  QgsComposition *c = dynamic_cast<QgsComposition *>( scene() );
2145  if ( c )
2146  {
2147  return c;
2148  }
2149  }
2150  return nullptr;
2151 }
2152 
2154 {
2155  if ( !composition() )
2156  {
2157  return;
2158  }
2159 
2160  //group selected items
2161  QList<QgsComposerItem *> selectionList = composition()->selectedComposerItems();
2162  QgsComposerItemGroup *itemGroup = composition()->groupItems( selectionList );
2163 
2164  if ( !itemGroup )
2165  {
2166  //group could not be created
2167  return;
2168  }
2169 
2170  itemGroup->setSelected( true );
2171  emit selectedItemChanged( itemGroup );
2172 }
2173 
2175 {
2176  if ( !composition() )
2177  {
2178  return;
2179  }
2180 
2181  //hunt through selection for any groups, and ungroup them
2182  QList<QgsComposerItem *> selectionList = composition()->selectedComposerItems();
2183  QList<QgsComposerItem *>::iterator itemIter = selectionList.begin();
2184  for ( ; itemIter != selectionList.end(); ++itemIter )
2185  {
2186  QgsComposerItemGroup *itemGroup = dynamic_cast<QgsComposerItemGroup *>( *itemIter );
2187  if ( itemGroup )
2188  {
2189  composition()->ungroupItems( itemGroup );
2190  }
2191  }
2192 }
2193 
2195 {
2196  QMainWindow *composerObject = nullptr;
2197  QObject *currentObject = parent();
2198  if ( !currentObject )
2199  {
2200  return qobject_cast<QMainWindow *>( currentObject );
2201  }
2202 
2203  while ( true )
2204  {
2205  composerObject = qobject_cast<QMainWindow *>( currentObject );
2206  if ( composerObject || !currentObject->parent() )
2207  {
2208  return composerObject;
2209  }
2210  currentObject = currentObject->parent();
2211  }
2212 
2213  return nullptr;
2214 }
2215 
2216 void QgsComposerView::addPolygonNode( QPointF scenePoint )
2217 {
2218  QPolygonF polygon = mPolygonItem->polygon();
2219  polygon.append( QPointF( scenePoint.x(), scenePoint.y() ) );
2220 
2221  if ( polygon.size() == 1 )
2222  polygon.append( QPointF( scenePoint.x(), scenePoint.y() ) );
2223 
2224  mPolygonItem->setPolygon( polygon );
2225 }
2226 
2227 void QgsComposerView::movePolygonNode( QPointF scenePoint, bool constrainAngle )
2228 {
2229  QPolygonF polygon = mPolygonItem->polygon();
2230 
2231  if ( polygon.isEmpty() )
2232  return;
2233 
2234  if ( polygon.size() > 1 && constrainAngle )
2235  {
2236  QPointF start = polygon.at( polygon.size() - 2 );
2237  QLineF newLine = QLineF( start, scenePoint );
2238 
2239  //movement is contrained to 45 degree angles
2240  double angle = QgsComposerUtils::snappedAngle( newLine.angle() );
2241  newLine.setAngle( angle );
2242  scenePoint = newLine.p2();
2243  }
2244 
2245  polygon.replace( polygon.size() - 1, scenePoint );
2246  mPolygonItem->setPolygon( polygon );
2247 }
2248 
2249 void QgsComposerView::displayNodes( const bool display )
2250 {
2251  QList<QgsComposerNodesItem *> nodesShapes;
2252  composition()->composerItems( nodesShapes );
2253 
2254  QList<QgsComposerNodesItem *>::iterator it = nodesShapes.begin();
2255  for ( ; it != nodesShapes.end(); ++it )
2256  ( *it )->setDisplayNodes( display );
2257 
2258  scene()->update();
2259 }
2260 
2261 void QgsComposerView::setSelectedNode( QgsComposerNodesItem *shape,
2262  const int index )
2263 {
2264  QList<QgsComposerNodesItem *> nodesShapes;
2265  composition()->composerItems( nodesShapes );
2266 
2267  QList<QgsComposerNodesItem *>::iterator it = nodesShapes.begin();
2268  for ( ; it != nodesShapes.end(); ++it )
2269  {
2270  if ( ( *it ) == shape )
2271  {
2272  ( *it )->setSelectedNode( index );
2273  selectNone();
2274  ( *it )->setSelected( true );
2275  emit selectedItemChanged( ( *it ) );
2276  }
2277  else
2278  ( *it )->deselectNode();
2279  }
2280 
2281  scene()->update();
2282 }
2283 
2284 void QgsComposerView::deselectNode()
2285 {
2286  QList<QgsComposerNodesItem *> nodesShapes;
2287  composition()->composerItems( nodesShapes );
2288 
2289  QList<QgsComposerNodesItem *>::iterator it = nodesShapes.begin();
2290  for ( ; it != nodesShapes.end(); ++it )
2291  ( *it )->deselectNode();
2292 
2293  scene()->update();
2294 }
QgsComposerMouseHandles::MouseAction mouseActionForScenePos(QPointF sceneCoordPos)
Finds out which mouse move action to choose depending on the scene cursor position.
int selectedNode()
Returns the currently selected node.
void setShapeType(QgsComposerShape::Shape s)
Item representing the paper.
Definition: qgspaperitem.h:46
An abstract composer item that provides generic methods for nodes based shapes such as polygon or pol...
A scale bar item that can be added to a map composition.
QUndoStack * undoStack()
Returns pointer to undo/redo command storage.
QgsComposerItemGroup * groupItems(QList< QgsComposerItem *> items)
Creates a new group from a list of composer items and adds it to the composition. ...
A rectangle specified with double values.
Definition: qgsrectangle.h:39
Composer item for polylines.
QMainWindow * composerWindow()
Returns the composer main window.
void composerItems(QList< T *> &itemList)
Return composer items of a specific type.
void setAllDeselected()
Clears any selected items in the composition.
bool removeNode(const int index)
Remove a node from the shape.
int nodeAtPosition(QPointF node, const bool searchInRadius=true, const double radius=10)
Search the nearest node in shape within a maximal area.
An item that draws an arrow between two points.
void keyPressEvent(QKeyEvent *e) override
This class is a composition of two QSettings instances:
Definition: qgssettings.h:55
void zoomLevelChanged()
Is emitted when the view zoom changes.
void selectAll()
Selects all items.
void setOffset(double xOffset, double yOffset)
Sets offset values to shift image (useful for live updates when moving item content) ...
#define MIN_VIEW_SCALE
void selectInvert()
Inverts current selection.
ZoomMode
Modes for zooming item content.
A class to represent a 2D point.
Definition: qgspointxy.h:43
void setComposerMap(QgsComposerMap *map)
Sets the map item linked to the scalebar.
void scale(double scaleFactor, const QgsPointXY *c=nullptr)
Scale the rectangle around its center point.
bool moveNode(const int index, QPointF node)
Move a node to a new position.
void updateRulers()
Update rulers with current scene rect.
QgsComposerMouseHandles * selectionHandles()
Returns pointer to selection handles.
void mousePressEvent(QMouseEvent *) override
void mouseReleaseEvent(QMouseEvent *) override
void addComposerScaleBar(QgsComposerScaleBar *scaleBar)
Adds scale bar to the graphics scene and advises composer to create a widget for it (through signal) ...
A item that forms part of a map composition.
void pushAddRemoveCommand(QgsComposerItem *item, const QString &text, const QgsAddRemoveItemCommand::State state=QgsAddRemoveItemCommand::Added)
Convenience function to create a QgsAddRemoveItemCommand, connect its signals and push it to the undo...
QSet< QgsComposerItem * > items()
void setZoomLevel(double zoomLevel)
Set zoom level, where a zoom level of 1.0 corresponds to 100%.
A container for grouping several QgsComposerItems.
void deleteSelectedItems()
Deletes selected items.
virtual void setSelected(bool s)
Set selected, selected item should be highlighted.
bool isDragging()
Returns true is user is currently dragging the handles.
void applyDefaultSize(QgsUnitTypes::DistanceUnit u=QgsUnitTypes::DistanceMeters)
Apply default size (scale bar 1/5 of map item width)
void setComposition(QgsComposition *c)
MouseAction
Describes the action (move or resize in different directon) to be done during mouse move...
void setComposerMap(const QgsComposerMap *map)
Sets the composer map to use to limit the extent of features shown in the attribute table...
void setCurrentTool(QgsComposerView::Tool t)
void groupItems()
Add an item group containing the selected items.
void updateLegend()
Updates the model and all legend entries.
void selectNone()
Deselects all items.
QList< const QgsComposerMap * > composerMapItems() const
Returns pointers to all composer maps in the scene.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:74
QgsRectangle visibleExtent() const
Return the actual extent derived from requested extent that takes takes output image size into accoun...
double ANALYSIS_EXPORT angle(QgsPoint *p1, QgsPoint *p2, QgsPoint *p3, QgsPoint *p4)
Calculates the angle between two segments (in 2 dimension, z-values are ignored)
Definition: MathUtils.cpp:786
A table that displays attributes from a vector layer.
void composerViewHide(QgsComposerView *)
Emitted before composerview is hidden.
A graphics effect which can be applied to a widget to simulate various printing and color blindness m...
void compositionSet(QgsComposition *)
Emitted when the composition is set for the view.
A composer class that displays svg files or raster format (jpg, png, ...)
bool isResizing()
Returns true is user is currently resizing with the handles.
bool addNode(QPointF pt, const bool checkArea=true, const double radius=10)
Add a node in current shape.
QgsComposerView(QWidget *parent=nullptr, const char *name=nullptr, Qt::WindowFlags f=0)
void addComposerShape(QgsComposerShape *shape)
Adds a composer shape to the graphics scene and advises composer to create a widget for it (through s...
void zoomToExtent(const QgsRectangle &extent)
Zooms the map so that the specified extent is fully visible within the map item.
virtual void moveContent(double dx, double dy)
Move Content of item.
void setUseSymbol(bool useSymbol)
Controls whether the shape should be drawn using a QgsFillSymbol.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the view.
void showEvent(QShowEvent *e) override
void wheelEvent(QWheelEvent *event) override
void paintEvent(QPaintEvent *event) override
void cancelCommand()
Deletes current command.
void setPreventCursorChange(const bool preventChange)
If true, prevents any mouse cursor changes by the composition or by any composer items Used by QgsCom...
void endCommand()
Saves end state of item and pushes command to the undo history.
virtual bool selected() const
Is selected.
bool nodePosition(const int index, QPointF &position)
Gets the position of a node in scene coordinate.
void addFrame(QgsComposerFrame *frame, bool recalcFrameSizes=true) override
Adds a frame to the multiframe.
void selectedItemChanged(QgsComposerItem *selected)
Is emitted when selected item changed. If 0, no item is selected.
void scaleSafe(double scale)
Scales the view in a safe way, by limiting the acceptable range of the scale applied.
void setSceneTransform(const QTransform &transform)
void setComposerMap(const QgsComposerMap *map)
QList< QgsComposerItem * > ungroupItems(QgsComposerItemGroup *group)
Ungroups items by removing them from an item group and removing the group from the composition...
#define MAX_VIEW_SCALE
void removeComposerItem(QgsComposerItem *item, const bool createCommand=true, const bool removeGroupItems=true)
Remove item from the graphics scene. Additionally to QGraphicsScene::removeItem, this function consid...
void setPreviewModeEnabled(bool enabled)
Sets whether a preview effect should be used to alter the view&#39;s appearance.
void pasteItems(PasteMode mode)
Pastes items from clipboard.
void setMode(PreviewMode mode)
Sets the mode for the preview effect, which controls how the effect modifies a widgets appearance...
Graphics scene for map printing.
Object representing map window.
Frame item for a composer multiframe item.
QgsComposerItem * composerItemAt(QPointF position, const bool ignoreLocked=false) const
Returns the topmost composer item at a specified position.
void ungroupItems()
Ungroups the selected items.
Tool
Current tool.
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the view.
void copyItems(ClipboardMode mode)
Cuts or copies the selected items.
static QCursor getThemeCursor(const Cursor &cursor)
Helper to get a theme cursor.
const QgsMapSettings & mapSettings() const
Get access to properties used for map rendering.
void addComposerPolyline(QgsComposerPolyline *polyline)
Adds a composer polyline and advises composer to create a widget for it (through signal) ...
void addItemsFromXml(const QDomElement &elem, const QDomDocument &doc, bool addUndoCommands=false, QPointF *pos=nullptr, bool pasteInPlace=false)
Add items from XML representation to the graphics scene (for project file reading, pasting items from clipboard)
virtual void addFrame(QgsComposerFrame *frame, bool recalcFrameSizes=true) override
Adds a frame to the multiframe.
void setPreviewMode(QgsPreviewEffect::PreviewMode mode)
Sets the preview mode which should be used to modify the view&#39;s appearance.
QRectF toRectF() const
Returns a QRectF with same coordinates as the rectangle.
A composer items that draws common shapes (ellipse, triangle, rectangle)
Composer item for polygons.
void addComposerMap(QgsComposerMap *map)
Adds map to the graphics scene and advises composer to create a widget for it (through signal) ...
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), const Section section=NoSection) const
Returns the value for setting key.
void resizeEvent(QResizeEvent *event) override
QPointF snapPointToGrid(QPointF scenePoint) const
Snaps a scene coordinate point to grid.
void cursorPosChanged(QPointF)
Is emitted when mouse cursor coordinates change.
void setComposition(QgsComposition *c)
Sets the composition for the view.
virtual void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
void keyReleaseEvent(QKeyEvent *e) override
int nodesSize()
Returns the number of nodes in the shape.
void setText(const QString &text)
void setSceneRect(const QRectF &rectangle) override
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
A label that can be placed onto a map composition.
static double snappedAngle(const double angle)
Snaps an angle to its closest 45 degree angle.
void addComposerPicture(QgsComposerPicture *picture)
Adds picture to the graphics scene and advises composer to create a widget for it (through signal) ...
void hideEvent(QHideEvent *e) override
QgsComposerView::Tool currentTool() const
void updateMarker(QPointF pos)
void setSceneRect(const QRectF &rectangle) override
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
QgsComposition * composition()
Returns the composition or 0 in case of error.
QgsPointXY center() const
Returns the center point of the rectangle.
Definition: qgsrectangle.h:166
bool positionLock() const
Returns whether position lock for mouse drags is enabled returns true if item is locked for mouse mov...
void addComposerPolygon(QgsComposerPolygon *polygon)
Adds a composer polygon and advises composer to create a widget for it (through signal) ...
void actionFinished()
Current action (e.g.
void mouseMoveEvent(QMouseEvent *) override
A legend that can be placed onto a map composition.
void addComposerLabel(QgsComposerLabel *label)
Adds label to the graphics scene and advises composer to create a widget for it (through signal) ...
void addComposerArrow(QgsComposerArrow *arrow)
Adds an arrow item to the graphics scene and advises composer to create a widget for it (through sign...
void addComposerLegend(QgsComposerLegend *legend)
Adds legend to the graphics scene and advises composer to create a widget for it (through signal) ...
void adjustSizeToText()
Resizes the widget such that the text fits to the item. Keeps top left point.
virtual int type() const override
Return correct graphics item type.
void composerViewShow(QgsComposerView *)
Emitted before composerview is shown.
void beginCommand(QgsComposerItem *item, const QString &commandText, const QgsComposerMergeCommand::Context c=QgsComposerMergeCommand::Unknown)
Allocates new item command and saves initial state in it.
void scrollContentsBy(int dx, int dy) override
QList< QgsComposerItem * > selectedComposerItems(const bool includeLockedItems=true)
Returns list of selected composer items.
void mouseDoubleClickEvent(QMouseEvent *e) override
void beginMultiFrameCommand(QgsComposerMultiFrame *multiFrame, const QString &text, const QgsComposerMultiFrameMergeCommand::Context c=QgsComposerMultiFrameMergeCommand::Unknown)