QGIS API Documentation  2.2.0-Valmiera
 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 : blazek@itc.it
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 
18 #include <QApplication>
19 #include <QMainWindow>
20 #include <QMouseEvent>
21 #include <QKeyEvent>
22 #include <QClipboard>
23 #include <QMimeData>
24 #include <QGridLayout>
25 
26 #include "qgsapplication.h"
27 #include "qgscomposerview.h"
28 #include "qgscomposerarrow.h"
29 #include "qgscomposerframe.h"
30 #include "qgscomposerhtml.h"
31 #include "qgscomposerlabel.h"
32 #include "qgscomposerlegend.h"
33 #include "qgscomposermap.h"
35 #include "qgscomposeritemgroup.h"
36 #include "qgscomposerpicture.h"
37 #include "qgscomposerruler.h"
38 #include "qgscomposerscalebar.h"
39 #include "qgscomposershape.h"
41 #include "qgslogger.h"
43 #include "qgspaperitem.h"
44 #include "qgsmapcanvas.h" //for QgsMapCanvas::WheelAction
45 #include "qgscursors.h"
46 
47 QgsComposerView::QgsComposerView( QWidget* parent, const char* name, Qt::WFlags f )
48  : QGraphicsView( parent )
49  , mRubberBandItem( 0 )
50  , mRubberBandLineItem( 0 )
51  , mMoveContentItem( 0 )
52  , mMarqueeSelect( false )
53  , mMarqueeZoom( false )
54  , mTemporaryZoomStatus( QgsComposerView::Inactive )
55  , mPaintingEnabled( true )
56  , mHorizontalRuler( 0 )
57  , mVerticalRuler( 0 )
58  , mToolPanning( false )
59  , mMousePanning( false )
60  , mKeyPanning( false )
61  , mMovingItemContent( false )
62 {
63  Q_UNUSED( f );
64  Q_UNUSED( name );
65 
66  setResizeAnchor( QGraphicsView::AnchorViewCenter );
67  setMouseTracking( true );
68  viewport()->setMouseTracking( true );
69  setFrameShape( QFrame::NoFrame );
70 }
71 
73 {
74  mCurrentTool = t;
75 
76  //update mouse cursor for current tool
77  if ( !composition() )
78  {
79  return;
80  }
81  switch ( t )
82  {
84  {
85  //lock cursor to prevent composer items changing it
87  viewport()->setCursor( defaultCursorForTool( Pan ) );
88  break;
89  }
91  {
92  //lock cursor to prevent composer items changing it
94  //set the cursor to zoom in
95  viewport()->setCursor( defaultCursorForTool( Zoom ) );
96  break;
97  }
109  {
110  //using a drawing tool
111  //lock cursor to prevent composer items changing it
113  viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
114  break;
115  }
116  default:
117  {
118  //not using pan tool, composer items can change cursor
120  viewport()->setCursor( Qt::ArrowCursor );
121  }
122  }
123 }
124 
125 void QgsComposerView::mousePressEvent( QMouseEvent* e )
126 {
127  if ( !composition() )
128  {
129  return;
130  }
131 
133  {
134  //ignore clicks during certain operations
135  return;
136  }
137 
138  if ( composition()->selectionHandles()->isDragging() || composition()->selectionHandles()->isResizing() )
139  {
140  //ignore clicks while dragging/resizing items
141  return;
142  }
143 
144  QPointF scenePoint = mapToScene( e->pos() );
145  QPointF snappedScenePoint = composition()->snapPointToGrid( scenePoint );
146  mMousePressStartPos = e->pos();
147 
148  //lock/unlock position of item with right click
149  if ( e->button() == Qt::RightButton )
150  {
151  QgsComposerItem* selectedItem = composition()->composerItemAt( scenePoint );
152  if ( selectedItem )
153  {
154  bool lock = selectedItem->positionLock() ? false : true;
155  selectedItem->setPositionLock( lock );
156  selectedItem->update();
157  }
158  return;
159  }
160  else if ( e->button() == Qt::MidButton )
161  {
162  //pan composer with middle button
163  mMousePanning = true;
164  mMouseLastXY = e->pos();
165  if ( composition() )
166  {
167  //lock cursor to closed hand cursor
169  }
170  viewport()->setCursor( Qt::ClosedHandCursor );
171  return;
172  }
173 
174  switch ( mCurrentTool )
175  {
176  //select/deselect items and pass mouse event further
177  case Select:
178  {
179  //check if we are clicking on a selection handle
180  if ( composition()->selectionHandles()->isVisible() )
181  {
182  //selection handles are being shown, get mouse action for current cursor position
184 
186  {
187  //mouse is over a resize handle, so propagate event onward
188  QGraphicsView::mousePressEvent( e );
189  return;
190  }
191  }
192 
193  QgsComposerItem* selectedItem = 0;
194  QgsComposerItem* previousSelectedItem = 0;
195 
196  if ( e->modifiers() & Qt::ControlModifier )
197  {
198  //CTRL modifier, so we are trying to select the next item below the current one
199  //first, find currently selected item
200  QList<QgsComposerItem*> selectedItems = composition()->selectedComposerItems();
201  if ( selectedItems.size() > 0 )
202  {
203  previousSelectedItem = selectedItems.at( 0 );
204  }
205  }
206 
207  if ( previousSelectedItem )
208  {
209  //select highest item just below previously selected item at position of event
210  selectedItem = composition()->composerItemAt( scenePoint, previousSelectedItem );
211 
212  //if we didn't find a lower item we'll use the top-most as fall-back
213  //this duplicates mapinfo/illustrator/etc behaviour where ctrl-clicks are "cyclic"
214  if ( !selectedItem )
215  {
216  selectedItem = composition()->composerItemAt( scenePoint );
217  }
218  }
219  else
220  {
221  //select topmost item at position of event
222  selectedItem = composition()->composerItemAt( scenePoint );
223  }
224 
225  if ( !selectedItem )
226  {
227  //not clicking over an item, so start marquee selection
228  startMarqueeSelect( scenePoint );
229  break;
230  }
231 
232  if (( !selectedItem->selected() ) && //keep selection if an already selected item pressed
233  !( e->modifiers() & Qt::ShiftModifier ) ) //keep selection if shift key pressed
234  {
235  composition()->clearSelection();
236  }
237 
238  if (( e->modifiers() & Qt::ShiftModifier ) && ( selectedItem->selected() ) )
239  {
240  //SHIFT-clicking a selected item deselects it
241  selectedItem->setSelected( false );
242 
243  //Check if we have any remaining selected items, and if so, update the item panel
244  QList<QgsComposerItem*> selectedItems = composition()->selectedComposerItems();
245  if ( selectedItems.size() > 0 )
246  {
247  emit selectedItemChanged( selectedItems.at( 0 ) );
248  }
249  }
250  else
251  {
252  selectedItem->setSelected( true );
253  QGraphicsView::mousePressEvent( e );
254  emit selectedItemChanged( selectedItem );
255  }
256  break;
257  }
258 
259  case Zoom:
260  {
261  if ( !( e->modifiers() & Qt::ShiftModifier ) )
262  {
263  //zoom in action
264  startMarqueeZoom( scenePoint );
265  }
266  else
267  {
268  //zoom out action, so zoom out and recenter on clicked point
269  double scaleFactor = 2;
270  //get current visible part of scene
271  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
272  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
273 
274  //transform the mouse pos to scene coordinates
275  QPointF scenePoint = mapToScene( e->pos() );
276 
277  visibleRect.scale( scaleFactor, scenePoint.x(), scenePoint.y() );
278  QRectF boundsRect = visibleRect.toRectF();
279 
280  //zoom view to fit desired bounds
281  fitInView( boundsRect, Qt::KeepAspectRatio );
282  }
283  break;
284  }
285 
286  case Pan:
287  {
288  //pan action
289  mToolPanning = true;
290  mMouseLastXY = e->pos();
291  viewport()->setCursor( Qt::ClosedHandCursor );
292  break;
293  }
294 
295  case MoveItemContent:
296  {
297  //get a list of items at clicked position
298  QList<QGraphicsItem *> itemsAtCursorPos = items( e->pos() );
299  if ( itemsAtCursorPos.size() == 0 )
300  {
301  //no items at clicked position
302  return;
303  }
304 
305  //find highest QgsComposerItem at clicked position
306  //(other graphics items may be higher, eg selection handles)
307  QList<QGraphicsItem*>::iterator itemIter = itemsAtCursorPos.begin();
308  for ( ; itemIter != itemsAtCursorPos.end(); ++itemIter )
309  {
310  QgsComposerItem* item = dynamic_cast<QgsComposerItem *>(( *itemIter ) );
311  if ( item )
312  {
313  //we've found the highest QgsComposerItem
314  mMoveContentStartPos = scenePoint;
315  mMoveContentItem = item;
316  mMovingItemContent = true;
317  break;
318  }
319  }
320 
321  //no QgsComposerItem at clicked position
322  return;
323  }
324 
325  case AddArrow:
326  {
327  mRubberBandStartPos = QPointF( snappedScenePoint.x(), snappedScenePoint.y() );
328  mRubberBandLineItem = new QGraphicsLineItem( snappedScenePoint.x(), snappedScenePoint.y(), snappedScenePoint.x(), snappedScenePoint.y() );
329  mRubberBandLineItem->setZValue( 1000 );
330  scene()->addItem( mRubberBandLineItem );
331  scene()->update();
332  break;
333  }
334 
335  //create rubber band for map and ellipse items
336  case AddMap:
337  case AddRectangle:
338  case AddTriangle:
339  case AddEllipse:
340  case AddHtml:
341  {
342  QTransform t;
343  mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
344  mRubberBandStartPos = QPointF( snappedScenePoint.x(), snappedScenePoint.y() );
345  t.translate( snappedScenePoint.x(), snappedScenePoint.y() );
346  mRubberBandItem->setTransform( t );
347  mRubberBandItem->setZValue( 1000 );
348  scene()->addItem( mRubberBandItem );
349  scene()->update();
350  }
351  break;
352 
353  case AddLabel:
354  if ( composition() )
355  {
356  QgsComposerLabel* newLabelItem = new QgsComposerLabel( composition() );
357  newLabelItem->setText( tr( "QGIS" ) );
358  newLabelItem->adjustSizeToText();
359  newLabelItem->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), newLabelItem->rect().width(), newLabelItem->rect().height() ) );
360  composition()->addComposerLabel( newLabelItem );
361 
362  composition()->clearSelection();
363  newLabelItem->setSelected( true );
364  emit selectedItemChanged( newLabelItem );
365 
366  emit actionFinished();
367  composition()->pushAddRemoveCommand( newLabelItem, tr( "Label added" ) );
368  }
369  break;
370 
371  case AddScalebar:
372  if ( composition() )
373  {
374  QgsComposerScaleBar* newScaleBar = new QgsComposerScaleBar( composition() );
375  newScaleBar->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), 20, 20 ) );
376  composition()->addComposerScaleBar( newScaleBar );
377  QList<const QgsComposerMap*> mapItemList = composition()->composerMapItems();
378  if ( mapItemList.size() > 0 )
379  {
380  newScaleBar->setComposerMap( mapItemList.at( 0 ) );
381  }
382  newScaleBar->applyDefaultSize(); //4 segments, 1/5 of composer map width
383 
384  composition()->clearSelection();
385  newScaleBar->setSelected( true );
386  emit selectedItemChanged( newScaleBar );
387 
388  emit actionFinished();
389  composition()->pushAddRemoveCommand( newScaleBar, tr( "Scale bar added" ) );
390  }
391  break;
392 
393  case AddLegend:
394  {
395  if ( composition() )
396  {
397  QgsComposerLegend* newLegend = new QgsComposerLegend( composition() );
398  newLegend->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), newLegend->rect().width(), newLegend->rect().height() ) );
399  composition()->addComposerLegend( newLegend );
400  newLegend->updateLegend();
401 
402  composition()->clearSelection();
403  newLegend->setSelected( true );
404  emit selectedItemChanged( newLegend );
405 
406  emit actionFinished();
407  composition()->pushAddRemoveCommand( newLegend, tr( "Legend added" ) );
408  }
409  break;
410  }
411  case AddPicture:
412  if ( composition() )
413  {
414  QgsComposerPicture* newPicture = new QgsComposerPicture( composition() );
415  newPicture->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), 30, 30 ) );
416  composition()->addComposerPicture( newPicture );
417 
418  composition()->clearSelection();
419  newPicture->setSelected( true );
420  emit selectedItemChanged( newPicture );
421 
422  emit actionFinished();
423  composition()->pushAddRemoveCommand( newPicture, tr( "Picture added" ) );
424  }
425  break;
426  case AddTable:
427  if ( composition() )
428  {
430  newTable->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), 50, 50 ) );
431  composition()->addComposerTable( newTable );
432 
433  composition()->clearSelection();
434  newTable->setSelected( true );
435  emit selectedItemChanged( newTable );
436 
437  emit actionFinished();
438  composition()->pushAddRemoveCommand( newTable, tr( "Table added" ) );
439  }
440  break;
441  default:
442  break;
443  }
444 }
445 
447 {
448  switch ( currentTool )
449  {
450  case Select:
451  return Qt::ArrowCursor;
452 
453  case Zoom:
454  {
455  QPixmap myZoomQPixmap = QPixmap(( const char ** )( zoom_in ) );
456  return QCursor( myZoomQPixmap, 7, 7 );
457  }
458 
459  case Pan:
460  return Qt::OpenHandCursor;
461 
462  case MoveItemContent:
463  return Qt::ArrowCursor;
464 
465  case AddArrow:
466  case AddMap:
467  case AddRectangle:
468  case AddTriangle:
469  case AddEllipse:
470  case AddHtml:
471  case AddLabel:
472  case AddScalebar:
473  case AddLegend:
474  case AddPicture:
475  case AddTable:
476  {
477  QPixmap myCrosshairQPixmap = QPixmap(( const char ** )( cross_hair_cursor ) );
478  return QCursor( myCrosshairQPixmap, 8, 8 );
479  }
480  }
481  return Qt::ArrowCursor;
482 }
483 
484 void QgsComposerView::addShape( Tool currentTool )
485 {
487 
488  if ( currentTool == AddRectangle )
490  else if ( currentTool == AddTriangle )
492 
493  if ( !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
494  {
496  return;
497  }
498  if ( composition() )
499  {
500  QgsComposerShape* composerShape = new QgsComposerShape( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height(), composition() );
501  composerShape->setShapeType( shape );
502  //new shapes use symbol v2 by default
503  composerShape->setUseSymbolV2( true );
504  composition()->addComposerShape( composerShape );
506 
507  composition()->clearSelection();
508  composerShape->setSelected( true );
509  emit selectedItemChanged( composerShape );
510 
511  emit actionFinished();
512  composition()->pushAddRemoveCommand( composerShape, tr( "Shape added" ) );
513  }
514 }
515 
517 {
518  if ( mHorizontalRuler )
519  {
520  mHorizontalRuler->setSceneTransform( viewportTransform() );
521  }
522  if ( mVerticalRuler )
523  {
524  mVerticalRuler->setSceneTransform( viewportTransform() );
525  }
526 }
527 
529 {
530  if ( mRubberBandItem )
531  {
532  scene()->removeItem( mRubberBandItem );
533  delete mRubberBandItem;
534  mRubberBandItem = 0;
535  }
536 }
537 
538 void QgsComposerView::startMarqueeSelect( QPointF & scenePoint )
539 {
540  mMarqueeSelect = true;
541 
542  QTransform t;
543  mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
544  mRubberBandItem->setBrush( QBrush( QColor( 225, 50, 70, 25 ) ) );
545  mRubberBandItem->setPen( QPen( Qt::DotLine ) );
546  mRubberBandStartPos = QPointF( scenePoint.x(), scenePoint.y() );
547  t.translate( scenePoint.x(), scenePoint.y() );
548  mRubberBandItem->setTransform( t );
549  mRubberBandItem->setZValue( 1000 );
550  scene()->addItem( mRubberBandItem );
551  scene()->update();
552 }
553 
554 void QgsComposerView::endMarqueeSelect( QMouseEvent* e )
555 {
556  mMarqueeSelect = false;
557 
558  bool subtractingSelection = false;
559  if ( e->modifiers() & Qt::ShiftModifier )
560  {
561  //shift modifer means adding to selection, nothing required here
562  }
563  else if ( e->modifiers() & Qt::ControlModifier )
564  {
565  //control modifier means subtract from current selection
566  subtractingSelection = true;
567  }
568  else
569  {
570  //not adding to or removing from selection, so clear current selection
571  composition()->clearSelection();
572  }
573 
574  if ( !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
575  {
576  //just a click, do nothing
578  return;
579  }
580 
581  QRectF boundsRect = QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(),
582  mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
583 
584  //determine item selection mode, default to intersection
585  Qt::ItemSelectionMode selectionMode = Qt::IntersectsItemShape;
586  if ( e->modifiers() & Qt::AltModifier )
587  {
588  //alt modifier switches to contains selection mode
589  selectionMode = Qt::ContainsItemShape;
590  }
591 
592  //find all items in rubber band
593  QList<QGraphicsItem *> itemList = composition()->items( boundsRect, selectionMode );
594  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
595  for ( ; itemIt != itemList.end(); ++itemIt )
596  {
597  QgsComposerItem* mypItem = dynamic_cast<QgsComposerItem *>( *itemIt );
598  QgsPaperItem* paperItem = dynamic_cast<QgsPaperItem*>( *itemIt );
599  if ( mypItem && !paperItem )
600  {
601  if ( !mypItem->positionLock() )
602  {
603  if ( subtractingSelection )
604  {
605  mypItem->setSelected( false );
606  }
607  else
608  {
609  mypItem->setSelected( true );
610  }
611  }
612  }
613  }
615 
616  //update item panel
617  QList<QgsComposerItem*> selectedItemList = composition()->selectedComposerItems();
618  if ( selectedItemList.size() > 0 )
619  {
620  emit selectedItemChanged( selectedItemList[0] );
621  }
622 }
623 
624 void QgsComposerView::startMarqueeZoom( QPointF & scenePoint )
625 {
626  mMarqueeZoom = true;
627 
628  QTransform t;
629  mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
630  mRubberBandItem->setBrush( QBrush( QColor( 70, 50, 255, 25 ) ) );
631  mRubberBandItem->setPen( QPen( QColor( 70, 50, 255, 100 ) ) );
632  mRubberBandStartPos = QPointF( scenePoint.x(), scenePoint.y() );
633  t.translate( scenePoint.x(), scenePoint.y() );
634  mRubberBandItem->setTransform( t );
635  mRubberBandItem->setZValue( 1000 );
636  scene()->addItem( mRubberBandItem );
637  scene()->update();
638 }
639 
640 void QgsComposerView::endMarqueeZoom( QMouseEvent* e )
641 {
642  mMarqueeZoom = false;
643 
644  QRectF boundsRect;
645 
646  if ( !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
647  {
648  //just a click, so zoom to clicked point and recenter
649  double scaleFactor = 0.5;
650  //get current visible part of scene
651  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
652  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
653 
654  //transform the mouse pos to scene coordinates
655  QPointF scenePoint = mapToScene( e->pos() );
656 
657  visibleRect.scale( scaleFactor, scenePoint.x(), scenePoint.y() );
658  boundsRect = visibleRect.toRectF();
659  }
660  else
661  {
662  //marquee zoom
663  //zoom bounds are size marquee object
664  boundsRect = QRectF( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(),
665  mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
666  }
667 
669  //zoom view to fit desired bounds
670  fitInView( boundsRect, Qt::KeepAspectRatio );
671 
673  {
674  //user was using the temporary keyboard activated zoom tool
675  //and the control or space key was released before mouse button, so end temporary zoom
678  }
679 }
680 
682 {
683  if ( !composition() )
684  {
685  return;
686  }
687 
688  if ( e->button() != Qt::LeftButton &&
690  {
691  //ignore clicks while dragging/resizing items
692  return;
693  }
694 
695  QPoint mousePressStopPoint = e->pos();
696  int diffX = mousePressStopPoint.x() - mMousePressStartPos.x();
697  int diffY = mousePressStopPoint.y() - mMousePressStartPos.y();
698 
699  //was this just a click? or a click and drag?
700  bool clickOnly = false;
701  if ( qAbs( diffX ) < 2 && qAbs( diffY ) < 2 )
702  {
703  clickOnly = true;
704  }
705 
706  QPointF scenePoint = mapToScene( e->pos() );
707 
708  if ( mMousePanning || mToolPanning )
709  {
710  mMousePanning = false;
711  mToolPanning = false;
712 
713  if ( clickOnly && e->button() == Qt::MidButton )
714  {
715  //middle mouse button click = recenter on point
716 
717  //get current visible part of scene
718  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
719  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
720  visibleRect.scale( 1, scenePoint.x(), scenePoint.y() );
721  QRectF boundsRect = visibleRect.toRectF();
722 
723  //zoom view to fit desired bounds
724  fitInView( boundsRect, Qt::KeepAspectRatio );
725  }
726 
727  //set new cursor
728  if ( mCurrentTool != Pan )
729  {
730  if ( composition() )
731  {
732  //allow composer items to change cursor
734  }
735  }
736  viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
737  }
738 
739  //for every other tool, ignore clicks of non-left button
740  if ( e->button() != Qt::LeftButton )
741  {
742  return;
743  }
744 
745  if ( mMarqueeSelect )
746  {
747  endMarqueeSelect( e );
748  return;
749  }
750 
751  switch ( mCurrentTool )
752  {
753  case Select:
754  {
755  QGraphicsView::mouseReleaseEvent( e );
756  break;
757  }
758 
759  case Zoom:
760  {
761  if ( mMarqueeZoom )
762  {
763  endMarqueeZoom( e );
764  }
765  break;
766  }
767 
768  case MoveItemContent:
769  {
770  if ( mMoveContentItem )
771  {
772  //update map preview if composer map
773  QgsComposerMap* composerMap = dynamic_cast<QgsComposerMap *>( mMoveContentItem );
774  if ( composerMap )
775  {
776  composerMap->setOffset( 0, 0 );
777  }
778 
779  double moveX = scenePoint.x() - mMoveContentStartPos.x();
780  double moveY = scenePoint.y() - mMoveContentStartPos.y();
781 
782  composition()->beginCommand( mMoveContentItem, tr( "Move item content" ) );
783  mMoveContentItem->moveContent( -moveX, -moveY );
784  composition()->endCommand();
785  mMoveContentItem = 0;
786  mMovingItemContent = false;
787  }
788  break;
789  }
790  case AddArrow:
791  if ( composition() )
792  {
793  QPointF scenePoint = mapToScene( e->pos() );
794  QPointF snappedScenePoint = composition()->snapPointToGrid( scenePoint );
795  QgsComposerArrow* composerArrow = new QgsComposerArrow( mRubberBandStartPos, QPointF( snappedScenePoint.x(), snappedScenePoint.y() ), composition() );
796  composition()->addComposerArrow( composerArrow );
797 
798  composition()->clearSelection();
799  composerArrow->setSelected( true );
800  emit selectedItemChanged( composerArrow );
801 
802  scene()->removeItem( mRubberBandLineItem );
803  delete mRubberBandLineItem;
805  emit actionFinished();
806  composition()->pushAddRemoveCommand( composerArrow, tr( "Arrow added" ) );
807  }
808  break;
809 
810  case AddRectangle:
811  case AddTriangle:
812  case AddEllipse:
814  break;
815 
816  case AddMap:
817  if ( !mRubberBandItem || ( mRubberBandItem->rect().width() < 0.1 && mRubberBandItem->rect().height() < 0.1 ) )
818  {
820  return;
821  }
822  if ( composition() )
823  {
824  QgsComposerMap* composerMap = new QgsComposerMap( composition(), mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
825  composition()->addComposerMap( composerMap );
826 
827  composition()->clearSelection();
828  composerMap->setSelected( true );
829  emit selectedItemChanged( composerMap );
830 
832  emit actionFinished();
833  composition()->pushAddRemoveCommand( composerMap, tr( "Map added" ) );
834  }
835  break;
836 
837  case AddHtml:
838  if ( composition() )
839  {
840  QgsComposerHtml* composerHtml = new QgsComposerHtml( composition(), true );
842  composerHtml, composition(), tr( "Html item added" ) );
843  composition()->undoStack()->push( command );
844  QgsComposerFrame* frame = new QgsComposerFrame( composition(), composerHtml, mRubberBandItem->transform().dx(),
845  mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(),
846  mRubberBandItem->rect().height() );
847  composition()->beginMultiFrameCommand( composerHtml, tr( "Html frame added" ) );
848  composerHtml->addFrame( frame );
850 
851  composition()->clearSelection();
852  frame->setSelected( true );
853  emit selectedItemChanged( frame );
854 
856  emit actionFinished();
857  }
858  default:
859  break;
860  }
861 }
862 
863 void QgsComposerView::mouseMoveEvent( QMouseEvent* e )
864 {
865  if ( !composition() )
866  {
867  return;
868  }
869 
870  mMouseCurrentXY = e->pos();
871  //update cursor position in composer status bar
872  emit cursorPosChanged( mapToScene( e->pos() ) );
873 
874  updateRulers();
875  if ( mHorizontalRuler )
876  {
877  mHorizontalRuler->updateMarker( e->posF() );
878  }
879  if ( mVerticalRuler )
880  {
881  mVerticalRuler->updateMarker( e->posF() );
882  }
883 
885  {
886  //panning, so scroll view
887  horizontalScrollBar()->setValue( horizontalScrollBar()->value() - ( e->x() - mMouseLastXY.x() ) );
888  verticalScrollBar()->setValue( verticalScrollBar()->value() - ( e->y() - mMouseLastXY.y() ) );
889  mMouseLastXY = e->pos();
890  return;
891  }
892  else if ( e->buttons() == Qt::NoButton )
893  {
894  if ( mCurrentTool == Select )
895  {
896  QGraphicsView::mouseMoveEvent( e );
897  }
898  }
899  else
900  {
901  QPointF scenePoint = mapToScene( e->pos() );
902 
903  if ( mMarqueeSelect || mMarqueeZoom )
904  {
905  updateRubberBand( scenePoint );
906  return;
907  }
908 
909  switch ( mCurrentTool )
910  {
911  case Select:
912  QGraphicsView::mouseMoveEvent( e );
913  break;
914 
915  case AddArrow:
916  {
917  if ( mRubberBandLineItem )
918  {
919  mRubberBandLineItem->setLine( mRubberBandStartPos.x(), mRubberBandStartPos.y(), scenePoint.x(), scenePoint.y() );
920  }
921  break;
922  }
923 
924  case AddMap:
925  case AddRectangle:
926  case AddTriangle:
927  case AddEllipse:
928  case AddHtml:
929  //adjust rubber band item
930  {
931  updateRubberBand( scenePoint );
932  break;
933  }
934 
935  case MoveItemContent:
936  {
937  //update map preview if composer map
938  QgsComposerMap* composerMap = dynamic_cast<QgsComposerMap *>( mMoveContentItem );
939  if ( composerMap )
940  {
941  composerMap->setOffset( scenePoint.x() - mMoveContentStartPos.x(), scenePoint.y() - mMoveContentStartPos.y() );
942  composerMap->update();
943  }
944  break;
945  }
946  default:
947  break;
948  }
949  }
950 }
951 
953 {
954  double x = 0;
955  double y = 0;
956  double width = 0;
957  double height = 0;
958 
959  double dx = pos.x() - mRubberBandStartPos.x();
960  double dy = pos.y() - mRubberBandStartPos.y();
961 
962  if ( dx < 0 )
963  {
964  x = pos.x();
965  width = -dx;
966  }
967  else
968  {
969  x = mRubberBandStartPos.x();
970  width = dx;
971  }
972 
973  if ( dy < 0 )
974  {
975  y = pos.y();
976  height = -dy;
977  }
978  else
979  {
980  y = mRubberBandStartPos.y();
981  height = dy;
982  }
983 
984  if ( mRubberBandItem )
985  {
986  mRubberBandItem->setRect( 0, 0, width, height );
987  QTransform t;
988  t.translate( x, y );
989  mRubberBandItem->setTransform( t );
990  }
991 }
992 
994 {
995  e->ignore();
996 }
997 
999 {
1000  if ( !composition() )
1001  {
1002  return;
1003  }
1004 
1005  QList<QgsComposerItem*> composerItemList = composition()->selectedComposerItems();
1006  QList<QgsComposerItem*>::iterator itemIt = composerItemList.begin();
1007 
1008  QDomDocument doc;
1009  QDomElement documentElement = doc.createElement( "ComposerItemClipboard" );
1010  for ( ; itemIt != composerItemList.end(); ++itemIt )
1011  {
1012  // copy each item in a group
1013  QgsComposerItemGroup* itemGroup = dynamic_cast<QgsComposerItemGroup*>( *itemIt );
1014  if ( itemGroup && composition() )
1015  {
1016  QSet<QgsComposerItem*> groupedItems = itemGroup->items();
1017  QSet<QgsComposerItem*>::iterator it = groupedItems.begin();
1018  for ( ; it != groupedItems.end(); ++it )
1019  {
1020  ( *it )->writeXML( documentElement, doc );
1021  }
1022  }
1023  ( *itemIt )->writeXML( documentElement, doc );
1024  if ( mode == ClipboardModeCut )
1025  {
1026  composition()->removeComposerItem( *itemIt );
1027  }
1028  }
1029  doc.appendChild( documentElement );
1030 
1031  //if it's a copy, we have to remove the UUIDs since we don't want any duplicate UUID
1032  if ( mode == ClipboardModeCopy )
1033  {
1034  // remove all uuid attributes
1035  QDomNodeList composerItemsNodes = doc.elementsByTagName( "ComposerItem" );
1036  for ( int i = 0; i < composerItemsNodes.count(); ++i )
1037  {
1038  QDomNode composerItemNode = composerItemsNodes.at( i );
1039  if ( composerItemNode.isElement() )
1040  {
1041  composerItemNode.toElement().removeAttribute( "uuid" );
1042  }
1043  }
1044  }
1045 
1046  QMimeData *mimeData = new QMimeData;
1047  mimeData->setData( "text/xml", doc.toByteArray() );
1048  QClipboard *clipboard = QApplication::clipboard();
1049  clipboard->setMimeData( mimeData );
1050 }
1051 
1053 {
1054  if ( !composition() )
1055  {
1056  return;
1057  }
1058 
1059  QDomDocument doc;
1060  QClipboard *clipboard = QApplication::clipboard();
1061  if ( doc.setContent( clipboard->mimeData()->data( "text/xml" ) ) )
1062  {
1063  QDomElement docElem = doc.documentElement();
1064  if ( docElem.tagName() == "ComposerItemClipboard" )
1065  {
1066  if ( composition() )
1067  {
1068  QPointF pt;
1070  {
1071  // place items at cursor position
1072  pt = mapToScene( mapFromGlobal( QCursor::pos() ) );
1073  }
1074  else
1075  {
1076  // place items in center of viewport
1077  pt = mapToScene( viewport()->rect().center() );
1078  }
1079  bool pasteInPlace = ( mode == PasteModeInPlace );
1080  composition()->addItemsFromXML( docElem, doc, 0, true, &pt, pasteInPlace );
1081  }
1082  }
1083  }
1084 
1085  //switch back to select tool so that pasted items can be moved/resized (#8958)
1087 }
1088 
1090 {
1091  if ( !composition() )
1092  {
1093  return;
1094  }
1095 
1096  QList<QgsComposerItem*> composerItemList = composition()->selectedComposerItems();
1097  QList<QgsComposerItem*>::iterator itemIt = composerItemList.begin();
1098 
1099  //delete selected items
1100  for ( ; itemIt != composerItemList.end(); ++itemIt )
1101  {
1102  if ( composition() )
1103  {
1104  composition()->removeComposerItem( *itemIt );
1105  }
1106  }
1107 }
1108 
1110 {
1111  if ( !composition() )
1112  {
1113  return;
1114  }
1115 
1116  //select all items in composer
1117  QList<QGraphicsItem *> itemList = composition()->items();
1118  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1119  for ( ; itemIt != itemList.end(); ++itemIt )
1120  {
1121  QgsComposerItem* mypItem = dynamic_cast<QgsComposerItem *>( *itemIt );
1122  QgsPaperItem* paperItem = dynamic_cast<QgsPaperItem*>( *itemIt );
1123  if ( mypItem && !paperItem )
1124  {
1125  if ( !mypItem->positionLock() )
1126  {
1127  mypItem->setSelected( true );
1128  }
1129  else
1130  {
1131  //deselect all locked items
1132  mypItem->setSelected( false );
1133  }
1134  emit selectedItemChanged( mypItem );
1135  }
1136  }
1137 }
1138 
1140 {
1141  if ( !composition() )
1142  {
1143  return;
1144  }
1145 
1146  composition()->clearSelection();
1147 }
1148 
1150 {
1151  if ( !composition() )
1152  {
1153  return;
1154  }
1155 
1156  //check all items in composer
1157  QList<QGraphicsItem *> itemList = composition()->items();
1158  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1159  for ( ; itemIt != itemList.end(); ++itemIt )
1160  {
1161  QgsComposerItem* mypItem = dynamic_cast<QgsComposerItem *>( *itemIt );
1162  QgsPaperItem* paperItem = dynamic_cast<QgsPaperItem*>( *itemIt );
1163  if ( mypItem && !paperItem )
1164  {
1165  //flip selected state for items (and deselect any locked items)
1166  if ( mypItem->selected() || mypItem->positionLock() )
1167  {
1168 
1169  mypItem->setSelected( false );
1170  }
1171  else
1172  {
1173  mypItem->setSelected( true );
1174  emit selectedItemChanged( mypItem );
1175  }
1176  }
1177  }
1178 }
1179 
1180 void QgsComposerView::keyPressEvent( QKeyEvent * e )
1181 {
1182  if ( !composition() )
1183  {
1184  return;
1185  }
1186 
1188  composition()->selectionHandles()->isDragging() || composition()->selectionHandles()->isResizing() )
1189  {
1190  return;
1191  }
1192 
1194  {
1195  //temporary keyboard based zoom is active
1196  if ( e->isAutoRepeat() )
1197  {
1198  return;
1199  }
1200 
1201  //respond to changes in ctrl key status
1202  if ( !( e->modifiers() & Qt::ControlModifier ) && !mMarqueeZoom )
1203  {
1204  //space pressed, but control key was released, end of temporary zoom tool
1207  }
1208  else if ( !( e->modifiers() & Qt::ControlModifier ) && mMarqueeZoom )
1209  {
1210  //control key released, but user is mid-way through a marquee zoom
1211  //so end temporary zoom when user releases the mouse button
1213  }
1214  else
1215  {
1216  //both control and space pressed
1217  //set cursor to zoom in/out depending on shift key status
1218  QPixmap myZoomQPixmap = QPixmap(( const char ** )( e->modifiers() & Qt::ShiftModifier ? zoom_out : zoom_in ) );
1219  QCursor zoomCursor = QCursor( myZoomQPixmap, 7, 7 );
1220  viewport()->setCursor( zoomCursor );
1221  }
1222  return;
1223  }
1224 
1226  {
1227  //disable keystrokes while drawing a box
1228  return;
1229  }
1230 
1231  if ( e->key() == Qt::Key_Space && ! e->isAutoRepeat() )
1232  {
1233  if ( !( e->modifiers() & Qt::ControlModifier ) )
1234  {
1235  // Pan composer with space bar
1236  mKeyPanning = true;
1238  if ( composition() )
1239  {
1240  //prevent cursor changes while panning
1242  }
1243  viewport()->setCursor( Qt::ClosedHandCursor );
1244  return;
1245  }
1246  else
1247  {
1248  //ctrl+space pressed, so switch to temporary keyboard based zoom tool
1251  setCurrentTool( Zoom );
1252  //set cursor to zoom in/out depending on shift key status
1253  QPixmap myZoomQPixmap = QPixmap(( const char ** )( e->modifiers() & Qt::ShiftModifier ? zoom_out : zoom_in ) );
1254  QCursor zoomCursor = QCursor( myZoomQPixmap, 7, 7 );
1255  viewport()->setCursor( zoomCursor );
1256  return;
1257  }
1258  }
1259 
1261  {
1262  //using the zoom tool, respond to changes in shift key status and update mouse cursor accordingly
1263  if ( ! e->isAutoRepeat() )
1264  {
1265  QPixmap myZoomQPixmap = QPixmap(( const char ** )( e->modifiers() & Qt::ShiftModifier ? zoom_out : zoom_in ) );
1266  QCursor zoomCursor = QCursor( myZoomQPixmap, 7, 7 );
1267  viewport()->setCursor( zoomCursor );
1268  }
1269  return;
1270  }
1271 
1272  QList<QgsComposerItem*> composerItemList = composition()->selectedComposerItems();
1273  QList<QgsComposerItem*>::iterator itemIt = composerItemList.begin();
1274 
1275  // increment used for cursor key item movement
1276  double increment = 1.0;
1277  if ( e->modifiers() & Qt::ShiftModifier )
1278  {
1279  //holding shift while pressing cursor keys results in a big step
1280  increment = 10.0;
1281  }
1282 
1283  if ( e->key() == Qt::Key_Left )
1284  {
1285  for ( ; itemIt != composerItemList.end(); ++itemIt )
1286  {
1287  ( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
1288  ( *itemIt )->move( -1 * increment, 0.0 );
1289  ( *itemIt )->endCommand();
1290  }
1291  }
1292  else if ( e->key() == Qt::Key_Right )
1293  {
1294  for ( ; itemIt != composerItemList.end(); ++itemIt )
1295  {
1296  ( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
1297  ( *itemIt )->move( increment, 0.0 );
1298  ( *itemIt )->endCommand();
1299  }
1300  }
1301  else if ( e->key() == Qt::Key_Down )
1302  {
1303  for ( ; itemIt != composerItemList.end(); ++itemIt )
1304  {
1305  ( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
1306  ( *itemIt )->move( 0.0, increment );
1307  ( *itemIt )->endCommand();
1308  }
1309  }
1310  else if ( e->key() == Qt::Key_Up )
1311  {
1312  for ( ; itemIt != composerItemList.end(); ++itemIt )
1313  {
1314  ( *itemIt )->beginCommand( tr( "Item moved" ), QgsComposerMergeCommand::ItemMove );
1315  ( *itemIt )->move( 0.0, -1 * increment );
1316  ( *itemIt )->endCommand();
1317  }
1318  }
1319 }
1320 
1322 {
1323  if ( e->key() == Qt::Key_Space && !e->isAutoRepeat() && mKeyPanning )
1324  {
1325  //end of panning with space key
1326  mKeyPanning = false;
1327 
1328  //reset cursor
1329  if ( mCurrentTool != Pan )
1330  {
1331  if ( composition() )
1332  {
1333  //allow cursor changes again
1334  composition()->setPreventCursorChange( false );
1335  }
1336  }
1337  viewport()->setCursor( defaultCursorForTool( mCurrentTool ) );
1338  return;
1339  }
1340  else if ( e->key() == Qt::Key_Space && !e->isAutoRepeat() && mTemporaryZoomStatus != QgsComposerView::Inactive )
1341  {
1342  //temporary keyboard-based zoom tool is active and space key has been released
1343  if ( mMarqueeZoom )
1344  {
1345  //currently in the middle of a marquee operation, so don't switch tool back immediately
1346  //instead, wait until mouse button has been released before switching tool back
1348  }
1349  else
1350  {
1351  //switch tool back
1354  }
1355  }
1356  else if ( mCurrentTool == QgsComposerView::Zoom )
1357  {
1358  //if zoom tool is active, respond to changes in the shift key status and update cursor accordingly
1359  if ( ! e->isAutoRepeat() )
1360  {
1361  QPixmap myZoomQPixmap = QPixmap(( const char ** )( e->modifiers() & Qt::ShiftModifier ? zoom_out : zoom_in ) );
1362  QCursor zoomCursor = QCursor( myZoomQPixmap, 7, 7 );
1363  viewport()->setCursor( zoomCursor );
1364  }
1365  return;
1366  }
1367 }
1368 
1369 void QgsComposerView::wheelEvent( QWheelEvent* event )
1370 {
1372  {
1373  //ignore wheel events while marquee operations are active (eg, creating new item)
1374  return;
1375  }
1376 
1377  if ( composition()->selectionHandles()->isDragging() || composition()->selectionHandles()->isResizing() )
1378  {
1379  //ignore wheel events while dragging/resizing items
1380  return;
1381  }
1382 
1383  if ( currentTool() == MoveItemContent )
1384  {
1385  //move item content tool, so scroll events get handled by the selected composer item
1386 
1387  QPointF scenePoint = mapToScene( event->pos() );
1388  //select topmost item at position of event
1389  QgsComposerItem* theItem = composition()->composerItemAt( scenePoint );
1390  if ( theItem )
1391  {
1392  if ( theItem->isSelected() )
1393  {
1394  QPointF itemPoint = theItem->mapFromScene( scenePoint );
1395  theItem->beginCommand( tr( "Zoom item content" ) );
1396  theItem->zoomContent( event->delta(), itemPoint.x(), itemPoint.y() );
1397  theItem->endCommand();
1398  }
1399  }
1400  }
1401  else
1402  {
1403  //not using move item content tool, so zoom whole composition
1404  wheelZoom( event );
1405  }
1406 }
1407 
1408 void QgsComposerView::wheelZoom( QWheelEvent * event )
1409 {
1410  //get mouse wheel zoom behaviour settings
1411  QSettings mySettings;
1412  int wheelAction = mySettings.value( "/qgis/wheel_action", 2 ).toInt();
1413  double zoomFactor = mySettings.value( "/qgis/zoom_factor", 2 ).toDouble();
1414 
1416  {
1417  return;
1418  }
1419 
1420  if ( event->modifiers() & Qt::ControlModifier )
1421  {
1422  //holding ctrl while wheel zooming results in a finer zoom
1423  zoomFactor = 1.0 + ( zoomFactor - 1.0 ) / 10.0;
1424  }
1425 
1426  //caculate zoom scale factor
1427  bool zoomIn = event->delta() > 0;
1428  double scaleFactor = ( zoomIn ? 1 / zoomFactor : zoomFactor );
1429 
1430  //get current visible part of scene
1431  QRect viewportRect( 0, 0, viewport()->width(), viewport()->height() );
1432  QgsRectangle visibleRect = QgsRectangle( mapToScene( viewportRect ).boundingRect() );
1433 
1434  //transform the mouse pos to scene coordinates
1435  QPointF scenePoint = mapToScene( event->pos() );
1436 
1437  //adjust view center according to wheel action setting
1438  switch (( QgsMapCanvas::WheelAction )wheelAction )
1439  {
1441  {
1442  centerOn( scenePoint.x(), scenePoint.y() );
1443  break;
1444  }
1445 
1447  {
1448  QgsPoint oldCenter( visibleRect.center() );
1449  QgsPoint newCenter( scenePoint.x() + (( oldCenter.x() - scenePoint.x() ) * scaleFactor ),
1450  scenePoint.y() + (( oldCenter.y() - scenePoint.y() ) * scaleFactor ) );
1451  centerOn( newCenter.x(), newCenter.y() );
1452  break;
1453  }
1454 
1455  default:
1456  break;
1457  }
1458 
1459  //zoom composition
1460  if ( zoomIn )
1461  {
1462  scale( zoomFactor, zoomFactor );
1463  }
1464  else
1465  {
1466  scale( 1 / zoomFactor, 1 / zoomFactor );
1467  }
1468 
1469  //update composition for new zoom
1470  emit zoomLevelChanged();
1471  updateRulers();
1472  update();
1473  //redraw cached map items
1474  QList<QGraphicsItem *> itemList = composition()->items();
1475  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1476  for ( ; itemIt != itemList.end(); ++itemIt )
1477  {
1478  QgsComposerMap* mypItem = dynamic_cast<QgsComposerMap *>( *itemIt );
1479  if (( mypItem ) && ( mypItem->previewMode() == QgsComposerMap::Render ) )
1480  {
1481  mypItem->updateCachedImage();
1482  }
1483  }
1484 }
1485 
1486 void QgsComposerView::setZoomLevel( double zoomLevel )
1487 {
1488  double dpi = QgsApplication::desktop()->logicalDpiX();
1489  //monitor dpi is not always correct - so make sure the value is sane
1490  if (( dpi < 60 ) || ( dpi > 250 ) )
1491  dpi = 72;
1492 
1493  //desired pixel width for 1mm on screen
1494  double scale = zoomLevel * dpi / 25.4;
1495  setTransform( QTransform::fromScale( scale , scale ) );
1496 
1497  updateRulers();
1498  update();
1499  emit zoomLevelChanged();
1500 }
1501 
1502 void QgsComposerView::paintEvent( QPaintEvent* event )
1503 {
1504  if ( mPaintingEnabled )
1505  {
1506  QGraphicsView::paintEvent( event );
1507  event->accept();
1508  }
1509  else
1510  {
1511  event->ignore();
1512  }
1513 }
1514 
1515 void QgsComposerView::hideEvent( QHideEvent* e )
1516 {
1517  emit( composerViewHide( this ) );
1518  e->ignore();
1519 }
1520 
1521 void QgsComposerView::showEvent( QShowEvent* e )
1522 {
1523  emit( composerViewShow( this ) );
1524  e->ignore();
1525 }
1526 
1527 void QgsComposerView::resizeEvent( QResizeEvent* event )
1528 {
1529  QGraphicsView::resizeEvent( event );
1530  emit zoomLevelChanged();
1531  updateRulers();
1532 }
1533 
1535 {
1536  QGraphicsView::scrollContentsBy( dx, dy );
1537  updateRulers();
1538 }
1539 
1541 {
1542  setScene( c );
1543  if ( mHorizontalRuler )
1544  {
1546  }
1547  if ( mVerticalRuler )
1548  {
1550  }
1551 }
1552 
1554 {
1555  if ( scene() )
1556  {
1557  QgsComposition* c = dynamic_cast<QgsComposition *>( scene() );
1558  if ( c )
1559  {
1560  return c;
1561  }
1562  }
1563  return 0;
1564 }
1565 
1567 {
1568  if ( !composition() )
1569  {
1570  return;
1571  }
1572 
1573  QList<QgsComposerItem*> selectionList = composition()->selectedComposerItems();
1574  if ( selectionList.size() < 2 )
1575  {
1576  return; //not enough items for a group
1577  }
1579 
1580  QList<QgsComposerItem*>::iterator itemIter = selectionList.begin();
1581  for ( ; itemIter != selectionList.end(); ++itemIter )
1582  {
1583  itemGroup->addItem( *itemIter );
1584  }
1585 
1586  composition()->addItem( itemGroup );
1587  itemGroup->setSelected( true );
1588  emit selectedItemChanged( itemGroup );
1589 }
1590 
1592 {
1593  if ( !composition() )
1594  {
1595  return;
1596  }
1597 
1598  QList<QgsComposerItem*> selectionList = composition()->selectedComposerItems();
1599  QList<QgsComposerItem*>::iterator itemIter = selectionList.begin();
1600  for ( ; itemIter != selectionList.end(); ++itemIter )
1601  {
1602  QgsComposerItemGroup* itemGroup = dynamic_cast<QgsComposerItemGroup *>( *itemIter );
1603  if ( itemGroup )
1604  {
1605  itemGroup->removeItems();
1606  composition()->removeItem( *itemIter );
1607  delete( *itemIter );
1608  emit itemRemoved( *itemIter );
1609  }
1610  }
1611 }
1612 
1614 {
1615  QMainWindow* composerObject = 0;
1616  QObject* currentObject = parent();
1617  if ( !currentObject )
1618  {
1619  return qobject_cast<QMainWindow *>( currentObject );
1620  }
1621 
1622  while ( true )
1623  {
1624  composerObject = qobject_cast<QMainWindow*>( currentObject );
1625  if ( composerObject || currentObject->parent() == 0 )
1626  {
1627  return composerObject;
1628  }
1629  currentObject = currentObject->parent();
1630  }
1631 
1632  return 0;
1633 }
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 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 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)
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 wheelEvent(QWheelEvent *event)
void endMarqueeZoom(QMouseEvent *e)
Finalises a marquee zoom.
void pasteItems(PasteMode mode)
Pastes items from clipboard.
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.
QgsComposerView(QWidget *parent=0, const char *name=0, Qt::WFlags f=0)
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 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)
void cursorPosChanged(QPointF)
Is emitted when mouse cursor coordinates change.
void setComposition(QgsComposition *c)
Sets composition (derived from QGraphicsScene)
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:209
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.