Quantum GIS API Documentation  1.8
src/core/composer/qgscomposition.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                               qgscomposition.cpp
00003                              -------------------
00004     begin                : January 2005
00005     copyright            : (C) 2005 by Radim Blazek
00006     email                : blazek@itc.it
00007  ***************************************************************************/
00008 /***************************************************************************
00009  *                                                                         *
00010  *   This program is free software; you can redistribute it and/or modify  *
00011  *   it under the terms of the GNU General Public License as published by  *
00012  *   the Free Software Foundation; either version 2 of the License, or     *
00013  *   (at your option) any later version.                                   *
00014  *                                                                         *
00015  ***************************************************************************/
00016 
00017 #include "qgscomposition.h"
00018 #include "qgscomposeritem.h"
00019 #include "qgspaperitem.h"
00020 #include "qgscomposerarrow.h"
00021 #include "qgscomposerlabel.h"
00022 #include "qgscomposerlegend.h"
00023 #include "qgscomposermap.h"
00024 #include "qgscomposeritemgroup.h"
00025 #include "qgscomposerpicture.h"
00026 #include "qgscomposerscalebar.h"
00027 #include "qgscomposershape.h"
00028 #include "qgscomposerattributetable.h"
00029 #include "qgslogger.h"
00030 #include <QDomDocument>
00031 #include <QDomElement>
00032 #include <QGraphicsRectItem>
00033 #include <QSettings>
00034 
00035 QgsComposition::QgsComposition( QgsMapRenderer* mapRenderer ):
00036     QGraphicsScene( 0 ), mMapRenderer( mapRenderer ), mPlotStyle( QgsComposition::Preview ), mPaperItem( 0 ), mPrintAsRaster( false ), mSelectionTolerance( 0.0 ),
00037     mSnapToGrid( false ), mSnapGridResolution( 0.0 ), mSnapGridOffsetX( 0.0 ), mSnapGridOffsetY( 0.0 ), mActiveCommand( 0 )
00038 {
00039   setBackgroundBrush( Qt::gray );
00040 
00041   //set paper item
00042   mPaperItem = new QgsPaperItem( 0, 0, 297, 210, this ); //default size A4
00043   mPaperItem->setBrush( Qt::white );
00044   addItem( mPaperItem );
00045   mPaperItem->setZValue( 0 );
00046   mPrintResolution = 300; //hardcoded default
00047   loadSettings();
00048 }
00049 
00050 QgsComposition::QgsComposition():
00051     QGraphicsScene( 0 ), mMapRenderer( 0 ), mPlotStyle( QgsComposition::Preview ), mPaperItem( 0 ), mPrintAsRaster( false ),
00052     mSelectionTolerance( 0.0 ), mSnapToGrid( false ), mSnapGridResolution( 0.0 ), mSnapGridOffsetX( 0.0 ), mSnapGridOffsetY( 0.0 ), mActiveCommand( 0 )
00053 {
00054   loadSettings();
00055 }
00056 
00057 QgsComposition::~QgsComposition()
00058 {
00059   delete mPaperItem;
00060 
00061   // make sure that all composer items are removed before
00062   // this class is deconstructed - to avoid segfaults
00063   // when composer items access in destructor composition that isn't valid anymore
00064   clear();
00065 }
00066 
00067 void QgsComposition::setPaperSize( double width, double height )
00068 {
00069   if ( mPaperItem )
00070   {
00071     mPaperItem->setRect( QRectF( 0, 0, width, height ) );
00072     emit paperSizeChanged();
00073   }
00074 }
00075 
00076 double QgsComposition::paperHeight() const
00077 {
00078   return mPaperItem->rect().height();
00079 }
00080 
00081 double QgsComposition::paperWidth() const
00082 {
00083   return mPaperItem->rect().width();
00084 }
00085 
00086 QgsComposerItem* QgsComposition::composerItemAt( const QPointF & position )
00087 {
00088   QList<QGraphicsItem*> itemList;
00089   if ( mSelectionTolerance <= 0.0 )
00090   {
00091     itemList = items( position );
00092   }
00093   else
00094   {
00095     itemList = items( QRectF( position.x() - mSelectionTolerance, position.y() - mSelectionTolerance, 2 * mSelectionTolerance, 2 * mSelectionTolerance ),
00096                       Qt::IntersectsItemShape, Qt::DescendingOrder );
00097   }
00098   QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
00099 
00100   for ( ; itemIt != itemList.end(); ++itemIt )
00101   {
00102     QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem *>( *itemIt );
00103     if ( composerItem && composerItem != mPaperItem )
00104     {
00105       return composerItem;
00106     }
00107   }
00108   return 0;
00109 }
00110 
00111 QList<QgsComposerItem*> QgsComposition::selectedComposerItems()
00112 {
00113   QList<QgsComposerItem*> composerItemList;
00114 
00115   QList<QGraphicsItem *> graphicsItemList = selectedItems();
00116   QList<QGraphicsItem *>::iterator itemIter = graphicsItemList.begin();
00117 
00118   for ( ; itemIter != graphicsItemList.end(); ++itemIter )
00119   {
00120     QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem *>( *itemIter );
00121     if ( composerItem )
00122     {
00123       composerItemList.push_back( composerItem );
00124     }
00125   }
00126 
00127   return composerItemList;
00128 }
00129 
00130 QList<const QgsComposerMap*> QgsComposition::composerMapItems() const
00131 {
00132   QList<const QgsComposerMap*> resultList;
00133 
00134   QList<QGraphicsItem *> itemList = items();
00135   QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
00136   for ( ; itemIt != itemList.end(); ++itemIt )
00137   {
00138     const QgsComposerMap* composerMap = dynamic_cast<const QgsComposerMap *>( *itemIt );
00139     if ( composerMap )
00140     {
00141       resultList.push_back( composerMap );
00142     }
00143   }
00144 
00145   return resultList;
00146 }
00147 
00148 const QgsComposerMap* QgsComposition::getComposerMapById( int id ) const
00149 {
00150   QList<const QgsComposerMap*> resultList;
00151 
00152   QList<QGraphicsItem *> itemList = items();
00153   QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
00154   for ( ; itemIt != itemList.end(); ++itemIt )
00155   {
00156     const QgsComposerMap* composerMap = dynamic_cast<const QgsComposerMap *>( *itemIt );
00157     if ( composerMap )
00158     {
00159       if ( composerMap->id() == id )
00160       {
00161         return composerMap;
00162       }
00163     }
00164   }
00165 
00166   return 0;
00167 }
00168 
00169 int QgsComposition::pixelFontSize( double pointSize ) const
00170 {
00171   //in QgsComposition, one unit = one mm
00172   double sizeMillimeters = pointSize * 0.3527;
00173   return ( sizeMillimeters + 0.5 ); //round to nearest mm
00174 }
00175 
00176 double QgsComposition::pointFontSize( int pixelSize ) const
00177 {
00178   double sizePoint = pixelSize / 0.3527;
00179   return sizePoint;
00180 }
00181 
00182 bool QgsComposition::writeXML( QDomElement& composerElem, QDomDocument& doc )
00183 {
00184   if ( composerElem.isNull() )
00185   {
00186     return false;
00187   }
00188 
00189   QDomElement compositionElem = doc.createElement( "Composition" );
00190   if ( mPaperItem )
00191   {
00192     compositionElem.setAttribute( "paperWidth", QString::number( mPaperItem->rect().width() ) );
00193     compositionElem.setAttribute( "paperHeight", QString::number( mPaperItem->rect().height() ) );
00194   }
00195 
00196   //snapping
00197   if ( mSnapToGrid )
00198   {
00199     compositionElem.setAttribute( "snapping", "1" );
00200   }
00201   else
00202   {
00203     compositionElem.setAttribute( "snapping", "0" );
00204   }
00205   compositionElem.setAttribute( "snapGridResolution", QString::number( mSnapGridResolution ) );
00206   compositionElem.setAttribute( "snapGridOffsetX", QString::number( mSnapGridOffsetX ) );
00207   compositionElem.setAttribute( "snapGridOffsetY", QString::number( mSnapGridOffsetY ) );
00208 
00209   compositionElem.setAttribute( "printResolution", mPrintResolution );
00210   compositionElem.setAttribute( "printAsRaster", mPrintAsRaster );
00211 
00212   composerElem.appendChild( compositionElem );
00213 
00214   return true;
00215 }
00216 
00217 bool QgsComposition::readXML( const QDomElement& compositionElem, const QDomDocument& doc )
00218 {
00219   Q_UNUSED( doc );
00220   if ( compositionElem.isNull() )
00221   {
00222     return false;
00223   }
00224 
00225   //create paper item
00226   bool widthConversionOk, heightConversionOk;
00227   double paperWidth = compositionElem.attribute( "paperWidth" ).toDouble( &widthConversionOk );
00228   double paperHeight = compositionElem.attribute( "paperHeight" ).toDouble( &heightConversionOk );
00229 
00230   if ( widthConversionOk && heightConversionOk )
00231   {
00232     delete mPaperItem;
00233     mPaperItem = new QgsPaperItem( 0, 0, paperWidth, paperHeight, this );
00234     mPaperItem->setBrush( Qt::white );
00235     addItem( mPaperItem );
00236     mPaperItem->setZValue( 0 );
00237   }
00238 
00239   //snapping
00240   if ( compositionElem.attribute( "snapping" ) == "0" )
00241   {
00242     mSnapToGrid = false;
00243   }
00244   else
00245   {
00246     mSnapToGrid = true;
00247   }
00248   mSnapGridResolution = compositionElem.attribute( "snapGridResolution" ).toDouble();
00249   mSnapGridOffsetX = compositionElem.attribute( "snapGridOffsetX" ).toDouble();
00250   mSnapGridOffsetY = compositionElem.attribute( "snapGridOffsetY" ).toDouble();
00251   mPrintAsRaster = compositionElem.attribute( "printAsRaster" ).toInt();
00252 
00253   mPrintResolution = compositionElem.attribute( "printResolution", "300" ).toInt();
00254 
00255   if ( mPaperItem )
00256   {
00257     mPaperItem->update();
00258   }
00259 
00260   return true;
00261 }
00262 
00263 void QgsComposition::addItemsFromXML( const QDomElement& elem, const QDomDocument& doc, QMap< QgsComposerMap*, int >* mapsToRestore,
00264                                       bool addUndoCommands, QPointF* pos )
00265 {
00266   QDomNodeList composerLabelList = elem.elementsByTagName( "ComposerLabel" );
00267   for ( int i = 0; i < composerLabelList.size(); ++i )
00268   {
00269     QDomElement currentComposerLabelElem = composerLabelList.at( i ).toElement();
00270     QgsComposerLabel* newLabel = new QgsComposerLabel( this );
00271     newLabel->readXML( currentComposerLabelElem, doc );
00272     if ( pos )
00273     {
00274       newLabel->setItemPosition( pos->x(), pos->y() );
00275     }
00276     addComposerLabel( newLabel );
00277     if ( addUndoCommands )
00278     {
00279       pushAddRemoveCommand( newLabel, tr( "Label added" ) );
00280     }
00281   }
00282   // map
00283   QDomNodeList composerMapList = elem.elementsByTagName( "ComposerMap" );
00284   for ( int i = 0; i < composerMapList.size(); ++i )
00285   {
00286     QDomElement currentComposerMapElem = composerMapList.at( i ).toElement();
00287     QgsComposerMap* newMap = new QgsComposerMap( this );
00288     newMap->readXML( currentComposerMapElem, doc );
00289 
00290     if ( mapsToRestore )
00291     {
00292       mapsToRestore->insert( newMap, ( int )( newMap->previewMode() ) );
00293       newMap->setPreviewMode( QgsComposerMap::Rectangle );
00294     }
00295     addComposerMap( newMap, false );
00296 
00297     if ( pos )
00298     {
00299       newMap->setItemPosition( pos->x(), pos->y() );
00300     }
00301 
00302     if ( addUndoCommands )
00303     {
00304       pushAddRemoveCommand( newMap, tr( "Map added" ) );
00305     }
00306   }
00307   // arrow
00308   QDomNodeList composerArrowList = elem.elementsByTagName( "ComposerArrow" );
00309   for ( int i = 0; i < composerArrowList.size(); ++i )
00310   {
00311     QDomElement currentComposerArrowElem = composerArrowList.at( i ).toElement();
00312     QgsComposerArrow* newArrow = new QgsComposerArrow( this );
00313     newArrow->readXML( currentComposerArrowElem, doc );
00314     if ( pos )
00315     {
00316       newArrow->setItemPosition( pos->x(), pos->y() );
00317     }
00318     addComposerArrow( newArrow );
00319     if ( addUndoCommands )
00320     {
00321       pushAddRemoveCommand( newArrow, tr( "Arrow added" ) );
00322     }
00323   }
00324   // scalebar
00325   QDomNodeList composerScaleBarList = elem.elementsByTagName( "ComposerScaleBar" );
00326   for ( int i = 0; i < composerScaleBarList.size(); ++i )
00327   {
00328     QDomElement currentComposerScaleBarElem = composerScaleBarList.at( i ).toElement();
00329     QgsComposerScaleBar* newScaleBar = new QgsComposerScaleBar( this );
00330     newScaleBar->readXML( currentComposerScaleBarElem, doc );
00331     if ( pos )
00332     {
00333       newScaleBar->setItemPosition( pos->x(), pos->y() );
00334     }
00335     addComposerScaleBar( newScaleBar );
00336     if ( addUndoCommands )
00337     {
00338       pushAddRemoveCommand( newScaleBar, tr( "Scale bar added" ) );
00339     }
00340   }
00341   // shape
00342   QDomNodeList composerShapeList = elem.elementsByTagName( "ComposerShape" );
00343   for ( int i = 0; i < composerShapeList.size(); ++i )
00344   {
00345     QDomElement currentComposerShapeElem = composerShapeList.at( i ).toElement();
00346     QgsComposerShape* newShape = new QgsComposerShape( this );
00347     newShape->readXML( currentComposerShapeElem, doc );
00348     if ( pos )
00349     {
00350       newShape->setItemPosition( pos->x(), pos->y() );
00351     }
00352     addComposerShape( newShape );
00353     if ( addUndoCommands )
00354     {
00355       pushAddRemoveCommand( newShape, tr( "Shape added" ) );
00356     }
00357   }
00358   // picture
00359   QDomNodeList composerPictureList = elem.elementsByTagName( "ComposerPicture" );
00360   for ( int i = 0; i < composerPictureList.size(); ++i )
00361   {
00362     QDomElement currentComposerPictureElem = composerPictureList.at( i ).toElement();
00363     QgsComposerPicture* newPicture = new QgsComposerPicture( this );
00364     newPicture->readXML( currentComposerPictureElem, doc );
00365     if ( pos )
00366     {
00367       newPicture->setItemPosition( pos->x(), pos->y() );
00368     }
00369     addComposerPicture( newPicture );
00370     if ( addUndoCommands )
00371     {
00372       pushAddRemoveCommand( newPicture, tr( "Picture added" ) );
00373     }
00374   }
00375   // legend
00376   QDomNodeList composerLegendList = elem.elementsByTagName( "ComposerLegend" );
00377   for ( int i = 0; i < composerLegendList.size(); ++i )
00378   {
00379     QDomElement currentComposerLegendElem = composerLegendList.at( i ).toElement();
00380     QgsComposerLegend* newLegend = new QgsComposerLegend( this );
00381     newLegend->readXML( currentComposerLegendElem, doc );
00382     if ( pos )
00383     {
00384       newLegend->setItemPosition( pos->x(), pos->y() );
00385     }
00386     addComposerLegend( newLegend );
00387     if ( addUndoCommands )
00388     {
00389       pushAddRemoveCommand( newLegend, tr( "Legend added" ) );
00390     }
00391   }
00392   // table
00393   QDomNodeList composerTableList = elem.elementsByTagName( "ComposerAttributeTable" );
00394   for ( int i = 0; i < composerTableList.size(); ++i )
00395   {
00396     QDomElement currentComposerTableElem = composerTableList.at( i ).toElement();
00397     QgsComposerAttributeTable* newTable = new QgsComposerAttributeTable( this );
00398     newTable->readXML( currentComposerTableElem, doc );
00399     if ( pos )
00400     {
00401       newTable->setItemPosition( pos->x(), pos->y() );
00402     }
00403     addComposerTable( newTable );
00404     if ( addUndoCommands )
00405     {
00406       pushAddRemoveCommand( newTable, tr( "Table added" ) );
00407     }
00408   }
00409 }
00410 
00411 void QgsComposition::addItemToZList( QgsComposerItem* item )
00412 {
00413   if ( !item )
00414   {
00415     return;
00416   }
00417   mItemZList.push_back( item );
00418   QgsDebugMsg( QString::number( mItemZList.size() ) );
00419   item->setZValue( mItemZList.size() );
00420 }
00421 
00422 void QgsComposition::removeItemFromZList( QgsComposerItem* item )
00423 {
00424   if ( !item )
00425   {
00426     return;
00427   }
00428   mItemZList.removeAll( item );
00429 }
00430 
00431 void QgsComposition::raiseSelectedItems()
00432 {
00433   QList<QgsComposerItem*> selectedItems = selectedComposerItems();
00434   QList<QgsComposerItem*>::iterator it = selectedItems.begin();
00435   for ( ; it != selectedItems.end(); ++it )
00436   {
00437     raiseItem( *it );
00438   }
00439 
00440   //update all positions
00441   updateZValues();
00442   update();
00443 }
00444 
00445 void QgsComposition::raiseItem( QgsComposerItem* item )
00446 {
00447   //search item
00448   QMutableLinkedListIterator<QgsComposerItem*> it( mItemZList );
00449   if ( it.findNext( item ) )
00450   {
00451     if ( it.hasNext() )
00452     {
00453       it.remove();
00454       it.next();
00455       it.insert( item );
00456     }
00457   }
00458 }
00459 
00460 void QgsComposition::lowerSelectedItems()
00461 {
00462   QList<QgsComposerItem*> selectedItems = selectedComposerItems();
00463   QList<QgsComposerItem*>::iterator it = selectedItems.begin();
00464   for ( ; it != selectedItems.end(); ++it )
00465   {
00466     lowerItem( *it );
00467   }
00468 
00469   //update all positions
00470   updateZValues();
00471   update();
00472 }
00473 
00474 void QgsComposition::lowerItem( QgsComposerItem* item )
00475 {
00476   //search item
00477   QMutableLinkedListIterator<QgsComposerItem*> it( mItemZList );
00478   if ( it.findNext( item ) )
00479   {
00480     it.previous();
00481     if ( it.hasPrevious() )
00482     {
00483       it.remove();
00484       it.previous();
00485       it.insert( item );
00486     }
00487   }
00488 }
00489 
00490 void QgsComposition::moveSelectedItemsToTop()
00491 {
00492   QList<QgsComposerItem*> selectedItems = selectedComposerItems();
00493   QList<QgsComposerItem*>::iterator it = selectedItems.begin();
00494 
00495   for ( ; it != selectedItems.end(); ++it )
00496   {
00497     moveItemToTop( *it );
00498   }
00499 
00500   //update all positions
00501   updateZValues();
00502   update();
00503 }
00504 
00505 void QgsComposition::moveItemToTop( QgsComposerItem* item )
00506 {
00507   //search item
00508   QMutableLinkedListIterator<QgsComposerItem*> it( mItemZList );
00509   if ( it.findNext( item ) )
00510   {
00511     it.remove();
00512   }
00513   mItemZList.push_back( item );
00514 }
00515 
00516 void QgsComposition::moveSelectedItemsToBottom()
00517 {
00518   QList<QgsComposerItem*> selectedItems = selectedComposerItems();
00519   QList<QgsComposerItem*>::iterator it = selectedItems.begin();
00520   for ( ; it != selectedItems.end(); ++it )
00521   {
00522     moveItemToBottom( *it );
00523   }
00524 
00525   //update all positions
00526   updateZValues();
00527   update();
00528 }
00529 
00530 void QgsComposition::moveItemToBottom( QgsComposerItem* item )
00531 {
00532   //search item
00533   QMutableLinkedListIterator<QgsComposerItem*> it( mItemZList );
00534   if ( it.findNext( item ) )
00535   {
00536     it.remove();
00537   }
00538   mItemZList.push_front( item );
00539 }
00540 
00541 void QgsComposition::alignSelectedItemsLeft()
00542 {
00543   QList<QgsComposerItem*> selectedItems = selectedComposerItems();
00544   if ( selectedItems.size() < 2 )
00545   {
00546     return;
00547   }
00548 
00549   QRectF selectedItemBBox;
00550   if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
00551   {
00552     return;
00553   }
00554 
00555   double minXCoordinate = selectedItemBBox.left();
00556 
00557   //align items left to minimum x coordinate
00558   QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items left" ) );
00559   QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
00560   for ( ; align_it != selectedItems.end(); ++align_it )
00561   {
00562     QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
00563     subcommand->savePreviousState();
00564     QTransform itemTransform = ( *align_it )->transform();
00565     itemTransform.translate( minXCoordinate - itemTransform.dx(), 0 );
00566     ( *align_it )->setTransform( itemTransform );
00567     subcommand->saveAfterState();
00568   }
00569   mUndoStack.push( parentCommand );
00570 }
00571 
00572 void QgsComposition::alignSelectedItemsHCenter()
00573 {
00574   QList<QgsComposerItem*> selectedItems = selectedComposerItems();
00575   if ( selectedItems.size() < 2 )
00576   {
00577     return;
00578   }
00579 
00580   QRectF selectedItemBBox;
00581   if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
00582   {
00583     return;
00584   }
00585 
00586   double averageXCoord = ( selectedItemBBox.left() + selectedItemBBox.right() ) / 2.0;
00587 
00588   //place items
00589   QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items hcenter" ) );
00590   QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
00591   for ( ; align_it != selectedItems.end(); ++align_it )
00592   {
00593     QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
00594     subcommand->savePreviousState();
00595     QTransform itemTransform = ( *align_it )->transform();
00596     itemTransform.translate( averageXCoord - itemTransform.dx() - ( *align_it )->rect().width() / 2.0, 0 );
00597     ( *align_it )->setTransform( itemTransform );
00598     subcommand->saveAfterState();
00599   }
00600   mUndoStack.push( parentCommand );
00601 }
00602 
00603 void QgsComposition::alignSelectedItemsRight()
00604 {
00605   QList<QgsComposerItem*> selectedItems = selectedComposerItems();
00606   if ( selectedItems.size() < 2 )
00607   {
00608     return;
00609   }
00610 
00611   QRectF selectedItemBBox;
00612   if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
00613   {
00614     return;
00615   }
00616 
00617   double maxXCoordinate = selectedItemBBox.right();
00618 
00619   //align items right to maximum x coordinate
00620   QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items right" ) );
00621   QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
00622   for ( ; align_it != selectedItems.end(); ++align_it )
00623   {
00624     QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
00625     subcommand->savePreviousState();
00626     QTransform itemTransform = ( *align_it )->transform();
00627     itemTransform.translate( maxXCoordinate - itemTransform.dx() - ( *align_it )->rect().width(), 0 );
00628     ( *align_it )->setTransform( itemTransform );
00629     subcommand->saveAfterState();
00630   }
00631   mUndoStack.push( parentCommand );
00632 }
00633 
00634 void QgsComposition::alignSelectedItemsTop()
00635 {
00636   QList<QgsComposerItem*> selectedItems = selectedComposerItems();
00637   if ( selectedItems.size() < 2 )
00638   {
00639     return;
00640   }
00641 
00642   QRectF selectedItemBBox;
00643   if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
00644   {
00645     return;
00646   }
00647 
00648   double minYCoordinate = selectedItemBBox.top();
00649 
00650   QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items top" ) );
00651   QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
00652   for ( ; align_it != selectedItems.end(); ++align_it )
00653   {
00654     QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
00655     subcommand->savePreviousState();
00656     QTransform itemTransform = ( *align_it )->transform();
00657     itemTransform.translate( 0, minYCoordinate - itemTransform.dy() );
00658     ( *align_it )->setTransform( itemTransform );
00659     subcommand->saveAfterState();
00660   }
00661   mUndoStack.push( parentCommand );
00662 }
00663 
00664 void QgsComposition::alignSelectedItemsVCenter()
00665 {
00666   QList<QgsComposerItem*> selectedItems = selectedComposerItems();
00667   if ( selectedItems.size() < 2 )
00668   {
00669     return;
00670   }
00671 
00672   QRectF selectedItemBBox;
00673   if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
00674   {
00675     return;
00676   }
00677 
00678   double averageYCoord = ( selectedItemBBox.top() + selectedItemBBox.bottom() ) / 2.0;
00679   QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items vcenter" ) );
00680   QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
00681   for ( ; align_it != selectedItems.end(); ++align_it )
00682   {
00683     QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
00684     subcommand->savePreviousState();
00685     QTransform itemTransform = ( *align_it )->transform();
00686     itemTransform.translate( 0, averageYCoord - itemTransform.dy() - ( *align_it )->rect().height() / 2 );
00687     ( *align_it )->setTransform( itemTransform );
00688     subcommand->saveAfterState();
00689   }
00690   mUndoStack.push( parentCommand );
00691 }
00692 
00693 void QgsComposition::alignSelectedItemsBottom()
00694 {
00695   QList<QgsComposerItem*> selectedItems = selectedComposerItems();
00696   if ( selectedItems.size() < 2 )
00697   {
00698     return;
00699   }
00700 
00701   QRectF selectedItemBBox;
00702   if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
00703   {
00704     return;
00705   }
00706 
00707   double maxYCoord = selectedItemBBox.bottom();
00708   QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items bottom" ) );
00709   QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
00710   for ( ; align_it != selectedItems.end(); ++align_it )
00711   {
00712     QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
00713     subcommand->savePreviousState();
00714     QTransform itemTransform = ( *align_it )->transform();
00715     itemTransform.translate( 0, maxYCoord - itemTransform.dy() - ( *align_it )->rect().height() );
00716     ( *align_it )->setTransform( itemTransform );
00717     subcommand->saveAfterState();
00718   }
00719   mUndoStack.push( parentCommand );
00720 }
00721 
00722 void QgsComposition::updateZValues()
00723 {
00724   int counter = 1;
00725   QLinkedList<QgsComposerItem*>::iterator it = mItemZList.begin();
00726   QgsComposerItem* currentItem = 0;
00727 
00728   QUndoCommand* parentCommand = new QUndoCommand( tr( "Item z-order changed" ) );
00729   for ( ; it != mItemZList.end(); ++it )
00730   {
00731     currentItem = *it;
00732     if ( currentItem )
00733     {
00734       QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *it, "", parentCommand );
00735       subcommand->savePreviousState();
00736       currentItem->setZValue( counter );
00737       subcommand->saveAfterState();
00738     }
00739     ++counter;
00740   }
00741   mUndoStack.push( parentCommand );
00742 }
00743 
00744 void QgsComposition::sortZList()
00745 {
00746   if ( mItemZList.size() < 2 )
00747   {
00748     return;
00749   }
00750 
00751   QLinkedList<QgsComposerItem*>::const_iterator lIt = mItemZList.constBegin();
00752   QLinkedList<QgsComposerItem*> sortedList;
00753 
00754   for ( ; lIt != mItemZList.constEnd(); ++lIt )
00755   {
00756     QLinkedList<QgsComposerItem*>::iterator insertIt = sortedList.begin();
00757     for ( ; insertIt != sortedList.end(); ++insertIt )
00758     {
00759       if (( *lIt )->zValue() < ( *insertIt )->zValue() )
00760       {
00761         break;
00762       }
00763     }
00764     sortedList.insert( insertIt, ( *lIt ) );
00765   }
00766 
00767   mItemZList = sortedList;
00768 }
00769 
00770 QPointF QgsComposition::snapPointToGrid( const QPointF& scenePoint ) const
00771 {
00772   if ( !mSnapToGrid || mSnapGridResolution <= 0 )
00773   {
00774     return scenePoint;
00775   }
00776 
00777   //snap x coordinate //todo: add support for x- and y- offset
00778   int xRatio = ( int )(( scenePoint.x() - mSnapGridOffsetX ) / mSnapGridResolution + 0.5 );
00779   int yRatio = ( int )(( scenePoint.y() - mSnapGridOffsetY ) / mSnapGridResolution + 0.5 );
00780 
00781   return QPointF( xRatio * mSnapGridResolution + mSnapGridOffsetX, yRatio * mSnapGridResolution + mSnapGridOffsetY );
00782 }
00783 
00784 int QgsComposition::boundingRectOfSelectedItems( QRectF& bRect )
00785 {
00786   QList<QgsComposerItem*> selectedItems = selectedComposerItems();
00787   if ( selectedItems.size() < 1 )
00788   {
00789     return 1;
00790   }
00791 
00792   //set the box to the first item
00793   QgsComposerItem* currentItem = selectedItems.at( 0 );
00794   double minX = currentItem->transform().dx();
00795   double minY = currentItem->transform().dy();
00796   double maxX = minX + currentItem->rect().width();
00797   double maxY = minY + currentItem->rect().height();
00798 
00799   double currentMinX, currentMinY, currentMaxX, currentMaxY;
00800 
00801   for ( int i = 1; i < selectedItems.size(); ++i )
00802   {
00803     currentItem = selectedItems.at( i );
00804     currentMinX = currentItem->transform().dx();
00805     currentMinY = currentItem->transform().dy();
00806     currentMaxX = currentMinX + currentItem->rect().width();
00807     currentMaxY = currentMinY + currentItem->rect().height();
00808 
00809     if ( currentMinX < minX )
00810       minX = currentMinX;
00811     if ( currentMaxX > maxX )
00812       maxX = currentMaxX;
00813     if ( currentMinY < minY )
00814       minY = currentMinY;
00815     if ( currentMaxY > maxY )
00816       maxY = currentMaxY;
00817   }
00818 
00819   bRect.setTopLeft( QPointF( minX, minY ) );
00820   bRect.setBottomRight( QPointF( maxX, maxY ) );
00821   return 0;
00822 }
00823 
00824 void QgsComposition::setSnapToGridEnabled( bool b )
00825 {
00826   mSnapToGrid = b;
00827   if ( mPaperItem )
00828   {
00829     mPaperItem->update();
00830   }
00831   saveSettings();
00832 }
00833 
00834 void QgsComposition::setSnapGridResolution( double r )
00835 {
00836   mSnapGridResolution = r;
00837   if ( mPaperItem )
00838   {
00839     mPaperItem->update();
00840   }
00841   saveSettings();
00842 }
00843 
00844 void QgsComposition::setSnapGridOffsetX( double offset )
00845 {
00846   mSnapGridOffsetX = offset;
00847   if ( mPaperItem )
00848   {
00849     mPaperItem->update();
00850   }
00851   saveSettings();
00852 }
00853 
00854 void QgsComposition::setSnapGridOffsetY( double offset )
00855 {
00856   mSnapGridOffsetY = offset;
00857   if ( mPaperItem )
00858   {
00859     mPaperItem->update();
00860   }
00861   saveSettings();
00862 }
00863 
00864 void QgsComposition::setGridPen( const QPen& p )
00865 {
00866   mGridPen = p;
00867   if ( mPaperItem )
00868   {
00869     mPaperItem->update();
00870   }
00871   saveSettings();
00872 }
00873 
00874 void QgsComposition::setGridStyle( GridStyle s )
00875 {
00876   mGridStyle = s;
00877   if ( mPaperItem )
00878   {
00879     mPaperItem->update();
00880   }
00881   saveSettings();
00882 }
00883 
00884 void QgsComposition::setSelectionTolerance( double tol )
00885 {
00886   mSelectionTolerance = tol;
00887   saveSettings();
00888 }
00889 
00890 void QgsComposition::loadSettings()
00891 {
00892   //read grid style, grid color and pen width from settings
00893   QSettings s;
00894 
00895   QString gridStyleString;
00896   int red, green, blue;
00897   double penWidth;
00898 
00899   gridStyleString = s.value( "/qgis/composerGridStyle", "Dots" ).toString();
00900   penWidth = s.value( "/qgis/composerGridWidth", 0.5 ).toDouble();
00901   red = s.value( "/qgis/composerGridRed", 0 ).toInt();
00902   green = s.value( "/qgis/composerGridGreen", 0 ).toInt();
00903   blue = s.value( "/qgis/composerGridBlue", 0 ).toInt();
00904 
00905   mGridPen.setColor( QColor( red, green, blue ) );
00906   mGridPen.setWidthF( penWidth );
00907 
00908   if ( gridStyleString == "Dots" )
00909   {
00910     mGridStyle = Dots;
00911   }
00912   else if ( gridStyleString == "Crosses" )
00913   {
00914     mGridStyle = Crosses;
00915   }
00916   else
00917   {
00918     mGridStyle = Solid;
00919   }
00920 
00921   mSelectionTolerance = s.value( "/qgis/composerSelectionTolerance", 0.0 ).toDouble();
00922 }
00923 
00924 void QgsComposition::saveSettings()
00925 {
00926   //store grid appearance settings
00927   QSettings s;
00928   s.setValue( "/qgis/composerGridWidth", mGridPen.widthF() );
00929   s.setValue( "/qgis/composerGridRed", mGridPen.color().red() );
00930   s.setValue( "/qgis/composerGridGreen", mGridPen.color().green() );
00931   s.setValue( "/qgis/composerGridBlue", mGridPen.color().blue() );
00932 
00933   if ( mGridStyle == Solid )
00934   {
00935     s.setValue( "/qgis/composerGridStyle", "Solid" );
00936   }
00937   else if ( mGridStyle == Dots )
00938   {
00939     s.setValue( "/qgis/composerGridStyle", "Dots" );
00940   }
00941   else if ( mGridStyle == Crosses )
00942   {
00943     s.setValue( "/qgis/composerGridStyle", "Crosses" );
00944   }
00945 
00946   //store also selection tolerance
00947   s.setValue( "/qgis/composerSelectionTolerance", mSelectionTolerance );
00948 }
00949 
00950 void QgsComposition::beginCommand( QgsComposerItem* item, const QString& commandText, QgsComposerMergeCommand::Context c )
00951 {
00952   delete mActiveCommand;
00953   if ( !item )
00954   {
00955     mActiveCommand = 0;
00956     return;
00957   }
00958 
00959   if ( c == QgsComposerMergeCommand::Unknown )
00960   {
00961     mActiveCommand = new QgsComposerItemCommand( item, commandText );
00962   }
00963   else
00964   {
00965     mActiveCommand = new QgsComposerMergeCommand( c, item, commandText );
00966   }
00967   mActiveCommand->savePreviousState();
00968 }
00969 
00970 void QgsComposition::endCommand()
00971 {
00972   if ( mActiveCommand )
00973   {
00974     mActiveCommand->saveAfterState();
00975     if ( mActiveCommand->containsChange() ) //protect against empty commands
00976     {
00977       mUndoStack.push( mActiveCommand );
00978     }
00979     else
00980     {
00981       delete mActiveCommand;
00982     }
00983     mActiveCommand = 0;
00984   }
00985 }
00986 
00987 void QgsComposition::cancelCommand()
00988 {
00989   delete mActiveCommand;
00990   mActiveCommand = 0;
00991 }
00992 
00993 void QgsComposition::addComposerArrow( QgsComposerArrow* arrow )
00994 {
00995   addItem( arrow );
00996   emit composerArrowAdded( arrow );
00997   clearSelection();
00998   arrow->setSelected( true );
00999   emit selectedItemChanged( arrow );
01000 }
01001 
01002 void QgsComposition::addComposerLabel( QgsComposerLabel* label )
01003 {
01004   addItem( label );
01005   emit composerLabelAdded( label );
01006   clearSelection();
01007   label->setSelected( true );
01008   emit selectedItemChanged( label );
01009 }
01010 
01011 void QgsComposition::addComposerMap( QgsComposerMap* map, bool setDefaultPreviewStyle )
01012 {
01013   addItem( map );
01014   if ( setDefaultPreviewStyle )
01015   {
01016     //set default preview mode to cache. Must be done here between adding composer map to scene and emiting signal
01017     map->setPreviewMode( QgsComposerMap::Cache );
01018   }
01019 
01020   if ( map->previewMode() != QgsComposerMap::Rectangle )
01021   {
01022     map->cache();
01023   }
01024 
01025   emit composerMapAdded( map );
01026   clearSelection();
01027   map->setSelected( true );
01028   emit selectedItemChanged( map );
01029 }
01030 
01031 void QgsComposition::addComposerScaleBar( QgsComposerScaleBar* scaleBar )
01032 {
01033   //take first available map
01034   QList<const QgsComposerMap*> mapItemList = composerMapItems();
01035   if ( mapItemList.size() > 0 )
01036   {
01037     scaleBar->setComposerMap( mapItemList.at( 0 ) );
01038   }
01039   addItem( scaleBar );
01040   emit composerScaleBarAdded( scaleBar );
01041   clearSelection();
01042   scaleBar->setSelected( true );
01043   emit selectedItemChanged( scaleBar );
01044 }
01045 
01046 void QgsComposition::addComposerLegend( QgsComposerLegend* legend )
01047 {
01048   //take first available map
01049   QList<const QgsComposerMap*> mapItemList = composerMapItems();
01050   if ( mapItemList.size() > 0 )
01051   {
01052     legend->setComposerMap( mapItemList.at( 0 ) );
01053   }
01054   addItem( legend );
01055   emit composerLegendAdded( legend );
01056   clearSelection();
01057   legend->setSelected( true );
01058   emit selectedItemChanged( legend );
01059 }
01060 
01061 void QgsComposition::addComposerPicture( QgsComposerPicture* picture )
01062 {
01063   addItem( picture );
01064   emit composerPictureAdded( picture );
01065   clearSelection();
01066   picture->setSelected( true );
01067   emit selectedItemChanged( picture );
01068 }
01069 
01070 void QgsComposition::addComposerShape( QgsComposerShape* shape )
01071 {
01072   addItem( shape );
01073   emit composerShapeAdded( shape );
01074   clearSelection();
01075   shape->setSelected( true );
01076   emit selectedItemChanged( shape );
01077 }
01078 
01079 void QgsComposition::addComposerTable( QgsComposerAttributeTable* table )
01080 {
01081   addItem( table );
01082   emit composerTableAdded( table );
01083   clearSelection();
01084   table->setSelected( true );
01085   emit selectedItemChanged( table );
01086 }
01087 
01088 void QgsComposition::removeComposerItem( QgsComposerItem* item )
01089 {
01090   QgsComposerMap* map = dynamic_cast<QgsComposerMap *>( item );
01091   if ( !map || !map->isDrawing() ) //don't delete a composer map while it draws
01092   {
01093     removeItem( item );
01094     QgsComposerItemGroup* itemGroup = dynamic_cast<QgsComposerItemGroup*>( item );
01095     if ( itemGroup )
01096     {
01097       //add add/remove item command for every item in the group
01098       QUndoCommand* parentCommand = new QUndoCommand( tr( "Remove item group" ) );
01099 
01100       QSet<QgsComposerItem*> groupedItems = itemGroup->items();
01101       QSet<QgsComposerItem*>::iterator it = groupedItems.begin();
01102       for ( ; it != groupedItems.end(); ++it )
01103       {
01104         QgsAddRemoveItemCommand* subcommand = new QgsAddRemoveItemCommand( QgsAddRemoveItemCommand::Removed, *it, this, "", parentCommand );
01105         connectAddRemoveCommandSignals( subcommand );
01106         emit itemRemoved( *it );
01107       }
01108 
01109       undoStack()->push( parentCommand );
01110       delete itemGroup;
01111       emit itemRemoved( itemGroup );
01112     }
01113     else
01114     {
01115       emit itemRemoved( item );
01116       pushAddRemoveCommand( item, tr( "Item deleted" ), QgsAddRemoveItemCommand::Removed );
01117     }
01118   }
01119 }
01120 
01121 void QgsComposition::pushAddRemoveCommand( QgsComposerItem* item, const QString& text, QgsAddRemoveItemCommand::State state )
01122 {
01123   QgsAddRemoveItemCommand* c = new QgsAddRemoveItemCommand( state, item, this, text );
01124   connectAddRemoveCommandSignals( c );
01125   undoStack()->push( c );
01126 }
01127 
01128 void QgsComposition::connectAddRemoveCommandSignals( QgsAddRemoveItemCommand* c )
01129 {
01130   if ( !c )
01131   {
01132     return;
01133   }
01134 
01135   QObject::connect( c, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SIGNAL( itemRemoved( QgsComposerItem* ) ) );
01136   QObject::connect( c, SIGNAL( itemAdded( QgsComposerItem* ) ), this, SLOT( sendItemAddedSignal( QgsComposerItem* ) ) );
01137 }
01138 
01139 void QgsComposition::sendItemAddedSignal( QgsComposerItem* item )
01140 {
01141   //cast and send proper signal
01142   item->setSelected( true );
01143   QgsComposerArrow* arrow = dynamic_cast<QgsComposerArrow*>( item );
01144   if ( arrow )
01145   {
01146     emit composerArrowAdded( arrow );
01147     emit selectedItemChanged( arrow );
01148     return;
01149   }
01150   QgsComposerLabel* label = dynamic_cast<QgsComposerLabel*>( item );
01151   if ( label )
01152   {
01153     emit composerLabelAdded( label );
01154     emit selectedItemChanged( label );
01155     return;
01156   }
01157   QgsComposerMap* map = dynamic_cast<QgsComposerMap*>( item );
01158   if ( map )
01159   {
01160     emit composerMapAdded( map );
01161     emit selectedItemChanged( map );
01162     return;
01163   }
01164   QgsComposerScaleBar* scalebar = dynamic_cast<QgsComposerScaleBar*>( item );
01165   if ( scalebar )
01166   {
01167     emit composerScaleBarAdded( scalebar );
01168     emit selectedItemChanged( scalebar );
01169     return;
01170   }
01171   QgsComposerLegend* legend = dynamic_cast<QgsComposerLegend*>( item );
01172   if ( legend )
01173   {
01174     emit composerLegendAdded( legend );
01175     emit selectedItemChanged( legend );
01176     return;
01177   }
01178   QgsComposerPicture* picture = dynamic_cast<QgsComposerPicture*>( item );
01179   if ( picture )
01180   {
01181     emit composerPictureAdded( picture );
01182     emit selectedItemChanged( picture );
01183     return;
01184   }
01185   QgsComposerShape* shape = dynamic_cast<QgsComposerShape*>( item );
01186   if ( shape )
01187   {
01188     emit composerShapeAdded( shape );
01189     emit selectedItemChanged( shape );
01190     return;
01191   }
01192   QgsComposerAttributeTable* table = dynamic_cast<QgsComposerAttributeTable*>( item );
01193   if ( table )
01194   {
01195     emit composerTableAdded( table );
01196     emit selectedItemChanged( table );
01197     return;
01198   }
01199 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines