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