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