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 : [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 
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
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 );
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  {
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  {
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:
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 {
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 }