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