|
QGIS API Documentation
master-59fd5e0
|
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 <stdexcept> 00018 00019 #include "qgscomposition.h" 00020 #include "qgscomposerarrow.h" 00021 #include "qgscomposerframe.h" 00022 #include "qgscomposerhtml.h" 00023 #include "qgscomposerlabel.h" 00024 #include "qgscomposerlegend.h" 00025 #include "qgscomposermap.h" 00026 #include "qgscomposeritemgroup.h" 00027 #include "qgscomposerpicture.h" 00028 #include "qgscomposerscalebar.h" 00029 #include "qgscomposershape.h" 00030 #include "qgscomposerlabel.h" 00031 #include "qgscomposerattributetable.h" 00032 #include "qgsaddremovemultiframecommand.h" 00033 #include "qgscomposermultiframecommand.h" 00034 #include "qgslogger.h" 00035 #include "qgspaintenginehack.h" 00036 #include "qgspaperitem.h" 00037 #include "qgsproject.h" 00038 #include "qgsgeometry.h" 00039 #include "qgsvectorlayer.h" 00040 #include "qgsvectordataprovider.h" 00041 #include "qgsexpression.h" 00042 #include <QDomDocument> 00043 #include <QDomElement> 00044 #include <QGraphicsRectItem> 00045 #include <QPainter> 00046 #include <QPrinter> 00047 #include <QSettings> 00048 #include <QDir> 00049 00050 00051 QgsComposition::QgsComposition( QgsMapRenderer* mapRenderer ) 00052 : QGraphicsScene( 0 ), 00053 mMapRenderer( mapRenderer ), 00054 mPlotStyle( QgsComposition::Preview ), 00055 mPageWidth( 297 ), 00056 mPageHeight( 210 ), 00057 mSpaceBetweenPages( 10 ), 00058 mPrintAsRaster( false ), 00059 mUseAdvancedEffects( true ), 00060 mSelectionTolerance( 0.0 ), 00061 mSnapToGrid( false ), 00062 mSnapGridResolution( 10.0 ), 00063 mSnapGridOffsetX( 0.0 ), 00064 mSnapGridOffsetY( 0.0 ), 00065 mAlignmentSnap( true ), 00066 mAlignmentSnapTolerance( 2 ), 00067 mActiveItemCommand( 0 ), 00068 mActiveMultiFrameCommand( 0 ), 00069 mAtlasComposition( this ) 00070 { 00071 setBackgroundBrush( Qt::gray ); 00072 addPaperItem(); 00073 00074 mPrintResolution = 300; //hardcoded default 00075 loadSettings(); 00076 } 00077 00078 QgsComposition::QgsComposition() 00079 : QGraphicsScene( 0 ), 00080 mMapRenderer( 0 ), 00081 mPlotStyle( QgsComposition::Preview ), 00082 mPageWidth( 297 ), 00083 mPageHeight( 210 ), 00084 mSpaceBetweenPages( 10 ), 00085 mPrintAsRaster( false ), 00086 mUseAdvancedEffects( true ), 00087 mSelectionTolerance( 0.0 ), 00088 mSnapToGrid( false ), 00089 mSnapGridResolution( 10.0 ), 00090 mSnapGridOffsetX( 0.0 ), 00091 mSnapGridOffsetY( 0.0 ), 00092 mAlignmentSnap( true ), 00093 mAlignmentSnapTolerance( 2 ), 00094 mActiveItemCommand( 0 ), 00095 mActiveMultiFrameCommand( 0 ), 00096 mAtlasComposition( this ) 00097 { 00098 loadSettings(); 00099 00100 } 00101 00102 QgsComposition::~QgsComposition() 00103 { 00104 removePaperItems(); 00105 deleteAndRemoveMultiFrames(); 00106 00107 // make sure that all composer items are removed before 00108 // this class is deconstructed - to avoid segfaults 00109 // when composer items access in destructor composition that isn't valid anymore 00110 clear(); 00111 delete mActiveItemCommand; 00112 delete mActiveMultiFrameCommand; 00113 } 00114 00115 void QgsComposition::setPaperSize( double width, double height ) 00116 { 00117 mPageWidth = width; 00118 mPageHeight = height; 00119 double currentY = 0; 00120 for ( int i = 0; i < mPages.size(); ++i ) 00121 { 00122 mPages.at( i )->setSceneRect( QRectF( 0, currentY, width, height ) ); 00123 currentY += ( height + mSpaceBetweenPages ); 00124 } 00125 } 00126 00127 double QgsComposition::paperHeight() const 00128 { 00129 return mPageHeight; 00130 } 00131 00132 double QgsComposition::paperWidth() const 00133 { 00134 return mPageWidth; 00135 } 00136 00137 void QgsComposition::setNumPages( int pages ) 00138 { 00139 int currentPages = numPages(); 00140 int diff = pages - currentPages; 00141 if ( diff >= 0 ) 00142 { 00143 for ( int i = 0; i < diff; ++i ) 00144 { 00145 addPaperItem(); 00146 } 00147 } 00148 else 00149 { 00150 diff = -diff; 00151 for ( int i = 0; i < diff; ++i ) 00152 { 00153 delete mPages.last(); 00154 mPages.removeLast(); 00155 } 00156 } 00157 00158 // update the corresponding variable 00159 QgsExpression::setSpecialColumn( "$numpages", QVariant(( int )numPages() ) ); 00160 00161 emit nPagesChanged(); 00162 } 00163 00164 int QgsComposition::numPages() const 00165 { 00166 return mPages.size(); 00167 } 00168 00169 QgsComposerItem* QgsComposition::composerItemAt( const QPointF & position ) 00170 { 00171 QList<QGraphicsItem*> itemList; 00172 if ( mSelectionTolerance <= 0.0 ) 00173 { 00174 itemList = items( position ); 00175 } 00176 else 00177 { 00178 itemList = items( QRectF( position.x() - mSelectionTolerance, position.y() - mSelectionTolerance, 2 * mSelectionTolerance, 2 * mSelectionTolerance ), 00179 Qt::IntersectsItemShape, Qt::DescendingOrder ); 00180 } 00181 QList<QGraphicsItem *>::iterator itemIt = itemList.begin(); 00182 00183 for ( ; itemIt != itemList.end(); ++itemIt ) 00184 { 00185 QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem *>( *itemIt ); 00186 QgsPaperItem* paperItem = dynamic_cast<QgsPaperItem*>( *itemIt ); 00187 if ( composerItem && !paperItem ) 00188 { 00189 return composerItem; 00190 } 00191 } 00192 return 0; 00193 } 00194 00195 int QgsComposition::pageNumberAt( const QPointF& position ) const 00196 { 00197 return position.y() / ( paperHeight() + spaceBetweenPages() ); 00198 } 00199 00200 int QgsComposition::itemPageNumber( const QgsComposerItem* item ) const 00201 { 00202 return pageNumberAt( QPointF( item->transform().dx(), item->transform().dy() ) ); 00203 } 00204 00205 QList<QgsComposerItem*> QgsComposition::selectedComposerItems() 00206 { 00207 QList<QgsComposerItem*> composerItemList; 00208 00209 QList<QGraphicsItem *> graphicsItemList = selectedItems(); 00210 QList<QGraphicsItem *>::iterator itemIter = graphicsItemList.begin(); 00211 00212 for ( ; itemIter != graphicsItemList.end(); ++itemIter ) 00213 { 00214 QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem *>( *itemIter ); 00215 if ( composerItem ) 00216 { 00217 composerItemList.push_back( composerItem ); 00218 } 00219 } 00220 00221 return composerItemList; 00222 } 00223 00224 QList<const QgsComposerMap*> QgsComposition::composerMapItems() const 00225 { 00226 QList<const QgsComposerMap*> resultList; 00227 00228 QList<QGraphicsItem *> itemList = items(); 00229 QList<QGraphicsItem *>::iterator itemIt = itemList.begin(); 00230 for ( ; itemIt != itemList.end(); ++itemIt ) 00231 { 00232 const QgsComposerMap* composerMap = dynamic_cast<const QgsComposerMap *>( *itemIt ); 00233 if ( composerMap ) 00234 { 00235 resultList.push_back( composerMap ); 00236 } 00237 } 00238 00239 return resultList; 00240 } 00241 00242 const QgsComposerMap* QgsComposition::getComposerMapById( int id ) const 00243 { 00244 QList<QGraphicsItem *> itemList = items(); 00245 QList<QGraphicsItem *>::iterator itemIt = itemList.begin(); 00246 for ( ; itemIt != itemList.end(); ++itemIt ) 00247 { 00248 const QgsComposerMap* composerMap = dynamic_cast<const QgsComposerMap *>( *itemIt ); 00249 if ( composerMap ) 00250 { 00251 if ( composerMap->id() == id ) 00252 { 00253 return composerMap; 00254 } 00255 } 00256 } 00257 return 0; 00258 } 00259 00260 const QgsComposerHtml* QgsComposition::getComposerHtmlByItem( QgsComposerItem *item ) const 00261 { 00262 // an html item will be a composer frame and if it is we can try to get 00263 // its multiframe parent and then try to cast that to a composer html 00264 const QgsComposerFrame* composerFrame = 00265 dynamic_cast<const QgsComposerFrame *>( item ); 00266 if ( composerFrame ) 00267 { 00268 const QgsComposerMultiFrame * mypMultiFrame = composerFrame->multiFrame(); 00269 const QgsComposerHtml* composerHtml = 00270 dynamic_cast<const QgsComposerHtml *>( mypMultiFrame ); 00271 if ( composerHtml ) 00272 { 00273 return composerHtml; 00274 } 00275 } 00276 return 0; 00277 } 00278 00279 const QgsComposerItem* QgsComposition::getComposerItemById( QString theId ) const 00280 { 00281 QList<QGraphicsItem *> itemList = items(); 00282 QList<QGraphicsItem *>::iterator itemIt = itemList.begin(); 00283 for ( ; itemIt != itemList.end(); ++itemIt ) 00284 { 00285 const QgsComposerItem* mypItem = dynamic_cast<const QgsComposerItem *>( *itemIt ); 00286 if ( mypItem ) 00287 { 00288 if ( mypItem->id() == theId ) 00289 { 00290 return mypItem; 00291 } 00292 } 00293 } 00294 return 0; 00295 } 00296 /* 00297 const QgsComposerItem* QgsComposition::getComposerItemByUuid( QString theUuid, bool inAllComposers ) const 00298 { 00299 //This does not work since it seems impossible to get the QgisApp::instance() from here... Is there a workaround ? 00300 QSet<QgsComposer*> composers = QSet<QgsComposer*>(); 00301 00302 if( inAllComposers ) 00303 { 00304 composers = QgisApp::instance()->printComposers(); 00305 } 00306 else 00307 { 00308 composers.insert( this ) 00309 } 00310 00311 QSet<QgsComposer*>::const_iterator it = composers.constBegin(); 00312 for ( ; it != composers.constEnd(); ++it ) 00313 { 00314 QList<QGraphicsItem *> itemList = ( *it )->items(); 00315 QList<QGraphicsItem *>::iterator itemIt = itemList.begin(); 00316 for ( ; itemIt != itemList.end(); ++itemIt ) 00317 { 00318 const QgsComposerItem* mypItem = dynamic_cast<const QgsComposerItem *>( *itemIt ); 00319 if ( mypItem ) 00320 { 00321 if ( mypItem->uuid() == theUuid ) 00322 { 00323 return mypItem; 00324 } 00325 } 00326 } 00327 } 00328 00329 return 0; 00330 } 00331 */ 00332 00333 const QgsComposerItem* QgsComposition::getComposerItemByUuid( QString theUuid ) const 00334 { 00335 QList<QGraphicsItem *> itemList = items(); 00336 QList<QGraphicsItem *>::iterator itemIt = itemList.begin(); 00337 for ( ; itemIt != itemList.end(); ++itemIt ) 00338 { 00339 const QgsComposerItem* mypItem = dynamic_cast<const QgsComposerItem *>( *itemIt ); 00340 if ( mypItem ) 00341 { 00342 if ( mypItem->uuid() == theUuid ) 00343 { 00344 return mypItem; 00345 } 00346 } 00347 } 00348 00349 return 0; 00350 } 00351 00352 00353 void QgsComposition::setUseAdvancedEffects( bool effectsEnabled ) 00354 { 00355 mUseAdvancedEffects = effectsEnabled; 00356 00357 //toggle effects for all composer items 00358 QList<QGraphicsItem*> itemList = items(); 00359 QList<QGraphicsItem*>::const_iterator itemIt = itemList.constBegin(); 00360 for ( ; itemIt != itemList.constEnd(); ++itemIt ) 00361 { 00362 QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem*>( *itemIt ); 00363 if ( composerItem ) 00364 { 00365 composerItem->setEffectsEnabled( effectsEnabled ); 00366 } 00367 } 00368 } 00369 00370 int QgsComposition::pixelFontSize( double pointSize ) const 00371 { 00372 //in QgsComposition, one unit = one mm 00373 double sizeMillimeters = pointSize * 0.3527; 00374 return qRound( sizeMillimeters ); //round to nearest mm 00375 } 00376 00377 double QgsComposition::pointFontSize( int pixelSize ) const 00378 { 00379 double sizePoint = pixelSize / 0.3527; 00380 return sizePoint; 00381 } 00382 00383 bool QgsComposition::writeXML( QDomElement& composerElem, QDomDocument& doc ) 00384 { 00385 if ( composerElem.isNull() ) 00386 { 00387 return false; 00388 } 00389 00390 QDomElement compositionElem = doc.createElement( "Composition" ); 00391 compositionElem.setAttribute( "paperWidth", QString::number( mPageWidth ) ); 00392 compositionElem.setAttribute( "paperHeight", QString::number( mPageHeight ) ); 00393 compositionElem.setAttribute( "numPages", mPages.size() ); 00394 00395 //snapping 00396 if ( mSnapToGrid ) 00397 { 00398 compositionElem.setAttribute( "snapping", "1" ); 00399 } 00400 else 00401 { 00402 compositionElem.setAttribute( "snapping", "0" ); 00403 } 00404 compositionElem.setAttribute( "snapGridResolution", QString::number( mSnapGridResolution ) ); 00405 compositionElem.setAttribute( "snapGridOffsetX", QString::number( mSnapGridOffsetX ) ); 00406 compositionElem.setAttribute( "snapGridOffsetY", QString::number( mSnapGridOffsetY ) ); 00407 00408 //custom snap lines 00409 QList< QGraphicsLineItem* >::const_iterator snapLineIt = mSnapLines.constBegin(); 00410 for ( ; snapLineIt != mSnapLines.constEnd(); ++snapLineIt ) 00411 { 00412 QDomElement snapLineElem = doc.createElement( "SnapLine" ); 00413 QLineF line = ( *snapLineIt )->line(); 00414 snapLineElem.setAttribute( "x1", QString::number( line.x1() ) ); 00415 snapLineElem.setAttribute( "y1", QString::number( line.y1() ) ); 00416 snapLineElem.setAttribute( "x2", QString::number( line.x2() ) ); 00417 snapLineElem.setAttribute( "y2", QString::number( line.y2() ) ); 00418 compositionElem.appendChild( snapLineElem ); 00419 } 00420 00421 compositionElem.setAttribute( "printResolution", mPrintResolution ); 00422 compositionElem.setAttribute( "printAsRaster", mPrintAsRaster ); 00423 00424 compositionElem.setAttribute( "alignmentSnap", mAlignmentSnap ? 1 : 0 ); 00425 compositionElem.setAttribute( "alignmentSnapTolerance", mAlignmentSnapTolerance ); 00426 00427 //save items except paper items and frame items (they are saved with the corresponding multiframe) 00428 QList<QGraphicsItem*> itemList = items(); 00429 QList<QGraphicsItem*>::const_iterator itemIt = itemList.constBegin(); 00430 for ( ; itemIt != itemList.constEnd(); ++itemIt ) 00431 { 00432 const QgsComposerItem* composerItem = dynamic_cast<const QgsComposerItem*>( *itemIt ); 00433 if ( composerItem ) 00434 { 00435 if ( composerItem->type() != QgsComposerItem::ComposerPaper && composerItem->type() != QgsComposerItem::ComposerFrame ) 00436 { 00437 composerItem->writeXML( compositionElem, doc ); 00438 } 00439 } 00440 } 00441 00442 //save multiframes 00443 QSet<QgsComposerMultiFrame*>::const_iterator multiFrameIt = mMultiFrames.constBegin(); 00444 for ( ; multiFrameIt != mMultiFrames.constEnd(); ++multiFrameIt ) 00445 { 00446 ( *multiFrameIt )->writeXML( compositionElem, doc ); 00447 } 00448 composerElem.appendChild( compositionElem ); 00449 00450 return true; 00451 } 00452 00453 bool QgsComposition::readXML( const QDomElement& compositionElem, const QDomDocument& doc ) 00454 { 00455 Q_UNUSED( doc ); 00456 if ( compositionElem.isNull() ) 00457 { 00458 return false; 00459 } 00460 00461 //create pages 00462 bool widthConversionOk, heightConversionOk; 00463 mPageWidth = compositionElem.attribute( "paperWidth" ).toDouble( &widthConversionOk ); 00464 mPageHeight = compositionElem.attribute( "paperHeight" ).toDouble( &heightConversionOk ); 00465 emit paperSizeChanged(); 00466 int numPages = compositionElem.attribute( "numPages", "1" ).toInt(); 00467 00468 if ( widthConversionOk && heightConversionOk ) 00469 { 00470 removePaperItems(); 00471 for ( int i = 0; i < numPages; ++i ) 00472 { 00473 addPaperItem(); 00474 } 00475 } 00476 00477 //snapping 00478 if ( compositionElem.attribute( "snapping" ) == "0" ) 00479 { 00480 mSnapToGrid = false; 00481 } 00482 else 00483 { 00484 mSnapToGrid = true; 00485 } 00486 mSnapGridResolution = compositionElem.attribute( "snapGridResolution" ).toDouble(); 00487 mSnapGridOffsetX = compositionElem.attribute( "snapGridOffsetX" ).toDouble(); 00488 mSnapGridOffsetY = compositionElem.attribute( "snapGridOffsetY" ).toDouble(); 00489 00490 //custom snap lines 00491 QDomNodeList snapLineNodes = compositionElem.elementsByTagName( "SnapLine" ); 00492 for ( int i = 0; i < snapLineNodes.size(); ++i ) 00493 { 00494 QDomElement snapLineElem = snapLineNodes.at( i ).toElement(); 00495 QGraphicsLineItem* snapItem = addSnapLine(); 00496 double x1 = snapLineElem.attribute( "x1" ).toDouble(); 00497 double y1 = snapLineElem.attribute( "y1" ).toDouble(); 00498 double x2 = snapLineElem.attribute( "x2" ).toDouble(); 00499 double y2 = snapLineElem.attribute( "y2" ).toDouble(); 00500 snapItem->setLine( x1, y1, x2, y2 ); 00501 } 00502 00503 mAlignmentSnap = compositionElem.attribute( "alignmentSnap", "1" ).toInt() == 0 ? false : true; 00504 mAlignmentSnapTolerance = compositionElem.attribute( "alignmentSnapTolerance", "2.0" ).toDouble(); 00505 00506 mPrintAsRaster = compositionElem.attribute( "printAsRaster" ).toInt(); 00507 mPrintResolution = compositionElem.attribute( "printResolution", "300" ).toInt(); 00508 00509 updatePaperItems(); 00510 return true; 00511 } 00512 00513 bool QgsComposition::loadFromTemplate( const QDomDocument& doc, QMap<QString, QString>* substitutionMap, bool addUndoCommands ) 00514 { 00515 deleteAndRemoveMultiFrames(); 00516 00517 //delete all items and emit itemRemoved signal 00518 QList<QGraphicsItem *> itemList = items(); 00519 QList<QGraphicsItem *>::iterator itemIter = itemList.begin(); 00520 for ( ; itemIter != itemList.end(); ++itemIter ) 00521 { 00522 QgsComposerItem* cItem = dynamic_cast<QgsComposerItem*>( *itemIter ); 00523 if ( cItem ) 00524 { 00525 removeItem( cItem ); 00526 emit itemRemoved( cItem ); 00527 delete cItem; 00528 } 00529 } 00530 mItemZList.clear(); 00531 00532 mPages.clear(); 00533 mUndoStack.clear(); 00534 00535 QDomDocument importDoc; 00536 if ( substitutionMap ) 00537 { 00538 QString xmlString = doc.toString(); 00539 QMap<QString, QString>::const_iterator sIt = substitutionMap->constBegin(); 00540 for ( ; sIt != substitutionMap->constEnd(); ++sIt ) 00541 { 00542 xmlString = xmlString.replace( "[" + sIt.key() + "]", encodeStringForXML( sIt.value() ) ); 00543 } 00544 00545 QString errorMsg; 00546 int errorLine, errorColumn; 00547 if ( !importDoc.setContent( xmlString, &errorMsg, &errorLine, &errorColumn ) ) 00548 { 00549 return false; 00550 } 00551 } 00552 else 00553 { 00554 importDoc = doc; 00555 } 00556 00557 //read general settings 00558 QDomElement compositionElem = importDoc.documentElement().firstChildElement( "Composition" ); 00559 if ( compositionElem.isNull() ) 00560 { 00561 return false; 00562 } 00563 00564 bool ok = readXML( compositionElem, importDoc ); 00565 if ( !ok ) 00566 { 00567 return false; 00568 } 00569 00570 // remove all uuid attributes since we don't want duplicates UUIDS 00571 QDomNodeList composerItemsNodes = importDoc.elementsByTagName( "ComposerItem" ); 00572 for ( int i = 0; i < composerItemsNodes.count(); ++i ) 00573 { 00574 QDomNode composerItemNode = composerItemsNodes.at( i ); 00575 if ( composerItemNode.isElement() ) 00576 { 00577 composerItemNode.toElement().removeAttribute( "uuid" ); 00578 } 00579 } 00580 00581 //addItemsFromXML 00582 addItemsFromXML( importDoc.documentElement(), importDoc, 0, addUndoCommands, 0 ); 00583 00584 // read atlas parameters 00585 QDomElement atlasElem = importDoc.documentElement().firstChildElement( "Atlas" ); 00586 atlasComposition().readXML( atlasElem, importDoc ); 00587 return true; 00588 } 00589 00590 void QgsComposition::addItemsFromXML( const QDomElement& elem, const QDomDocument& doc, QMap< QgsComposerMap*, int >* mapsToRestore, 00591 bool addUndoCommands, QPointF* pos, bool pasteInPlace ) 00592 { 00593 QPointF* pasteInPlacePt = 0; 00594 if ( pasteInPlace ) 00595 { 00596 pasteInPlacePt = new QPointF( 0, pageNumberAt( *pos ) * ( mPageHeight + mSpaceBetweenPages ) ); 00597 } 00598 QDomNodeList composerLabelList = elem.elementsByTagName( "ComposerLabel" ); 00599 for ( int i = 0; i < composerLabelList.size(); ++i ) 00600 { 00601 QDomElement currentComposerLabelElem = composerLabelList.at( i ).toElement(); 00602 QgsComposerLabel* newLabel = new QgsComposerLabel( this ); 00603 newLabel->readXML( currentComposerLabelElem, doc ); 00604 if ( pos ) 00605 { 00606 if ( pasteInPlacePt ) 00607 { 00608 newLabel->setItemPosition( newLabel->transform().dx(), fmod( newLabel->transform().dy(), ( paperHeight() + spaceBetweenPages() ) ) ); 00609 newLabel->move( pasteInPlacePt->x(), pasteInPlacePt->y() ); 00610 } 00611 else 00612 { 00613 newLabel->setItemPosition( pos->x(), pos->y() ); 00614 } 00615 } 00616 addComposerLabel( newLabel ); 00617 if ( addUndoCommands ) 00618 { 00619 pushAddRemoveCommand( newLabel, tr( "Label added" ) ); 00620 } 00621 } 00622 // map 00623 QDomNodeList composerMapList = elem.elementsByTagName( "ComposerMap" ); 00624 for ( int i = 0; i < composerMapList.size(); ++i ) 00625 { 00626 QDomElement currentComposerMapElem = composerMapList.at( i ).toElement(); 00627 QgsComposerMap* newMap = new QgsComposerMap( this ); 00628 newMap->readXML( currentComposerMapElem, doc ); 00629 newMap->assignFreeId(); 00630 00631 if ( mapsToRestore ) 00632 { 00633 mapsToRestore->insert( newMap, ( int )( newMap->previewMode() ) ); 00634 newMap->setPreviewMode( QgsComposerMap::Rectangle ); 00635 } 00636 addComposerMap( newMap, false ); 00637 00638 if ( pos ) 00639 { 00640 if ( pasteInPlace ) 00641 { 00642 newMap->setItemPosition( newMap->transform().dx(), fmod( newMap->transform().dy(), ( paperHeight() + spaceBetweenPages() ) ) ); 00643 newMap->move( pasteInPlacePt->x(), pasteInPlacePt->y() ); 00644 } 00645 else 00646 { 00647 newMap->setItemPosition( pos->x(), pos->y() ); 00648 } 00649 } 00650 00651 if ( addUndoCommands ) 00652 { 00653 pushAddRemoveCommand( newMap, tr( "Map added" ) ); 00654 } 00655 } 00656 // arrow 00657 QDomNodeList composerArrowList = elem.elementsByTagName( "ComposerArrow" ); 00658 for ( int i = 0; i < composerArrowList.size(); ++i ) 00659 { 00660 QDomElement currentComposerArrowElem = composerArrowList.at( i ).toElement(); 00661 QgsComposerArrow* newArrow = new QgsComposerArrow( this ); 00662 newArrow->readXML( currentComposerArrowElem, doc ); 00663 if ( pos ) 00664 { 00665 if ( pasteInPlace ) 00666 { 00667 newArrow->setItemPosition( newArrow->transform().dx(), fmod( newArrow->transform().dy(), ( paperHeight() + spaceBetweenPages() ) ) ); 00668 newArrow->move( pasteInPlacePt->x(), pasteInPlacePt->y() ); 00669 } 00670 else 00671 { 00672 newArrow->setItemPosition( pos->x(), pos->y() ); 00673 } 00674 } 00675 addComposerArrow( newArrow ); 00676 if ( addUndoCommands ) 00677 { 00678 pushAddRemoveCommand( newArrow, tr( "Arrow added" ) ); 00679 } 00680 } 00681 // scalebar 00682 QDomNodeList composerScaleBarList = elem.elementsByTagName( "ComposerScaleBar" ); 00683 for ( int i = 0; i < composerScaleBarList.size(); ++i ) 00684 { 00685 QDomElement currentComposerScaleBarElem = composerScaleBarList.at( i ).toElement(); 00686 QgsComposerScaleBar* newScaleBar = new QgsComposerScaleBar( this ); 00687 newScaleBar->readXML( currentComposerScaleBarElem, doc ); 00688 if ( pos ) 00689 { 00690 if ( pasteInPlace ) 00691 { 00692 newScaleBar->setItemPosition( newScaleBar->transform().dx(), fmod( newScaleBar->transform().dy(), ( paperHeight() + spaceBetweenPages() ) ) ); 00693 newScaleBar->move( pasteInPlacePt->x(), pasteInPlacePt->y() ); 00694 } 00695 else 00696 { 00697 newScaleBar->setItemPosition( pos->x(), pos->y() ); 00698 } 00699 } 00700 addComposerScaleBar( newScaleBar ); 00701 if ( addUndoCommands ) 00702 { 00703 pushAddRemoveCommand( newScaleBar, tr( "Scale bar added" ) ); 00704 } 00705 } 00706 // shape 00707 QDomNodeList composerShapeList = elem.elementsByTagName( "ComposerShape" ); 00708 for ( int i = 0; i < composerShapeList.size(); ++i ) 00709 { 00710 QDomElement currentComposerShapeElem = composerShapeList.at( i ).toElement(); 00711 QgsComposerShape* newShape = new QgsComposerShape( this ); 00712 newShape->readXML( currentComposerShapeElem, doc ); 00713 if ( pos ) 00714 { 00715 if ( pasteInPlace ) 00716 { 00717 newShape->setItemPosition( newShape->transform().dx(), fmod( newShape->transform().dy(), ( paperHeight() + spaceBetweenPages() ) ) ); 00718 newShape->move( pasteInPlacePt->x(), pasteInPlacePt->y() ); 00719 } 00720 else 00721 { 00722 newShape->setItemPosition( pos->x(), pos->y() ); 00723 } 00724 } 00725 addComposerShape( newShape ); 00726 if ( addUndoCommands ) 00727 { 00728 pushAddRemoveCommand( newShape, tr( "Shape added" ) ); 00729 } 00730 } 00731 // picture 00732 QDomNodeList composerPictureList = elem.elementsByTagName( "ComposerPicture" ); 00733 for ( int i = 0; i < composerPictureList.size(); ++i ) 00734 { 00735 QDomElement currentComposerPictureElem = composerPictureList.at( i ).toElement(); 00736 QgsComposerPicture* newPicture = new QgsComposerPicture( this ); 00737 newPicture->readXML( currentComposerPictureElem, doc ); 00738 if ( pos ) 00739 { 00740 if ( pasteInPlace ) 00741 { 00742 newPicture->setItemPosition( newPicture->transform().dx(), fmod( newPicture->transform().dy(), ( paperHeight() + spaceBetweenPages() ) ) ); 00743 newPicture->move( pasteInPlacePt->x(), pasteInPlacePt->y() ); 00744 } 00745 else 00746 { 00747 newPicture->setItemPosition( pos->x(), pos->y() ); 00748 } 00749 } 00750 addComposerPicture( newPicture ); 00751 if ( addUndoCommands ) 00752 { 00753 pushAddRemoveCommand( newPicture, tr( "Picture added" ) ); 00754 } 00755 } 00756 // legend 00757 QDomNodeList composerLegendList = elem.elementsByTagName( "ComposerLegend" ); 00758 for ( int i = 0; i < composerLegendList.size(); ++i ) 00759 { 00760 QDomElement currentComposerLegendElem = composerLegendList.at( i ).toElement(); 00761 QgsComposerLegend* newLegend = new QgsComposerLegend( this ); 00762 newLegend->readXML( currentComposerLegendElem, doc ); 00763 if ( pos ) 00764 { 00765 if ( pasteInPlace ) 00766 { 00767 newLegend->setItemPosition( newLegend->transform().dx(), fmod( newLegend->transform().dy(), ( paperHeight() + spaceBetweenPages() ) ) ); 00768 newLegend->move( pasteInPlacePt->x(), pasteInPlacePt->y() ); 00769 } 00770 else 00771 { 00772 newLegend->setItemPosition( pos->x(), pos->y() ); 00773 } 00774 } 00775 addComposerLegend( newLegend ); 00776 if ( addUndoCommands ) 00777 { 00778 pushAddRemoveCommand( newLegend, tr( "Legend added" ) ); 00779 } 00780 } 00781 // table 00782 QDomNodeList composerTableList = elem.elementsByTagName( "ComposerAttributeTable" ); 00783 for ( int i = 0; i < composerTableList.size(); ++i ) 00784 { 00785 QDomElement currentComposerTableElem = composerTableList.at( i ).toElement(); 00786 QgsComposerAttributeTable* newTable = new QgsComposerAttributeTable( this ); 00787 newTable->readXML( currentComposerTableElem, doc ); 00788 if ( pos ) 00789 { 00790 if ( pasteInPlace ) 00791 { 00792 newTable->setItemPosition( newTable->transform().dx(), fmod( newTable->transform().dy(), ( paperHeight() + spaceBetweenPages() ) ) ); 00793 newTable->move( pasteInPlacePt->x(), pasteInPlacePt->y() ); 00794 } 00795 else 00796 { 00797 newTable->setItemPosition( pos->x(), pos->y() ); 00798 } 00799 } 00800 addComposerTable( newTable ); 00801 if ( addUndoCommands ) 00802 { 00803 pushAddRemoveCommand( newTable, tr( "Table added" ) ); 00804 } 00805 } 00806 //html 00807 QDomNodeList composerHtmlList = elem.elementsByTagName( "ComposerHtml" ); 00808 for ( int i = 0; i < composerHtmlList.size(); ++i ) 00809 { 00810 QDomElement currentHtmlElem = composerHtmlList.at( i ).toElement(); 00811 QgsComposerHtml* newHtml = new QgsComposerHtml( this, false ); 00812 newHtml->readXML( currentHtmlElem, doc ); 00813 newHtml->setCreateUndoCommands( true ); 00814 this->addMultiFrame( newHtml ); 00815 } 00816 } 00817 00818 void QgsComposition::addItemToZList( QgsComposerItem* item ) 00819 { 00820 if ( !item ) 00821 { 00822 return; 00823 } 00824 mItemZList.push_back( item ); 00825 QgsDebugMsg( QString::number( mItemZList.size() ) ); 00826 item->setZValue( mItemZList.size() ); 00827 } 00828 00829 void QgsComposition::removeItemFromZList( QgsComposerItem* item ) 00830 { 00831 if ( !item ) 00832 { 00833 return; 00834 } 00835 mItemZList.removeAll( item ); 00836 } 00837 00838 void QgsComposition::raiseSelectedItems() 00839 { 00840 QList<QgsComposerItem*> selectedItems = selectedComposerItems(); 00841 QList<QgsComposerItem*>::iterator it = selectedItems.begin(); 00842 for ( ; it != selectedItems.end(); ++it ) 00843 { 00844 raiseItem( *it ); 00845 } 00846 00847 //update all positions 00848 updateZValues(); 00849 update(); 00850 } 00851 00852 void QgsComposition::raiseItem( QgsComposerItem* item ) 00853 { 00854 //search item 00855 QMutableLinkedListIterator<QgsComposerItem*> it( mItemZList ); 00856 if ( it.findNext( item ) ) 00857 { 00858 if ( it.hasNext() ) 00859 { 00860 it.remove(); 00861 it.next(); 00862 it.insert( item ); 00863 } 00864 } 00865 } 00866 00867 void QgsComposition::lowerSelectedItems() 00868 { 00869 QList<QgsComposerItem*> selectedItems = selectedComposerItems(); 00870 QList<QgsComposerItem*>::iterator it = selectedItems.begin(); 00871 for ( ; it != selectedItems.end(); ++it ) 00872 { 00873 lowerItem( *it ); 00874 } 00875 00876 //update all positions 00877 updateZValues(); 00878 update(); 00879 } 00880 00881 void QgsComposition::lowerItem( QgsComposerItem* item ) 00882 { 00883 //search item 00884 QMutableLinkedListIterator<QgsComposerItem*> it( mItemZList ); 00885 if ( it.findNext( item ) ) 00886 { 00887 it.previous(); 00888 if ( it.hasPrevious() ) 00889 { 00890 it.remove(); 00891 it.previous(); 00892 it.insert( item ); 00893 } 00894 } 00895 } 00896 00897 void QgsComposition::moveSelectedItemsToTop() 00898 { 00899 QList<QgsComposerItem*> selectedItems = selectedComposerItems(); 00900 QList<QgsComposerItem*>::iterator it = selectedItems.begin(); 00901 00902 for ( ; it != selectedItems.end(); ++it ) 00903 { 00904 moveItemToTop( *it ); 00905 } 00906 00907 //update all positions 00908 updateZValues(); 00909 update(); 00910 } 00911 00912 void QgsComposition::moveItemToTop( QgsComposerItem* item ) 00913 { 00914 //search item 00915 QMutableLinkedListIterator<QgsComposerItem*> it( mItemZList ); 00916 if ( it.findNext( item ) ) 00917 { 00918 it.remove(); 00919 } 00920 mItemZList.push_back( item ); 00921 } 00922 00923 void QgsComposition::moveSelectedItemsToBottom() 00924 { 00925 QList<QgsComposerItem*> selectedItems = selectedComposerItems(); 00926 QList<QgsComposerItem*>::iterator it = selectedItems.begin(); 00927 for ( ; it != selectedItems.end(); ++it ) 00928 { 00929 moveItemToBottom( *it ); 00930 } 00931 00932 //update all positions 00933 updateZValues(); 00934 update(); 00935 } 00936 00937 void QgsComposition::moveItemToBottom( QgsComposerItem* item ) 00938 { 00939 //search item 00940 QMutableLinkedListIterator<QgsComposerItem*> it( mItemZList ); 00941 if ( it.findNext( item ) ) 00942 { 00943 it.remove(); 00944 } 00945 mItemZList.push_front( item ); 00946 } 00947 00948 void QgsComposition::alignSelectedItemsLeft() 00949 { 00950 QList<QgsComposerItem*> selectedItems = selectedComposerItems(); 00951 if ( selectedItems.size() < 2 ) 00952 { 00953 return; 00954 } 00955 00956 QRectF selectedItemBBox; 00957 if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 ) 00958 { 00959 return; 00960 } 00961 00962 double minXCoordinate = selectedItemBBox.left(); 00963 00964 //align items left to minimum x coordinate 00965 QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items left" ) ); 00966 QList<QgsComposerItem*>::iterator align_it = selectedItems.begin(); 00967 for ( ; align_it != selectedItems.end(); ++align_it ) 00968 { 00969 QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand ); 00970 subcommand->savePreviousState(); 00971 QTransform itemTransform = ( *align_it )->transform(); 00972 itemTransform.translate( minXCoordinate - itemTransform.dx(), 0 ); 00973 ( *align_it )->setTransform( itemTransform ); 00974 subcommand->saveAfterState(); 00975 } 00976 mUndoStack.push( parentCommand ); 00977 } 00978 00979 void QgsComposition::alignSelectedItemsHCenter() 00980 { 00981 QList<QgsComposerItem*> selectedItems = selectedComposerItems(); 00982 if ( selectedItems.size() < 2 ) 00983 { 00984 return; 00985 } 00986 00987 QRectF selectedItemBBox; 00988 if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 ) 00989 { 00990 return; 00991 } 00992 00993 double averageXCoord = ( selectedItemBBox.left() + selectedItemBBox.right() ) / 2.0; 00994 00995 //place items 00996 QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items horizontal center" ) ); 00997 QList<QgsComposerItem*>::iterator align_it = selectedItems.begin(); 00998 for ( ; align_it != selectedItems.end(); ++align_it ) 00999 { 01000 QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand ); 01001 subcommand->savePreviousState(); 01002 QTransform itemTransform = ( *align_it )->transform(); 01003 itemTransform.translate( averageXCoord - itemTransform.dx() - ( *align_it )->rect().width() / 2.0, 0 ); 01004 ( *align_it )->setTransform( itemTransform ); 01005 subcommand->saveAfterState(); 01006 } 01007 mUndoStack.push( parentCommand ); 01008 } 01009 01010 void QgsComposition::alignSelectedItemsRight() 01011 { 01012 QList<QgsComposerItem*> selectedItems = selectedComposerItems(); 01013 if ( selectedItems.size() < 2 ) 01014 { 01015 return; 01016 } 01017 01018 QRectF selectedItemBBox; 01019 if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 ) 01020 { 01021 return; 01022 } 01023 01024 double maxXCoordinate = selectedItemBBox.right(); 01025 01026 //align items right to maximum x coordinate 01027 QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items right" ) ); 01028 QList<QgsComposerItem*>::iterator align_it = selectedItems.begin(); 01029 for ( ; align_it != selectedItems.end(); ++align_it ) 01030 { 01031 QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand ); 01032 subcommand->savePreviousState(); 01033 QTransform itemTransform = ( *align_it )->transform(); 01034 itemTransform.translate( maxXCoordinate - itemTransform.dx() - ( *align_it )->rect().width(), 0 ); 01035 ( *align_it )->setTransform( itemTransform ); 01036 subcommand->saveAfterState(); 01037 } 01038 mUndoStack.push( parentCommand ); 01039 } 01040 01041 void QgsComposition::alignSelectedItemsTop() 01042 { 01043 QList<QgsComposerItem*> selectedItems = selectedComposerItems(); 01044 if ( selectedItems.size() < 2 ) 01045 { 01046 return; 01047 } 01048 01049 QRectF selectedItemBBox; 01050 if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 ) 01051 { 01052 return; 01053 } 01054 01055 double minYCoordinate = selectedItemBBox.top(); 01056 01057 QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items top" ) ); 01058 QList<QgsComposerItem*>::iterator align_it = selectedItems.begin(); 01059 for ( ; align_it != selectedItems.end(); ++align_it ) 01060 { 01061 QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand ); 01062 subcommand->savePreviousState(); 01063 QTransform itemTransform = ( *align_it )->transform(); 01064 itemTransform.translate( 0, minYCoordinate - itemTransform.dy() ); 01065 ( *align_it )->setTransform( itemTransform ); 01066 subcommand->saveAfterState(); 01067 } 01068 mUndoStack.push( parentCommand ); 01069 } 01070 01071 void QgsComposition::alignSelectedItemsVCenter() 01072 { 01073 QList<QgsComposerItem*> selectedItems = selectedComposerItems(); 01074 if ( selectedItems.size() < 2 ) 01075 { 01076 return; 01077 } 01078 01079 QRectF selectedItemBBox; 01080 if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 ) 01081 { 01082 return; 01083 } 01084 01085 double averageYCoord = ( selectedItemBBox.top() + selectedItemBBox.bottom() ) / 2.0; 01086 QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items vertical center" ) ); 01087 QList<QgsComposerItem*>::iterator align_it = selectedItems.begin(); 01088 for ( ; align_it != selectedItems.end(); ++align_it ) 01089 { 01090 QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand ); 01091 subcommand->savePreviousState(); 01092 QTransform itemTransform = ( *align_it )->transform(); 01093 itemTransform.translate( 0, averageYCoord - itemTransform.dy() - ( *align_it )->rect().height() / 2 ); 01094 ( *align_it )->setTransform( itemTransform ); 01095 subcommand->saveAfterState(); 01096 } 01097 mUndoStack.push( parentCommand ); 01098 } 01099 01100 void QgsComposition::alignSelectedItemsBottom() 01101 { 01102 QList<QgsComposerItem*> selectedItems = selectedComposerItems(); 01103 if ( selectedItems.size() < 2 ) 01104 { 01105 return; 01106 } 01107 01108 QRectF selectedItemBBox; 01109 if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 ) 01110 { 01111 return; 01112 } 01113 01114 double maxYCoord = selectedItemBBox.bottom(); 01115 QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items bottom" ) ); 01116 QList<QgsComposerItem*>::iterator align_it = selectedItems.begin(); 01117 for ( ; align_it != selectedItems.end(); ++align_it ) 01118 { 01119 QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand ); 01120 subcommand->savePreviousState(); 01121 QTransform itemTransform = ( *align_it )->transform(); 01122 itemTransform.translate( 0, maxYCoord - itemTransform.dy() - ( *align_it )->rect().height() ); 01123 ( *align_it )->setTransform( itemTransform ); 01124 subcommand->saveAfterState(); 01125 } 01126 mUndoStack.push( parentCommand ); 01127 } 01128 01129 void QgsComposition::updateZValues() 01130 { 01131 int counter = 1; 01132 QLinkedList<QgsComposerItem*>::iterator it = mItemZList.begin(); 01133 QgsComposerItem* currentItem = 0; 01134 01135 QUndoCommand* parentCommand = new QUndoCommand( tr( "Item z-order changed" ) ); 01136 for ( ; it != mItemZList.end(); ++it ) 01137 { 01138 currentItem = *it; 01139 if ( currentItem ) 01140 { 01141 QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *it, "", parentCommand ); 01142 subcommand->savePreviousState(); 01143 currentItem->setZValue( counter ); 01144 subcommand->saveAfterState(); 01145 } 01146 ++counter; 01147 } 01148 mUndoStack.push( parentCommand ); 01149 } 01150 01151 void QgsComposition::sortZList() 01152 { 01153 if ( mItemZList.size() < 2 ) 01154 { 01155 return; 01156 } 01157 01158 QLinkedList<QgsComposerItem*>::const_iterator lIt = mItemZList.constBegin(); 01159 QLinkedList<QgsComposerItem*> sortedList; 01160 01161 for ( ; lIt != mItemZList.constEnd(); ++lIt ) 01162 { 01163 QLinkedList<QgsComposerItem*>::iterator insertIt = sortedList.begin(); 01164 for ( ; insertIt != sortedList.end(); ++insertIt ) 01165 { 01166 if (( *lIt )->zValue() < ( *insertIt )->zValue() ) 01167 { 01168 break; 01169 } 01170 } 01171 sortedList.insert( insertIt, ( *lIt ) ); 01172 } 01173 01174 mItemZList = sortedList; 01175 } 01176 01177 QPointF QgsComposition::snapPointToGrid( const QPointF& scenePoint ) const 01178 { 01179 if ( !mSnapToGrid || mSnapGridResolution <= 0 ) 01180 { 01181 return scenePoint; 01182 } 01183 01184 //y offset to current page 01185 int pageNr = ( int )( scenePoint.y() / ( mPageHeight + mSpaceBetweenPages ) ); 01186 double yOffset = pageNr * ( mPageHeight + mSpaceBetweenPages ); 01187 double yPage = scenePoint.y() - yOffset; //y-coordinate relative to current page 01188 01189 //snap x coordinate 01190 int xRatio = ( int )(( scenePoint.x() - mSnapGridOffsetX ) / mSnapGridResolution + 0.5 ); 01191 int yRatio = ( int )(( yPage - mSnapGridOffsetY ) / mSnapGridResolution + 0.5 ); 01192 01193 return QPointF( xRatio * mSnapGridResolution + mSnapGridOffsetX, yRatio * mSnapGridResolution + mSnapGridOffsetY + yOffset ); 01194 } 01195 01196 QPointF QgsComposition::alignItem( const QgsComposerItem* item, double& alignX, double& alignY, double dx, double dy ) 01197 { 01198 if ( !item ) 01199 { 01200 return QPointF(); 01201 } 01202 01203 double left = item->transform().dx() + dx; 01204 double right = left + item->rect().width(); 01205 double midH = ( left + right ) / 2.0; 01206 double top = item->transform().dy() + dy; 01207 double bottom = top + item->rect().height(); 01208 double midV = ( top + bottom ) / 2.0; 01209 01210 QMap<double, const QgsComposerItem* > xAlignCoordinates; 01211 QMap<double, const QgsComposerItem* > yAlignCoordinates; 01212 collectAlignCoordinates( xAlignCoordinates, yAlignCoordinates, item ); 01213 01214 //find nearest matches x 01215 double xItemLeft = left; //new left coordinate of the item 01216 double xAlignCoord = 0; 01217 double smallestDiffX = DBL_MAX; 01218 01219 checkNearestItem( left, xAlignCoordinates, smallestDiffX, 0, xItemLeft, xAlignCoord ); 01220 checkNearestItem( midH, xAlignCoordinates, smallestDiffX, ( left - right ) / 2.0, xItemLeft, xAlignCoord ); 01221 checkNearestItem( right, xAlignCoordinates, smallestDiffX, left - right, xItemLeft, xAlignCoord ); 01222 01223 //find nearest matches y 01224 double yItemTop = top; //new top coordinate of the item 01225 double yAlignCoord = 0; 01226 double smallestDiffY = DBL_MAX; 01227 01228 checkNearestItem( top, yAlignCoordinates, smallestDiffY, 0, yItemTop, yAlignCoord ); 01229 checkNearestItem( midV, yAlignCoordinates, smallestDiffY, ( top - bottom ) / 2.0, yItemTop, yAlignCoord ); 01230 checkNearestItem( bottom, yAlignCoordinates, smallestDiffY, top - bottom, yItemTop, yAlignCoord ); 01231 01232 double xCoord = ( smallestDiffX < 5 ) ? xItemLeft : item->transform().dx() + dx; 01233 alignX = ( smallestDiffX < 5 ) ? xAlignCoord : -1; 01234 double yCoord = ( smallestDiffY < 5 ) ? yItemTop : item->transform().dy() + dy; 01235 alignY = ( smallestDiffY < 5 ) ? yAlignCoord : -1; 01236 return QPointF( xCoord, yCoord ); 01237 } 01238 01239 QPointF QgsComposition::alignPos( const QPointF& pos, const QgsComposerItem* excludeItem, double& alignX, double& alignY ) 01240 { 01241 QMap<double, const QgsComposerItem* > xAlignCoordinates; 01242 QMap<double, const QgsComposerItem* > yAlignCoordinates; 01243 collectAlignCoordinates( xAlignCoordinates, yAlignCoordinates, excludeItem ); 01244 01245 double nearestX = pos.x(); 01246 double nearestY = pos.y(); 01247 if ( !nearestItem( xAlignCoordinates, pos.x(), nearestX ) 01248 || !nearestItem( yAlignCoordinates, pos.y(), nearestY ) ) 01249 { 01250 alignX = -1; 01251 alignY = -1; 01252 return pos; 01253 } 01254 01255 QPointF result( pos.x(), pos.y() ); 01256 if ( abs( nearestX - pos.x() ) < mAlignmentSnapTolerance ) 01257 { 01258 result.setX( nearestX ); 01259 alignX = nearestX; 01260 } 01261 else 01262 { 01263 alignX = -1; 01264 } 01265 01266 if ( abs( nearestY - pos.y() ) < mAlignmentSnapTolerance ) 01267 { 01268 result.setY( nearestY ); 01269 alignY = nearestY; 01270 } 01271 else 01272 { 01273 alignY = -1; 01274 } 01275 return result; 01276 } 01277 01278 QGraphicsLineItem* QgsComposition::addSnapLine() 01279 { 01280 QGraphicsLineItem* item = new QGraphicsLineItem(); 01281 QPen linePen( Qt::SolidLine ); 01282 linePen.setColor( Qt::red ); 01283 // use a pen width of 0, since this activates a cosmetic pen 01284 // which doesn't scale with the composer and keeps a constant size 01285 linePen.setWidthF( 0 ); 01286 item->setPen( linePen ); 01287 item->setZValue( 100 ); 01288 addItem( item ); 01289 mSnapLines.push_back( item ); 01290 return item; 01291 } 01292 01293 void QgsComposition::removeSnapLine( QGraphicsLineItem* line ) 01294 { 01295 removeItem( line ); 01296 mSnapLines.removeAll( line ); 01297 delete line; 01298 } 01299 01300 void QgsComposition::setSnapLinesVisible( bool visible ) 01301 { 01302 QList< QGraphicsLineItem* >::iterator it = mSnapLines.begin(); 01303 for ( ; it != mSnapLines.end(); ++it ) 01304 { 01305 if ( visible ) 01306 { 01307 ( *it )->show(); 01308 } 01309 else 01310 { 01311 ( *it )->hide(); 01312 } 01313 } 01314 } 01315 01316 QGraphicsLineItem* QgsComposition::nearestSnapLine( bool horizontal, double x, double y, double tolerance, 01317 QList< QPair< QgsComposerItem*, QgsComposerItem::ItemPositionMode> >& snappedItems ) 01318 { 01319 double minSqrDist = DBL_MAX; 01320 QGraphicsLineItem* item = 0; 01321 double currentXCoord = 0; 01322 double currentYCoord = 0; 01323 double currentSqrDist = 0; 01324 double sqrTolerance = tolerance * tolerance; 01325 01326 snappedItems.clear(); 01327 01328 QList< QGraphicsLineItem* >::const_iterator it = mSnapLines.constBegin(); 01329 for ( ; it != mSnapLines.constEnd(); ++it ) 01330 { 01331 bool itemHorizontal = qgsDoubleNear(( *it )->line().y2() - ( *it )->line().y1(), 0 ); 01332 if ( horizontal && itemHorizontal ) 01333 { 01334 currentYCoord = ( *it )->line().y1(); 01335 currentSqrDist = ( y - currentYCoord ) * ( y - currentYCoord ); 01336 } 01337 else if ( !itemHorizontal ) 01338 { 01339 currentXCoord = ( *it )->line().x1(); 01340 currentSqrDist = ( x - currentXCoord ) * ( x - currentXCoord ); 01341 } 01342 01343 if ( currentSqrDist < minSqrDist && currentSqrDist < sqrTolerance ) 01344 { 01345 item = *it; 01346 minSqrDist = currentSqrDist; 01347 } 01348 } 01349 01350 double itemTolerance = 0.0000001; 01351 if ( item ) 01352 { 01353 //go through all the items to find items snapped to this snap line 01354 QList<QGraphicsItem *> itemList = items(); 01355 QList<QGraphicsItem *>::iterator itemIt = itemList.begin(); 01356 for ( ; itemIt != itemList.end(); ++itemIt ) 01357 { 01358 QgsComposerItem* currentItem = dynamic_cast<QgsComposerItem*>( *itemIt ); 01359 if ( !currentItem || currentItem->type() == QgsComposerItem::ComposerPaper ) 01360 { 01361 continue; 01362 } 01363 01364 if ( horizontal ) 01365 { 01366 if ( qgsDoubleNear( currentYCoord, currentItem->transform().dy() + currentItem->rect().top(), itemTolerance ) ) 01367 { 01368 snappedItems.append( qMakePair( currentItem, QgsComposerItem::UpperMiddle ) ); 01369 } 01370 else if ( qgsDoubleNear( currentYCoord, currentItem->transform().dy() + currentItem->rect().center().y(), itemTolerance ) ) 01371 { 01372 snappedItems.append( qMakePair( currentItem, QgsComposerItem::Middle ) ); 01373 } 01374 else if ( qgsDoubleNear( currentYCoord, currentItem->transform().dy() + currentItem->rect().bottom(), itemTolerance ) ) 01375 { 01376 snappedItems.append( qMakePair( currentItem, QgsComposerItem::LowerMiddle ) ); 01377 } 01378 } 01379 else 01380 { 01381 if ( qgsDoubleNear( currentXCoord, currentItem->transform().dx(), itemTolerance ) ) 01382 { 01383 snappedItems.append( qMakePair( currentItem, QgsComposerItem::MiddleLeft ) ); 01384 } 01385 else if ( qgsDoubleNear( currentXCoord, currentItem->transform().dx() + currentItem->rect().center().x(), itemTolerance ) ) 01386 { 01387 snappedItems.append( qMakePair( currentItem, QgsComposerItem::Middle ) ); 01388 } 01389 else if ( qgsDoubleNear( currentXCoord, currentItem->transform().dx() + currentItem->rect().width(), itemTolerance ) ) 01390 { 01391 snappedItems.append( qMakePair( currentItem, QgsComposerItem::MiddleRight ) ); 01392 } 01393 } 01394 } 01395 } 01396 01397 return item; 01398 } 01399 01400 int QgsComposition::boundingRectOfSelectedItems( QRectF& bRect ) 01401 { 01402 QList<QgsComposerItem*> selectedItems = selectedComposerItems(); 01403 if ( selectedItems.size() < 1 ) 01404 { 01405 return 1; 01406 } 01407 01408 //set the box to the first item 01409 QgsComposerItem* currentItem = selectedItems.at( 0 ); 01410 double minX = currentItem->transform().dx(); 01411 double minY = currentItem->transform().dy(); 01412 double maxX = minX + currentItem->rect().width(); 01413 double maxY = minY + currentItem->rect().height(); 01414 01415 double currentMinX, currentMinY, currentMaxX, currentMaxY; 01416 01417 for ( int i = 1; i < selectedItems.size(); ++i ) 01418 { 01419 currentItem = selectedItems.at( i ); 01420 currentMinX = currentItem->transform().dx(); 01421 currentMinY = currentItem->transform().dy(); 01422 currentMaxX = currentMinX + currentItem->rect().width(); 01423 currentMaxY = currentMinY + currentItem->rect().height(); 01424 01425 if ( currentMinX < minX ) 01426 minX = currentMinX; 01427 if ( currentMaxX > maxX ) 01428 maxX = currentMaxX; 01429 if ( currentMinY < minY ) 01430 minY = currentMinY; 01431 if ( currentMaxY > maxY ) 01432 maxY = currentMaxY; 01433 } 01434 01435 bRect.setTopLeft( QPointF( minX, minY ) ); 01436 bRect.setBottomRight( QPointF( maxX, maxY ) ); 01437 return 0; 01438 } 01439 01440 void QgsComposition::setSnapToGridEnabled( bool b ) 01441 { 01442 mSnapToGrid = b; 01443 updatePaperItems(); 01444 saveSettings(); 01445 } 01446 01447 void QgsComposition::setSnapGridResolution( double r ) 01448 { 01449 mSnapGridResolution = r; 01450 updatePaperItems(); 01451 saveSettings(); 01452 } 01453 01454 void QgsComposition::setSnapGridOffsetX( double offset ) 01455 { 01456 mSnapGridOffsetX = offset; 01457 updatePaperItems(); 01458 saveSettings(); 01459 } 01460 01461 void QgsComposition::setSnapGridOffsetY( double offset ) 01462 { 01463 mSnapGridOffsetY = offset; 01464 updatePaperItems(); 01465 saveSettings(); 01466 } 01467 01468 void QgsComposition::setGridPen( const QPen& p ) 01469 { 01470 mGridPen = p; 01471 updatePaperItems(); 01472 saveSettings(); 01473 } 01474 01475 void QgsComposition::setGridStyle( GridStyle s ) 01476 { 01477 mGridStyle = s; 01478 updatePaperItems(); 01479 saveSettings(); 01480 } 01481 01482 void QgsComposition::setSelectionTolerance( double tol ) 01483 { 01484 mSelectionTolerance = tol; 01485 saveSettings(); 01486 } 01487 01488 void QgsComposition::loadSettings() 01489 { 01490 //read grid style, grid color and pen width from settings 01491 QSettings s; 01492 01493 QString gridStyleString; 01494 int red, green, blue; 01495 double penWidth; 01496 01497 gridStyleString = s.value( "/qgis/composerGridStyle", "Dots" ).toString(); 01498 penWidth = s.value( "/qgis/composerGridWidth", 0.5 ).toDouble(); 01499 red = s.value( "/qgis/composerGridRed", 0 ).toInt(); 01500 green = s.value( "/qgis/composerGridGreen", 0 ).toInt(); 01501 blue = s.value( "/qgis/composerGridBlue", 0 ).toInt(); 01502 01503 mGridPen.setColor( QColor( red, green, blue ) ); 01504 mGridPen.setWidthF( penWidth ); 01505 01506 if ( gridStyleString == "Dots" ) 01507 { 01508 mGridStyle = Dots; 01509 } 01510 else if ( gridStyleString == "Crosses" ) 01511 { 01512 mGridStyle = Crosses; 01513 } 01514 else 01515 { 01516 mGridStyle = Solid; 01517 } 01518 01519 mSelectionTolerance = s.value( "/qgis/composerSelectionTolerance", 0.0 ).toDouble(); 01520 } 01521 01522 void QgsComposition::saveSettings() 01523 { 01524 //store grid appearance settings 01525 QSettings s; 01526 s.setValue( "/qgis/composerGridWidth", mGridPen.widthF() ); 01527 s.setValue( "/qgis/composerGridRed", mGridPen.color().red() ); 01528 s.setValue( "/qgis/composerGridGreen", mGridPen.color().green() ); 01529 s.setValue( "/qgis/composerGridBlue", mGridPen.color().blue() ); 01530 01531 if ( mGridStyle == Solid ) 01532 { 01533 s.setValue( "/qgis/composerGridStyle", "Solid" ); 01534 } 01535 else if ( mGridStyle == Dots ) 01536 { 01537 s.setValue( "/qgis/composerGridStyle", "Dots" ); 01538 } 01539 else if ( mGridStyle == Crosses ) 01540 { 01541 s.setValue( "/qgis/composerGridStyle", "Crosses" ); 01542 } 01543 01544 //store also selection tolerance 01545 s.setValue( "/qgis/composerSelectionTolerance", mSelectionTolerance ); 01546 } 01547 01548 void QgsComposition::beginCommand( QgsComposerItem* item, const QString& commandText, QgsComposerMergeCommand::Context c ) 01549 { 01550 delete mActiveItemCommand; 01551 if ( !item ) 01552 { 01553 mActiveItemCommand = 0; 01554 return; 01555 } 01556 01557 if ( c == QgsComposerMergeCommand::Unknown ) 01558 { 01559 mActiveItemCommand = new QgsComposerItemCommand( item, commandText ); 01560 } 01561 else 01562 { 01563 mActiveItemCommand = new QgsComposerMergeCommand( c, item, commandText ); 01564 } 01565 mActiveItemCommand->savePreviousState(); 01566 } 01567 01568 void QgsComposition::endCommand() 01569 { 01570 if ( mActiveItemCommand ) 01571 { 01572 mActiveItemCommand->saveAfterState(); 01573 if ( mActiveItemCommand->containsChange() ) //protect against empty commands 01574 { 01575 mUndoStack.push( mActiveItemCommand ); 01576 QgsProject::instance()->dirty( true ); 01577 } 01578 else 01579 { 01580 delete mActiveItemCommand; 01581 } 01582 mActiveItemCommand = 0; 01583 } 01584 } 01585 01586 void QgsComposition::cancelCommand() 01587 { 01588 delete mActiveItemCommand; 01589 mActiveItemCommand = 0; 01590 } 01591 01592 void QgsComposition::beginMultiFrameCommand( QgsComposerMultiFrame* multiFrame, const QString& text ) 01593 { 01594 delete mActiveMultiFrameCommand; 01595 mActiveMultiFrameCommand = new QgsComposerMultiFrameCommand( multiFrame, text ); 01596 mActiveMultiFrameCommand->savePreviousState(); 01597 } 01598 01599 void QgsComposition::endMultiFrameCommand() 01600 { 01601 if ( mActiveMultiFrameCommand ) 01602 { 01603 mActiveMultiFrameCommand->saveAfterState(); 01604 if ( mActiveMultiFrameCommand->containsChange() ) 01605 { 01606 mUndoStack.push( mActiveMultiFrameCommand ); 01607 QgsProject::instance()->dirty( true ); 01608 } 01609 else 01610 { 01611 delete mActiveMultiFrameCommand; 01612 } 01613 mActiveMultiFrameCommand = 0; 01614 } 01615 } 01616 01617 void QgsComposition::addMultiFrame( QgsComposerMultiFrame* multiFrame ) 01618 { 01619 mMultiFrames.insert( multiFrame ); 01620 } 01621 01622 void QgsComposition::removeMultiFrame( QgsComposerMultiFrame* multiFrame ) 01623 { 01624 mMultiFrames.remove( multiFrame ); 01625 } 01626 01627 void QgsComposition::addComposerArrow( QgsComposerArrow* arrow ) 01628 { 01629 addItem( arrow ); 01630 emit composerArrowAdded( arrow ); 01631 clearSelection(); 01632 arrow->setSelected( true ); 01633 emit selectedItemChanged( arrow ); 01634 } 01635 01636 void QgsComposition::addComposerLabel( QgsComposerLabel* label ) 01637 { 01638 addItem( label ); 01639 emit composerLabelAdded( label ); 01640 clearSelection(); 01641 label->setSelected( true ); 01642 emit selectedItemChanged( label ); 01643 } 01644 01645 void QgsComposition::addComposerMap( QgsComposerMap* map, bool setDefaultPreviewStyle ) 01646 { 01647 addItem( map ); 01648 if ( setDefaultPreviewStyle ) 01649 { 01650 //set default preview mode to cache. Must be done here between adding composer map to scene and emiting signal 01651 map->setPreviewMode( QgsComposerMap::Cache ); 01652 } 01653 01654 if ( map->previewMode() != QgsComposerMap::Rectangle ) 01655 { 01656 map->cache(); 01657 } 01658 01659 emit composerMapAdded( map ); 01660 clearSelection(); 01661 map->setSelected( true ); 01662 emit selectedItemChanged( map ); 01663 } 01664 01665 void QgsComposition::addComposerScaleBar( QgsComposerScaleBar* scaleBar ) 01666 { 01667 addItem( scaleBar ); 01668 emit composerScaleBarAdded( scaleBar ); 01669 clearSelection(); 01670 scaleBar->setSelected( true ); 01671 emit selectedItemChanged( scaleBar ); 01672 } 01673 01674 void QgsComposition::addComposerLegend( QgsComposerLegend* legend ) 01675 { 01676 //take first available map 01677 QList<const QgsComposerMap*> mapItemList = composerMapItems(); 01678 if ( mapItemList.size() > 0 ) 01679 { 01680 legend->setComposerMap( mapItemList.at( 0 ) ); 01681 } 01682 addItem( legend ); 01683 emit composerLegendAdded( legend ); 01684 clearSelection(); 01685 legend->setSelected( true ); 01686 emit selectedItemChanged( legend ); 01687 } 01688 01689 void QgsComposition::addComposerPicture( QgsComposerPicture* picture ) 01690 { 01691 addItem( picture ); 01692 emit composerPictureAdded( picture ); 01693 clearSelection(); 01694 picture->setSelected( true ); 01695 emit selectedItemChanged( picture ); 01696 } 01697 01698 void QgsComposition::addComposerShape( QgsComposerShape* shape ) 01699 { 01700 addItem( shape ); 01701 emit composerShapeAdded( shape ); 01702 clearSelection(); 01703 shape->setSelected( true ); 01704 emit selectedItemChanged( shape ); 01705 } 01706 01707 void QgsComposition::addComposerTable( QgsComposerAttributeTable* table ) 01708 { 01709 addItem( table ); 01710 emit composerTableAdded( table ); 01711 clearSelection(); 01712 table->setSelected( true ); 01713 emit selectedItemChanged( table ); 01714 } 01715 01716 void QgsComposition::addComposerHtmlFrame( QgsComposerHtml* html, QgsComposerFrame* frame ) 01717 { 01718 addItem( frame ); 01719 emit composerHtmlFrameAdded( html, frame ); 01720 clearSelection(); 01721 frame->setSelected( true ); 01722 emit selectedItemChanged( frame ); 01723 } 01724 01725 void QgsComposition::removeComposerItem( QgsComposerItem* item, bool createCommand ) 01726 { 01727 QgsComposerMap* map = dynamic_cast<QgsComposerMap *>( item ); 01728 01729 if ( !map || !map->isDrawing() ) //don't delete a composer map while it draws 01730 { 01731 removeItem( item ); 01732 QgsComposerItemGroup* itemGroup = dynamic_cast<QgsComposerItemGroup*>( item ); 01733 if ( itemGroup ) 01734 { 01735 //add add/remove item command for every item in the group 01736 QUndoCommand* parentCommand = new QUndoCommand( tr( "Remove item group" ) ); 01737 01738 QSet<QgsComposerItem*> groupedItems = itemGroup->items(); 01739 QSet<QgsComposerItem*>::iterator it = groupedItems.begin(); 01740 for ( ; it != groupedItems.end(); ++it ) 01741 { 01742 QgsAddRemoveItemCommand* subcommand = new QgsAddRemoveItemCommand( QgsAddRemoveItemCommand::Removed, *it, this, "", parentCommand ); 01743 connectAddRemoveCommandSignals( subcommand ); 01744 emit itemRemoved( *it ); 01745 } 01746 01747 undoStack()->push( parentCommand ); 01748 delete itemGroup; 01749 emit itemRemoved( itemGroup ); 01750 } 01751 else 01752 { 01753 bool frameItem = ( item->type() == QgsComposerItem::ComposerFrame ); 01754 QgsComposerMultiFrame* multiFrame = 0; 01755 if ( createCommand ) 01756 { 01757 if ( frameItem ) //multiframe tracks item changes 01758 { 01759 multiFrame = static_cast<QgsComposerFrame*>( item )->multiFrame(); 01760 item->beginItemCommand( tr( "Frame deleted" ) ); 01761 emit itemRemoved( item ); 01762 item->endItemCommand(); 01763 } 01764 else 01765 { 01766 emit itemRemoved( item ); 01767 pushAddRemoveCommand( item, tr( "Item deleted" ), QgsAddRemoveItemCommand::Removed ); 01768 } 01769 } 01770 else 01771 { 01772 emit itemRemoved( item ); 01773 } 01774 01775 //check if there are frames left. If not, remove the multi frame 01776 if ( frameItem && multiFrame ) 01777 { 01778 if ( multiFrame->frameCount() < 1 ) 01779 { 01780 removeMultiFrame( multiFrame ); 01781 if ( createCommand ) 01782 { 01783 QgsAddRemoveMultiFrameCommand* command = new QgsAddRemoveMultiFrameCommand( QgsAddRemoveMultiFrameCommand::Removed, 01784 multiFrame, this, tr( "Multiframe removed" ) ); 01785 undoStack()->push( command ); 01786 } 01787 else 01788 { 01789 delete multiFrame; 01790 } 01791 } 01792 } 01793 } 01794 } 01795 } 01796 01797 void QgsComposition::pushAddRemoveCommand( QgsComposerItem* item, const QString& text, QgsAddRemoveItemCommand::State state ) 01798 { 01799 QgsAddRemoveItemCommand* c = new QgsAddRemoveItemCommand( state, item, this, text ); 01800 connectAddRemoveCommandSignals( c ); 01801 undoStack()->push( c ); 01802 QgsProject::instance()->dirty( true ); 01803 } 01804 01805 void QgsComposition::connectAddRemoveCommandSignals( QgsAddRemoveItemCommand* c ) 01806 { 01807 if ( !c ) 01808 { 01809 return; 01810 } 01811 01812 QObject::connect( c, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SIGNAL( itemRemoved( QgsComposerItem* ) ) ); 01813 QObject::connect( c, SIGNAL( itemAdded( QgsComposerItem* ) ), this, SLOT( sendItemAddedSignal( QgsComposerItem* ) ) ); 01814 } 01815 01816 void QgsComposition::sendItemAddedSignal( QgsComposerItem* item ) 01817 { 01818 //cast and send proper signal 01819 item->setSelected( true ); 01820 QgsComposerArrow* arrow = dynamic_cast<QgsComposerArrow*>( item ); 01821 if ( arrow ) 01822 { 01823 emit composerArrowAdded( arrow ); 01824 emit selectedItemChanged( arrow ); 01825 return; 01826 } 01827 QgsComposerLabel* label = dynamic_cast<QgsComposerLabel*>( item ); 01828 if ( label ) 01829 { 01830 emit composerLabelAdded( label ); 01831 emit selectedItemChanged( label ); 01832 return; 01833 } 01834 QgsComposerMap* map = dynamic_cast<QgsComposerMap*>( item ); 01835 if ( map ) 01836 { 01837 emit composerMapAdded( map ); 01838 emit selectedItemChanged( map ); 01839 return; 01840 } 01841 QgsComposerScaleBar* scalebar = dynamic_cast<QgsComposerScaleBar*>( item ); 01842 if ( scalebar ) 01843 { 01844 emit composerScaleBarAdded( scalebar ); 01845 emit selectedItemChanged( scalebar ); 01846 return; 01847 } 01848 QgsComposerLegend* legend = dynamic_cast<QgsComposerLegend*>( item ); 01849 if ( legend ) 01850 { 01851 emit composerLegendAdded( legend ); 01852 emit selectedItemChanged( legend ); 01853 return; 01854 } 01855 QgsComposerPicture* picture = dynamic_cast<QgsComposerPicture*>( item ); 01856 if ( picture ) 01857 { 01858 emit composerPictureAdded( picture ); 01859 emit selectedItemChanged( picture ); 01860 return; 01861 } 01862 QgsComposerShape* shape = dynamic_cast<QgsComposerShape*>( item ); 01863 if ( shape ) 01864 { 01865 emit composerShapeAdded( shape ); 01866 emit selectedItemChanged( shape ); 01867 return; 01868 } 01869 QgsComposerAttributeTable* table = dynamic_cast<QgsComposerAttributeTable*>( item ); 01870 if ( table ) 01871 { 01872 emit composerTableAdded( table ); 01873 emit selectedItemChanged( table ); 01874 return; 01875 } 01876 QgsComposerFrame* frame = dynamic_cast<QgsComposerFrame*>( item ); 01877 if ( frame ) 01878 { 01879 //emit composerFrameAdded( multiframe, frame, ); 01880 QgsComposerMultiFrame* mf = frame->multiFrame(); 01881 QgsComposerHtml* html = dynamic_cast<QgsComposerHtml*>( mf ); 01882 if ( html ) 01883 { 01884 emit composerHtmlFrameAdded( html, frame ); 01885 } 01886 emit selectedItemChanged( frame ); 01887 return; 01888 } 01889 } 01890 01891 void QgsComposition::updatePaperItems() 01892 { 01893 QList< QgsPaperItem* >::iterator paperIt = mPages.begin(); 01894 for ( ; paperIt != mPages.end(); ++paperIt ) 01895 { 01896 ( *paperIt )->update(); 01897 } 01898 } 01899 01900 void QgsComposition::addPaperItem() 01901 { 01902 double paperHeight = this->paperHeight(); 01903 double paperWidth = this->paperWidth(); 01904 double currentY = paperHeight * mPages.size() + mPages.size() * mSpaceBetweenPages; //add 10mm visible space between pages 01905 QgsPaperItem* paperItem = new QgsPaperItem( 0, currentY, paperWidth, paperHeight, this ); //default size A4 01906 paperItem->setBrush( Qt::white ); 01907 addItem( paperItem ); 01908 paperItem->setZValue( 0 ); 01909 mPages.push_back( paperItem ); 01910 01911 QgsExpression::setSpecialColumn( "$numpages", QVariant(( int )mPages.size() ) ); 01912 } 01913 01914 void QgsComposition::removePaperItems() 01915 { 01916 for ( int i = 0; i < mPages.size(); ++i ) 01917 { 01918 delete mPages.at( i ); 01919 } 01920 mPages.clear(); 01921 QgsExpression::setSpecialColumn( "$numpages", QVariant(( int )0 ) ); 01922 } 01923 01924 void QgsComposition::deleteAndRemoveMultiFrames() 01925 { 01926 QSet<QgsComposerMultiFrame*>::iterator multiFrameIt = mMultiFrames.begin(); 01927 for ( ; multiFrameIt != mMultiFrames.end(); ++multiFrameIt ) 01928 { 01929 delete *multiFrameIt; 01930 } 01931 mMultiFrames.clear(); 01932 } 01933 01934 void QgsComposition::beginPrintAsPDF( QPrinter& printer, const QString& file ) 01935 { 01936 printer.setOutputFormat( QPrinter::PdfFormat ); 01937 printer.setOutputFileName( file ); 01938 printer.setPaperSize( QSizeF( paperWidth(), paperHeight() ), QPrinter::Millimeter ); 01939 01940 QgsPaintEngineHack::fixEngineFlags( printer.paintEngine() ); 01941 } 01942 01943 void QgsComposition::exportAsPDF( const QString& file ) 01944 { 01945 QPrinter printer; 01946 beginPrintAsPDF( printer, file ); 01947 print( printer ); 01948 } 01949 01950 void QgsComposition::doPrint( QPrinter& printer, QPainter& p ) 01951 { 01952 //QgsComposition starts page numbering at 0 01953 int fromPage = ( printer.fromPage() < 1 ) ? 0 : printer.fromPage() - 1 ; 01954 int toPage = ( printer.toPage() < 1 ) ? numPages() - 1 : printer.toPage() - 1; 01955 01956 if ( mPrintAsRaster ) 01957 { 01958 for ( int i = fromPage; i <= toPage; ++i ) 01959 { 01960 if ( i > fromPage ) 01961 { 01962 printer.newPage(); 01963 } 01964 01965 QImage image = printPageAsRaster( i ); 01966 if ( !image.isNull() ) 01967 { 01968 QRectF targetArea( 0, 0, image.width(), image.height() ); 01969 p.drawImage( targetArea, image, targetArea ); 01970 } 01971 } 01972 } 01973 01974 if ( !mPrintAsRaster ) 01975 { 01976 for ( int i = fromPage; i <= toPage; ++i ) 01977 { 01978 if ( i > fromPage ) 01979 { 01980 printer.newPage(); 01981 } 01982 renderPage( &p, i ); 01983 } 01984 } 01985 } 01986 01987 void QgsComposition::beginPrint( QPrinter &printer ) 01988 { 01989 //set resolution based on composer setting 01990 printer.setFullPage( true ); 01991 printer.setColorMode( QPrinter::Color ); 01992 01993 //set user-defined resolution 01994 printer.setResolution( printResolution() ); 01995 } 01996 01997 void QgsComposition::print( QPrinter &printer ) 01998 { 01999 beginPrint( printer ); 02000 QPainter p( &printer ); 02001 doPrint( printer, p ); 02002 } 02003 02004 QImage QgsComposition::printPageAsRaster( int page ) 02005 { 02006 //print out via QImage, code copied from on_mActionExportAsImage_activated 02007 int width = ( int )( printResolution() * paperWidth() / 25.4 ); 02008 int height = ( int )( printResolution() * paperHeight() / 25.4 ); 02009 QImage image( QSize( width, height ), QImage::Format_ARGB32 ); 02010 if ( !image.isNull() ) 02011 { 02012 image.setDotsPerMeterX( printResolution() / 25.4 * 1000 ); 02013 image.setDotsPerMeterY( printResolution() / 25.4 * 1000 ); 02014 image.fill( 0 ); 02015 QPainter imagePainter( &image ); 02016 renderPage( &imagePainter, page ); 02017 } 02018 return image; 02019 } 02020 02021 void QgsComposition::renderPage( QPainter* p, int page ) 02022 { 02023 if ( mPages.size() <= page ) 02024 { 02025 return; 02026 } 02027 02028 QgsPaperItem* paperItem = mPages[page]; 02029 if ( !paperItem ) 02030 { 02031 return; 02032 } 02033 02034 QPaintDevice* paintDevice = p->device(); 02035 if ( !paintDevice ) 02036 { 02037 return; 02038 } 02039 02040 QRectF paperRect = QRectF( paperItem->transform().dx(), paperItem->transform().dy(), paperItem->rect().width(), paperItem->rect().height() ); 02041 02042 QgsComposition::PlotStyle savedPlotStyle = mPlotStyle; 02043 mPlotStyle = QgsComposition::Print; 02044 02045 setSnapLinesVisible( false ); 02046 render( p, QRectF( 0, 0, paintDevice->width(), paintDevice->height() ), paperRect ); 02047 setSnapLinesVisible( true ); 02048 02049 mPlotStyle = savedPlotStyle; 02050 } 02051 02052 QString QgsComposition::encodeStringForXML( const QString& str ) 02053 { 02054 QString modifiedStr( str ); 02055 modifiedStr.replace( "&", "&" ); 02056 modifiedStr.replace( "\"", """ ); 02057 modifiedStr.replace( "'", "'" ); 02058 modifiedStr.replace( "<", "<" ); 02059 modifiedStr.replace( ">", ">" ); 02060 return modifiedStr; 02061 } 02062 02063 void QgsComposition::collectAlignCoordinates( QMap< double, const QgsComposerItem* >& alignCoordsX, QMap< double, const QgsComposerItem* >& alignCoordsY, 02064 const QgsComposerItem* excludeItem ) 02065 { 02066 alignCoordsX.clear(); 02067 alignCoordsY.clear(); 02068 02069 QList<QGraphicsItem *> itemList = items(); 02070 QList<QGraphicsItem *>::iterator itemIt = itemList.begin(); 02071 for ( ; itemIt != itemList.end(); ++itemIt ) 02072 { 02073 const QgsComposerItem* currentItem = dynamic_cast<const QgsComposerItem *>( *itemIt ); 02074 if ( excludeItem ) 02075 { 02076 if ( !currentItem || currentItem == excludeItem ) 02077 { 02078 continue; 02079 } 02080 alignCoordsX.insert( currentItem->transform().dx(), currentItem ); 02081 alignCoordsX.insert( currentItem->transform().dx() + currentItem->rect().width(), currentItem ); 02082 alignCoordsX.insert( currentItem->transform().dx() + currentItem->rect().center().x(), currentItem ); 02083 alignCoordsY.insert( currentItem->transform().dy() + currentItem->rect().top(), currentItem ); 02084 alignCoordsY.insert( currentItem->transform().dy() + currentItem->rect().center().y(), currentItem ); 02085 alignCoordsY.insert( currentItem->transform().dy() + currentItem->rect().bottom(), currentItem ); 02086 } 02087 } 02088 02089 //arbitrary snap lines 02090 QList< QGraphicsLineItem* >::const_iterator sIt = mSnapLines.constBegin(); 02091 for ( ; sIt != mSnapLines.constEnd(); ++sIt ) 02092 { 02093 double x = ( *sIt )->line().x1(); 02094 double y = ( *sIt )->line().y1(); 02095 if ( qgsDoubleNear( y, 0.0 ) ) 02096 { 02097 alignCoordsX.insert( x, 0 ); 02098 } 02099 else 02100 { 02101 alignCoordsY.insert( y, 0 ); 02102 } 02103 } 02104 } 02105 02106 void QgsComposition::checkNearestItem( double checkCoord, const QMap< double, const QgsComposerItem* >& alignCoords, double& smallestDiff, 02107 double itemCoordOffset, double& itemCoord, double& alignCoord ) const 02108 { 02109 double currentCoord = 0; 02110 if ( !nearestItem( alignCoords, checkCoord, currentCoord ) ) 02111 { 02112 return; 02113 } 02114 02115 double currentDiff = abs( checkCoord - currentCoord ); 02116 if ( currentDiff < mAlignmentSnapTolerance ) 02117 { 02118 itemCoord = currentCoord + itemCoordOffset; 02119 alignCoord = currentCoord; 02120 smallestDiff = currentDiff; 02121 } 02122 } 02123 02124 bool QgsComposition::nearestItem( const QMap< double, const QgsComposerItem* >& coords, double value, double& nearestValue ) 02125 { 02126 if ( coords.size() < 1 ) 02127 { 02128 return false; 02129 } 02130 02131 QMap< double, const QgsComposerItem* >::const_iterator it = coords.lowerBound( value ); 02132 if ( it == coords.constBegin() ) //value smaller than first map value 02133 { 02134 nearestValue = it.key(); 02135 return true; 02136 } 02137 else if ( it == coords.constEnd() ) //value larger than last map value 02138 { 02139 --it; 02140 nearestValue = it.key(); 02141 return true; 02142 } 02143 else 02144 { 02145 //get smaller value and larger value and return the closer one 02146 double upperVal = it.key(); 02147 --it; 02148 double lowerVal = it.key(); 02149 02150 double lowerDiff = value - lowerVal; 02151 double upperDiff = upperVal - value; 02152 if ( lowerDiff < upperDiff ) 02153 { 02154 nearestValue = lowerVal; 02155 return true; 02156 } 02157 else 02158 { 02159 nearestValue = upperVal; 02160 return true; 02161 } 02162 } 02163 } 02164