QGIS API Documentation  2.4.0-Chugiak
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
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 "qgscomposerhtml.h"
33 #include "qgscomposerlabel.h"
34 #include "qgscomposerlegend.h"
35 #include "qgscomposermap.h"
37 #include "qgscomposeritemgroup.h"
38 #include "qgscomposerpicture.h"
39 #include "qgscomposerruler.h"
40 #include "qgscomposerscalebar.h"
41 #include "qgscomposershape.h"
43 #include "qgslogger.h"
45 #include "qgspaperitem.h"
46 #include "qgsmapcanvas.h" //for QgsMapCanvas::WheelAction
47 #include "qgscursors.h"
48 
49 QgsComposerView::QgsComposerView( QWidget* parent, const char* name, Qt::WindowFlags f )
50  : QGraphicsView( parent )
51  , mRubberBandItem( 0 )
52  , mRubberBandLineItem( 0 )
53  , mMoveContentItem( 0 )
54  , mMarqueeSelect( false )
55  , mMarqueeZoom( false )
56  , mTemporaryZoomStatus( QgsComposerView::Inactive )
57  , mPaintingEnabled( true )
58  , mHorizontalRuler( 0 )
59  , mVerticalRuler( 0 )
60  , mToolPanning( false )
61  , mMousePanning( false )
62  , mKeyPanning( false )
63  , mMovingItemContent( false )
64  , mPreviewEffect( 0 )
65 {
66  Q_UNUSED( f );
67  Q_UNUSED( name );
68 
69  setResizeAnchor( QGraphicsView::AnchorViewCenter );
70  setMouseTracking( true );
71  viewport()->setMouseTracking( true );
72  setFrameShape( QFrame::NoFrame );
73 
74  mPreviewEffect = new QgsPreviewEffect( this );
75  viewport()->setGraphicsEffect( mPreviewEffect );
76 }
77 
79 {
80  mCurrentTool = t;
81 
82  //update mouse cursor for current tool
83  if ( !composition() )
84  {
85  return;
86  }
87  switch ( t )
88  {
90  {
91  //lock cursor to prevent composer items changing it
93  viewport()->setCursor( defaultCursorForTool( Pan ) );
94  break;
95  }
97  {
98  //lock cursor to prevent composer items changing it
100  //set the cursor to zoom in
101  viewport()->setCursor( defaultCursorForTool( Zoom ) );
102  break;
103  }
115  {
116  //using a drawing tool
117  //lock cursor to prevent composer items changing it
119  viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
120  break;
121  }
122  default:
123  {
124  //not using pan tool, composer items can change cursor
126  viewport()->setCursor( Qt::ArrowCursor );
127  }
128  }
129 }
130 
131 void QgsComposerView::mousePressEvent( QMouseEvent* e )
132 {
133  if ( !composition() )
134  {
135  return;
136  }
137 
139  {
140  //ignore clicks during certain operations
141  return;
142  }
143 
144  if ( composition()->selectionHandles()->isDragging() || composition()->selectionHandles()->isResizing() )
145  {
146  //ignore clicks while dragging/resizing items
147  return;
148  }
149 
150  QPointF scenePoint = mapToScene( e->pos() );
151  QPointF snappedScenePoint = composition()->snapPointToGrid( scenePoint );
152  mMousePressStartPos = e->pos();
153 
154  //lock/unlock position of item with right click
155  if ( e->button() == Qt::RightButton )
156  {
157  QgsComposerItem* selectedItem = composition()->composerItemAt( scenePoint );
158  if ( selectedItem )
159  {
160  bool lock = selectedItem->positionLock() ? false : true;
161  selectedItem->setPositionLock( lock );
162  selectedItem->update();
163  }
164  return;
165  }
166  else if ( e->button() == Qt::MidButton )
167  {
168  //pan composer with middle button
169  mMousePanning = true;
170  mMouseLastXY = e->pos();
171  if ( composition() )
172  {
173  //lock cursor to closed hand cursor
175  }
176  viewport()->setCursor( Qt::ClosedHandCursor );
177  return;
178  }
179 
180  switch ( mCurrentTool )
181  {
182  //select/deselect items and pass mouse event further
183  case Select:
184  {
185  //check if we are clicking on a selection handle
186  if ( composition()->selectionHandles()->isVisible() )
187  {
188  //selection handles are being shown, get mouse action for current cursor position
190 
192  {
193  //mouse is over a resize handle, so propagate event onward
194  QGraphicsView::mousePressEvent( e );
195  return;
196  }
197  }
198 
199  QgsComposerItem* selectedItem = 0;
200  QgsComposerItem* previousSelectedItem = 0;
201 
202  if ( e->modifiers() & Qt::ControlModifier )
203  {
204  //CTRL modifier, so we are trying to select the next item below the current one
205  //first, find currently selected item
206  QList<QgsComposerItem*> selectedItems = composition()->selectedComposerItems();
207  if ( selectedItems.size() > 0 )
208  {
209  previousSelectedItem = selectedItems.at( 0 );
210  }
211  }
212 
213  if ( previousSelectedItem )
214  {
215  //select highest item just below previously selected item at position of event
216  selectedItem = composition()->composerItemAt( scenePoint, previousSelectedItem );
217 
218  //if we didn't find a lower item we'll use the top-most as fall-back
219  //this duplicates mapinfo/illustrator/etc behaviour where ctrl-clicks are "cyclic"
220  if ( !selectedItem )
221  {
222  selectedItem = composition()->composerItemAt( scenePoint );
223  }
224  }
225  else
226  {
227  //select topmost item at position of event
228  selectedItem = composition()->composerItemAt( scenePoint );
229  }
230 
231  if ( !selectedItem )
232  {
233  //not clicking over an item, so start marquee selection
234  startMarqueeSelect( scenePoint );
235  break;
236  }
237 
238  if (( !selectedItem->selected() ) && //keep selection if an already selected item pressed
239  !( e->modifiers() & Qt::ShiftModifier ) ) //keep selection if shift key pressed
240  {
241  composition()->clearSelection();
242  }
243 
244  if (( e->modifiers() & Qt::ShiftModifier ) && ( selectedItem->selected() ) )
245  {
246  //SHIFT-clicking a selected item deselects it
247  selectedItem->setSelected( false );
248 
249  //Check if we have any remaining selected items, and if so, update the item panel
250  QList<QgsComposerItem*> selectedItems = composition()->selectedComposerItems();
251  if ( selectedItems.size() > 0 )
252  {
253  emit selectedItemChanged( selectedItems.at( 0 ) );
254  }
255  }
256  else
257  {
258  selectedItem->setSelected( true );
259  QGraphicsView::mousePressEvent( e );
260  emit selectedItemChanged( selectedItem );
261  }
262  break;
263  }
264 
265  case Zoom:
266  {
267  if ( !( e->modifiers() & Qt::ShiftModifier ) )
268  {
269  //zoom in action
270  startMarqueeZoom( scenePoint );
271  }
272  else
273  {
274  //zoom out action, so zoom out and recenter on clicked point
275  double scaleFactor = 2;
276  //get current visible part of scene
277  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
278  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
279 
280  //transform the mouse pos to scene coordinates
281  QPointF scenePoint = mapToScene( e->pos() );
282 
283  visibleRect.scale( scaleFactor, scenePoint.x(), scenePoint.y() );
284  QRectF boundsRect = visibleRect.toRectF();
285 
286  //zoom view to fit desired bounds
287  fitInView( boundsRect, Qt::KeepAspectRatio );
288  }
289  break;
290  }
291 
292  case Pan:
293  {
294  //pan action
295  mToolPanning = true;
296  mMouseLastXY = e->pos();
297  viewport()->setCursor( Qt::ClosedHandCursor );
298  break;
299  }
300 
301  case MoveItemContent:
302  {
303  //get a list of items at clicked position
304  QList<QGraphicsItem *> itemsAtCursorPos = items( e->pos() );
305  if ( itemsAtCursorPos.size() == 0 )
306  {
307  //no items at clicked position
308  return;
309  }
310 
311  //find highest QgsComposerItem at clicked position
312  //(other graphics items may be higher, eg selection handles)
313  QList<QGraphicsItem*>::iterator itemIter = itemsAtCursorPos.begin();
314  for ( ; itemIter != itemsAtCursorPos.end(); ++itemIter )
315  {
316  QgsComposerItem* item = dynamic_cast<QgsComposerItem *>(( *itemIter ) );
317  if ( item )
318  {
319  //we've found the highest QgsComposerItem
320  mMoveContentStartPos = scenePoint;
321  mMoveContentItem = item;
322  mMovingItemContent = true;
323  break;
324  }
325  }
326 
327  //no QgsComposerItem at clicked position
328  return;
329  }
330 
331  //create rubber band for adding line items
332  case AddArrow:
333  {
334  mRubberBandStartPos = QPointF( snappedScenePoint.x(), snappedScenePoint.y() );
335  mRubberBandLineItem = new QGraphicsLineItem( snappedScenePoint.x(), snappedScenePoint.y(), snappedScenePoint.x(), snappedScenePoint.y() );
336  mRubberBandLineItem->setZValue( 1000 );
337  scene()->addItem( mRubberBandLineItem );
338  scene()->update();
339  break;
340  }
341 
342  //create rubber band for adding rectangular items
343  case AddMap:
344  case AddRectangle:
345  case AddTriangle:
346  case AddEllipse:
347  case AddHtml:
348  case AddPicture:
349  case AddLabel:
350  case AddLegend:
351  case AddTable:
352  {
353  QTransform t;
354  mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
355  mRubberBandStartPos = QPointF( snappedScenePoint.x(), snappedScenePoint.y() );
356  t.translate( snappedScenePoint.x(), snappedScenePoint.y() );
357  mRubberBandItem->setTransform( t );
358  mRubberBandItem->setZValue( 1000 );
359  scene()->addItem( mRubberBandItem );
360  scene()->update();
361  }
362  break;
363 
364  case AddScalebar:
365  if ( composition() )
366  {
367  QgsComposerScaleBar* newScaleBar = new QgsComposerScaleBar( composition() );
368  newScaleBar->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), 20, 20 ) );
369  composition()->addComposerScaleBar( newScaleBar );
370  QList<const QgsComposerMap*> mapItemList = composition()->composerMapItems();
371  if ( mapItemList.size() > 0 )
372  {
373  newScaleBar->setComposerMap( mapItemList.at( 0 ) );
374  }
375  newScaleBar->applyDefaultSize(); //4 segments, 1/5 of composer map width
376 
377  composition()->clearSelection();
378  newScaleBar->setSelected( true );
379  emit selectedItemChanged( newScaleBar );
380 
381  emit actionFinished();
382  composition()->pushAddRemoveCommand( newScaleBar, tr( "Scale bar added" ) );
383  }
384  break;
385 
386  default:
387  break;
388  }
389 }
390 
392 {
393  switch ( currentTool )
394  {
395  case Select:
396  return Qt::ArrowCursor;
397 
398  case Zoom:
399  {
400  QPixmap myZoomQPixmap = QPixmap(( const char ** )( zoom_in ) );
401  return QCursor( myZoomQPixmap, 7, 7 );
402  }
403 
404  case Pan:
405  return Qt::OpenHandCursor;
406 
407  case MoveItemContent:
408  return Qt::ArrowCursor;
409 
410  case AddArrow:
411  case AddMap:
412  case AddRectangle:
413  case AddTriangle:
414  case AddEllipse:
415  case AddHtml:
416  case AddLabel:
417  case AddScalebar:
418  case AddLegend:
419  case AddPicture:
420  case AddTable:
421  {
422  QPixmap myCrosshairQPixmap = QPixmap(( const char ** )( cross_hair_cursor ) );
423  return QCursor( myCrosshairQPixmap, 8, 8 );
424  }
425  }
426  return Qt::ArrowCursor;
427 }
428 
429 void QgsComposerView::addShape( Tool currentTool )
430 {
432 
433  if ( currentTool == AddRectangle )
435  else if ( currentTool == AddTriangle )
437 
438  if ( !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
439  {
441  return;
442  }
443  if ( composition() )
444  {
445  QgsComposerShape* composerShape = new QgsComposerShape( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height(), composition() );
446  composerShape->setShapeType( shape );
447  //new shapes use symbol v2 by default
448  composerShape->setUseSymbolV2( true );
449  composition()->addComposerShape( composerShape );
451 
452  composition()->clearSelection();
453  composerShape->setSelected( true );
454  emit selectedItemChanged( composerShape );
455 
456  emit actionFinished();
457  composition()->pushAddRemoveCommand( composerShape, tr( "Shape added" ) );
458  }
459 }
460 
462 {
463  if ( mHorizontalRuler )
464  {
465  mHorizontalRuler->setSceneTransform( viewportTransform() );
466  }
467  if ( mVerticalRuler )
468  {
469  mVerticalRuler->setSceneTransform( viewportTransform() );
470  }
471 }
472 
474 {
475  if ( mRubberBandItem )
476  {
477  scene()->removeItem( mRubberBandItem );
478  delete mRubberBandItem;
479  mRubberBandItem = 0;
480  }
481 }
482 
483 void QgsComposerView::startMarqueeSelect( QPointF & scenePoint )
484 {
485  mMarqueeSelect = true;
486 
487  QTransform t;
488  mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
489  mRubberBandItem->setBrush( QBrush( QColor( 225, 50, 70, 25 ) ) );
490  mRubberBandItem->setPen( QPen( Qt::DotLine ) );
491  mRubberBandStartPos = QPointF( scenePoint.x(), scenePoint.y() );
492  t.translate( scenePoint.x(), scenePoint.y() );
493  mRubberBandItem->setTransform( t );
494  mRubberBandItem->setZValue( 1000 );
495  scene()->addItem( mRubberBandItem );
496  scene()->update();
497 }
498 
499 void QgsComposerView::endMarqueeSelect( QMouseEvent* e )
500 {
501  mMarqueeSelect = false;
502 
503  bool subtractingSelection = false;
504  if ( e->modifiers() & Qt::ShiftModifier )
505  {
506  //shift modifer means adding to selection, nothing required here
507  }
508  else if ( e->modifiers() & Qt::ControlModifier )
509  {
510  //control modifier means subtract from current selection
511  subtractingSelection = true;
512  }
513  else
514  {
515  //not adding to or removing from selection, so clear current selection
516  composition()->clearSelection();
517  }
518 
519  if ( !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
520  {
521  //just a click, do nothing
523  return;
524  }
525 
526  QRectF boundsRect = QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(),
527  mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
528 
529  //determine item selection mode, default to intersection
530  Qt::ItemSelectionMode selectionMode = Qt::IntersectsItemShape;
531  if ( e->modifiers() & Qt::AltModifier )
532  {
533  //alt modifier switches to contains selection mode
534  selectionMode = Qt::ContainsItemShape;
535  }
536 
537  //find all items in rubber band
538  QList<QGraphicsItem *> itemList = composition()->items( boundsRect, selectionMode );
539  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
540  for ( ; itemIt != itemList.end(); ++itemIt )
541  {
542  QgsComposerItem* mypItem = dynamic_cast<QgsComposerItem *>( *itemIt );
543  QgsPaperItem* paperItem = dynamic_cast<QgsPaperItem*>( *itemIt );
544  if ( mypItem && !paperItem )
545  {
546  if ( !mypItem->positionLock() )
547  {
548  if ( subtractingSelection )
549  {
550  mypItem->setSelected( false );
551  }
552  else
553  {
554  mypItem->setSelected( true );
555  }
556  }
557  }
558  }
560 
561  //update item panel
562  QList<QgsComposerItem*> selectedItemList = composition()->selectedComposerItems();
563  if ( selectedItemList.size() > 0 )
564  {
565  emit selectedItemChanged( selectedItemList[0] );
566  }
567 }
568 
569 void QgsComposerView::startMarqueeZoom( QPointF & scenePoint )
570 {
571  mMarqueeZoom = true;
572 
573  QTransform t;
574  mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
575  mRubberBandItem->setBrush( QBrush( QColor( 70, 50, 255, 25 ) ) );
576  mRubberBandItem->setPen( QPen( QColor( 70, 50, 255, 100 ) ) );
577  mRubberBandStartPos = QPointF( scenePoint.x(), scenePoint.y() );
578  t.translate( scenePoint.x(), scenePoint.y() );
579  mRubberBandItem->setTransform( t );
580  mRubberBandItem->setZValue( 1000 );
581  scene()->addItem( mRubberBandItem );
582  scene()->update();
583 }
584 
585 void QgsComposerView::endMarqueeZoom( QMouseEvent* e )
586 {
587  mMarqueeZoom = false;
588 
589  QRectF boundsRect;
590 
591  if ( !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
592  {
593  //just a click, so zoom to clicked point and recenter
594  double scaleFactor = 0.5;
595  //get current visible part of scene
596  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
597  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
598 
599  //transform the mouse pos to scene coordinates
600  QPointF scenePoint = mapToScene( e->pos() );
601 
602  visibleRect.scale( scaleFactor, scenePoint.x(), scenePoint.y() );
603  boundsRect = visibleRect.toRectF();
604  }
605  else
606  {
607  //marquee zoom
608  //zoom bounds are size marquee object
609  boundsRect = QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(),
610  mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
611  }
612 
614  //zoom view to fit desired bounds
615  fitInView( boundsRect, Qt::KeepAspectRatio );
616 
618  {
619  //user was using the temporary keyboard activated zoom tool
620  //and the control or space key was released before mouse button, so end temporary zoom
623  }
624 }
625 
627 {
628  if ( !composition() )
629  {
630  return;
631  }
632 
633  if ( e->button() != Qt::LeftButton &&
635  {
636  //ignore clicks while dragging/resizing items
637  return;
638  }
639 
640  QPoint mousePressStopPoint = e->pos();
641  int diffX = mousePressStopPoint.x() - mMousePressStartPos.x();
642  int diffY = mousePressStopPoint.y() - mMousePressStartPos.y();
643 
644  //was this just a click? or a click and drag?
645  bool clickOnly = false;
646  if ( qAbs( diffX ) < 2 && qAbs( diffY ) < 2 )
647  {
648  clickOnly = true;
649  }
650 
651  QPointF scenePoint = mapToScene( e->pos() );
652 
653  if ( mMousePanning || mToolPanning )
654  {
655  mMousePanning = false;
656  mToolPanning = false;
657 
658  if ( clickOnly && e->button() == Qt::MidButton )
659  {
660  //middle mouse button click = recenter on point
661 
662  //get current visible part of scene
663  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
664  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
665  visibleRect.scale( 1, scenePoint.x(), scenePoint.y() );
666  QRectF boundsRect = visibleRect.toRectF();
667 
668  //zoom view to fit desired bounds
669  fitInView( boundsRect, Qt::KeepAspectRatio );
670  }
671 
672  //set new cursor
673  if ( mCurrentTool != Pan )
674  {
675  if ( composition() )
676  {
677  //allow composer items to change cursor
679  }
680  }
681  viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
682  }
683 
684  //for every other tool, ignore clicks of non-left button
685  if ( e->button() != Qt::LeftButton )
686  {
687  return;
688  }
689 
690  if ( mMarqueeSelect )
691  {
692  endMarqueeSelect( e );
693  return;
694  }
695 
696  switch ( mCurrentTool )
697  {
698  case Select:
699  {
700  QGraphicsView::mouseReleaseEvent( e );
701  break;
702  }
703 
704  case Zoom:
705  {
706  if ( mMarqueeZoom )
707  {
708  endMarqueeZoom( e );
709  }
710  break;
711  }
712 
713  case MoveItemContent:
714  {
715  if ( mMoveContentItem )
716  {
717  //update map preview if composer map
718  QgsComposerMap* composerMap = dynamic_cast<QgsComposerMap *>( mMoveContentItem );
719  if ( composerMap )
720  {
721  composerMap->setOffset( 0, 0 );
722  }
723 
724  double moveX = scenePoint.x() - mMoveContentStartPos.x();
725  double moveY = scenePoint.y() - mMoveContentStartPos.y();
726 
727  composition()->beginCommand( mMoveContentItem, tr( "Move item content" ) );
728  mMoveContentItem->moveContent( -moveX, -moveY );
729  composition()->endCommand();
730  mMoveContentItem = 0;
731  mMovingItemContent = false;
732  }
733  break;
734  }
735  case AddArrow:
736  if ( !composition() || !mRubberBandLineItem )
737  {
738  scene()->removeItem( mRubberBandLineItem );
739  delete mRubberBandLineItem;
741  return;
742  }
743  else
744  {
745  QPointF scenePoint = mapToScene( e->pos() );
746  QPointF snappedScenePoint = composition()->snapPointToGrid( scenePoint );
747  QgsComposerArrow* composerArrow = new QgsComposerArrow( mRubberBandStartPos, QPointF( snappedScenePoint.x(), snappedScenePoint.y() ), composition() );
748  composition()->addComposerArrow( composerArrow );
749 
750  composition()->clearSelection();
751  composerArrow->setSelected( true );
752  emit selectedItemChanged( composerArrow );
753 
754  scene()->removeItem( mRubberBandLineItem );
755  delete mRubberBandLineItem;
757  emit actionFinished();
758  composition()->pushAddRemoveCommand( composerArrow, tr( "Arrow added" ) );
759  }
760  break;
761 
762  case AddRectangle:
763  case AddTriangle:
764  case AddEllipse:
766  break;
767 
768  case AddMap:
769  if ( !composition() || !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
770  {
772  return;
773  }
774  else
775  {
776  QgsComposerMap* composerMap = new QgsComposerMap( composition(), mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
777  composition()->addComposerMap( composerMap );
778 
779  composition()->clearSelection();
780  composerMap->setSelected( true );
781  emit selectedItemChanged( composerMap );
782 
784  emit actionFinished();
785  composition()->pushAddRemoveCommand( composerMap, tr( "Map added" ) );
786  }
787  break;
788 
789  case AddPicture:
790  if ( !composition() || !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
791  {
793  return;
794  }
795  else
796  {
797  QgsComposerPicture* newPicture = new QgsComposerPicture( composition() );
798  newPicture->setSceneRect( QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height() ) );
799  composition()->addComposerPicture( newPicture );
800 
801  composition()->clearSelection();
802  newPicture->setSelected( true );
803  emit selectedItemChanged( newPicture );
804 
806  emit actionFinished();
807  composition()->pushAddRemoveCommand( newPicture, tr( "Picture added" ) );
808  }
809  break;
810 
811  case AddLabel:
812  if ( !composition() || !mRubberBandItem )
813  {
815  return;
816  }
817  else
818  {
819  QgsComposerLabel* newLabelItem = new QgsComposerLabel( composition() );
820  newLabelItem->setText( tr( "QGIS" ) );
821  newLabelItem->adjustSizeToText();
822 
823  //make sure label size is sufficient to fit text
824  double labelWidth = qMax( mRubberBandItem->rect().width(), newLabelItem->rect().width() );
825  double labelHeight = qMax( mRubberBandItem->rect().height(), newLabelItem->rect().height() );
826  newLabelItem->setSceneRect( QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), labelWidth, labelHeight ) );
827 
828  composition()->addComposerLabel( newLabelItem );
829 
830  composition()->clearSelection();
831  newLabelItem->setSelected( true );
832  emit selectedItemChanged( newLabelItem );
833 
835  emit actionFinished();
836  composition()->pushAddRemoveCommand( newLabelItem, tr( "Label added" ) );
837  }
838  break;
839 
840  case AddLegend:
841  if ( !composition() || !mRubberBandItem )
842  {
844  return;
845  }
846  else
847  {
848  QgsComposerLegend* newLegend = new QgsComposerLegend( composition() );
849  newLegend->setSceneRect( QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height() ) );
850  composition()->addComposerLegend( newLegend );
851  newLegend->updateLegend();
852 
853  composition()->clearSelection();
854  newLegend->setSelected( true );
855  emit selectedItemChanged( newLegend );
856 
858  emit actionFinished();
859  composition()->pushAddRemoveCommand( newLegend, tr( "Legend added" ) );
860  }
861  break;
862 
863  case AddTable:
864  if ( !composition() || !mRubberBandItem )
865  {
867  return;
868  }
869  else
870  {
872  newTable->setSceneRect( QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), qMax( mRubberBandItem->rect().height(), 15.0 ) ) );
873  QList<const QgsComposerMap*> mapItemList = composition()->composerMapItems();
874  if ( mapItemList.size() > 0 )
875  {
876  newTable->setComposerMap( mapItemList.at( 0 ) );
877  }
878  composition()->addComposerTable( newTable );
879 
880  composition()->clearSelection();
881  newTable->setSelected( true );
882  emit selectedItemChanged( newTable );
883 
885  emit actionFinished();
886  composition()->pushAddRemoveCommand( newTable, tr( "Table added" ) );
887  }
888  break;
889 
890  case AddHtml:
891  if ( !composition() || !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
892  {
894  return;
895  }
896  else
897  {
898  QgsComposerHtml* composerHtml = new QgsComposerHtml( composition(), true );
900  composerHtml, composition(), tr( "Html item added" ) );
901  composition()->undoStack()->push( command );
902  QgsComposerFrame* frame = new QgsComposerFrame( composition(), composerHtml, mRubberBandItem->transform().dx(),
903  mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(),
904  mRubberBandItem->rect().height() );
905  composition()->beginMultiFrameCommand( composerHtml, tr( "Html frame added" ) );
906  composerHtml->addFrame( frame );
908 
909  composition()->clearSelection();
910  frame->setSelected( true );
911  emit selectedItemChanged( frame );
912 
914  emit actionFinished();
915  }
916  default:
917  break;
918  }
919 }
920 
921 void QgsComposerView::mouseMoveEvent( QMouseEvent* e )
922 {
923  if ( !composition() )
924  {
925  return;
926  }
927 
928  mMouseCurrentXY = e->pos();
929  //update cursor position in composer status bar
930  emit cursorPosChanged( mapToScene( e->pos() ) );
931 
932  updateRulers();
933  if ( mHorizontalRuler )
934  {
935  mHorizontalRuler->updateMarker( e->posF() );
936  }
937  if ( mVerticalRuler )
938  {
939  mVerticalRuler->updateMarker( e->posF() );
940  }
941 
943  {
944  //panning, so scroll view
945  horizontalScrollBar()->setValue( horizontalScrollBar()->value() - ( e->x() - mMouseLastXY.x() ) );
946  verticalScrollBar()->setValue( verticalScrollBar()->value() - ( e->y() - mMouseLastXY.y() ) );
947  mMouseLastXY = e->pos();
948  return;
949  }
950  else if ( e->buttons() == Qt::NoButton )
951  {
952  if ( mCurrentTool == Select )
953  {
954  QGraphicsView::mouseMoveEvent( e );
955  }
956  }
957  else
958  {
959  QPointF scenePoint = mapToScene( e->pos() );
960 
961  if ( mMarqueeSelect || mMarqueeZoom )
962  {
963  updateRubberBand( scenePoint );
964  return;
965  }
966 
967  switch ( mCurrentTool )
968  {
969  case Select:
970  QGraphicsView::mouseMoveEvent( e );
971  break;
972 
973  case AddArrow:
974  {
975  if ( mRubberBandLineItem )
976  {
977  mRubberBandLineItem->setLine( mRubberBandStartPos.x(), mRubberBandStartPos.y(), scenePoint.x(), scenePoint.y() );
978  }
979  break;
980  }
981 
982  case AddMap:
983  case AddRectangle:
984  case AddTriangle:
985  case AddEllipse:
986  case AddHtml:
987  case AddPicture:
988  case AddLabel:
989  case AddLegend:
990  case AddTable:
991  //adjust rubber band item
992  {
993  updateRubberBand( scenePoint );
994  break;
995  }
996 
997  case MoveItemContent:
998  {
999  //update map preview if composer map
1000  QgsComposerMap* composerMap = dynamic_cast<QgsComposerMap *>( mMoveContentItem );
1001  if ( composerMap )
1002  {
1003  composerMap->setOffset( scenePoint.x() - mMoveContentStartPos.x(), scenePoint.y() - mMoveContentStartPos.y() );
1004  composerMap->update();
1005  }
1006  break;
1007  }
1008  default:
1009  break;
1010  }
1011  }
1012 }
1013 
1015 {
1016  double x = 0;
1017  double y = 0;
1018  double width = 0;
1019  double height = 0;
1020 
1021  double dx = pos.x() - mRubberBandStartPos.x();
1022  double dy = pos.y() - mRubberBandStartPos.y();
1023 
1024  if ( dx < 0 )
1025  {
1026  x = pos.x();
1027  width = -dx;
1028  }
1029  else
1030  {
1031  x = mRubberBandStartPos.x();
1032  width = dx;
1033  }
1034 
1035  if ( dy < 0 )
1036  {
1037  y = pos.y();
1038  height = -dy;
1039  }
1040  else
1041  {
1042  y = mRubberBandStartPos.y();
1043  height = dy;
1044  }
1045 
1046  if ( mRubberBandItem )
1047  {
1048  mRubberBandItem->setRect( 0, 0, width, height );
1049  QTransform t;
1050  t.translate( x, y );
1051  mRubberBandItem->setTransform( t );
1052  }
1053 }
1054 
1056 {
1057  e->ignore();
1058 }
1059 
1061 {
1062  if ( !composition() )
1063  {
1064  return;
1065  }
1066 
1067  QList<QgsComposerItem*> composerItemList = composition()->selectedComposerItems();
1068  QList<QgsComposerItem*>::iterator itemIt = composerItemList.begin();
1069 
1070  QDomDocument doc;
1071  QDomElement documentElement = doc.createElement( "ComposerItemClipboard" );
1072  for ( ; itemIt != composerItemList.end(); ++itemIt )
1073  {
1074  // copy each item in a group
1075  QgsComposerItemGroup* itemGroup = dynamic_cast<QgsComposerItemGroup*>( *itemIt );
1076  if ( itemGroup && composition() )
1077  {
1078  QSet<QgsComposerItem*> groupedItems = itemGroup->items();
1079  QSet<QgsComposerItem*>::iterator it = groupedItems.begin();
1080  for ( ; it != groupedItems.end(); ++it )
1081  {
1082  ( *it )->writeXML( documentElement, doc );
1083  }
1084  }
1085  ( *itemIt )->writeXML( documentElement, doc );
1086  if ( mode == ClipboardModeCut )
1087  {
1088  composition()->removeComposerItem( *itemIt );
1089  }
1090  }
1091  doc.appendChild( documentElement );
1092 
1093  //if it's a copy, we have to remove the UUIDs since we don't want any duplicate UUID
1094  if ( mode == ClipboardModeCopy )
1095  {
1096  // remove all uuid attributes
1097  QDomNodeList composerItemsNodes = doc.elementsByTagName( "ComposerItem" );
1098  for ( int i = 0; i < composerItemsNodes.count(); ++i )
1099  {
1100  QDomNode composerItemNode = composerItemsNodes.at( i );
1101  if ( composerItemNode.isElement() )
1102  {
1103  composerItemNode.toElement().removeAttribute( "uuid" );
1104  }
1105  }
1106  }
1107 
1108  QMimeData *mimeData = new QMimeData;
1109  mimeData->setData( "text/xml", doc.toByteArray() );
1110  QClipboard *clipboard = QApplication::clipboard();
1111  clipboard->setMimeData( mimeData );
1112 }
1113 
1115 {
1116  if ( !composition() )
1117  {
1118  return;
1119  }
1120 
1121  QDomDocument doc;
1122  QClipboard *clipboard = QApplication::clipboard();
1123  if ( doc.setContent( clipboard->mimeData()->data( "text/xml" ) ) )
1124  {
1125  QDomElement docElem = doc.documentElement();
1126  if ( docElem.tagName() == "ComposerItemClipboard" )
1127  {
1128  if ( composition() )
1129  {
1130  QPointF pt;
1132  {
1133  // place items at cursor position
1134  pt = mapToScene( mapFromGlobal( QCursor::pos() ) );
1135  }
1136  else
1137  {
1138  // place items in center of viewport
1139  pt = mapToScene( viewport()->rect().center() );
1140  }
1141  bool pasteInPlace = ( mode == PasteModeInPlace );
1142  composition()->addItemsFromXML( docElem, doc, 0, true, &pt, pasteInPlace );
1143  }
1144  }
1145  }
1146 
1147  //switch back to select tool so that pasted items can be moved/resized (#8958)
1149 }
1150 
1152 {
1153  if ( !composition() )
1154  {
1155  return;
1156  }
1157 
1158  QList<QgsComposerItem*> composerItemList = composition()->selectedComposerItems();
1159  QList<QgsComposerItem*>::iterator itemIt = composerItemList.begin();
1160 
1161  //delete selected items
1162  for ( ; itemIt != composerItemList.end(); ++itemIt )
1163  {
1164  if ( composition() )
1165  {
1166  composition()->removeComposerItem( *itemIt );
1167  }
1168  }
1169 }
1170 
1172 {
1173  if ( !composition() )
1174  {
1175  return;
1176  }
1177 
1178  //select all items in composer
1179  QList<QGraphicsItem *> itemList = composition()->items();
1180  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1181  for ( ; itemIt != itemList.end(); ++itemIt )
1182  {
1183  QgsComposerItem* mypItem = dynamic_cast<QgsComposerItem *>( *itemIt );
1184  QgsPaperItem* paperItem = dynamic_cast<QgsPaperItem*>( *itemIt );
1185  if ( mypItem && !paperItem )
1186  {
1187  if ( !mypItem->positionLock() )
1188  {
1189  mypItem->setSelected( true );
1190  }
1191  else
1192  {
1193  //deselect all locked items
1194  mypItem->setSelected( false );
1195  }
1196  emit selectedItemChanged( mypItem );
1197  }
1198  }
1199 }
1200 
1202 {
1203  if ( !composition() )
1204  {
1205  return;
1206  }
1207 
1208  composition()->clearSelection();
1209 }
1210 
1212 {
1213  if ( !composition() )
1214  {
1215  return;
1216  }
1217 
1218  //check all items in composer
1219  QList<QGraphicsItem *> itemList = composition()->items();
1220  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1221  for ( ; itemIt != itemList.end(); ++itemIt )
1222  {
1223  QgsComposerItem* mypItem = dynamic_cast<QgsComposerItem *>( *itemIt );
1224  QgsPaperItem* paperItem = dynamic_cast<QgsPaperItem*>( *itemIt );
1225  if ( mypItem && !paperItem )
1226  {
1227  //flip selected state for items (and deselect any locked items)
1228  if ( mypItem->selected() || mypItem->positionLock() )
1229  {
1230 
1231  mypItem->setSelected( false );
1232  }
1233  else
1234  {
1235  mypItem->setSelected( true );
1236  emit selectedItemChanged( mypItem );
1237  }
1238  }
1239  }
1240 }
1241 
1242 void QgsComposerView::keyPressEvent( QKeyEvent * e )
1243 {
1244  if ( !composition() )
1245  {
1246  return;
1247  }
1248 
1250  composition()->selectionHandles()->isDragging() || composition()->selectionHandles()->isResizing() )
1251  {
1252  return;
1253  }
1254 
1256  {
1257  //temporary keyboard based zoom is active
1258  if ( e->isAutoRepeat() )
1259  {
1260  return;
1261  }
1262 
1263  //respond to changes in ctrl key status
1264  if ( !( e->modifiers() & Qt::ControlModifier ) && !mMarqueeZoom )
1265  {
1266  //space pressed, but control key was released, end of temporary zoom tool
1269  }
1270  else if ( !( e->modifiers() & Qt::ControlModifier ) && mMarqueeZoom )
1271  {
1272  //control key released, but user is mid-way through a marquee zoom
1273  //so end temporary zoom when user releases the mouse button
1275  }
1276  else
1277  {
1278  //both control and space pressed
1279  //set cursor to zoom in/out depending on shift key status
1280  QPixmap myZoomQPixmap = QPixmap(( const char ** )( e->modifiers() & Qt::ShiftModifier ? zoom_out : zoom_in ) );
1281  QCursor zoomCursor = QCursor( myZoomQPixmap, 7, 7 );
1282  viewport()->setCursor( zoomCursor );
1283  }
1284  return;
1285  }
1286 
1288  {
1289  //disable keystrokes while drawing a box
1290  return;
1291  }
1292 
1293  if ( e->key() == Qt::Key_Space && ! e->isAutoRepeat() )
1294  {
1295  if ( !( e->modifiers() & Qt::ControlModifier ) )
1296  {
1297  // Pan composer with space bar
1298  mKeyPanning = true;
1300  if ( composition() )
1301  {
1302  //prevent cursor changes while panning
1304  }
1305  viewport()->setCursor( Qt::ClosedHandCursor );
1306  return;
1307  }
1308  else
1309  {
1310  //ctrl+space pressed, so switch to temporary keyboard based zoom tool
1313  setCurrentTool( Zoom );
1314  //set cursor to zoom in/out depending on shift key status
1315  QPixmap myZoomQPixmap = QPixmap(( const char ** )( e->modifiers() & Qt::ShiftModifier ? zoom_out : zoom_in ) );
1316  QCursor zoomCursor = QCursor( myZoomQPixmap, 7, 7 );
1317  viewport()->setCursor( zoomCursor );
1318  return;
1319  }
1320  }
1321 
1323  {
1324  //using the zoom tool, respond to changes in shift key status and update mouse cursor accordingly
1325  if ( ! e->isAutoRepeat() )
1326  {
1327  QPixmap myZoomQPixmap = QPixmap(( const char ** )( e->modifiers() & Qt::ShiftModifier ? zoom_out : zoom_in ) );
1328  QCursor zoomCursor = QCursor( myZoomQPixmap, 7, 7 );
1329  viewport()->setCursor( zoomCursor );
1330  }
1331  return;
1332  }
1333 
1334  QList<QgsComposerItem*> composerItemList = composition()->selectedComposerItems();
1335  QList<QgsComposerItem*>::iterator itemIt = composerItemList.begin();
1336 
1337  // increment used for cursor key item movement
1338  double increment = 1.0;
1339  if ( e->modifiers() & Qt::ShiftModifier )
1340  {
1341  //holding shift while pressing cursor keys results in a big step
1342  increment = 10.0;
1343  }
1344 
1345  if ( e->key() == Qt::Key_Left )
1346  {
1347  for ( ; itemIt != composerItemList.end(); ++itemIt )
1348  {
1349  ( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
1350  ( *itemIt )->move( -1 * increment, 0.0 );
1351  ( *itemIt )->endCommand();
1352  }
1353  }
1354  else if ( e->key() == Qt::Key_Right )
1355  {
1356  for ( ; itemIt != composerItemList.end(); ++itemIt )
1357  {
1358  ( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
1359  ( *itemIt )->move( increment, 0.0 );
1360  ( *itemIt )->endCommand();
1361  }
1362  }
1363  else if ( e->key() == Qt::Key_Down )
1364  {
1365  for ( ; itemIt != composerItemList.end(); ++itemIt )
1366  {
1367  ( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
1368  ( *itemIt )->move( 0.0, increment );
1369  ( *itemIt )->endCommand();
1370  }
1371  }
1372  else if ( e->key() == Qt::Key_Up )
1373  {
1374  for ( ; itemIt != composerItemList.end(); ++itemIt )
1375  {
1376  ( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
1377  ( *itemIt )->move( 0.0, -1 * increment );
1378  ( *itemIt )->endCommand();
1379  }
1380  }
1381 }
1382 
1384 {
1385  if ( e->key() == Qt::Key_Space && !e->isAutoRepeat() && mKeyPanning )
1386  {
1387  //end of panning with space key
1388  mKeyPanning = false;
1389 
1390  //reset cursor
1391  if ( mCurrentTool != Pan )
1392  {
1393  if ( composition() )
1394  {
1395  //allow cursor changes again
1396  composition()->setPreventCursorChange( false );
1397  }
1398  }
1399  viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
1400  return;
1401  }
1402  else if ( e->key() == Qt::Key_Space && !e->isAutoRepeat() && mTemporaryZoomStatus != QgsComposerView::Inactive )
1403  {
1404  //temporary keyboard-based zoom tool is active and space key has been released
1405  if ( mMarqueeZoom )
1406  {
1407  //currently in the middle of a marquee operation, so don't switch tool back immediately
1408  //instead, wait until mouse button has been released before switching tool back
1410  }
1411  else
1412  {
1413  //switch tool back
1416  }
1417  }
1418  else if ( mCurrentTool == QgsComposerView::Zoom )
1419  {
1420  //if zoom tool is active, respond to changes in the shift key status and update cursor accordingly
1421  if ( ! e->isAutoRepeat() )
1422  {
1423  QPixmap myZoomQPixmap = QPixmap(( const char ** )( e->modifiers() & Qt::ShiftModifier ? zoom_out : zoom_in ) );
1424  QCursor zoomCursor = QCursor( myZoomQPixmap, 7, 7 );
1425  viewport()->setCursor( zoomCursor );
1426  }
1427  return;
1428  }
1429 }
1430 
1431 void QgsComposerView::wheelEvent( QWheelEvent* event )
1432 {
1434  {
1435  //ignore wheel events while marquee operations are active (eg, creating new item)
1436  return;
1437  }
1438 
1439  if ( composition()->selectionHandles()->isDragging() || composition()->selectionHandles()->isResizing() )
1440  {
1441  //ignore wheel events while dragging/resizing items
1442  return;
1443  }
1444 
1445  if ( currentTool() == MoveItemContent )
1446  {
1447  //move item content tool, so scroll events get handled by the selected composer item
1448 
1449  QPointF scenePoint = mapToScene( event->pos() );
1450  //select topmost item at position of event
1451  QgsComposerItem* theItem = composition()->composerItemAt( scenePoint );
1452  if ( theItem )
1453  {
1454  if ( theItem->isSelected() )
1455  {
1456  QPointF itemPoint = theItem->mapFromScene( scenePoint );
1457  theItem->beginCommand( tr( "Zoom item content" ) );
1458  theItem->zoomContent( event->delta(), itemPoint.x(), itemPoint.y() );
1459  theItem->endCommand();
1460  }
1461  }
1462  }
1463  else
1464  {
1465  //not using move item content tool, so zoom whole composition
1466  wheelZoom( event );
1467  }
1468 }
1469 
1470 void QgsComposerView::wheelZoom( QWheelEvent * event )
1471 {
1472  //get mouse wheel zoom behaviour settings
1473  QSettings mySettings;
1474  int wheelAction = mySettings.value( "/qgis/wheel_action", 2 ).toInt();
1475  double zoomFactor = mySettings.value( "/qgis/zoom_factor", 2 ).toDouble();
1476 
1478  {
1479  return;
1480  }
1481 
1482  if ( event->modifiers() & Qt::ControlModifier )
1483  {
1484  //holding ctrl while wheel zooming results in a finer zoom
1485  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 10.0;
1486  }
1487 
1488  //caculate zoom scale factor
1489  bool zoomIn = event->delta() > 0;
1490  double scaleFactor = ( zoomIn ? 1 / zoomFactor : zoomFactor );
1491 
1492  //get current visible part of scene
1493  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
1494  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
1495 
1496  //transform the mouse pos to scene coordinates
1497  QPointF scenePoint = mapToScene( event->pos() );
1498 
1499  //adjust view center according to wheel action setting
1500  switch (( QgsMapCanvas::WheelAction )wheelAction )
1501  {
1503  {
1504  centerOn( scenePoint.x(), scenePoint.y() );
1505  break;
1506  }
1507 
1509  {
1510  QgsPoint oldCenter( visibleRect.center() );
1511  QgsPoint newCenter( scenePoint.x() + (( oldCenter.x() - scenePoint.x() ) * scaleFactor ),
1512  scenePoint.y() + (( oldCenter.y() - scenePoint.y() ) * scaleFactor ) );
1513  centerOn( newCenter.x(), newCenter.y() );
1514  break;
1515  }
1516 
1517  default:
1518  break;
1519  }
1520 
1521  //zoom composition
1522  if ( zoomIn )
1523  {
1524  scale( zoomFactor, zoomFactor );
1525  }
1526  else
1527  {
1528  scale( 1 / zoomFactor, 1 / zoomFactor );
1529  }
1530 
1531  //update composition for new zoom
1532  emit zoomLevelChanged();
1533  updateRulers();
1534  update();
1535  //redraw cached map items
1536  QList<QGraphicsItem *> itemList = composition()->items();
1537  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1538  for ( ; itemIt != itemList.end(); ++itemIt )
1539  {
1540  QgsComposerMap* mypItem = dynamic_cast<QgsComposerMap *>( *itemIt );
1541  if (( mypItem ) && ( mypItem->previewMode() == QgsComposerMap::Render ) )
1542  {
1543  mypItem->updateCachedImage();
1544  }
1545  }
1546 }
1547 
1548 void QgsComposerView::setZoomLevel( double zoomLevel )
1549 {
1550  double dpi = QgsApplication::desktop()->logicalDpiX();
1551  //monitor dpi is not always correct - so make sure the value is sane
1552  if (( dpi < 60 ) || ( dpi > 250 ) )
1553  dpi = 72;
1554 
1555  //desired pixel width for 1mm on screen
1556  double scale = zoomLevel * dpi / 25.4;
1557  setTransform( QTransform::fromScale( scale , scale ) );
1558 
1559  updateRulers();
1560  update();
1561  emit zoomLevelChanged();
1562 }
1563 
1565 {
1566  if ( !mPreviewEffect )
1567  {
1568  return;
1569  }
1570 
1571  mPreviewEffect->setEnabled( enabled );
1572 }
1573 
1575 {
1576  if ( !mPreviewEffect )
1577  {
1578  return;
1579  }
1580 
1581  mPreviewEffect->setMode( mode );
1582 }
1583 
1584 void QgsComposerView::paintEvent( QPaintEvent* event )
1585 {
1586  if ( mPaintingEnabled )
1587  {
1588  QGraphicsView::paintEvent( event );
1589  event->accept();
1590  }
1591  else
1592  {
1593  event->ignore();
1594  }
1595 }
1596 
1597 void QgsComposerView::hideEvent( QHideEvent* e )
1598 {
1599  emit( composerViewHide( this ) );
1600  e->ignore();
1601 }
1602 
1603 void QgsComposerView::showEvent( QShowEvent* e )
1604 {
1605  emit( composerViewShow( this ) );
1606  e->ignore();
1607 }
1608 
1609 void QgsComposerView::resizeEvent( QResizeEvent* event )
1610 {
1611  QGraphicsView::resizeEvent( event );
1612  emit zoomLevelChanged();
1613  updateRulers();
1614 }
1615 
1617 {
1618  QGraphicsView::scrollContentsBy( dx, dy );
1619  updateRulers();
1620 }
1621 
1623 {
1624  setScene( c );
1625  if ( mHorizontalRuler )
1626  {
1628  }
1629  if ( mVerticalRuler )
1630  {
1632  }
1633 
1634  //emit compositionSet, so that composer windows can update for the new composition
1635  emit compositionSet( c );
1636 }
1637 
1639 {
1640  if ( scene() )
1641  {
1642  QgsComposition* c = dynamic_cast<QgsComposition *>( scene() );
1643  if ( c )
1644  {
1645  return c;
1646  }
1647  }
1648  return 0;
1649 }
1650 
1652 {
1653  if ( !composition() )
1654  {
1655  return;
1656  }
1657 
1658  QList<QgsComposerItem*> selectionList = composition()->selectedComposerItems();
1659  if ( selectionList.size() < 2 )
1660  {
1661  return; //not enough items for a group
1662  }
1664 
1665  QList<QgsComposerItem*>::iterator itemIter = selectionList.begin();
1666  for ( ; itemIter != selectionList.end(); ++itemIter )
1667  {
1668  itemGroup->addItem( *itemIter );
1669  }
1670 
1671  composition()->addItem( itemGroup );
1672  itemGroup->setSelected( true );
1673  emit selectedItemChanged( itemGroup );
1674 }
1675 
1677 {
1678  if ( !composition() )
1679  {
1680  return;
1681  }
1682 
1683  QList<QgsComposerItem*> selectionList = composition()->selectedComposerItems();
1684  QList<QgsComposerItem*>::iterator itemIter = selectionList.begin();
1685  for ( ; itemIter != selectionList.end(); ++itemIter )
1686  {
1687  QgsComposerItemGroup* itemGroup = dynamic_cast<QgsComposerItemGroup *>( *itemIter );
1688  if ( itemGroup )
1689  {
1690  itemGroup->removeItems();
1691  composition()->removeItem( *itemIter );
1692  delete( *itemIter );
1693  emit itemRemoved( *itemIter );
1694  }
1695  }
1696 }
1697 
1699 {
1700  QMainWindow* composerObject = 0;
1701  QObject* currentObject = parent();
1702  if ( !currentObject )
1703  {
1704  return qobject_cast<QMainWindow *>( currentObject );
1705  }
1706 
1707  while ( true )
1708  {
1709  composerObject = qobject_cast<QMainWindow*>( currentObject );
1710  if ( composerObject || currentObject->parent() == 0 )
1711  {
1712  return composerObject;
1713  }
1714  currentObject = currentObject->parent();
1715  }
1716 
1717  return 0;
1718 }
void mouseDoubleClickEvent(QMouseEvent *e)
bool positionLock() const
Returns position lock for mouse drags (true means locked)
void setShapeType(QgsComposerShape::Shape s)
Item representing the paper.
Definition: qgspaperitem.h:40
A scale bar item that can be added to a map composition.
QUndoStack * undoStack()
Returns pointer to undo/redo command storage.
QPointF mMoveContentStartPos
Start position of content move.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
QRectF toRectF() const
returns a QRectF with same coordinates.
QMainWindow * composerWindow()
Returns the composer main window.
QgsComposerRuler * mVerticalRuler
An item that draws an arrow between to points.
const char * zoom_in[]
Bitmap cursors for map operations.
Definition: qgscursors.cpp:21
void wheelZoom(QWheelEvent *event)
Zoom composition from a mouse wheel event.
QPoint mMousePressStartPos
bool mToolPanning
True if user is currently panning by clicking and dragging with the pan tool.
void zoomLevelChanged()
Is emitted when the view zoom changes.
void selectAll()
Selects all items.
void mouseReleaseEvent(QMouseEvent *)
void removeItems()
Removes the items but does not delete them.
void setOffset(double xOffset, double yOffset)
Sets offset values to shift image (useful for live updates when moving item content) ...
QgsComposerView::Tool mCurrentTool
Current composer tool.
virtual bool selected() const
Is selected.
void selectInvert()
Inverts current selection.
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.
void applyDefaultSize(ScaleBarUnits u=Meters)
Apply default size (scale bar 1/5 of map item width)
QgsComposerMouseHandles * selectionHandles()
Returns pointer to selection handles.
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 advices composer to create a widget for it (through signal) ...
A item that forms part of a map composition.
void setZoomLevel(double zoomLevel)
Set zoom level, where a zoom level of 1.0 corresponds to 100%.
void updateMarker(const QPointF &pos)
QPointF snapPointToGrid(const QPointF &scenePoint) const
Snaps a scene coordinate point to grid.
void removeComposerItem(QgsComposerItem *item, bool createCommand=true)
Remove item from the graphics scene.
bool mKeyPanning
True if user is currently panning by holding the space key.
A container for grouping several QgsComposerItems.
void deleteSelectedItems()
Deletes selected items.
virtual void setSelected(bool s)
Set selected, selected item should be highlighted.
bool isDragging()
Returns true is user is currently dragging the handles.
void setComposition(QgsComposition *c)
MouseAction
Describes the action (move or resize in different directon) to be done during mouse move...
void updateCachedImage()
Called if map canvas has changed.
void setCurrentTool(QgsComposerView::Tool t)
void groupItems()
Add an item group containing the selected items.
void paintEvent(QPaintEvent *event)
QGraphicsLineItem * mRubberBandLineItem
Rubber band item for arrows.
void updateLegend()
Updates the model and all legend entries.
void beginMultiFrameCommand(QgsComposerMultiFrame *multiFrame, const QString &text)
void selectNone()
Deselects all items.
void composerViewHide(QgsComposerView *)
Emitted before composerview is hidden.
void scrollContentsBy(int dx, int dy)
A graphics effect which can be applied to a widget to simulate various printing and color blindness m...
void compositionSet(QgsComposition *)
Emitted when the composition is set for the view.
A composer class that displays svg files or raster format (jpg, png, ...)
QgsComposerView::Tool mPreviousTool
Previous composer tool.
bool isResizing()
Returns true is user is currently resizing with the handles.
QSet< QgsComposerItem * > items()
QgsComposerItem * composerItemAt(const QPointF &position)
Returns the topmost composer item.
void addComposerShape(QgsComposerShape *shape)
Adds a composer shape to the graphics scene and advices composer to create a widget for it (through s...
virtual void moveContent(double dx, double dy)
Move Content of item.
void updateRubberBand(QPointF &pos)
Redraws the rubber band.
void addShape(Tool currentTool)
Draw a shape on the canvas.
void hideEvent(QHideEvent *e)
const char * zoom_out[]
Definition: qgscursors.cpp:45
void setSceneRect(const QRectF &rectangle)
Adapts mMaximumNumberOfFeatures depending on the rectangle height.
void endMarqueeSelect(QMouseEvent *e)
Finalises a marquee selection.
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 resizeEvent(QResizeEvent *event)
QgsPreviewEffect * mPreviewEffect
void mousePressEvent(QMouseEvent *)
bool mMousePanning
True if user is currently panning by holding the middle mouse button.
void selectedItemChanged(QgsComposerItem *selected)
Is emitted when selected item changed.
void setSceneTransform(const QTransform &transform)
Widget to display the composer items.
QCursor defaultCursorForTool(Tool currentTool)
Returns the default mouse cursor for a tool.
void beginCommand(const QString &commandText, QgsComposerMergeCommand::Context c=QgsComposerMergeCommand::Unknown)
Starts new composer undo command.
QPointF mRubberBandStartPos
Start of rubber band creation.
void setPreviewModeEnabled(bool enabled)
Sets whether a preview effect should be used to alter the view's appearance.
void wheelEvent(QWheelEvent *event)
void endMarqueeZoom(QMouseEvent *e)
Finalises a marquee zoom.
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 geometry.
Definition: qgspoint.h:63
Graphics scene for map printing.
bool mMovingItemContent
True if user is currently dragging with the move item content tool.
Object representing map window.
Frame for html, table, text which can be divided onto several frames.
void addItemsFromXML(const QDomElement &elem, const QDomDocument &doc, QMap< QgsComposerMap *, int > *mapsToRestore=0, bool addUndoCommands=false, QPointF *pos=0, bool pasteInPlace=false)
Add items from XML representation to the graphics scene (for project file reading, pasting items from clipboard)
void setComposerMap(const QgsComposerMap *map)
void ungroupItems()
Ungroups the selected items.
void setPositionLock(bool lock)
Locks / unlocks the item position for mouse drags.
Tool
Current tool.
PreviewMode previewMode() const
QgsComposerItem * mMoveContentItem
Item to move content.
void startMarqueeZoom(QPointF &scenePoint)
Starts a zoom in marquee.
void copyItems(ClipboardMode mode)
Cuts or copies the selected items.
void setPreventCursorChange(bool preventChange)
If true, prevents any mouse cursor changes by the composition or by any composer items Used by QgsCom...
void removeRubberBand()
Removes the rubber band and cleans up.
A table class that displays a vector attribute table.
void setPreviewMode(QgsPreviewEffect::PreviewMode mode)
Sets the preview mode which should be used to modify the view's appearance.
void addItem(QgsComposerItem *item)
Adds an item to the group.
A composer items that draws common shapes (ellipse, triangle, rectangle)
void keyReleaseEvent(QKeyEvent *e)
void keyPressEvent(QKeyEvent *e)
void addFrame(QgsComposerFrame *frame, bool recalcFrameSizes=true)
QgsComposerView(QWidget *parent=0, const char *name=0, Qt::WindowFlags f=0)
void cursorPosChanged(QPointF)
Is emitted when mouse cursor coordinates change.
void setComposition(QgsComposition *c)
Sets the composition for the view.
virtual void setSceneRect(const QRectF &rectangle)
Sets this items bound in scene coordinates such that 1 item size units corresponds to 1 scene size un...
void startMarqueeSelect(QPointF &scenePoint)
Starts a marquee selection.
void setText(const QString &text)
void showEvent(QShowEvent *e)
void pushAddRemoveCommand(QgsComposerItem *item, const QString &text, QgsAddRemoveItemCommand::State state=QgsAddRemoveItemCommand::Added)
Convenience function to create a QgsAddRemoveItemCommand, connect its signals and push it to the undo...
A label that can be placed onto a map composition.
void addComposerPicture(QgsComposerPicture *picture)
Adds picture to the graphics scene and advices composer to create a widget for it (through signal) ...
void addComposerTable(QgsComposerAttributeTable *table)
Adds a composer table to the graphics scene and advices composer to create a widget for it (through s...
bool mMarqueeZoom
True if user is currently zooming by marquee.
QgsComposition * composition()
Returns the composition or 0 in case of error.
const char * cross_hair_cursor[]
Definition: qgscursors.cpp:159
void mouseMoveEvent(QMouseEvent *)
void actionFinished()
Current action (e.g.
QList< QgsComposerItem * > selectedComposerItems()
QgsComposerRuler * mHorizontalRuler
QgsComposerView::ToolStatus mTemporaryZoomStatus
True if user is currently temporarily activating the zoom tool by holding control+space.
A legend that can be placed onto a map composition.
void addComposerLabel(QgsComposerLabel *label)
Adds label to the graphics scene and advices composer to create a widget for it (through signal) ...
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:214
QgsComposerMouseHandles::MouseAction mouseActionForScenePos(const QPointF &sceneCoordPos)
Finds out which mouse move action to choose depending on the scene cursor position.
bool mMarqueeSelect
True if user is currently selecting by marquee.
void addComposerArrow(QgsComposerArrow *arrow)
Adds an arrow item to the graphics scene and advices composer to create a widget for it (through sign...
QgsComposerView::Tool currentTool() const
QGraphicsRectItem * mRubberBandItem
Rubber band item.
void addComposerMap(QgsComposerMap *map, bool setDefaultPreviewStyle=true)
Adds map to the graphics scene and advices composer to create a widget for it (through signal) ...
void addComposerLegend(QgsComposerLegend *legend)
Adds legend to the graphics scene and advices composer to create a widget for it (through signal) ...
void adjustSizeToText()
resizes the widget such that the text fits to the item.
void beginCommand(QgsComposerItem *item, const QString &commandText, QgsComposerMergeCommand::Context c=QgsComposerMergeCommand::Unknown)
Allocates new item command and saves initial state in it.
void composerViewShow(QgsComposerView *)
Emitted before composerview is shown.
#define tr(sourceText)
void scale(double scaleFactor, const QgsPoint *c=0)
Scale the rectangle around its center point.
void itemRemoved(QgsComposerItem *)
Is emitted when a composer item has been removed from the scene.