Quantum GIS API Documentation  1.8
src/gui/qgscomposerview.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                          qgscomposerview.cpp
00003                          -------------------
00004     begin                : January 2005
00005     copyright            : (C) 2005 by Radim Blazek
00006     email                : blazek@itc.it
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00018 #include <QApplication>
00019 #include <QMainWindow>
00020 #include <QMouseEvent>
00021 #include <QKeyEvent>
00022 #include <QClipboard>
00023 #include <QMimeData>
00024 
00025 #include "qgscomposerview.h"
00026 #include "qgscomposerarrow.h"
00027 #include "qgscomposerlabel.h"
00028 #include "qgscomposerlegend.h"
00029 #include "qgscomposermap.h"
00030 #include "qgscomposeritemgroup.h"
00031 #include "qgscomposerpicture.h"
00032 #include "qgscomposerscalebar.h"
00033 #include "qgscomposershape.h"
00034 #include "qgscomposerattributetable.h"
00035 #include "qgslogger.h"
00036 
00037 QgsComposerView::QgsComposerView( QWidget* parent, const char* name, Qt::WFlags f )
00038     : QGraphicsView( parent )
00039     , mShiftKeyPressed( false )
00040     , mRubberBandItem( 0 )
00041     , mRubberBandLineItem( 0 )
00042     , mMoveContentItem( 0 )
00043     , mPaintingEnabled( true )
00044 {
00045   Q_UNUSED( f );
00046   Q_UNUSED( name );
00047 
00048   setResizeAnchor( QGraphicsView::AnchorViewCenter );
00049   setMouseTracking( true );
00050   viewport()->setMouseTracking( true );
00051 }
00052 
00053 void QgsComposerView::mousePressEvent( QMouseEvent* e )
00054 {
00055   if ( !composition() )
00056   {
00057     return;
00058   }
00059 
00060   QPointF scenePoint = mapToScene( e->pos() );
00061   QPointF snappedScenePoint = composition()->snapPointToGrid( scenePoint );
00062 
00063   //lock/unlock position of item with right click
00064   if ( e->button() == Qt::RightButton )
00065   {
00066     QgsComposerItem* selectedItem = composition()->composerItemAt( scenePoint );
00067     if ( selectedItem )
00068     {
00069       bool lock = selectedItem->positionLock() ? false : true;
00070       selectedItem->setPositionLock( lock );
00071       selectedItem->update();
00072       //make sure the new cursor is correct
00073       QPointF itemPoint = selectedItem->mapFromScene( scenePoint );
00074       selectedItem->updateCursor( itemPoint );
00075     }
00076     return;
00077   }
00078 
00079   switch ( mCurrentTool )
00080   {
00081       //select/deselect items and pass mouse event further
00082     case Select:
00083     {
00084       if ( !mShiftKeyPressed ) //keep selection if shift key pressed
00085       {
00086         composition()->clearSelection();
00087       }
00088 
00089       //select topmost item at position of event
00090       QgsComposerItem* selectedItem = composition()->composerItemAt( scenePoint );
00091       if ( !selectedItem )
00092       {
00093         break;
00094       }
00095 
00096       selectedItem->setSelected( true );
00097       QGraphicsView::mousePressEvent( e );
00098       emit selectedItemChanged( selectedItem );
00099       break;
00100     }
00101 
00102     case MoveItemContent:
00103     {
00104       //store item as member if it is selected and cursor is over item
00105       QgsComposerItem* item = dynamic_cast<QgsComposerItem *>( itemAt( e->pos() ) );
00106       if ( item )
00107       {
00108         mMoveContentStartPos = scenePoint;
00109       }
00110       mMoveContentItem = item;
00111       break;
00112     }
00113 
00114     case AddArrow:
00115     {
00116       mRubberBandStartPos = QPointF( snappedScenePoint.x(), snappedScenePoint.y() );
00117       mRubberBandLineItem = new QGraphicsLineItem( snappedScenePoint.x(), snappedScenePoint.y(), snappedScenePoint.x(), snappedScenePoint.y() );
00118       mRubberBandLineItem->setZValue( 100 );
00119       scene()->addItem( mRubberBandLineItem );
00120       scene()->update();
00121       break;
00122     }
00123 
00124     //create rubber band for map and ellipse items
00125     case AddMap:
00126     case AddRectangle:
00127     case AddTriangle:
00128     case AddEllipse:
00129     {
00130       QTransform t;
00131       mRubberBandItem = new QGraphicsRectItem( 0, 0, 0, 0 );
00132       mRubberBandStartPos = QPointF( snappedScenePoint.x(), snappedScenePoint.y() );
00133       t.translate( snappedScenePoint.x(), snappedScenePoint.y() );
00134       mRubberBandItem->setTransform( t );
00135       mRubberBandItem->setZValue( 100 );
00136       scene()->addItem( mRubberBandItem );
00137       scene()->update();
00138     }
00139     break;
00140 
00141     case AddLabel:
00142       if ( composition() )
00143       {
00144         QgsComposerLabel* newLabelItem = new QgsComposerLabel( composition() );
00145         newLabelItem->setText( tr( "Quantum GIS" ) );
00146         newLabelItem->adjustSizeToText();
00147         newLabelItem->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), newLabelItem->rect().width(), newLabelItem->rect().height() ) );
00148         composition()->addComposerLabel( newLabelItem );
00149         emit actionFinished();
00150         composition()->pushAddRemoveCommand( newLabelItem, tr( "Label added" ) );
00151       }
00152       break;
00153 
00154     case AddScalebar:
00155       if ( composition() )
00156       {
00157         QgsComposerScaleBar* newScaleBar = new QgsComposerScaleBar( composition() );
00158         newScaleBar->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), 20, 20 ) );
00159         composition()->addComposerScaleBar( newScaleBar );
00160         QList<const QgsComposerMap*> mapItemList = composition()->composerMapItems();
00161         if ( mapItemList.size() > 0 )
00162         {
00163           newScaleBar->setComposerMap( mapItemList.at( 0 ) );
00164         }
00165         newScaleBar->applyDefaultSize(); //4 segments, 1/5 of composer map width
00166         emit actionFinished();
00167         composition()->pushAddRemoveCommand( newScaleBar, tr( "Scale bar added" ) );
00168       }
00169       break;
00170 
00171     case AddLegend:
00172     {
00173       if ( composition() )
00174       {
00175         QgsComposerLegend* newLegend = new QgsComposerLegend( composition() );
00176         newLegend->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), newLegend->rect().width(), newLegend->rect().height() ) );
00177         composition()->addComposerLegend( newLegend );
00178         newLegend->updateLegend();
00179         emit actionFinished();
00180         composition()->pushAddRemoveCommand( newLegend, tr( "Legend added" ) );
00181       }
00182       break;
00183     }
00184     case AddPicture:
00185       if ( composition() )
00186       {
00187         QgsComposerPicture* newPicture = new QgsComposerPicture( composition() );
00188         newPicture->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), 30, 30 ) );
00189         composition()->addComposerPicture( newPicture );
00190         emit actionFinished();
00191         composition()->pushAddRemoveCommand( newPicture, tr( "Picture added" ) );
00192       }
00193       break;
00194     case AddTable:
00195       if ( composition() )
00196       {
00197         QgsComposerAttributeTable* newTable = new QgsComposerAttributeTable( composition() );
00198         newTable->setSceneRect( QRectF( snappedScenePoint.x(), snappedScenePoint.y(), 50, 50 ) );
00199         composition()->addComposerTable( newTable );
00200         emit actionFinished();
00201         composition()->pushAddRemoveCommand( newTable, tr( "Table added" ) );
00202       }
00203       break;
00204     default:
00205       break;
00206   }
00207 }
00208 
00209 void QgsComposerView::addShape( Tool currentTool )
00210 {
00211   QgsComposerShape::Shape shape = QgsComposerShape::Ellipse;
00212 
00213   if ( currentTool == AddRectangle )
00214     shape = QgsComposerShape::Rectangle;
00215   else if ( currentTool == AddTriangle )
00216     shape = QgsComposerShape::Triangle;
00217 
00218   if ( !mRubberBandItem || mRubberBandItem->rect().width() < 0.1 || mRubberBandItem->rect().width() < 0.1 )
00219   {
00220     scene()->removeItem( mRubberBandItem );
00221     delete mRubberBandItem;
00222     mRubberBandItem = 0;
00223     return;
00224   }
00225   if ( composition() )
00226   {
00227     QgsComposerShape* composerShape = new QgsComposerShape( mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height(), composition() );
00228     composerShape->setShapeType( shape );
00229     composition()->addComposerShape( composerShape );
00230     scene()->removeItem( mRubberBandItem );
00231     delete mRubberBandItem;
00232     mRubberBandItem = 0;
00233     emit actionFinished();
00234     composition()->pushAddRemoveCommand( composerShape, tr( "Shape added" ) );
00235   }
00236 }
00237 
00238 void QgsComposerView::mouseReleaseEvent( QMouseEvent* e )
00239 {
00240   if ( !composition() )
00241   {
00242     return;
00243   }
00244 
00245   QPointF scenePoint = mapToScene( e->pos() );
00246 
00247   switch ( mCurrentTool )
00248   {
00249     case Select:
00250     {
00251       QGraphicsView::mouseReleaseEvent( e );
00252       break;
00253     }
00254 
00255     case MoveItemContent:
00256     {
00257       if ( mMoveContentItem )
00258       {
00259         //update map preview if composer map
00260         QgsComposerMap* composerMap = dynamic_cast<QgsComposerMap *>( mMoveContentItem );
00261         if ( composerMap )
00262         {
00263           composerMap->setOffset( 0, 0 );
00264         }
00265 
00266         double moveX = scenePoint.x() - mMoveContentStartPos.x();
00267         double moveY = scenePoint.y() - mMoveContentStartPos.y();
00268 
00269         composition()->beginCommand( mMoveContentItem, tr( "Move item content" ) );
00270         mMoveContentItem->moveContent( -moveX, -moveY );
00271         composition()->endCommand();
00272         mMoveContentItem = 0;
00273       }
00274       break;
00275     }
00276     case AddArrow:
00277       if ( composition() )
00278       {
00279         QPointF scenePoint = mapToScene( e->pos() );
00280         QPointF snappedScenePoint = composition()->snapPointToGrid( scenePoint );
00281         QgsComposerArrow* composerArrow = new QgsComposerArrow( mRubberBandStartPos, QPointF( snappedScenePoint.x(), snappedScenePoint.y() ), composition() );
00282         composition()->addComposerArrow( composerArrow );
00283         scene()->removeItem( mRubberBandLineItem );
00284         delete mRubberBandLineItem;
00285         mRubberBandLineItem = 0;
00286         emit actionFinished();
00287         composition()->pushAddRemoveCommand( composerArrow, tr( "Arrow added" ) );
00288       }
00289       break;
00290 
00291     case AddRectangle:
00292     case AddTriangle:
00293     case AddEllipse:
00294       addShape( mCurrentTool );
00295       break;
00296 
00297     case AddMap:
00298       if ( !mRubberBandItem || mRubberBandItem->rect().width() < 0.1 || mRubberBandItem->rect().width() < 0.1 )
00299       {
00300         if ( mRubberBandItem )
00301         {
00302           scene()->removeItem( mRubberBandItem );
00303           delete mRubberBandItem;
00304           mRubberBandItem = 0;
00305         }
00306         return;
00307       }
00308       if ( composition() )
00309       {
00310         QgsComposerMap* composerMap = new QgsComposerMap( composition(), mRubberBandItem->transform().dx(), mRubberBandItem->transform().dy(), mRubberBandItem->rect().width(), mRubberBandItem->rect().height() );
00311         composition()->addComposerMap( composerMap );
00312         scene()->removeItem( mRubberBandItem );
00313         delete mRubberBandItem;
00314         mRubberBandItem = 0;
00315         emit actionFinished();
00316         composition()->pushAddRemoveCommand( composerMap, tr( "Map added" ) );
00317       }
00318       break;
00319 
00320     default:
00321       break;
00322   }
00323 }
00324 
00325 void QgsComposerView::mouseMoveEvent( QMouseEvent* e )
00326 {
00327   if ( !composition() )
00328   {
00329     return;
00330   }
00331 
00332   if ( e->buttons() == Qt::NoButton )
00333   {
00334     if ( mCurrentTool == Select )
00335     {
00336       QGraphicsView::mouseMoveEvent( e );
00337     }
00338   }
00339   else
00340   {
00341     QPointF scenePoint = mapToScene( e->pos() );
00342 
00343     switch ( mCurrentTool )
00344     {
00345       case Select:
00346         QGraphicsView::mouseMoveEvent( e );
00347         break;
00348 
00349       case AddArrow:
00350       {
00351         if ( mRubberBandLineItem )
00352         {
00353           mRubberBandLineItem->setLine( mRubberBandStartPos.x(), mRubberBandStartPos.y(),  scenePoint.x(),  scenePoint.y() );
00354         }
00355         break;
00356       }
00357 
00358       case AddMap:
00359       case AddRectangle:
00360       case AddTriangle:
00361       case AddEllipse:
00362         //adjust rubber band item
00363       {
00364         double x = 0;
00365         double y = 0;
00366         double width = 0;
00367         double height = 0;
00368 
00369         double dx = scenePoint.x() - mRubberBandStartPos.x();
00370         double dy = scenePoint.y() - mRubberBandStartPos.y();
00371 
00372         if ( dx < 0 )
00373         {
00374           x = scenePoint.x();
00375           width = -dx;
00376         }
00377         else
00378         {
00379           x = mRubberBandStartPos.x();
00380           width = dx;
00381         }
00382 
00383         if ( dy < 0 )
00384         {
00385           y = scenePoint.y();
00386           height = -dy;
00387         }
00388         else
00389         {
00390           y = mRubberBandStartPos.y();
00391           height = dy;
00392         }
00393 
00394         if ( mRubberBandItem )
00395         {
00396           mRubberBandItem->setRect( 0, 0, width, height );
00397           QTransform t;
00398           t.translate( x, y );
00399           mRubberBandItem->setTransform( t );
00400         }
00401         break;
00402       }
00403 
00404       case MoveItemContent:
00405       {
00406         //update map preview if composer map
00407         QgsComposerMap* composerMap = dynamic_cast<QgsComposerMap *>( mMoveContentItem );
00408         if ( composerMap )
00409         {
00410           composerMap->setOffset( scenePoint.x() - mMoveContentStartPos.x(), scenePoint.y() - mMoveContentStartPos.y() );
00411           composerMap->update();
00412         }
00413         break;
00414       }
00415       default:
00416         break;
00417     }
00418   }
00419 }
00420 
00421 void QgsComposerView::mouseDoubleClickEvent( QMouseEvent* e )
00422 {
00423   e->ignore();
00424 }
00425 
00426 void QgsComposerView::keyPressEvent( QKeyEvent * e )
00427 {
00428   if ( e->key() == Qt::Key_Shift )
00429   {
00430     mShiftKeyPressed = true;
00431   }
00432 
00433   if ( !composition() )
00434   {
00435     return;
00436   }
00437 
00438   QList<QgsComposerItem*> composerItemList = composition()->selectedComposerItems();
00439   QList<QgsComposerItem*>::iterator itemIt = composerItemList.begin();
00440 
00441   if ( e->matches( QKeySequence::Copy ) || e->matches( QKeySequence::Cut ) )
00442   {
00443     QDomDocument doc;
00444     QDomElement documentElement = doc.createElement( "ComposerItemClipboard" );
00445     for ( ; itemIt != composerItemList.end(); ++itemIt )
00446     {
00447       // copy each item in a group
00448       QgsComposerItemGroup* itemGroup = dynamic_cast<QgsComposerItemGroup*>( *itemIt );
00449       if ( itemGroup && composition() )
00450       {
00451         QSet<QgsComposerItem*> groupedItems = itemGroup->items();
00452         QSet<QgsComposerItem*>::iterator it = groupedItems.begin();
00453         for ( ; it != groupedItems.end(); ++it )
00454         {
00455           ( *it )->writeXML( documentElement, doc );
00456         }
00457       }
00458       ( *itemIt )->writeXML( documentElement, doc );
00459       if ( e->matches( QKeySequence::Cut ) )
00460       {
00461         composition()->removeComposerItem( *itemIt );
00462       }
00463     }
00464     doc.appendChild( documentElement );
00465     QMimeData *mimeData = new QMimeData;
00466     mimeData->setData( "text/xml", doc.toByteArray() );
00467     QClipboard *clipboard = QApplication::clipboard();
00468     clipboard->setMimeData( mimeData );
00469   }
00470 
00471   if ( e->matches( QKeySequence::Paste ) )
00472   {
00473     QDomDocument doc;
00474     QClipboard *clipboard = QApplication::clipboard();
00475     if ( doc.setContent( clipboard->mimeData()->data( "text/xml" ) ) )
00476     {
00477       QDomElement docElem = doc.documentElement();
00478       if ( docElem.tagName() == "ComposerItemClipboard" )
00479       {
00480         if ( composition() )
00481         {
00482           QPointF pt = mapToScene( mapFromGlobal( QCursor::pos() ) );
00483           composition()->addItemsFromXML( docElem, doc, 0, true, &pt );
00484         }
00485       }
00486     }
00487   }
00488 
00489   //delete selected items
00490   if ( e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace )
00491   {
00492     for ( ; itemIt != composerItemList.end(); ++itemIt )
00493     {
00494       if ( composition() )
00495       {
00496         composition()->removeComposerItem( *itemIt );
00497       }
00498     }
00499   }
00500 
00501   else if ( e->key() == Qt::Key_Left )
00502   {
00503     for ( ; itemIt != composerItemList.end(); ++itemIt )
00504     {
00505       ( *itemIt )->move( -1.0, 0.0 );
00506     }
00507   }
00508   else if ( e->key() == Qt::Key_Right )
00509   {
00510     for ( ; itemIt != composerItemList.end(); ++itemIt )
00511     {
00512       ( *itemIt )->move( 1.0, 0.0 );
00513     }
00514   }
00515   else if ( e->key() == Qt::Key_Down )
00516   {
00517     for ( ; itemIt != composerItemList.end(); ++itemIt )
00518     {
00519       ( *itemIt )->move( 0.0, 1.0 );
00520     }
00521   }
00522   else if ( e->key() == Qt::Key_Up )
00523   {
00524     for ( ; itemIt != composerItemList.end(); ++itemIt )
00525     {
00526       ( *itemIt )->move( 0.0, -1.0 );
00527     }
00528   }
00529 }
00530 
00531 void QgsComposerView::keyReleaseEvent( QKeyEvent * e )
00532 {
00533   if ( e->key() == Qt::Key_Shift )
00534   {
00535     mShiftKeyPressed = false;
00536   }
00537 }
00538 
00539 void QgsComposerView::wheelEvent( QWheelEvent* event )
00540 {
00541   QPointF scenePoint = mapToScene( event->pos() );
00542 
00543   //select topmost item at position of event
00544   QgsComposerItem* theItem = composition()->composerItemAt( scenePoint );
00545   if ( theItem )
00546   {
00547     if ( theItem->isSelected() )
00548     {
00549       QPointF itemPoint = theItem->mapFromScene( scenePoint );
00550       theItem->beginCommand( tr( "Zoom item content" ) );
00551       theItem->zoomContent( event->delta(), itemPoint.x(), itemPoint.y() );
00552       theItem->endCommand();
00553     }
00554   }
00555 }
00556 
00557 void QgsComposerView::paintEvent( QPaintEvent* event )
00558 {
00559   if ( mPaintingEnabled )
00560   {
00561     QGraphicsView::paintEvent( event );
00562     event->accept();
00563   }
00564   else
00565   {
00566     event->ignore();
00567   }
00568 }
00569 
00570 void QgsComposerView::hideEvent( QHideEvent* e )
00571 {
00572   emit( composerViewHide( this ) );
00573   e->ignore();
00574 }
00575 
00576 void QgsComposerView::showEvent( QShowEvent* e )
00577 {
00578   emit( composerViewShow( this ) );
00579   e->ignore();
00580 }
00581 
00582 void QgsComposerView::setComposition( QgsComposition* c )
00583 {
00584   setScene( c );
00585 }
00586 
00587 QgsComposition* QgsComposerView::composition()
00588 {
00589   if ( scene() )
00590   {
00591     QgsComposition* c = dynamic_cast<QgsComposition *>( scene() );
00592     if ( c )
00593     {
00594       return c;
00595     }
00596   }
00597   return 0;
00598 }
00599 
00600 void QgsComposerView::groupItems()
00601 {
00602   if ( !composition() )
00603   {
00604     return;
00605   }
00606 
00607   QList<QgsComposerItem*> selectionList = composition()->selectedComposerItems();
00608   if ( selectionList.size() < 2 )
00609   {
00610     return; //not enough items for a group
00611   }
00612   QgsComposerItemGroup* itemGroup = new QgsComposerItemGroup( composition() );
00613 
00614   QList<QgsComposerItem*>::iterator itemIter = selectionList.begin();
00615   for ( ; itemIter != selectionList.end(); ++itemIter )
00616   {
00617     itemGroup->addItem( *itemIter );
00618   }
00619 
00620   composition()->addItem( itemGroup );
00621   itemGroup->setSelected( true );
00622   emit selectedItemChanged( itemGroup );
00623 }
00624 
00625 void QgsComposerView::ungroupItems()
00626 {
00627   if ( !composition() )
00628   {
00629     return;
00630   }
00631 
00632   QList<QgsComposerItem*> selectionList = composition()->selectedComposerItems();
00633   QList<QgsComposerItem*>::iterator itemIter = selectionList.begin();
00634   for ( ; itemIter != selectionList.end(); ++itemIter )
00635   {
00636     QgsComposerItemGroup* itemGroup = dynamic_cast<QgsComposerItemGroup *>( *itemIter );
00637     if ( itemGroup )
00638     {
00639       itemGroup->removeItems();
00640       composition()->removeItem( *itemIter );
00641       delete( *itemIter );
00642       emit itemRemoved( *itemIter );
00643     }
00644   }
00645 }
00646 
00647 QMainWindow* QgsComposerView::composerWindow()
00648 {
00649   QMainWindow* composerObject = 0;
00650   QObject* currentObject = parent();
00651   if ( !currentObject )
00652   {
00653     return qobject_cast<QMainWindow *>( currentObject );
00654   }
00655 
00656   while ( true )
00657   {
00658     composerObject = qobject_cast<QMainWindow*>( currentObject );
00659     if ( composerObject || currentObject->parent() == 0 )
00660     {
00661       return composerObject;
00662     }
00663     currentObject = currentObject->parent();
00664   }
00665 
00666   return 0;
00667 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines