Quantum GIS API Documentation
1.8
|
00001 /*************************************************************************** 00002 qgscomposition.cpp 00003 ------------------- 00004 begin : January 2005 00005 copyright : (C) 2005 by Radim Blazek 00006 email : [email protected] 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 }