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