Quantum GIS API Documentation  1.7.5-Wroclaw
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator 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 <QMainWindow>
19 #include <QMouseEvent>
20 #include <QKeyEvent>
21 
22 #include "qgscomposerview.h"
23 #include "qgscomposerarrow.h"
24 #include "qgscomposerlabel.h"
25 #include "qgscomposerlegend.h"
26 #include "qgscomposermap.h"
27 #include "qgscomposeritemgroup.h"
28 #include "qgscomposerpicture.h"
29 #include "qgscomposerscalebar.h"
30 #include "qgscomposershape.h"
32 
33 QgsComposerView::QgsComposerView( QWidget* parent, const char* name, Qt::WFlags f ) :
34  QGraphicsView( parent ), mShiftKeyPressed( false ), mRubberBandItem( 0 ), mRubberBandLineItem( 0 ), mMoveContentItem( 0 ), mPaintingEnabled( true )
35 {
36  setResizeAnchor( QGraphicsView::AnchorViewCenter );
37  setMouseTracking( true );
38  viewport()->setMouseTracking( true );
39 }
40 
41 void QgsComposerView::mousePressEvent( QMouseEvent* e )
42 {
43  if ( !composition() )
44  {
45  return;
46  }
47 
48  QPointF scenePoint = mapToScene( e->pos() );
49  QPointF snappedScenePoint = composition()->snapPointToGrid( scenePoint );
50 
51  //lock/unlock position of item with right click
52  if ( e->button() == Qt::RightButton )
53  {
54  QgsComposerItem* selectedItem = composition()->composerItemAt( scenePoint );
55  if ( selectedItem )
56  {
57  bool lock = selectedItem->positionLock() ? false : true;
58  selectedItem->setPositionLock( lock );
59  selectedItem->update();
60  //make sure the new cursor is correct
61  QPointF itemPoint = selectedItem->mapFromScene( scenePoint );
62  selectedItem->updateCursor( itemPoint );
63  }
64  return;
65  }
66 
67  switch ( mCurrentTool )
68  {
69  //select/deselect items and pass mouse event further
70  case Select:
71  {
72  if ( !mShiftKeyPressed ) //keep selection if shift key pressed
73  {
74  composition()->clearSelection();
75  }
76 
77  //select topmost item at position of event
78  QgsComposerItem* selectedItem = composition()->composerItemAt( scenePoint );
79  if ( !selectedItem )
80  {
81  break;
82  }
83 
84  selectedItem->setSelected( true );
85  QGraphicsView::mousePressEvent( e );
86  emit selectedItemChanged( selectedItem );
87  break;
88  }
89 
90  case MoveItemContent:
91  {
92  //store item as member if it is selected and cursor is over item
93  QgsComposerItem* item = dynamic_cast<QgsComposerItem *>( itemAt( e->pos() ) );
94  if ( item )
95  {
96  mMoveContentStartPos = scenePoint;
97  }
98  mMoveContentItem = item;
99  break;
100  }
101 
102  case AddArrow:
103  {
104  mRubberBandStartPos = QPointF( snappedScenePoint.x(), snappedScenePoint.y() );
105  mRubberBandLineItem = new QGraphicsLineItem( snappedScenePoint.x(), snappedScenePoint.y(), snappedScenePoint.x(), snappedScenePoint.y() );
106  mRubberBandLineItem->setZValue( 100 );
107  scene()->addItem( mRubberBandLineItem );
108  scene()->update();
109  break;
110  }
111 
112  //create rubber band for map and ellipse items
113  case AddMap:
114  case AddShape:
115  {
116  QTransform t;
117  mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
118  mRubberBandStartPos = QPointF( snappedScenePoint.x(), snappedScenePoint.y() );
119  t.translate( snappedScenePoint.x(), snappedScenePoint.y() );
120  mRubberBandItem->setTransform( t );
121  mRubberBandItem->setZValue( 100 );
122  scene()->addItem( mRubberBandItem );
123  scene()->update();
124  }
125  break;
126 
127  case AddLabel:
128  {
129  QgsComposerLabel* newLabelItem = new QgsComposerLabel( composition() );
130  newLabelItem->setText( tr( "Quantum GIS" ) );
131  newLabelItem->adjustSizeToText();
132  newLabelItem->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), newLabelItem->rect().width(), newLabelItem->rect().height() ) );
133  addComposerLabel( newLabelItem );
134  emit actionFinished();
135  }
136  break;
137 
138  case AddScalebar:
139  {
140  QgsComposerScaleBar* newScaleBar = new QgsComposerScaleBar( composition() );
141  newScaleBar->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), 20, 20 ) );
142  addComposerScaleBar( newScaleBar );
143  emit actionFinished();
144  }
145  break;
146 
147  case AddLegend:
148  {
149  QgsComposerLegend* newLegend = new QgsComposerLegend( composition() );
150  newLegend->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), newLegend->rect().width(), newLegend->rect().height() ) );
151  addComposerLegend( newLegend );
152  emit actionFinished();
153  break;
154  }
155  case AddPicture:
156  {
157  QgsComposerPicture* newPicture = new QgsComposerPicture( composition() );
158  newPicture->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), 30, 30 ) );
159  addComposerPicture( newPicture );
160  emit actionFinished();
161  break;
162  }
163  case AddTable:
164  {
166  newTable->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), 50, 50 ) );
167  addComposerTable( newTable );
168  emit actionFinished();
169  break;
170  }
171 
172  default:
173  break;
174  }
175 }
176 
178 {
179  if ( !composition() )
180  {
181  return;
182  }
183 
184  QPointF scenePoint = mapToScene( e->pos() );
185 
186  switch ( mCurrentTool )
187  {
188  case Select:
189  {
190  QGraphicsView::mouseReleaseEvent( e );
191  break;
192  }
193 
194  case MoveItemContent:
195  {
196  if ( mMoveContentItem )
197  {
198  //update map preview if composer map
199  QgsComposerMap* composerMap = dynamic_cast<QgsComposerMap *>( mMoveContentItem );
200  if ( composerMap )
201  {
202  composerMap->setOffset( 0, 0 );
203  }
204 
205  double moveX = scenePoint.x() - mMoveContentStartPos.x();
206  double moveY = scenePoint.y() - mMoveContentStartPos.y();
207 
208  composition()->beginCommand( mMoveContentItem, tr( "Move item content" ) );
209  mMoveContentItem->moveContent( -moveX, -moveY );
210  composition()->endCommand();
211  mMoveContentItem = 0;
212  }
213  break;
214  }
215  case AddArrow:
216  {
217  QPointF scenePoint = mapToScene( e->pos() );
218  QPointF snappedScenePoint = composition()->snapPointToGrid( scenePoint );
219  QgsComposerArrow* composerArrow = new QgsComposerArrow( mRubberBandStartPos, QPointF( snappedScenePoint.x(), snappedScenePoint.y() ), composition() );
220  addComposerArrow( composerArrow );
221  scene()->removeItem( mRubberBandLineItem );
222  delete mRubberBandLineItem;
224  emit actionFinished();
225  break;
226  }
227 
228  case AddShape:
229  {
230  if ( !mRubberBandItem || mRubberBandItem->rect().width() < 0.1 || mRubberBandItem->rect().width() < 0.1 )
231  {
232  scene()->removeItem( mRubberBandItem );
233  delete mRubberBandItem;
234  mRubberBandItem = 0;
235  return;
236  }
237 
238  QgsComposerShape* composerShape = new QgsComposerShape( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height(), composition() );
239  addComposerShape( composerShape );
240  scene()->removeItem( mRubberBandItem );
241  delete mRubberBandItem;
242  mRubberBandItem = 0;
243  emit actionFinished();
244  break;
245  }
246 
247  case AddMap:
248  {
249  if ( !mRubberBandItem || mRubberBandItem->rect().width() < 0.1 || mRubberBandItem->rect().width() < 0.1 )
250  {
251  if ( mRubberBandItem )
252  {
253  scene()->removeItem( mRubberBandItem );
254  delete mRubberBandItem;
255  mRubberBandItem = 0;
256  }
257  return;
258  }
259 
260  QgsComposerMap* composerMap = new QgsComposerMap( composition(), mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
261  addComposerMap( composerMap );
262  scene()->removeItem( mRubberBandItem );
263  delete mRubberBandItem;
264  mRubberBandItem = 0;
265  emit actionFinished();
266  }
267  break;
268 
269  default:
270  break;
271  }
272 }
273 
274 void QgsComposerView::mouseMoveEvent( QMouseEvent* e )
275 {
276  if ( !composition() )
277  {
278  return;
279  }
280 
281  if ( e->buttons() == Qt::NoButton )
282  {
283  if ( mCurrentTool == Select )
284  {
285  QGraphicsView::mouseMoveEvent( e );
286  }
287  }
288  else
289  {
290  QPointF scenePoint = mapToScene( e->pos() );
291 
292  switch ( mCurrentTool )
293  {
294  case Select:
295  QGraphicsView::mouseMoveEvent( e );
296  break;
297 
298  case AddArrow:
299  {
300  if ( mRubberBandLineItem )
301  {
302  mRubberBandLineItem->setLine( mRubberBandStartPos.x(), mRubberBandStartPos.y(), scenePoint.x(), scenePoint.y() );
303  }
304  break;
305  }
306 
307  case AddMap:
308  case AddShape:
309  //adjust rubber band item
310  {
311  double x = 0;
312  double y = 0;
313  double width = 0;
314  double height = 0;
315 
316  double dx = scenePoint.x() - mRubberBandStartPos.x();
317  double dy = scenePoint.y() - mRubberBandStartPos.y();
318 
319  if ( dx < 0 )
320  {
321  x = scenePoint.x();
322  width = -dx;
323  }
324  else
325  {
326  x = mRubberBandStartPos.x();
327  width = dx;
328  }
329 
330  if ( dy < 0 )
331  {
332  y = scenePoint.y();
333  height = -dy;
334  }
335  else
336  {
337  y = mRubberBandStartPos.y();
338  height = dy;
339  }
340 
341  if ( mRubberBandItem )
342  {
343  mRubberBandItem->setRect( 0, 0, width, height );
344  QTransform t;
345  t.translate( x, y );
346  mRubberBandItem->setTransform( t );
347  }
348  break;
349  }
350 
351  case MoveItemContent:
352  {
353  //update map preview if composer map
354  QgsComposerMap* composerMap = dynamic_cast<QgsComposerMap *>( mMoveContentItem );
355  if ( composerMap )
356  {
357  composerMap->setOffset( scenePoint.x() - mMoveContentStartPos.x(), scenePoint.y() - mMoveContentStartPos.y() );
358  composerMap->update();
359  }
360  break;
361  }
362  default:
363  break;
364  }
365  }
366 }
367 
369 {
370  e->ignore();
371 }
372 
373 void QgsComposerView::keyPressEvent( QKeyEvent * e )
374 {
375  if ( e->key() == Qt::Key_Shift )
376  {
377  mShiftKeyPressed = true;
378  }
379 
380  if ( !composition() )
381  {
382  return;
383  }
384 
385  QList<QgsComposerItem*> composerItemList = composition()->selectedComposerItems();
386  QList<QgsComposerItem*>::iterator itemIt = composerItemList.begin();
387 
388  //delete selected items
389  if ( e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace )
390  {
391  for ( ; itemIt != composerItemList.end(); ++itemIt )
392  {
393  QgsComposerMap* map = dynamic_cast<QgsComposerMap *>( *itemIt );
394  if ( !map || !map->isDrawing() ) //don't delete a composer map while it draws
395  {
396  composition()->removeItem( *itemIt );
397  QgsComposerItemGroup* itemGroup = dynamic_cast<QgsComposerItemGroup*>( *itemIt );
398  if ( itemGroup && composition() )
399  {
400  //add add/remove item command for every item in the group
401  QUndoCommand* parentCommand = new QUndoCommand( tr( "Remove item group" ) );
402 
403  QSet<QgsComposerItem*> groupedItems = itemGroup->items();
404  QSet<QgsComposerItem*>::iterator it = groupedItems.begin();
405  for ( ; it != groupedItems.end(); ++it )
406  {
408  connectAddRemoveCommandSignals( subcommand );
409  emit itemRemoved( *it );
410  }
411 
412  composition()->undoStack()->push( parentCommand );
413  delete itemGroup;
414  emit itemRemoved( itemGroup );
415  }
416  else
417  {
418  emit itemRemoved( *itemIt );
419  pushAddRemoveCommand( *itemIt, tr( "Item deleted" ), QgsAddRemoveItemCommand::Removed );
420  }
421  }
422  }
423  }
424 
425  else if ( e->key() == Qt::Key_Left )
426  {
427  for ( ; itemIt != composerItemList.end(); ++itemIt )
428  {
429  ( *itemIt )->move( -1.0, 0.0 );
430  }
431  }
432  else if ( e->key() == Qt::Key_Right )
433  {
434  for ( ; itemIt != composerItemList.end(); ++itemIt )
435  {
436  ( *itemIt )->move( 1.0, 0.0 );
437  }
438  }
439  else if ( e->key() == Qt::Key_Down )
440  {
441  for ( ; itemIt != composerItemList.end(); ++itemIt )
442  {
443  ( *itemIt )->move( 0.0, 1.0 );
444  }
445  }
446  else if ( e->key() == Qt::Key_Up )
447  {
448  for ( ; itemIt != composerItemList.end(); ++itemIt )
449  {
450  ( *itemIt )->move( 0.0, -1.0 );
451  }
452  }
453 }
454 
455 void QgsComposerView::keyReleaseEvent( QKeyEvent * e )
456 {
457  if ( e->key() == Qt::Key_Shift )
458  {
459  mShiftKeyPressed = false;
460  }
461 }
462 
463 void QgsComposerView::wheelEvent( QWheelEvent* event )
464 {
465  QPointF scenePoint = mapToScene( event->pos() );
466 
467  //select topmost item at position of event
468  QgsComposerItem* theItem = composition()->composerItemAt( scenePoint );
469  if ( theItem )
470  {
471  if ( theItem->isSelected() )
472  {
473  QPointF itemPoint = theItem->mapFromScene( scenePoint );
474  theItem->beginCommand( tr( "Zoom item content" ) );
475  theItem->zoomContent( event->delta(), itemPoint.x(), itemPoint.y() );
476  theItem->endCommand();
477  }
478  }
479 }
480 
481 void QgsComposerView::paintEvent( QPaintEvent* event )
482 {
483  if ( mPaintingEnabled )
484  {
485  QGraphicsView::paintEvent( event );
486  event->accept();
487  }
488  else
489  {
490  event->ignore();
491  }
492 }
493 
495 {
496  setScene( c );
497 }
498 
500 {
501  if ( scene() )
502  {
503  QgsComposition* c = dynamic_cast<QgsComposition *>( scene() );
504  if ( c )
505  {
506  return c;
507  }
508  }
509  return 0;
510 }
511 
513 {
514  composition()->addItem( arrow );
515  emit composerArrowAdded( arrow );
516  scene()->clearSelection();
517  arrow->setSelected( true );
518  emit selectedItemChanged( arrow );
519  pushAddRemoveCommand( arrow, tr( "Arrow added" ) );
520 }
521 
523 {
524  composition()->addItem( label );
525  emit composerLabelAdded( label );
526  scene()->clearSelection();
527  label->setSelected( true );
528  emit selectedItemChanged( label );
529  pushAddRemoveCommand( label, tr( "Label added" ) );
530 }
531 
533 {
534  scene()->addItem( map );
535  //set default preview mode to cache. Must be done here between adding composer map to scene and emiting signal
537  map->cache();
538  emit composerMapAdded( map );
539  scene()->clearSelection();
540  map->setSelected( true );
541  emit selectedItemChanged( map );
542  pushAddRemoveCommand( map, tr( "Map added" ) );
543 }
544 
546 {
547  //take first available map
548  QList<const QgsComposerMap*> mapItemList = composition()->composerMapItems();
549  if ( mapItemList.size() > 0 )
550  {
551  scaleBar->setComposerMap( mapItemList.at( 0 ) );
552  }
553  scaleBar->applyDefaultSize(); //4 segments, 1/5 of composer map width
554  scene()->addItem( scaleBar );
555  emit composerScaleBarAdded( scaleBar );
556  scene()->clearSelection();
557  scaleBar->setSelected( true );
558  emit selectedItemChanged( scaleBar );
559  pushAddRemoveCommand( scaleBar, tr( "Scale bar added" ) );
560 }
561 
563 {
564  //take first available map
565  QList<const QgsComposerMap*> mapItemList = composition()->composerMapItems();
566  if ( mapItemList.size() > 0 )
567  {
568  legend->setComposerMap( mapItemList.at( 0 ) );
569  }
570  scene()->addItem( legend );
571  emit composerLegendAdded( legend );
572  scene()->clearSelection();
573  legend->setSelected( true );
574  emit selectedItemChanged( legend );
575  pushAddRemoveCommand( legend, tr( "Legend added" ) );
576 }
577 
579 {
580  scene()->addItem( picture );
581  emit composerPictureAdded( picture );
582  scene()->clearSelection();
583  picture->setSelected( true );
584  emit selectedItemChanged( picture );
585  pushAddRemoveCommand( picture, tr( "Picture added" ) );
586 }
587 
589 {
590  scene()->addItem( shape );
591  emit composerShapeAdded( shape );
592  scene()->clearSelection();
593  shape->setSelected( true );
594  emit selectedItemChanged( shape );
595  pushAddRemoveCommand( shape, tr( "Shape added" ) );
596 }
597 
599 {
600  scene()->addItem( table );
601  emit composerTableAdded( table );
602  scene()->clearSelection();
603  table->setSelected( true );
604  emit selectedItemChanged( table );
605  pushAddRemoveCommand( table, tr( "Table added" ) );
606 }
607 
609 {
610  if ( !composition() )
611  {
612  return;
613  }
614 
615  QList<QgsComposerItem*> selectionList = composition()->selectedComposerItems();
616  if ( selectionList.size() < 2 )
617  {
618  return; //not enough items for a group
619  }
621 
622  QList<QgsComposerItem*>::iterator itemIter = selectionList.begin();
623  for ( ; itemIter != selectionList.end(); ++itemIter )
624  {
625  itemGroup->addItem( *itemIter );
626  }
627 
628  composition()->addItem( itemGroup );
629  itemGroup->setSelected( true );
630  emit selectedItemChanged( itemGroup );
631 }
632 
634 {
635  if ( !composition() )
636  {
637  return;
638  }
639 
640  QList<QgsComposerItem*> selectionList = composition()->selectedComposerItems();
641  QList<QgsComposerItem*>::iterator itemIter = selectionList.begin();
642  for ( ; itemIter != selectionList.end(); ++itemIter )
643  {
644  QgsComposerItemGroup* itemGroup = dynamic_cast<QgsComposerItemGroup *>( *itemIter );
645  if ( itemGroup )
646  {
647  itemGroup->removeItems();
648  composition()->removeItem( *itemIter );
649  delete( *itemIter );
650  emit itemRemoved( *itemIter );
651  }
652  }
653 }
654 
656 {
657  //cast and send proper signal
658  item->setSelected( true );
659  QgsComposerArrow* arrow = dynamic_cast<QgsComposerArrow*>( item );
660  if ( arrow )
661  {
662  emit composerArrowAdded( arrow );
663  emit selectedItemChanged( arrow );
664  return;
665  }
666  QgsComposerLabel* label = dynamic_cast<QgsComposerLabel*>( item );
667  if ( label )
668  {
669  emit composerLabelAdded( label );
670  emit selectedItemChanged( label );
671  return;
672  }
673  QgsComposerMap* map = dynamic_cast<QgsComposerMap*>( item );
674  if ( map )
675  {
676  emit composerMapAdded( map );
677  emit selectedItemChanged( map );
678  return;
679  }
680  QgsComposerScaleBar* scalebar = dynamic_cast<QgsComposerScaleBar*>( item );
681  if ( scalebar )
682  {
683  emit composerScaleBarAdded( scalebar );
684  emit selectedItemChanged( scalebar );
685  return;
686  }
687  QgsComposerLegend* legend = dynamic_cast<QgsComposerLegend*>( item );
688  if ( legend )
689  {
690  emit composerLegendAdded( legend );
691  emit selectedItemChanged( legend );
692  return;
693  }
694  QgsComposerPicture* picture = dynamic_cast<QgsComposerPicture*>( item );
695  if ( picture )
696  {
697  emit composerPictureAdded( picture );
698  emit selectedItemChanged( picture );
699  return;
700  }
701  QgsComposerShape* shape = dynamic_cast<QgsComposerShape*>( item );
702  if ( shape )
703  {
704  emit composerShapeAdded( shape );
705  emit selectedItemChanged( shape );
706  return;
707  }
708  QgsComposerAttributeTable* table = dynamic_cast<QgsComposerAttributeTable*>( item );
709  if ( table )
710  {
711  emit composerTableAdded( table );
712  emit selectedItemChanged( table );
713  return;
714  }
715 }
716 
718 {
719  QMainWindow* composerObject = 0;
720  QObject* currentObject = parent();
721  if ( !currentObject )
722  {
723  return qobject_cast<QMainWindow *>( currentObject );
724  }
725 
726  while ( true )
727  {
728  composerObject = qobject_cast<QMainWindow*>( currentObject );
729  if ( composerObject || currentObject->parent() == 0 )
730  {
731  return composerObject;
732  }
733  currentObject = currentObject->parent();
734  }
735 
736  return 0;
737 }
738 
740 {
741  if ( !c )
742  {
743  return;
744  }
745  QObject::connect( c, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SIGNAL( itemRemoved( QgsComposerItem* ) ) );
746  QObject::connect( c, SIGNAL( itemAdded( QgsComposerItem* ) ), this, SLOT( sendItemAddedSignal( QgsComposerItem* ) ) );
747 }
748 
750 {
751  if ( !composition() )
752  {
753  return;
754  }
755 
756  QgsAddRemoveItemCommand* c = new QgsAddRemoveItemCommand( state, item, composition(), text );
758  composition()->undoStack()->push( c );
759 }