QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgscomposition.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposition.cpp
3  -------------------
4  begin : January 2005
5  copyright : (C) 2005 by Radim Blazek
6  email : blazek@itc.it
7  ***************************************************************************/
8 /***************************************************************************
9  * *
10  * This program is free software; you can redistribute it and/or modify *
11  * it under the terms of the GNU General Public License as published by *
12  * the Free Software Foundation; either version 2 of the License, or *
13  * (at your option) any later version. *
14  * *
15  ***************************************************************************/
16 
17 #include "qgscomposition.h"
18 #include "qgscomposerutils.h"
19 #include "qgscomposerarrow.h"
20 #include "qgscomposerframe.h"
21 #include "qgscomposerhtml.h"
22 #include "qgscomposerlabel.h"
23 #include "qgscomposerlegend.h"
24 #include "qgscomposermap.h"
25 #include "qgscomposermapoverview.h"
27 #include "qgscomposeritemgroup.h"
28 #include "qgscomposerpicture.h"
29 #include "qgscomposerscalebar.h"
30 #include "qgscomposershape.h"
31 #include "qgscomposerlabel.h"
32 #include "qgscomposermodel.h"
36 #include "qgspaintenginehack.h"
37 #include "qgspaperitem.h"
38 #include "qgsproject.h"
39 #include "qgsgeometry.h"
40 #include "qgsvectorlayer.h"
41 #include "qgsvectordataprovider.h"
42 #include "qgsexpression.h"
43 #include "qgssymbolv2.h"
44 #include "qgssymbollayerv2utils.h"
45 #include "qgsdatadefined.h"
46 #include "qgslogger.h"
47 
48 #include <QDomDocument>
49 #include <QDomElement>
50 #include <QGraphicsRectItem>
51 #include <QGraphicsView>
52 #include <QPainter>
53 #include <QPrinter>
54 #include <QSettings>
55 #include <QDir>
56 
57 #include <limits>
58 
60  : QGraphicsScene( 0 )
61  , mMapRenderer( mapRenderer )
62  , mMapSettings( mapRenderer->mapSettings() )
63  , mAtlasComposition( this )
64 {
65  init();
66 }
67 
69  : QGraphicsScene( 0 )
70  , mMapRenderer( 0 )
71  , mMapSettings( mapSettings )
72  , mAtlasComposition( this )
73 {
74  init();
75 }
76 
78 {
79  // these members should be ideally in constructor's initialization list, but now we have two constructors...
81  mPageWidth = 297;
82  mPageHeight = 210;
83  mSpaceBetweenPages = 10;
84  mPageStyleSymbol = 0;
85  mPrintAsRaster = false;
86  mGenerateWorldFile = false;
87  mWorldFileMap = 0;
88  mUseAdvancedEffects = true;
89  mSnapToGrid = false;
90  mGridVisible = false;
92  mSnapGridOffsetX = 0;
93  mSnapGridOffsetY = 0;
94  mAlignmentSnap = true;
95  mGuidesVisible = true;
96  mSmartGuides = true;
97  mSnapTolerance = 0;
102  mPreventCursorChange = false;
103  mItemsModel = 0;
104  mUndoStack = new QUndoStack();
105 
106  //data defined strings
107  mDataDefinedNames.insert( QgsComposerObject::PresetPaperSize, QString( "dataDefinedPaperSize" ) );
108  mDataDefinedNames.insert( QgsComposerObject::PaperWidth, QString( "dataDefinedPaperWidth" ) );
109  mDataDefinedNames.insert( QgsComposerObject::PaperHeight, QString( "dataDefinedPaperHeight" ) );
110  mDataDefinedNames.insert( QgsComposerObject::NumPages, QString( "dataDefinedNumPages" ) );
111  mDataDefinedNames.insert( QgsComposerObject::PaperOrientation, QString( "dataDefinedPaperOrientation" ) );
112 
113  //connect to atlas toggling on/off and coverage layer and feature changes
114  //to update data defined values
115  connect( &mAtlasComposition, SIGNAL( toggled( bool ) ), this, SLOT( refreshDataDefinedProperty() ) );
116  connect( &mAtlasComposition, SIGNAL( coverageLayerChanged( QgsVectorLayer* ) ), this, SLOT( refreshDataDefinedProperty() ) );
117  connect( &mAtlasComposition, SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( refreshDataDefinedProperty() ) );
118  //also, refreshing composition triggers a recalculation of data defined properties
119  connect( this, SIGNAL( refreshItemsTriggered() ), this, SLOT( refreshDataDefinedProperty() ) );
120  //toggling atlas or changing coverage layer requires data defined expressions to be reprepared
121  connect( &mAtlasComposition, SIGNAL( toggled( bool ) ), this, SLOT( prepareAllDataDefinedExpressions() ) );
122  connect( &mAtlasComposition, SIGNAL( coverageLayerChanged( QgsVectorLayer* ) ), this, SLOT( prepareAllDataDefinedExpressions() ) );
123 
124  setBackgroundBrush( QColor( 215, 215, 215 ) );
126 
127  addPaperItem();
128 
129  updateBounds();
130 
131  //add mouse selection handles to composition, and initially hide
133  addItem( mSelectionHandles );
134  mSelectionHandles->hide();
135  mSelectionHandles->setZValue( 500 );
136 
137  mPrintResolution = 300; //hardcoded default
138 
139  //load default composition settings
140  loadDefaults();
141  loadSettings();
142 
143  mItemsModel = new QgsComposerModel( this );
144 }
145 
146 
147 /*
148 QgsComposition::QgsComposition()
149  : QGraphicsScene( 0 ),
150  mMapRenderer( 0 ),
151  mPlotStyle( QgsComposition::Preview ),
152  mPageWidth( 297 ),
153  mPageHeight( 210 ),
154  mSpaceBetweenPages( 10 ),
155  mPageStyleSymbol( 0 ),
156  mPrintAsRaster( false ),
157  mGenerateWorldFile( false ),
158  mWorldFileMap( 0 ),
159  mUseAdvancedEffects( true ),
160  mSnapToGrid( false ),
161  mGridVisible( false ),
162  mSnapGridResolution( 0 ),
163  mSnapGridTolerance( 0 ),
164  mSnapGridOffsetX( 0 ),
165  mSnapGridOffsetY( 0 ),
166  mAlignmentSnap( true ),
167  mGuidesVisible( true ),
168  mSmartGuides( true ),
169  mAlignmentSnapTolerance( 0 ),
170  mSelectionHandles( 0 ),
171  mActiveItemCommand( 0 ),
172  mActiveMultiFrameCommand( 0 ),
173  mAtlasComposition( this ),
174  mAtlasMode( QgsComposition::AtlasOff ),
175  mPreventCursorChange( false ),
176  mItemsModel( 0 )
177 {
178  //load default composition settings
179  loadDefaults();
180  loadSettings();
181  mItemsModel = new QgsComposerModel( this );
182 }*/
183 
185 {
188 
189  // clear pointers to QgsDataDefined objects
190  //TODO - should be qDeleteAll? Check original label code too for same leak.
191  mDataDefinedProperties.clear();
192 
193  // make sure that all composer items are removed before
194  // this class is deconstructed - to avoid segfaults
195  // when composer items access in destructor composition that isn't valid anymore
196  QList<QGraphicsItem*> itemList = items();
197  qDeleteAll( itemList );
198 
199  //order is important here - we need to delete model last so that all items have already
200  //been deleted. Deleting the undo stack will also delete any items which have been
201  //removed from the scene, so this needs to be done before deleting the model
202  delete mUndoStack;
203 
204  delete mActiveItemCommand;
206  delete mPageStyleSymbol;
207  delete mItemsModel;
208 }
209 
211 {
212  QSettings settings;
213  mSnapGridResolution = settings.value( "/Composer/defaultSnapGridResolution", 10.0 ).toDouble();
214  mSnapGridOffsetX = settings.value( "/Composer/defaultSnapGridOffsetX", 0 ).toDouble();
215  mSnapGridOffsetY = settings.value( "/Composer/defaultSnapGridOffsetY", 0 ).toDouble();
216  mSnapTolerance = settings.value( "/Composer/defaultSnapTolerancePixels", 5 ).toInt();
217 }
218 
220 {
221  setSceneRect( compositionBounds() );
222 }
223 
225 {
226  emit refreshItemsTriggered();
227 }
228 
230 {
231  clearSelection();
232  item->setSelected( true );
233  emit selectedItemChanged( item );
234 }
235 
237 {
238  //updates data defined properties and redraws composition to match
239  if ( property == QgsComposerObject::NumPages || property == QgsComposerObject::AllProperties )
240  {
241  setNumPages( numPages() );
242  }
243  if ( property == QgsComposerObject::PaperWidth || property == QgsComposerObject::PaperHeight ||
246  {
247  refreshPageSize();
248  }
249 }
250 
252 {
253  //start with an empty rectangle
254  QRectF bounds = QRectF( 0, 0, 0, 0 );
255 
256  //add all QgsComposerItems and QgsPaperItems which are in the composition
257  QList<QGraphicsItem *> itemList = items();
258  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
259  for ( ; itemIt != itemList.end(); ++itemIt )
260  {
261  const QgsComposerItem* composerItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
262  const QgsPaperItem* paperItem = dynamic_cast<const QgsPaperItem*>( *itemIt );
263  if (( composerItem || paperItem ) )
264  {
265  //expand bounds with current item's bounds
266  bounds = bounds.united(( *itemIt )->sceneBoundingRect() );
267  }
268  }
269 
270  //finally, expand bounds out by 5% page size to give a bit of a margin
271  bounds.adjust( -mPageWidth * 0.05, -mPageWidth * 0.05, mPageWidth * 0.05, mPageWidth * 0.05 );
272 
273  return bounds;
274 }
275 
276 void QgsComposition::setPaperSize( const double width, const double height )
277 {
278  //update item positions
279  QList<QGraphicsItem *> itemList = items();
280  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
281  for ( ; itemIt != itemList.end(); ++itemIt )
282  {
283  QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem *>( *itemIt );
284  if ( composerItem )
285  {
286  composerItem->updatePagePos( width, height );
287  }
288  }
289  //update guide positions and size
290  QList< QGraphicsLineItem* >* guides = snapLines();
291  QList< QGraphicsLineItem* >::iterator guideIt = guides->begin();
292  double totalHeight = ( height + spaceBetweenPages() ) * ( numPages() - 1 ) + height;
293  for ( ; guideIt != guides->end(); ++guideIt )
294  {
295  QLineF line = ( *guideIt )->line();
296  if ( line.dx() == 0 )
297  {
298  //vertical line, change height of line
299  ( *guideIt )->setLine( line.x1(), 0, line.x1(), totalHeight );
300  }
301  else
302  {
303  //horizontal line
304  //move to new vertical position and change width of line
305  QPointF curPagePos = positionOnPage( line.p1() );
306  int curPage = pageNumberForPoint( line.p1() ) - 1;
307  double newY = curPage * ( height + spaceBetweenPages() ) + curPagePos.y();
308  ( *guideIt )->setLine( 0, newY, width, newY );
309  }
310  }
311 
312  mPageWidth = width;
313  mPageHeight = height;
314  double currentY = 0;
315  for ( int i = 0; i < mPages.size(); ++i )
316  {
317  mPages.at( i )->setSceneRect( QRectF( 0, currentY, width, height ) );
318  currentY += ( height + mSpaceBetweenPages );
319  }
320  QgsProject::instance()->dirty( true );
321  updateBounds();
322  emit paperSizeChanged();
323 }
324 
326 {
327  return mPageHeight;
328 }
329 
331 {
332  return mPageWidth;
333 }
334 
335 void QgsComposition::setNumPages( const int pages )
336 {
337  int currentPages = numPages();
338  int desiredPages = pages;
339 
340  //data defined num pages set?
341  QVariant exprVal;
343  {
344  bool ok = false;
345  int pagesD = exprVal.toInt( &ok );
346  QgsDebugMsg( QString( "exprVal NumPages:%1" ).arg( pagesD ) );
347  if ( ok )
348  {
349  desiredPages = pagesD;
350  }
351  }
352 
353  int diff = desiredPages - currentPages;
354  if ( diff >= 0 )
355  {
356  for ( int i = 0; i < diff; ++i )
357  {
358  addPaperItem();
359  }
360  }
361  else
362  {
363  diff = -diff;
364  for ( int i = 0; i < diff; ++i )
365  {
366  delete mPages.last();
367  mPages.removeLast();
368  }
369  }
370 
371  //update vertical guide height
372  QList< QGraphicsLineItem* >* guides = snapLines();
373  QList< QGraphicsLineItem* >::iterator guideIt = guides->begin();
374  double totalHeight = ( mPageHeight + spaceBetweenPages() ) * ( pages - 1 ) + mPageHeight;
375  for ( ; guideIt != guides->end(); ++guideIt )
376  {
377  QLineF line = ( *guideIt )->line();
378  if ( line.dx() == 0 )
379  {
380  //vertical line, change height of line
381  ( *guideIt )->setLine( line.x1(), 0, line.x1(), totalHeight );
382  }
383  }
384 
385  //update the corresponding variable
386  QgsExpression::setSpecialColumn( "$numpages", QVariant(( int )numPages() ) );
387 
388  QgsProject::instance()->dirty( true );
389  updateBounds();
390 
391  emit nPagesChanged();
392 }
393 
395 {
396  return mPages.size();
397 }
398 
400 {
401  delete mPageStyleSymbol;
402  mPageStyleSymbol = symbol;
403  QgsProject::instance()->dirty( true );
404 }
405 
407 {
408  delete mPageStyleSymbol;
409  QgsStringMap properties;
410  properties.insert( "color", "white" );
411  properties.insert( "style", "solid" );
412  properties.insert( "style_border", "no" );
413  properties.insert( "joinstyle", "miter" );
415 }
416 
417 QPointF QgsComposition::positionOnPage( const QPointF & position ) const
418 {
419  double y;
420  if ( position.y() > ( mPages.size() - 1 ) * ( paperHeight() + spaceBetweenPages() ) )
421  {
422  //y coordinate is greater then the end of the last page, so return distance between
423  //top of last page and y coordinate
424  y = position.y() - ( mPages.size() - 1 ) * ( paperHeight() + spaceBetweenPages() );
425  }
426  else
427  {
428  //y coordinate is less then the end of the last page
429  y = fmod( position.y(), ( paperHeight() + spaceBetweenPages() ) );
430  }
431  return QPointF( position.x(), y );
432 }
433 
434 int QgsComposition::pageNumberForPoint( const QPointF & position ) const
435 {
436  int pageNumber = qFloor( position.y() / ( paperHeight() + spaceBetweenPages() ) ) + 1;
437  pageNumber = pageNumber < 1 ? 1 : pageNumber;
438  pageNumber = pageNumber > mPages.size() ? mPages.size() : pageNumber;
439  return pageNumber;
440 }
441 
442 void QgsComposition::setStatusMessage( const QString & message )
443 {
444  emit statusMsgChanged( message );
445 }
446 
447 QgsComposerItem* QgsComposition::composerItemAt( const QPointF & position , const bool ignoreLocked ) const
448 {
449  return composerItemAt( position, 0, ignoreLocked );
450 }
451 
452 QgsComposerItem* QgsComposition::composerItemAt( const QPointF & position, const QgsComposerItem* belowItem, const bool ignoreLocked ) const
453 {
454  //get a list of items which intersect the specified position, in descending z order
455  QList<QGraphicsItem*> itemList;
456  itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
457  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
458 
459  bool foundBelowItem = false;
460  for ( ; itemIt != itemList.end(); ++itemIt )
461  {
462  QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem *>( *itemIt );
463  QgsPaperItem* paperItem = dynamic_cast<QgsPaperItem*>( *itemIt );
464  if ( composerItem && !paperItem )
465  {
466  // If we are not checking for a an item below a specified item, or if we've
467  // already found that item, then we've found our target
468  if (( ! belowItem || foundBelowItem ) && ( !ignoreLocked || !composerItem->positionLock() ) )
469  {
470  return composerItem;
471  }
472  else
473  {
474  if ( composerItem == belowItem )
475  {
476  //Target item is next in list
477  foundBelowItem = true;
478  }
479  }
480  }
481  }
482  return 0;
483 }
484 
485 int QgsComposition::pageNumberAt( const QPointF& position ) const
486 {
487  return position.y() / ( paperHeight() + spaceBetweenPages() );
488 }
489 
491 {
492  return pageNumberAt( QPointF( item->pos().x(), item->pos().y() ) );
493 }
494 
495 QList<QgsComposerItem*> QgsComposition::selectedComposerItems()
496 {
497  QList<QgsComposerItem*> composerItemList;
498 
499  QList<QGraphicsItem *> graphicsItemList = selectedItems();
500  QList<QGraphicsItem *>::iterator itemIter = graphicsItemList.begin();
501 
502  for ( ; itemIter != graphicsItemList.end(); ++itemIter )
503  {
504  QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem *>( *itemIter );
505  if ( composerItem )
506  {
507  composerItemList.push_back( composerItem );
508  }
509  }
510 
511  return composerItemList;
512 }
513 
514 QList<const QgsComposerMap*> QgsComposition::composerMapItems() const
515 {
516  QList<const QgsComposerMap*> resultList;
517 
518  QList<QGraphicsItem *> itemList = items();
519  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
520  for ( ; itemIt != itemList.end(); ++itemIt )
521  {
522  const QgsComposerMap* composerMap = dynamic_cast<const QgsComposerMap *>( *itemIt );
523  if ( composerMap )
524  {
525  resultList.push_back( composerMap );
526  }
527  }
528 
529  return resultList;
530 }
531 
533 {
534  QList<QGraphicsItem *> itemList = items();
535  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
536  for ( ; itemIt != itemList.end(); ++itemIt )
537  {
538  const QgsComposerMap* composerMap = dynamic_cast<const QgsComposerMap *>( *itemIt );
539  if ( composerMap )
540  {
541  if ( composerMap->id() == id )
542  {
543  return composerMap;
544  }
545  }
546  }
547  return 0;
548 }
549 
551 {
552  // an html item will be a composer frame and if it is we can try to get
553  // its multiframe parent and then try to cast that to a composer html
554  const QgsComposerFrame* composerFrame =
555  dynamic_cast<const QgsComposerFrame *>( item );
556  if ( composerFrame )
557  {
558  const QgsComposerMultiFrame * mypMultiFrame = composerFrame->multiFrame();
559  const QgsComposerHtml* composerHtml =
560  dynamic_cast<const QgsComposerHtml *>( mypMultiFrame );
561  if ( composerHtml )
562  {
563  return composerHtml;
564  }
565  }
566  return 0;
567 }
568 
569 const QgsComposerItem* QgsComposition::getComposerItemById( const QString theId ) const
570 {
571  QList<QGraphicsItem *> itemList = items();
572  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
573  for ( ; itemIt != itemList.end(); ++itemIt )
574  {
575  const QgsComposerItem* mypItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
576  if ( mypItem )
577  {
578  if ( mypItem->id() == theId )
579  {
580  return mypItem;
581  }
582  }
583  }
584  return 0;
585 }
586 
587 #if 0
588 const QgsComposerItem* QgsComposition::getComposerItemByUuid( QString theUuid, bool inAllComposers ) const
589 {
590  //This does not work since it seems impossible to get the QgisApp::instance() from here... Is there a workaround ?
591  QSet<QgsComposer*> composers = QSet<QgsComposer*>();
592 
593  if ( inAllComposers )
594  {
595  composers = QgisApp::instance()->printComposers();
596  }
597  else
598  {
599  composers.insert( this )
600  }
601 
602  QSet<QgsComposer*>::const_iterator it = composers.constBegin();
603  for ( ; it != composers.constEnd(); ++it )
604  {
605  QList<QGraphicsItem *> itemList = ( *it )->items();
606  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
607  for ( ; itemIt != itemList.end(); ++itemIt )
608  {
609  const QgsComposerItem* mypItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
610  if ( mypItem )
611  {
612  if ( mypItem->uuid() == theUuid )
613  {
614  return mypItem;
615  }
616  }
617  }
618  }
619 
620  return 0;
621 }
622 #endif
623 
624 const QgsComposerItem* QgsComposition::getComposerItemByUuid( const QString theUuid ) const
625 {
626  QList<QGraphicsItem *> itemList = items();
627  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
628  for ( ; itemIt != itemList.end(); ++itemIt )
629  {
630  const QgsComposerItem* mypItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
631  if ( mypItem )
632  {
633  if ( mypItem->uuid() == theUuid )
634  {
635  return mypItem;
636  }
637  }
638  }
639 
640  return 0;
641 }
642 
644 {
645  mPrintResolution = dpi;
646  emit printResolutionChanged();
647  QgsProject::instance()->dirty( true );
648 }
649 
650 void QgsComposition::setUseAdvancedEffects( const bool effectsEnabled )
651 {
652  mUseAdvancedEffects = effectsEnabled;
653 
654  //toggle effects for all composer items
655  QList<QGraphicsItem*> itemList = items();
656  QList<QGraphicsItem*>::const_iterator itemIt = itemList.constBegin();
657  for ( ; itemIt != itemList.constEnd(); ++itemIt )
658  {
659  QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem*>( *itemIt );
660  if ( composerItem )
661  {
662  composerItem->setEffectsEnabled( effectsEnabled );
663  }
664  }
665 }
666 
667 int QgsComposition::pixelFontSize( double pointSize ) const
668 {
669  return qRound( QgsComposerUtils::pointsToMM( pointSize ) ); //round to nearest mm
670 }
671 
672 double QgsComposition::pointFontSize( int pixelSize ) const
673 {
674  return QgsComposerUtils::mmToPoints( pixelSize );
675 }
676 
677 bool QgsComposition::writeXML( QDomElement& composerElem, QDomDocument& doc )
678 {
679  if ( composerElem.isNull() )
680  {
681  return false;
682  }
683 
684  QDomElement compositionElem = doc.createElement( "Composition" );
685  compositionElem.setAttribute( "paperWidth", QString::number( mPageWidth ) );
686  compositionElem.setAttribute( "paperHeight", QString::number( mPageHeight ) );
687  compositionElem.setAttribute( "numPages", mPages.size() );
688 
689  QDomElement pageStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mPageStyleSymbol, doc );
690  compositionElem.appendChild( pageStyleElem );
691 
692  //snapping
693  if ( mSnapToGrid )
694  {
695  compositionElem.setAttribute( "snapping", "1" );
696  }
697  else
698  {
699  compositionElem.setAttribute( "snapping", "0" );
700  }
701  if ( mGridVisible )
702  {
703  compositionElem.setAttribute( "gridVisible", "1" );
704  }
705  else
706  {
707  compositionElem.setAttribute( "gridVisible", "0" );
708  }
709  compositionElem.setAttribute( "snapGridResolution", QString::number( mSnapGridResolution ) );
710  compositionElem.setAttribute( "snapGridOffsetX", QString::number( mSnapGridOffsetX ) );
711  compositionElem.setAttribute( "snapGridOffsetY", QString::number( mSnapGridOffsetY ) );
712 
713  //custom snap lines
714  QList< QGraphicsLineItem* >::const_iterator snapLineIt = mSnapLines.constBegin();
715  for ( ; snapLineIt != mSnapLines.constEnd(); ++snapLineIt )
716  {
717  QDomElement snapLineElem = doc.createElement( "SnapLine" );
718  QLineF line = ( *snapLineIt )->line();
719  snapLineElem.setAttribute( "x1", QString::number( line.x1() ) );
720  snapLineElem.setAttribute( "y1", QString::number( line.y1() ) );
721  snapLineElem.setAttribute( "x2", QString::number( line.x2() ) );
722  snapLineElem.setAttribute( "y2", QString::number( line.y2() ) );
723  compositionElem.appendChild( snapLineElem );
724  }
725 
726  compositionElem.setAttribute( "printResolution", mPrintResolution );
727  compositionElem.setAttribute( "printAsRaster", mPrintAsRaster );
728 
729  compositionElem.setAttribute( "generateWorldFile", mGenerateWorldFile ? 1 : 0 );
731  {
732  compositionElem.setAttribute( "worldFileMap", mWorldFileMap->id() );
733  }
734 
735  compositionElem.setAttribute( "alignmentSnap", mAlignmentSnap ? 1 : 0 );
736  compositionElem.setAttribute( "guidesVisible", mGuidesVisible ? 1 : 0 );
737  compositionElem.setAttribute( "smartGuides", mSmartGuides ? 1 : 0 );
738  compositionElem.setAttribute( "snapTolerancePixels", mSnapTolerance );
739 
740  //save items except paper items and frame items (they are saved with the corresponding multiframe)
741  QList<QGraphicsItem*> itemList = items();
742  QList<QGraphicsItem*>::const_iterator itemIt = itemList.constBegin();
743  for ( ; itemIt != itemList.constEnd(); ++itemIt )
744  {
745  const QgsComposerItem* composerItem = dynamic_cast<const QgsComposerItem*>( *itemIt );
746  if ( composerItem )
747  {
748  if ( composerItem->type() != QgsComposerItem::ComposerPaper && composerItem->type() != QgsComposerItem::ComposerFrame )
749  {
750  composerItem->writeXML( compositionElem, doc );
751  }
752  }
753  }
754 
755  //save multiframes
756  QSet<QgsComposerMultiFrame*>::const_iterator multiFrameIt = mMultiFrames.constBegin();
757  for ( ; multiFrameIt != mMultiFrames.constEnd(); ++multiFrameIt )
758  {
759  ( *multiFrameIt )->writeXML( compositionElem, doc );
760  }
761  composerElem.appendChild( compositionElem );
762 
763  //data defined properties
765 
766  return true;
767 }
768 
769 bool QgsComposition::readXML( const QDomElement& compositionElem, const QDomDocument& doc )
770 {
771  Q_UNUSED( doc );
772  if ( compositionElem.isNull() )
773  {
774  return false;
775  }
776 
777  //create pages
778  bool widthConversionOk, heightConversionOk;
779  mPageWidth = compositionElem.attribute( "paperWidth" ).toDouble( &widthConversionOk );
780  mPageHeight = compositionElem.attribute( "paperHeight" ).toDouble( &heightConversionOk );
781  emit paperSizeChanged();
782  int numPages = compositionElem.attribute( "numPages", "1" ).toInt();
783 
784  QDomElement pageStyleSymbolElem = compositionElem.firstChildElement( "symbol" );
785  if ( !pageStyleSymbolElem.isNull() )
786  {
787  delete mPageStyleSymbol;
788  mPageStyleSymbol = dynamic_cast<QgsFillSymbolV2*>( QgsSymbolLayerV2Utils::loadSymbol( pageStyleSymbolElem ) );
789  }
790 
791  if ( widthConversionOk && heightConversionOk )
792  {
794  for ( int i = 0; i < numPages; ++i )
795  {
796  addPaperItem();
797  }
798  }
799 
800  //snapping
801  mSnapToGrid = compositionElem.attribute( "snapping", "0" ).toInt() == 0 ? false : true;
802  mGridVisible = compositionElem.attribute( "gridVisible", "0" ).toInt() == 0 ? false : true;
803 
804  mSnapGridResolution = compositionElem.attribute( "snapGridResolution" ).toDouble();
805  mSnapGridOffsetX = compositionElem.attribute( "snapGridOffsetX" ).toDouble();
806  mSnapGridOffsetY = compositionElem.attribute( "snapGridOffsetY" ).toDouble();
807 
808  mAlignmentSnap = compositionElem.attribute( "alignmentSnap", "1" ).toInt() == 0 ? false : true;
809  mGuidesVisible = compositionElem.attribute( "guidesVisible", "1" ).toInt() == 0 ? false : true;
810  mSmartGuides = compositionElem.attribute( "smartGuides", "1" ).toInt() == 0 ? false : true;
811  mSnapTolerance = compositionElem.attribute( "snapTolerancePixels", "10" ).toInt();
812 
813  //custom snap lines
814  QDomNodeList snapLineNodes = compositionElem.elementsByTagName( "SnapLine" );
815  for ( int i = 0; i < snapLineNodes.size(); ++i )
816  {
817  QDomElement snapLineElem = snapLineNodes.at( i ).toElement();
818  QGraphicsLineItem* snapItem = addSnapLine();
819  double x1 = snapLineElem.attribute( "x1" ).toDouble();
820  double y1 = snapLineElem.attribute( "y1" ).toDouble();
821  double x2 = snapLineElem.attribute( "x2" ).toDouble();
822  double y2 = snapLineElem.attribute( "y2" ).toDouble();
823  snapItem->setLine( x1, y1, x2, y2 );
824  }
825 
826  mPrintAsRaster = compositionElem.attribute( "printAsRaster" ).toInt();
827  mPrintResolution = compositionElem.attribute( "printResolution", "300" ).toInt();
828 
829  mGenerateWorldFile = compositionElem.attribute( "generateWorldFile", "0" ).toInt() == 1 ? true : false;
830 
831  //data defined properties
833 
835 
836  updateBounds();
837 
838  return true;
839 }
840 
841 bool QgsComposition::loadFromTemplate( const QDomDocument& doc, QMap<QString, QString>* substitutionMap, bool addUndoCommands )
842 {
844 
845  //delete all items and emit itemRemoved signal
846  QList<QGraphicsItem *> itemList = items();
847  QList<QGraphicsItem *>::iterator itemIter = itemList.begin();
848  for ( ; itemIter != itemList.end(); ++itemIter )
849  {
850  QgsComposerItem* cItem = dynamic_cast<QgsComposerItem*>( *itemIter );
851  if ( cItem )
852  {
853  removeItem( cItem );
854  emit itemRemoved( cItem );
855  delete cItem;
856  }
857  }
858  mItemsModel->clear();
859 
860  mPages.clear();
861  mUndoStack->clear();
862 
863  QDomDocument importDoc;
864  if ( substitutionMap )
865  {
866  QString xmlString = doc.toString();
867  QMap<QString, QString>::const_iterator sIt = substitutionMap->constBegin();
868  for ( ; sIt != substitutionMap->constEnd(); ++sIt )
869  {
870  xmlString = xmlString.replace( "[" + sIt.key() + "]", encodeStringForXML( sIt.value() ) );
871  }
872 
873  QString errorMsg;
874  int errorLine, errorColumn;
875  if ( !importDoc.setContent( xmlString, &errorMsg, &errorLine, &errorColumn ) )
876  {
877  return false;
878  }
879  }
880  else
881  {
882  importDoc = doc;
883  }
884 
885  //read general settings
886  QDomElement compositionElem = importDoc.documentElement().firstChildElement( "Composition" );
887  if ( compositionElem.isNull() )
888  {
889  return false;
890  }
891 
892  bool ok = readXML( compositionElem, importDoc );
893  if ( !ok )
894  {
895  return false;
896  }
897 
898  // read atlas parameters - must be done before adding items
899  QDomElement atlasElem = importDoc.documentElement().firstChildElement( "Atlas" );
900  atlasComposition().readXML( atlasElem, importDoc );
901 
902  // remove all uuid attributes since we don't want duplicates UUIDS
903  QDomNodeList composerItemsNodes = importDoc.elementsByTagName( "ComposerItem" );
904  for ( int i = 0; i < composerItemsNodes.count(); ++i )
905  {
906  QDomNode composerItemNode = composerItemsNodes.at( i );
907  if ( composerItemNode.isElement() )
908  {
909  composerItemNode.toElement().setAttribute( "templateUuid", composerItemNode.toElement().attribute( "uuid" ) );
910  composerItemNode.toElement().removeAttribute( "uuid" );
911  }
912  }
913 
914  //addItemsFromXML
915  addItemsFromXML( importDoc.documentElement(), importDoc, 0, addUndoCommands, 0 );
916 
917  //read atlas map parameters (for pre 2.2 templates)
918  //this can only be done after items have been added
919  atlasComposition().readXMLMapSettings( atlasElem, importDoc );
920  return true;
921 }
922 
923 QPointF QgsComposition::minPointFromXml( const QDomElement& elem ) const
924 {
925  double minX = std::numeric_limits<double>::max();
926  double minY = std::numeric_limits<double>::max();
927  QDomNodeList composerItemList = elem.elementsByTagName( "ComposerItem" );
928  for ( int i = 0; i < composerItemList.size(); ++i )
929  {
930  QDomElement currentComposerItemElem = composerItemList.at( i ).toElement();
931  double x, y;
932  bool xOk, yOk;
933  x = currentComposerItemElem.attribute( "x" ).toDouble( &xOk );
934  y = currentComposerItemElem.attribute( "y" ).toDouble( &yOk );
935  if ( !xOk || !yOk )
936  {
937  continue;
938  }
939  minX = qMin( minX, x );
940  minY = qMin( minY, y );
941  }
942  if ( minX < std::numeric_limits<double>::max() )
943  {
944  return QPointF( minX, minY );
945  }
946  else
947  {
948  return QPointF( 0, 0 );
949  }
950 }
951 
952 void QgsComposition::addItemsFromXML( const QDomElement& elem, const QDomDocument& doc, QMap< QgsComposerMap*, int >* mapsToRestore,
953  bool addUndoCommands, QPointF* pos, bool pasteInPlace )
954 {
955  QPointF* pasteInPlacePt = 0;
956 
957  //if we are adding items to a composition which already contains items, we need to make sure
958  //these items are placed at the top of the composition and that zValues are not duplicated
959  //so, calculate an offset which needs to be added to the zValue of created items
960  int zOrderOffset = mItemsModel->zOrderListSize();
961 
962  QPointF pasteShiftPos;
963  QgsComposerItem* lastPastedItem = 0;
964  if ( pos )
965  {
966  //If we are placing items relative to a certain point, then calculate how much we need
967  //to shift the items by so that they are placed at this point
968  //First, calculate the minimum position from the xml
969  QPointF minItemPos = minPointFromXml( elem );
970  //next, calculate how much each item needs to be shifted from its original position
971  //so that it's placed at the correct relative position
972  pasteShiftPos = *pos - minItemPos;
973 
974  //since we are pasting items, clear the existing selection
975  clearSelection();
976  }
977 
978  if ( pasteInPlace )
979  {
980  pasteInPlacePt = new QPointF( 0, pageNumberAt( *pos ) * ( mPageHeight + mSpaceBetweenPages ) );
981  }
982  QDomNodeList composerLabelList = elem.elementsByTagName( "ComposerLabel" );
983  for ( int i = 0; i < composerLabelList.size(); ++i )
984  {
985  QDomElement currentComposerLabelElem = composerLabelList.at( i ).toElement();
986  QgsComposerLabel* newLabel = new QgsComposerLabel( this );
987  newLabel->readXML( currentComposerLabelElem, doc );
988  if ( pos )
989  {
990  if ( pasteInPlacePt )
991  {
992  newLabel->setItemPosition( newLabel->pos().x(), fmod( newLabel->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
993  newLabel->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
994  }
995  else
996  {
997  newLabel->move( pasteShiftPos.x(), pasteShiftPos.y() );
998  }
999  newLabel->setSelected( true );
1000  lastPastedItem = newLabel;
1001  }
1002  addComposerLabel( newLabel );
1003  newLabel->setZValue( newLabel->zValue() + zOrderOffset );
1004  if ( addUndoCommands )
1005  {
1006  pushAddRemoveCommand( newLabel, tr( "Label added" ) );
1007  }
1008  }
1009  // map
1010  QDomNodeList composerMapList = elem.elementsByTagName( "ComposerMap" );
1011  for ( int i = 0; i < composerMapList.size(); ++i )
1012  {
1013  QDomElement currentComposerMapElem = composerMapList.at( i ).toElement();
1014  QgsComposerMap* newMap = new QgsComposerMap( this );
1015 
1016  if ( mapsToRestore )
1017  {
1018  newMap->setUpdatesEnabled( false );
1019  }
1020 
1021  newMap->readXML( currentComposerMapElem, doc );
1022  newMap->assignFreeId();
1023 
1024  if ( mapsToRestore )
1025  {
1026  mapsToRestore->insert( newMap, ( int )( newMap->previewMode() ) );
1028  newMap->setUpdatesEnabled( true );
1029  }
1030  addComposerMap( newMap, false );
1031  newMap->setZValue( newMap->zValue() + zOrderOffset );
1032  if ( pos )
1033  {
1034  if ( pasteInPlace )
1035  {
1036  newMap->setItemPosition( newMap->pos().x(), fmod( newMap->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1037  newMap->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1038  }
1039  else
1040  {
1041  newMap->move( pasteShiftPos.x(), pasteShiftPos.y() );
1042  }
1043  newMap->setSelected( true );
1044  lastPastedItem = newMap;
1045  }
1046 
1047  if ( addUndoCommands )
1048  {
1049  pushAddRemoveCommand( newMap, tr( "Map added" ) );
1050  }
1051  }
1052  //now that all map items have been created, re-connect overview map signals
1053  QList<QgsComposerMap*> maps;
1054  composerItems( maps );
1055  for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
1056  {
1057  QgsComposerMap* map = ( *mit );
1058  if ( map )
1059  {
1060  QList<QgsComposerMapOverview* > overviews = map->mapOverviews();
1061  QList<QgsComposerMapOverview* >::iterator overviewIt = overviews.begin();
1062  for ( ; overviewIt != overviews.end(); ++overviewIt )
1063  {
1064  ( *overviewIt )->connectSignals();
1065  }
1066  }
1067  }
1068 
1069  // arrow
1070  QDomNodeList composerArrowList = elem.elementsByTagName( "ComposerArrow" );
1071  for ( int i = 0; i < composerArrowList.size(); ++i )
1072  {
1073  QDomElement currentComposerArrowElem = composerArrowList.at( i ).toElement();
1074  QgsComposerArrow* newArrow = new QgsComposerArrow( this );
1075  newArrow->readXML( currentComposerArrowElem, doc );
1076  if ( pos )
1077  {
1078  if ( pasteInPlace )
1079  {
1080  newArrow->setItemPosition( newArrow->pos().x(), fmod( newArrow->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1081  newArrow->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1082  }
1083  else
1084  {
1085  newArrow->move( pasteShiftPos.x(), pasteShiftPos.y() );
1086  }
1087  newArrow->setSelected( true );
1088  lastPastedItem = newArrow;
1089  }
1090  addComposerArrow( newArrow );
1091  newArrow->setZValue( newArrow->zValue() + zOrderOffset );
1092  if ( addUndoCommands )
1093  {
1094  pushAddRemoveCommand( newArrow, tr( "Arrow added" ) );
1095  }
1096  }
1097  // scalebar
1098  QDomNodeList composerScaleBarList = elem.elementsByTagName( "ComposerScaleBar" );
1099  for ( int i = 0; i < composerScaleBarList.size(); ++i )
1100  {
1101  QDomElement currentComposerScaleBarElem = composerScaleBarList.at( i ).toElement();
1102  QgsComposerScaleBar* newScaleBar = new QgsComposerScaleBar( this );
1103  newScaleBar->readXML( currentComposerScaleBarElem, doc );
1104  if ( pos )
1105  {
1106  if ( pasteInPlace )
1107  {
1108  newScaleBar->setItemPosition( newScaleBar->pos().x(), fmod( newScaleBar->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1109  newScaleBar->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1110  }
1111  else
1112  {
1113  newScaleBar->move( pasteShiftPos.x(), pasteShiftPos.y() );
1114  }
1115  newScaleBar->setSelected( true );
1116  lastPastedItem = newScaleBar;
1117  }
1118  addComposerScaleBar( newScaleBar );
1119  newScaleBar->setZValue( newScaleBar->zValue() + zOrderOffset );
1120  if ( addUndoCommands )
1121  {
1122  pushAddRemoveCommand( newScaleBar, tr( "Scale bar added" ) );
1123  }
1124  }
1125  // shape
1126  QDomNodeList composerShapeList = elem.elementsByTagName( "ComposerShape" );
1127  for ( int i = 0; i < composerShapeList.size(); ++i )
1128  {
1129  QDomElement currentComposerShapeElem = composerShapeList.at( i ).toElement();
1130  QgsComposerShape* newShape = new QgsComposerShape( this );
1131  newShape->readXML( currentComposerShapeElem, doc );
1132  //new shapes should default to symbol v2
1133  newShape->setUseSymbolV2( true );
1134  if ( pos )
1135  {
1136  if ( pasteInPlace )
1137  {
1138  newShape->setItemPosition( newShape->pos().x(), fmod( newShape->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1139  newShape->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1140  }
1141  else
1142  {
1143  newShape->move( pasteShiftPos.x(), pasteShiftPos.y() );
1144  }
1145  newShape->setSelected( true );
1146  lastPastedItem = newShape;
1147  }
1148  addComposerShape( newShape );
1149  newShape->setZValue( newShape->zValue() + zOrderOffset );
1150  if ( addUndoCommands )
1151  {
1152  pushAddRemoveCommand( newShape, tr( "Shape added" ) );
1153  }
1154  }
1155  // picture
1156  QDomNodeList composerPictureList = elem.elementsByTagName( "ComposerPicture" );
1157  for ( int i = 0; i < composerPictureList.size(); ++i )
1158  {
1159  QDomElement currentComposerPictureElem = composerPictureList.at( i ).toElement();
1160  QgsComposerPicture* newPicture = new QgsComposerPicture( this );
1161  newPicture->readXML( currentComposerPictureElem, doc );
1162  if ( pos )
1163  {
1164  if ( pasteInPlace )
1165  {
1166  newPicture->setItemPosition( newPicture->pos().x(), fmod( newPicture->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1167  newPicture->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1168  }
1169  else
1170  {
1171  newPicture->move( pasteShiftPos.x(), pasteShiftPos.y() );
1172  }
1173  newPicture->setSelected( true );
1174  lastPastedItem = newPicture;
1175  }
1176  addComposerPicture( newPicture );
1177  newPicture->setZValue( newPicture->zValue() + zOrderOffset );
1178  if ( addUndoCommands )
1179  {
1180  pushAddRemoveCommand( newPicture, tr( "Picture added" ) );
1181  }
1182  }
1183  // legend
1184  QDomNodeList composerLegendList = elem.elementsByTagName( "ComposerLegend" );
1185  for ( int i = 0; i < composerLegendList.size(); ++i )
1186  {
1187  QDomElement currentComposerLegendElem = composerLegendList.at( i ).toElement();
1188  QgsComposerLegend* newLegend = new QgsComposerLegend( this );
1189  newLegend->readXML( currentComposerLegendElem, doc );
1190  if ( pos )
1191  {
1192  if ( pasteInPlace )
1193  {
1194  newLegend->setItemPosition( newLegend->pos().x(), fmod( newLegend->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1195  newLegend->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1196  }
1197  else
1198  {
1199  newLegend->move( pasteShiftPos.x(), pasteShiftPos.y() );
1200  }
1201  newLegend->setSelected( true );
1202  lastPastedItem = newLegend;
1203  }
1204  addComposerLegend( newLegend );
1205  newLegend->setZValue( newLegend->zValue() + zOrderOffset );
1206  if ( addUndoCommands )
1207  {
1208  pushAddRemoveCommand( newLegend, tr( "Legend added" ) );
1209  }
1210  }
1211  // table
1212  QDomNodeList composerTableList = elem.elementsByTagName( "ComposerAttributeTable" );
1213  for ( int i = 0; i < composerTableList.size(); ++i )
1214  {
1215  QDomElement currentComposerTableElem = composerTableList.at( i ).toElement();
1216  QgsComposerAttributeTable* newTable = new QgsComposerAttributeTable( this );
1217  newTable->readXML( currentComposerTableElem, doc );
1218  if ( pos )
1219  {
1220  if ( pasteInPlace )
1221  {
1222  newTable->setItemPosition( newTable->pos().x(), fmod( newTable->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1223  newTable->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1224  }
1225  else
1226  {
1227  newTable->move( pasteShiftPos.x(), pasteShiftPos.y() );
1228  }
1229  newTable->setSelected( true );
1230  lastPastedItem = newTable;
1231  }
1232  addComposerTable( newTable );
1233  newTable->setZValue( newTable->zValue() + zOrderOffset );
1234  if ( addUndoCommands )
1235  {
1236  pushAddRemoveCommand( newTable, tr( "Table added" ) );
1237  }
1238  }
1239  // html
1240  //TODO - fix this. pasting html items has no effect
1241  QDomNodeList composerHtmlList = elem.elementsByTagName( "ComposerHtml" );
1242  for ( int i = 0; i < composerHtmlList.size(); ++i )
1243  {
1244  QDomElement currentHtmlElem = composerHtmlList.at( i ).toElement();
1245  QgsComposerHtml* newHtml = new QgsComposerHtml( this, false );
1246  newHtml->readXML( currentHtmlElem, doc );
1247  newHtml->setCreateUndoCommands( true );
1248  this->addMultiFrame( newHtml );
1249 
1250  //offset z values for frames
1251  //TODO - fix this after fixing html item paste
1252  /*for ( int frameIdx = 0; frameIdx < newHtml->frameCount(); ++frameIdx )
1253  {
1254  QgsComposerFrame * frame = newHtml->frame( frameIdx );
1255  frame->setZValue( frame->zValue() + zOrderOffset );
1256  }*/
1257  }
1258 
1259  // groups (must be last as it references uuids of above items)
1260  //TODO - pasted groups lose group properties, since the uuids of group items
1261  //changes
1262  QDomNodeList groupList = elem.elementsByTagName( "ComposerItemGroup" );
1263  for ( int i = 0; i < groupList.size(); ++i )
1264  {
1265  QDomElement groupElem = groupList.at( i ).toElement();
1266  QgsComposerItemGroup *newGroup = new QgsComposerItemGroup( this );
1267  newGroup->readXML( groupElem, doc );
1268  addItem( newGroup );
1269  }
1270 
1271  //Since this function adds items grouped by type, and each item is added to end of
1272  //z order list in turn, it will now be inconsistent with the actual order of items in the scene.
1273  //Make sure z order list matches the actual order of items in the scene.
1275 
1276  if ( lastPastedItem )
1277  {
1278  emit selectedItemChanged( lastPastedItem );
1279  }
1280 
1281  delete pasteInPlacePt;
1282  pasteInPlacePt = 0;
1283 
1284 }
1285 
1287 {
1288  if ( !item )
1289  {
1290  return;
1291  }
1292 
1293  //model handles changes to z list
1294  mItemsModel->addItemAtTop( item );
1295 }
1296 
1298 {
1299  if ( !item )
1300  {
1301  return;
1302  }
1303 
1304  //model handles changes to z list
1305  mItemsModel->removeItem( item );
1306 }
1307 
1309 {
1310  QList<QgsComposerItem*> selectedItems = selectedComposerItems();
1311  QList<QgsComposerItem*>::iterator it = selectedItems.begin();
1312  bool itemsRaised = false;
1313  for ( ; it != selectedItems.end(); ++it )
1314  {
1315  itemsRaised = itemsRaised | raiseItem( *it );
1316  }
1317 
1318  if ( !itemsRaised )
1319  {
1320  //no change
1321  return;
1322  }
1323 
1324  //update all positions
1325  updateZValues();
1326  update();
1327 }
1328 
1330 {
1331  //model handles reordering items
1332  return mItemsModel->reorderItemUp( item );
1333 }
1334 
1336 {
1337  return mItemsModel->getComposerItemAbove( item );
1338 }
1339 
1341 {
1342  return mItemsModel->getComposerItemBelow( item );
1343 }
1344 
1346 {
1347  QgsComposerItem* previousSelectedItem = 0;
1348  QList<QgsComposerItem*> selectedItems = selectedComposerItems();
1349  if ( selectedItems.size() > 0 )
1350  {
1351  previousSelectedItem = selectedItems.at( 0 );
1352  }
1353 
1354  if ( !previousSelectedItem )
1355  {
1356  return;
1357  }
1358 
1359  //select item with target z value
1360  QgsComposerItem* selectedItem = 0;
1361  switch ( direction )
1362  {
1364  selectedItem = getComposerItemBelow( previousSelectedItem );
1365  break;
1367  selectedItem = getComposerItemAbove( previousSelectedItem );
1368  break;
1369  }
1370 
1371  if ( !selectedItem )
1372  {
1373  return;
1374  }
1375 
1376  //ok, found a good target item
1377  clearSelection();
1378  selectedItem->setSelected( true );
1379  emit selectedItemChanged( selectedItem );
1380 }
1381 
1383 {
1384  QList<QgsComposerItem*> selectedItems = selectedComposerItems();
1385  QList<QgsComposerItem*>::iterator it = selectedItems.begin();
1386  bool itemsLowered = false;
1387  for ( ; it != selectedItems.end(); ++it )
1388  {
1389  itemsLowered = itemsLowered | lowerItem( *it );
1390  }
1391 
1392  if ( !itemsLowered )
1393  {
1394  //no change
1395  return;
1396  }
1397 
1398  //update all positions
1399  updateZValues();
1400  update();
1401 }
1402 
1404 {
1405  //model handles reordering items
1406  return mItemsModel->reorderItemDown( item );
1407 }
1408 
1410 {
1411  QList<QgsComposerItem*> selectedItems = selectedComposerItems();
1412  QList<QgsComposerItem*>::iterator it = selectedItems.begin();
1413  bool itemsRaised = false;
1414  for ( ; it != selectedItems.end(); ++it )
1415  {
1416  itemsRaised = itemsRaised | moveItemToTop( *it );
1417  }
1418 
1419  if ( !itemsRaised )
1420  {
1421  //no change
1422  return;
1423  }
1424 
1425  //update all positions
1426  updateZValues();
1427  update();
1428 }
1429 
1431 {
1432  //model handles reordering items
1433  return mItemsModel->reorderItemToTop( item );
1434 }
1435 
1437 {
1438  QList<QgsComposerItem*> selectedItems = selectedComposerItems();
1439  QList<QgsComposerItem*>::iterator it = selectedItems.begin();
1440  bool itemsLowered = false;
1441  for ( ; it != selectedItems.end(); ++it )
1442  {
1443  itemsLowered = itemsLowered | moveItemToBottom( *it );
1444  }
1445 
1446  if ( !itemsLowered )
1447  {
1448  //no change
1449  return;
1450  }
1451 
1452  //update all positions
1453  updateZValues();
1454  update();
1455 }
1456 
1458 {
1459  //model handles reordering items
1460  return mItemsModel->reorderItemToBottom( item );
1461 }
1462 
1464 {
1465  QList<QgsComposerItem*> selectedItems = selectedComposerItems();
1466  if ( selectedItems.size() < 2 )
1467  {
1468  return;
1469  }
1470 
1471  QRectF selectedItemBBox;
1472  if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
1473  {
1474  return;
1475  }
1476 
1477  double minXCoordinate = selectedItemBBox.left();
1478 
1479  //align items left to minimum x coordinate
1480  QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items left" ) );
1481  QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
1482  for ( ; align_it != selectedItems.end(); ++align_it )
1483  {
1484  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
1485  subcommand->savePreviousState();
1486  ( *align_it )->setPos( minXCoordinate, ( *align_it )->pos().y() );
1487  subcommand->saveAfterState();
1488  }
1489  mUndoStack->push( parentCommand );
1490  QgsProject::instance()->dirty( true );
1491 }
1492 
1494 {
1495  QList<QgsComposerItem*> selectedItems = selectedComposerItems();
1496  if ( selectedItems.size() < 2 )
1497  {
1498  return;
1499  }
1500 
1501  QRectF selectedItemBBox;
1502  if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
1503  {
1504  return;
1505  }
1506 
1507  double averageXCoord = ( selectedItemBBox.left() + selectedItemBBox.right() ) / 2.0;
1508 
1509  //place items
1510  QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items horizontal center" ) );
1511  QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
1512  for ( ; align_it != selectedItems.end(); ++align_it )
1513  {
1514  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
1515  subcommand->savePreviousState();
1516  ( *align_it )->setPos( averageXCoord - ( *align_it )->rect().width() / 2.0, ( *align_it )->pos().y() );
1517  subcommand->saveAfterState();
1518  }
1519  mUndoStack->push( parentCommand );
1520  QgsProject::instance()->dirty( true );
1521 }
1522 
1524 {
1525  QList<QgsComposerItem*> selectedItems = selectedComposerItems();
1526  if ( selectedItems.size() < 2 )
1527  {
1528  return;
1529  }
1530 
1531  QRectF selectedItemBBox;
1532  if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
1533  {
1534  return;
1535  }
1536 
1537  double maxXCoordinate = selectedItemBBox.right();
1538 
1539  //align items right to maximum x coordinate
1540  QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items right" ) );
1541  QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
1542  for ( ; align_it != selectedItems.end(); ++align_it )
1543  {
1544  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
1545  subcommand->savePreviousState();
1546  ( *align_it )->setPos( maxXCoordinate - ( *align_it )->rect().width(), ( *align_it )->pos().y() );
1547  subcommand->saveAfterState();
1548  }
1549  mUndoStack->push( parentCommand );
1550  QgsProject::instance()->dirty( true );
1551 }
1552 
1554 {
1555  QList<QgsComposerItem*> selectedItems = selectedComposerItems();
1556  if ( selectedItems.size() < 2 )
1557  {
1558  return;
1559  }
1560 
1561  QRectF selectedItemBBox;
1562  if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
1563  {
1564  return;
1565  }
1566 
1567  double minYCoordinate = selectedItemBBox.top();
1568 
1569  QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items top" ) );
1570  QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
1571  for ( ; align_it != selectedItems.end(); ++align_it )
1572  {
1573  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
1574  subcommand->savePreviousState();
1575  ( *align_it )->setPos(( *align_it )->pos().x(), minYCoordinate );
1576  subcommand->saveAfterState();
1577  }
1578  mUndoStack->push( parentCommand );
1579  QgsProject::instance()->dirty( true );
1580 }
1581 
1583 {
1584  QList<QgsComposerItem*> selectedItems = selectedComposerItems();
1585  if ( selectedItems.size() < 2 )
1586  {
1587  return;
1588  }
1589 
1590  QRectF selectedItemBBox;
1591  if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
1592  {
1593  return;
1594  }
1595 
1596  double averageYCoord = ( selectedItemBBox.top() + selectedItemBBox.bottom() ) / 2.0;
1597  QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items vertical center" ) );
1598  QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
1599  for ( ; align_it != selectedItems.end(); ++align_it )
1600  {
1601  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
1602  subcommand->savePreviousState();
1603  ( *align_it )->setPos(( *align_it )->pos().x(), averageYCoord - ( *align_it )->rect().height() / 2 );
1604  subcommand->saveAfterState();
1605  }
1606  mUndoStack->push( parentCommand );
1607  QgsProject::instance()->dirty( true );
1608 }
1609 
1611 {
1612  QList<QgsComposerItem*> selectedItems = selectedComposerItems();
1613  if ( selectedItems.size() < 2 )
1614  {
1615  return;
1616  }
1617 
1618  QRectF selectedItemBBox;
1619  if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
1620  {
1621  return;
1622  }
1623 
1624  double maxYCoord = selectedItemBBox.bottom();
1625  QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items bottom" ) );
1626  QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
1627  for ( ; align_it != selectedItems.end(); ++align_it )
1628  {
1629  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
1630  subcommand->savePreviousState();
1631  ( *align_it )->setPos(( *align_it )->pos().x(), maxYCoord - ( *align_it )->rect().height() );
1632  subcommand->saveAfterState();
1633  }
1634  mUndoStack->push( parentCommand );
1635  QgsProject::instance()->dirty( true );
1636 }
1637 
1639 {
1640  QUndoCommand* parentCommand = new QUndoCommand( tr( "Items locked" ) );
1641  QList<QgsComposerItem*> selectionList = selectedComposerItems();
1642  QList<QgsComposerItem*>::iterator itemIter = selectionList.begin();
1643  for ( ; itemIter != selectionList.end(); ++itemIter )
1644  {
1645  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *itemIter, "", parentCommand );
1646  subcommand->savePreviousState();
1647  ( *itemIter )->setPositionLock( true );
1648  subcommand->saveAfterState();
1649  }
1650 
1651  clearSelection();
1652  mUndoStack->push( parentCommand );
1653  QgsProject::instance()->dirty( true );
1654 }
1655 
1657 {
1658  //unlock all items in composer
1659 
1660  QUndoCommand* parentCommand = new QUndoCommand( tr( "Items unlocked" ) );
1661 
1662  //first, clear the selection
1663  clearSelection();
1664 
1665  QList<QGraphicsItem *> itemList = items();
1666  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1667  for ( ; itemIt != itemList.end(); ++itemIt )
1668  {
1669  QgsComposerItem* mypItem = dynamic_cast<QgsComposerItem *>( *itemIt );
1670  if ( mypItem && mypItem->positionLock() )
1671  {
1672  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( mypItem, "", parentCommand );
1673  subcommand->savePreviousState();
1674  mypItem->setPositionLock( false );
1675  //select unlocked items, same behaviour as illustrator
1676  mypItem->setSelected( true );
1677  emit selectedItemChanged( mypItem );
1678  subcommand->saveAfterState();
1679  }
1680  }
1681  mUndoStack->push( parentCommand );
1682  QgsProject::instance()->dirty( true );
1683 }
1684 
1685 void QgsComposition::updateZValues( const bool addUndoCommands )
1686 {
1687  int counter = mItemsModel->zOrderListSize();
1688  QList<QgsComposerItem*>::const_iterator it = mItemsModel->zOrderList()->constBegin();
1689  QgsComposerItem* currentItem = 0;
1690 
1691  QUndoCommand* parentCommand = 0;
1692  if ( addUndoCommands )
1693  {
1694  parentCommand = new QUndoCommand( tr( "Item z-order changed" ) );
1695  }
1696  for ( ; it != mItemsModel->zOrderList()->constEnd(); ++it )
1697  {
1698  currentItem = *it;
1699  if ( currentItem )
1700  {
1701  QgsComposerItemCommand* subcommand = 0;
1702  if ( addUndoCommands )
1703  {
1704  subcommand = new QgsComposerItemCommand( *it, "", parentCommand );
1705  subcommand->savePreviousState();
1706  }
1707  currentItem->setZValue( counter );
1708  if ( addUndoCommands )
1709  {
1710  subcommand->saveAfterState();
1711  }
1712  }
1713  --counter;
1714  }
1715  if ( addUndoCommands )
1716  {
1717  mUndoStack->push( parentCommand );
1718  QgsProject::instance()->dirty( true );
1719  }
1720 }
1721 
1723 {
1724  //model handles changes to item z order list
1726 
1727  //Finally, rebuild the zValue of all items to remove any duplicate zValues and make sure there's
1728  //no missing zValues.
1729  updateZValues( false );
1730 }
1731 
1732 QPointF QgsComposition::snapPointToGrid( const QPointF& scenePoint ) const
1733 {
1734  if ( !mSnapToGrid || mSnapGridResolution <= 0 || !graphicsView() )
1735  {
1736  return scenePoint;
1737  }
1738 
1739  //y offset to current page
1740  int pageNr = ( int )( scenePoint.y() / ( mPageHeight + mSpaceBetweenPages ) );
1741  double yOffset = pageNr * ( mPageHeight + mSpaceBetweenPages );
1742  double yPage = scenePoint.y() - yOffset; //y-coordinate relative to current page
1743 
1744  //snap x coordinate
1745  int xRatio = ( int )(( scenePoint.x() - mSnapGridOffsetX ) / mSnapGridResolution + 0.5 );
1746  int yRatio = ( int )(( yPage - mSnapGridOffsetY ) / mSnapGridResolution + 0.5 );
1747 
1748  double xSnapped = xRatio * mSnapGridResolution + mSnapGridOffsetX;
1749  double ySnapped = yRatio * mSnapGridResolution + mSnapGridOffsetY + yOffset;
1750 
1751  //convert snap tolerance from pixels to mm
1752  double viewScaleFactor = graphicsView()->transform().m11();
1753  double alignThreshold = mSnapTolerance / viewScaleFactor;
1754 
1755  if ( fabs( xSnapped - scenePoint.x() ) > alignThreshold )
1756  {
1757  //snap distance is outside of tolerance
1758  xSnapped = scenePoint.x();
1759  }
1760  if ( fabs( ySnapped - scenePoint.y() ) > alignThreshold )
1761  {
1762  //snap distance is outside of tolerance
1763  ySnapped = scenePoint.y();
1764  }
1765 
1766  return QPointF( xSnapped, ySnapped );
1767 }
1768 
1769 QGraphicsLineItem* QgsComposition::addSnapLine()
1770 {
1771  QGraphicsLineItem* item = new QGraphicsLineItem();
1772  QPen linePen( Qt::SolidLine );
1773  linePen.setColor( Qt::red );
1774  // use a pen width of 0, since this activates a cosmetic pen
1775  // which doesn't scale with the composer and keeps a constant size
1776  linePen.setWidthF( 0 );
1777  item->setPen( linePen );
1778  item->setZValue( 100 );
1779  item->setVisible( mGuidesVisible );
1780  addItem( item );
1781  mSnapLines.push_back( item );
1782  return item;
1783 }
1784 
1785 void QgsComposition::removeSnapLine( QGraphicsLineItem* line )
1786 {
1787  removeItem( line );
1788  mSnapLines.removeAll( line );
1789  delete line;
1790 }
1791 
1793 {
1794  QList< QGraphicsLineItem* >::iterator it = mSnapLines.begin();
1795  for ( ; it != mSnapLines.end(); ++it )
1796  {
1797  removeItem(( *it ) );
1798  delete( *it );
1799  }
1800  mSnapLines.clear();
1801 }
1802 
1803 void QgsComposition::setSnapLinesVisible( const bool visible )
1804 {
1805  mGuidesVisible = visible;
1806  QList< QGraphicsLineItem* >::iterator it = mSnapLines.begin();
1807  for ( ; it != mSnapLines.end(); ++it )
1808  {
1809  if ( visible )
1810  {
1811  ( *it )->show();
1812  }
1813  else
1814  {
1815  ( *it )->hide();
1816  }
1817  }
1818 }
1819 
1820 QGraphicsLineItem* QgsComposition::nearestSnapLine( const bool horizontal, const double x, const double y, const double tolerance,
1821  QList< QPair< QgsComposerItem*, QgsComposerItem::ItemPositionMode> >& snappedItems ) const
1822 {
1823  double minSqrDist = DBL_MAX;
1824  QGraphicsLineItem* item = 0;
1825  double currentXCoord = 0;
1826  double currentYCoord = 0;
1827  double currentSqrDist = 0;
1828  double sqrTolerance = tolerance * tolerance;
1829 
1830  snappedItems.clear();
1831 
1832  QList< QGraphicsLineItem* >::const_iterator it = mSnapLines.constBegin();
1833  for ( ; it != mSnapLines.constEnd(); ++it )
1834  {
1835  bool itemHorizontal = qgsDoubleNear(( *it )->line().y2() - ( *it )->line().y1(), 0 );
1836  if ( horizontal && itemHorizontal )
1837  {
1838  currentYCoord = ( *it )->line().y1();
1839  currentSqrDist = ( y - currentYCoord ) * ( y - currentYCoord );
1840  }
1841  else if ( !horizontal && !itemHorizontal )
1842  {
1843  currentXCoord = ( *it )->line().x1();
1844  currentSqrDist = ( x - currentXCoord ) * ( x - currentXCoord );
1845  }
1846  else
1847  {
1848  continue;
1849  }
1850 
1851  if ( currentSqrDist < minSqrDist && currentSqrDist < sqrTolerance )
1852  {
1853  item = *it;
1854  minSqrDist = currentSqrDist;
1855  }
1856  }
1857 
1858  double itemTolerance = 0.0000001;
1859  if ( item )
1860  {
1861  //go through all the items to find items snapped to this snap line
1862  QList<QGraphicsItem *> itemList = items();
1863  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1864  for ( ; itemIt != itemList.end(); ++itemIt )
1865  {
1866  QgsComposerItem* currentItem = dynamic_cast<QgsComposerItem*>( *itemIt );
1867  if ( !currentItem || currentItem->type() == QgsComposerItem::ComposerPaper )
1868  {
1869  continue;
1870  }
1871 
1872  if ( horizontal )
1873  {
1874  if ( qgsDoubleNear( currentYCoord, currentItem->pos().y() + currentItem->rect().top(), itemTolerance ) )
1875  {
1876  snappedItems.append( qMakePair( currentItem, QgsComposerItem::UpperMiddle ) );
1877  }
1878  else if ( qgsDoubleNear( currentYCoord, currentItem->pos().y() + currentItem->rect().center().y(), itemTolerance ) )
1879  {
1880  snappedItems.append( qMakePair( currentItem, QgsComposerItem::Middle ) );
1881  }
1882  else if ( qgsDoubleNear( currentYCoord, currentItem->pos().y() + currentItem->rect().bottom(), itemTolerance ) )
1883  {
1884  snappedItems.append( qMakePair( currentItem, QgsComposerItem::LowerMiddle ) );
1885  }
1886  }
1887  else
1888  {
1889  if ( qgsDoubleNear( currentXCoord, currentItem->pos().x(), itemTolerance ) )
1890  {
1891  snappedItems.append( qMakePair( currentItem, QgsComposerItem::MiddleLeft ) );
1892  }
1893  else if ( qgsDoubleNear( currentXCoord, currentItem->pos().x() + currentItem->rect().center().x(), itemTolerance ) )
1894  {
1895  snappedItems.append( qMakePair( currentItem, QgsComposerItem::Middle ) );
1896  }
1897  else if ( qgsDoubleNear( currentXCoord, currentItem->pos().x() + currentItem->rect().width(), itemTolerance ) )
1898  {
1899  snappedItems.append( qMakePair( currentItem, QgsComposerItem::MiddleRight ) );
1900  }
1901  }
1902  }
1903  }
1904 
1905  return item;
1906 }
1907 
1909 {
1910  QList<QgsComposerItem*> selectedItems = selectedComposerItems();
1911  if ( selectedItems.size() < 1 )
1912  {
1913  return 1;
1914  }
1915 
1916  //set the box to the first item
1917  QgsComposerItem* currentItem = selectedItems.at( 0 );
1918  double minX = currentItem->pos().x();
1919  double minY = currentItem->pos().y();
1920  double maxX = minX + currentItem->rect().width();
1921  double maxY = minY + currentItem->rect().height();
1922 
1923  double currentMinX, currentMinY, currentMaxX, currentMaxY;
1924 
1925  for ( int i = 1; i < selectedItems.size(); ++i )
1926  {
1927  currentItem = selectedItems.at( i );
1928  currentMinX = currentItem->pos().x();
1929  currentMinY = currentItem->pos().y();
1930  currentMaxX = currentMinX + currentItem->rect().width();
1931  currentMaxY = currentMinY + currentItem->rect().height();
1932 
1933  if ( currentMinX < minX )
1934  minX = currentMinX;
1935  if ( currentMaxX > maxX )
1936  maxX = currentMaxX;
1937  if ( currentMinY < minY )
1938  minY = currentMinY;
1939  if ( currentMaxY > maxY )
1940  maxY = currentMaxY;
1941  }
1942 
1943  bRect.setTopLeft( QPointF( minX, minY ) );
1944  bRect.setBottomRight( QPointF( maxX, maxY ) );
1945  return 0;
1946 }
1947 
1949 {
1950  mSnapToGrid = b;
1951  updatePaperItems();
1952 }
1953 
1955 {
1956  mGridVisible = b;
1957  updatePaperItems();
1958 }
1959 
1961 {
1962  mSnapGridResolution = r;
1963  updatePaperItems();
1964 }
1965 
1966 void QgsComposition::setSnapGridOffsetX( const double offset )
1967 {
1968  mSnapGridOffsetX = offset;
1969  updatePaperItems();
1970 }
1971 
1972 void QgsComposition::setSnapGridOffsetY( const double offset )
1973 {
1974  mSnapGridOffsetY = offset;
1975  updatePaperItems();
1976 }
1977 
1978 void QgsComposition::setGridPen( const QPen& p )
1979 {
1980  mGridPen = p;
1981  //make sure grid is drawn using a zero-width cosmetic pen
1982  mGridPen.setWidthF( 0 );
1983  updatePaperItems();
1984 }
1985 
1987 {
1988  mGridStyle = s;
1989  updatePaperItems();
1990 }
1991 
1993 {
1994  //load new composer setting values
1995  loadSettings();
1996  //update any paper items to reflect new settings
1997  updatePaperItems();
1998 }
1999 
2001 {
2002  //read grid style, grid color and pen width from settings
2003  QSettings s;
2004 
2005  QString gridStyleString;
2006  gridStyleString = s.value( "/Composer/gridStyle", "Dots" ).toString();
2007 
2008  int gridRed, gridGreen, gridBlue, gridAlpha;
2009  gridRed = s.value( "/Composer/gridRed", 190 ).toInt();
2010  gridGreen = s.value( "/Composer/gridGreen", 190 ).toInt();
2011  gridBlue = s.value( "/Composer/gridBlue", 190 ).toInt();
2012  gridAlpha = s.value( "/Composer/gridAlpha", 100 ).toInt();
2013  QColor gridColor = QColor( gridRed, gridGreen, gridBlue, gridAlpha );
2014 
2015  mGridPen.setColor( gridColor );
2016  mGridPen.setWidthF( 0 );
2017 
2018  if ( gridStyleString == "Dots" )
2019  {
2020  mGridStyle = Dots;
2021  }
2022  else if ( gridStyleString == "Crosses" )
2023  {
2024  mGridStyle = Crosses;
2025  }
2026  else
2027  {
2028  mGridStyle = Solid;
2029  }
2030 }
2031 
2032 void QgsComposition::beginCommand( QgsComposerItem* item, const QString& commandText, const QgsComposerMergeCommand::Context c )
2033 {
2034  delete mActiveItemCommand;
2035  if ( !item )
2036  {
2037  mActiveItemCommand = 0;
2038  return;
2039  }
2040 
2042  {
2043  mActiveItemCommand = new QgsComposerItemCommand( item, commandText );
2044  }
2045  else
2046  {
2047  mActiveItemCommand = new QgsComposerMergeCommand( c, item, commandText );
2048  }
2050 }
2051 
2053 {
2054  if ( mActiveItemCommand )
2055  {
2057  if ( mActiveItemCommand->containsChange() ) //protect against empty commands
2058  {
2059  mUndoStack->push( mActiveItemCommand );
2060  QgsProject::instance()->dirty( true );
2061  }
2062  else
2063  {
2064  delete mActiveItemCommand;
2065  }
2066  mActiveItemCommand = 0;
2067  }
2068 }
2069 
2071 {
2072  delete mActiveItemCommand;
2073  mActiveItemCommand = 0;
2074 }
2075 
2077 {
2078  delete mActiveMultiFrameCommand;
2079 
2080  if ( !multiFrame )
2081  {
2083  return;
2084  }
2085 
2087  {
2088  mActiveMultiFrameCommand = new QgsComposerMultiFrameCommand( multiFrame, text );
2089  }
2090  else
2091  {
2092  mActiveMultiFrameCommand = new QgsComposerMultiFrameMergeCommand( c, multiFrame, text );
2093  }
2095 }
2096 
2098 {
2100  {
2103  {
2105  QgsProject::instance()->dirty( true );
2106  }
2107  else
2108  {
2109  delete mActiveMultiFrameCommand;
2110  }
2112  }
2113 }
2114 
2116 {
2117  mMultiFrames.insert( multiFrame );
2118 
2119  updateBounds();
2120 }
2121 
2123 {
2124  mMultiFrames.remove( multiFrame );
2125 
2126  updateBounds();
2127 }
2128 
2130 {
2131  addItem( arrow );
2132 
2133  updateBounds();
2134  connect( arrow, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2135 
2136  emit composerArrowAdded( arrow );
2137 }
2138 
2140 {
2141  addItem( label );
2142 
2143  updateBounds();
2144  connect( label, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2145 
2146  emit composerLabelAdded( label );
2147 }
2148 
2149 void QgsComposition::addComposerMap( QgsComposerMap* map, const bool setDefaultPreviewStyle )
2150 {
2151  addItem( map );
2152  if ( setDefaultPreviewStyle )
2153  {
2154  //set default preview mode to cache. Must be done here between adding composer map to scene and emiting signal
2156  }
2157 
2158  if ( map->previewMode() != QgsComposerMap::Rectangle )
2159  {
2160  map->cache();
2161  }
2162 
2163  updateBounds();
2164  connect( map, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2165 
2166  emit composerMapAdded( map );
2167 }
2168 
2170 {
2171  addItem( scaleBar );
2172 
2173  updateBounds();
2174  connect( scaleBar, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2175 
2176  emit composerScaleBarAdded( scaleBar );
2177 }
2178 
2180 {
2181  addItem( legend );
2182 
2183  updateBounds();
2184  connect( legend, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2185 
2186  emit composerLegendAdded( legend );
2187 }
2188 
2190 {
2191  addItem( picture );
2192 
2193  updateBounds();
2194  connect( picture, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2195 
2196  emit composerPictureAdded( picture );
2197 }
2198 
2200 {
2201  addItem( shape );
2202 
2203  updateBounds();
2204  connect( shape, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2205 
2206  emit composerShapeAdded( shape );
2207 }
2208 
2210 {
2211  addItem( table );
2212 
2213  updateBounds();
2214  connect( table, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2215 
2216  emit composerTableAdded( table );
2217 }
2218 
2220 {
2221  addItem( frame );
2222 
2223  updateBounds();
2224  connect( frame, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2225 
2226  emit composerHtmlFrameAdded( html, frame );
2227 }
2228 
2229 void QgsComposition::removeComposerItem( QgsComposerItem* item, const bool createCommand, const bool removeGroupItems )
2230 {
2231  QgsComposerMap* map = dynamic_cast<QgsComposerMap *>( item );
2232 
2233  if ( !map || !map->isDrawing() ) //don't delete a composer map while it draws
2234  {
2235  mItemsModel->setItemRemoved( item );
2236  removeItem( item );
2237 
2238  QgsComposerItemGroup* itemGroup = dynamic_cast<QgsComposerItemGroup*>( item );
2239  if ( itemGroup && removeGroupItems )
2240  {
2241  //add add/remove item command for every item in the group
2242  QUndoCommand* parentCommand = new QUndoCommand( tr( "Remove item group" ) );
2243 
2244  QSet<QgsComposerItem*> groupedItems = itemGroup->items();
2245  QSet<QgsComposerItem*>::iterator it = groupedItems.begin();
2246  for ( ; it != groupedItems.end(); ++it )
2247  {
2248  QgsAddRemoveItemCommand* subcommand = new QgsAddRemoveItemCommand( QgsAddRemoveItemCommand::Removed, *it, this, "", parentCommand );
2249  connectAddRemoveCommandSignals( subcommand );
2250  emit itemRemoved( *it );
2251  }
2252 
2253  undoStack()->push( parentCommand );
2254  emit itemRemoved( itemGroup );
2255  delete itemGroup;
2256  }
2257  else
2258  {
2259  bool frameItem = ( item->type() == QgsComposerItem::ComposerFrame );
2260  QgsComposerMultiFrame* multiFrame = 0;
2261  if ( createCommand )
2262  {
2263  if ( frameItem ) //multiframe tracks item changes
2264  {
2265  multiFrame = static_cast<QgsComposerFrame*>( item )->multiFrame();
2266  item->beginItemCommand( tr( "Frame deleted" ) );
2267  emit itemRemoved( item );
2268  item->endItemCommand();
2269  }
2270  else
2271  {
2272  emit itemRemoved( item );
2273  pushAddRemoveCommand( item, tr( "Item deleted" ), QgsAddRemoveItemCommand::Removed );
2274  }
2275  }
2276  else
2277  {
2278  emit itemRemoved( item );
2279  }
2280 
2281  //check if there are frames left. If not, remove the multi frame
2282  if ( frameItem && multiFrame )
2283  {
2284  if ( multiFrame->frameCount() < 1 )
2285  {
2286  removeMultiFrame( multiFrame );
2287  if ( createCommand )
2288  {
2290  multiFrame, this, tr( "Multiframe removed" ) );
2291  undoStack()->push( command );
2292  }
2293  else
2294  {
2295  delete multiFrame;
2296  }
2297  }
2298  }
2299  }
2300  }
2301 
2302  updateBounds();
2303 }
2304 
2306 {
2307  QgsAddRemoveItemCommand* c = new QgsAddRemoveItemCommand( state, item, this, text );
2309  undoStack()->push( c );
2310  QgsProject::instance()->dirty( true );
2311 }
2312 
2314 {
2315  if ( !c )
2316  {
2317  return;
2318  }
2319 
2320  QObject::connect( c, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SIGNAL( itemRemoved( QgsComposerItem* ) ) );
2321  QObject::connect( c, SIGNAL( itemAdded( QgsComposerItem* ) ), this, SLOT( sendItemAddedSignal( QgsComposerItem* ) ) );
2322 }
2323 
2325 {
2326  //cast and send proper signal
2327  item->setSelected( true );
2328  QgsComposerArrow* arrow = dynamic_cast<QgsComposerArrow*>( item );
2329  if ( arrow )
2330  {
2331  emit composerArrowAdded( arrow );
2332  emit selectedItemChanged( arrow );
2333  return;
2334  }
2335  QgsComposerLabel* label = dynamic_cast<QgsComposerLabel*>( item );
2336  if ( label )
2337  {
2338  emit composerLabelAdded( label );
2339  emit selectedItemChanged( label );
2340  return;
2341  }
2342  QgsComposerMap* map = dynamic_cast<QgsComposerMap*>( item );
2343  if ( map )
2344  {
2345  emit composerMapAdded( map );
2346  emit selectedItemChanged( map );
2347  return;
2348  }
2349  QgsComposerScaleBar* scalebar = dynamic_cast<QgsComposerScaleBar*>( item );
2350  if ( scalebar )
2351  {
2352  emit composerScaleBarAdded( scalebar );
2353  emit selectedItemChanged( scalebar );
2354  return;
2355  }
2356  QgsComposerLegend* legend = dynamic_cast<QgsComposerLegend*>( item );
2357  if ( legend )
2358  {
2359  emit composerLegendAdded( legend );
2360  emit selectedItemChanged( legend );
2361  return;
2362  }
2363  QgsComposerPicture* picture = dynamic_cast<QgsComposerPicture*>( item );
2364  if ( picture )
2365  {
2366  emit composerPictureAdded( picture );
2367  emit selectedItemChanged( picture );
2368  return;
2369  }
2370  QgsComposerShape* shape = dynamic_cast<QgsComposerShape*>( item );
2371  if ( shape )
2372  {
2373  emit composerShapeAdded( shape );
2374  emit selectedItemChanged( shape );
2375  return;
2376  }
2377  QgsComposerAttributeTable* table = dynamic_cast<QgsComposerAttributeTable*>( item );
2378  if ( table )
2379  {
2380  emit composerTableAdded( table );
2381  emit selectedItemChanged( table );
2382  return;
2383  }
2384  QgsComposerFrame* frame = dynamic_cast<QgsComposerFrame*>( item );
2385  if ( frame )
2386  {
2387  //emit composerFrameAdded( multiframe, frame, );
2388  QgsComposerMultiFrame* mf = frame->multiFrame();
2389  QgsComposerHtml* html = dynamic_cast<QgsComposerHtml*>( mf );
2390  if ( html )
2391  {
2392  emit composerHtmlFrameAdded( html, frame );
2393  }
2394  emit selectedItemChanged( frame );
2395  return;
2396  }
2397 }
2398 
2400 {
2401  QList< QgsPaperItem* >::iterator paperIt = mPages.begin();
2402  for ( ; paperIt != mPages.end(); ++paperIt )
2403  {
2404  ( *paperIt )->update();
2405  }
2406 }
2407 
2409 {
2410  double paperHeight = this->paperHeight();
2411  double paperWidth = this->paperWidth();
2412  double currentY = paperHeight * mPages.size() + mPages.size() * mSpaceBetweenPages; //add 10mm visible space between pages
2413  QgsPaperItem* paperItem = new QgsPaperItem( 0, currentY, paperWidth, paperHeight, this ); //default size A4
2414  paperItem->setBrush( Qt::white );
2415  addItem( paperItem );
2416  paperItem->setZValue( 0 );
2417  mPages.push_back( paperItem );
2418 
2419  QgsExpression::setSpecialColumn( "$numpages", QVariant(( int )mPages.size() ) );
2420 }
2421 
2423 {
2424  for ( int i = 0; i < mPages.size(); ++i )
2425  {
2426  delete mPages.at( i );
2427  }
2428  mPages.clear();
2429  QgsExpression::setSpecialColumn( "$numpages", QVariant(( int )0 ) );
2430 }
2431 
2433 {
2434  QSet<QgsComposerMultiFrame*>::iterator multiFrameIt = mMultiFrames.begin();
2435  for ( ; multiFrameIt != mMultiFrames.end(); ++multiFrameIt )
2436  {
2437  delete *multiFrameIt;
2438  }
2439  mMultiFrames.clear();
2440 }
2441 
2442 void QgsComposition::beginPrintAsPDF( QPrinter& printer, const QString& file )
2443 {
2444  printer.setOutputFileName( file );
2445  // setOutputFormat should come after setOutputFileName, which auto-sets format to QPrinter::PdfFormat.
2446  // [LS] This should be QPrinter::NativeFormat for Mac, otherwise fonts are not embed-able
2447  // and text is not searchable; however, there are several bugs with <= Qt 4.8.5, 5.1.1, 5.2.0:
2448  // https://bugreports.qt-project.org/browse/QTBUG-10094 - PDF font embedding fails
2449  // https://bugreports.qt-project.org/browse/QTBUG-33583 - PDF output converts text to outline
2450  // Also an issue with PDF paper size using QPrinter::NativeFormat on Mac (always outputs portrait letter-size)
2451  printer.setOutputFormat( QPrinter::PdfFormat );
2452  printer.setOutputFileName( file );
2453  refreshPageSize();
2454  printer.setPaperSize( QSizeF( paperWidth(), paperHeight() ), QPrinter::Millimeter );
2455 
2456  // TODO: add option for this in Composer
2457  // May not work on Windows or non-X11 Linux. Works fine on Mac using QPrinter::NativeFormat
2458  //printer.setFontEmbeddingEnabled( true );
2459 
2460  QgsPaintEngineHack::fixEngineFlags( printer.paintEngine() );
2461 }
2462 
2463 bool QgsComposition::exportAsPDF( const QString& file )
2464 {
2465  QPrinter printer;
2466  beginPrintAsPDF( printer, file );
2467  return print( printer );
2468 }
2469 
2470 void QgsComposition::doPrint( QPrinter& printer, QPainter& p, bool startNewPage )
2471 {
2472  //set the page size again so that data defined page size takes effect
2473  refreshPageSize();
2474  printer.setPaperSize( QSizeF( paperWidth(), paperHeight() ), QPrinter::Millimeter );
2475 
2476  //QgsComposition starts page numbering at 0
2477  int fromPage = ( printer.fromPage() < 1 ) ? 0 : printer.fromPage() - 1 ;
2478  int toPage = ( printer.toPage() < 1 ) ? numPages() - 1 : printer.toPage() - 1;
2479 
2480  if ( mPrintAsRaster )
2481  {
2482  for ( int i = fromPage; i <= toPage; ++i )
2483  {
2484  if ( i > fromPage || startNewPage )
2485  {
2486  printer.newPage();
2487  }
2488 
2489  QImage image = printPageAsRaster( i );
2490  if ( !image.isNull() )
2491  {
2492  QRectF targetArea( 0, 0, image.width(), image.height() );
2493  p.drawImage( targetArea, image, targetArea );
2494  }
2495  }
2496  }
2497 
2498  if ( !mPrintAsRaster )
2499  {
2500  for ( int i = fromPage; i <= toPage; ++i )
2501  {
2502  if ( i > fromPage || startNewPage )
2503  {
2504  printer.newPage();
2505  }
2506  renderPage( &p, i );
2507  }
2508  }
2509 }
2510 
2511 void QgsComposition::beginPrint( QPrinter &printer, const bool evaluateDDPageSize )
2512 {
2513  //set resolution based on composer setting
2514  printer.setFullPage( true );
2515  printer.setColorMode( QPrinter::Color );
2516 
2517  //set user-defined resolution
2518  printer.setResolution( printResolution() );
2519 
2520  if ( evaluateDDPageSize )
2521  {
2522  //set data defined page size
2523  refreshPageSize();
2524  printer.setPaperSize( QSizeF( paperWidth(), paperHeight() ), QPrinter::Millimeter );
2525  printer.setOrientation( paperWidth() > paperHeight() ? QPrinter::Landscape : QPrinter::Portrait );
2526  }
2527 }
2528 
2529 bool QgsComposition::print( QPrinter &printer, const bool evaluateDDPageSize )
2530 {
2531  beginPrint( printer, evaluateDDPageSize );
2532  QPainter p;
2533  bool ready = p.begin( &printer );
2534  if ( !ready )
2535  {
2536  //error beginning print
2537  return false;
2538  }
2539  doPrint( printer, p );
2540  p.end();
2541  return true;
2542 }
2543 
2545 {
2546  //print out via QImage, code copied from on_mActionExportAsImage_activated
2547  int width = ( int )( printResolution() * paperWidth() / 25.4 );
2548  int height = ( int )( printResolution() * paperHeight() / 25.4 );
2549  QImage image( QSize( width, height ), QImage::Format_ARGB32 );
2550  if ( !image.isNull() )
2551  {
2552  image.setDotsPerMeterX( printResolution() / 25.4 * 1000 );
2553  image.setDotsPerMeterY( printResolution() / 25.4 * 1000 );
2554  image.fill( 0 );
2555  QPainter imagePainter( &image );
2556  renderPage( &imagePainter, page );
2557  if ( !imagePainter.isActive() ) return QImage();
2558  }
2559  return image;
2560 }
2561 
2562 void QgsComposition::renderPage( QPainter* p, int page )
2563 {
2564  if ( mPages.size() <= page )
2565  {
2566  return;
2567  }
2568 
2569  QgsPaperItem* paperItem = mPages[page];
2570  if ( !paperItem )
2571  {
2572  return;
2573  }
2574 
2575  QPaintDevice* paintDevice = p->device();
2576  if ( !paintDevice )
2577  {
2578  return;
2579  }
2580 
2581  QRectF paperRect = QRectF( paperItem->pos().x(), paperItem->pos().y(), paperItem->rect().width(), paperItem->rect().height() );
2582 
2583  QgsComposition::PlotStyle savedPlotStyle = mPlotStyle;
2585 
2586  setSnapLinesVisible( false );
2587  //hide background before rendering
2588  setBackgroundBrush( Qt::NoBrush );
2589  render( p, QRectF( 0, 0, paintDevice->width(), paintDevice->height() ), paperRect );
2590  //show background after rendering
2591  setBackgroundBrush( QColor( 215, 215, 215 ) );
2592  setSnapLinesVisible( true );
2593 
2594  mPlotStyle = savedPlotStyle;
2595 }
2596 
2597 QString QgsComposition::encodeStringForXML( const QString& str )
2598 {
2599  QString modifiedStr( str );
2600  modifiedStr.replace( "&", "&amp;" );
2601  modifiedStr.replace( "\"", "&quot;" );
2602  modifiedStr.replace( "'", "&apos;" );
2603  modifiedStr.replace( "<", "&lt;" );
2604  modifiedStr.replace( ">", "&gt;" );
2605  return modifiedStr;
2606 }
2607 
2608 QGraphicsView *QgsComposition::graphicsView() const
2609 {
2610  //try to find current view attached to composition
2611  QList<QGraphicsView*> viewList = views();
2612  if ( viewList.size() > 0 )
2613  {
2614  return viewList.at( 0 );
2615  }
2616 
2617  //no view attached to composition
2618  return 0;
2619 }
2620 
2621 void QgsComposition::computeWorldFileParameters( double& a, double& b, double& c, double& d, double& e, double& f ) const
2622 {
2623  //
2624  // Word file parameters : affine transformation parameters from pixel coordinates to map coordinates
2625 
2626  if ( !mWorldFileMap )
2627  {
2628  return;
2629  }
2630 
2631  QRectF brect = mWorldFileMap->mapRectToScene( mWorldFileMap->rect() );
2633 
2634  double alpha = mWorldFileMap->mapRotation() / 180 * M_PI;
2635 
2636  double xr = extent.width() / brect.width();
2637  double yr = extent.height() / brect.height();
2638 
2639  double XC = extent.center().x();
2640  double YC = extent.center().y();
2641 
2642  // get the extent for the page
2643  double xmin = extent.xMinimum() - mWorldFileMap->pos().x() * xr;
2644  double ymax = extent.yMaximum() + mWorldFileMap->pos().y() * yr;
2645  QgsRectangle paperExtent( xmin, ymax - paperHeight() * yr, xmin + paperWidth() * xr, ymax );
2646 
2647  double X0 = paperExtent.xMinimum();
2648  double Y0 = paperExtent.yMinimum();
2649 
2650  int widthPx = ( int )( printResolution() * paperWidth() / 25.4 );
2651  int heightPx = ( int )( printResolution() * paperHeight() / 25.4 );
2652 
2653  double Ww = paperExtent.width() / widthPx;
2654  double Hh = paperExtent.height() / heightPx;
2655 
2656  // scaling matrix
2657  double s[6];
2658  s[0] = Ww;
2659  s[1] = 0;
2660  s[2] = X0;
2661  s[3] = 0;
2662  s[4] = -Hh;
2663  s[5] = Y0 + paperExtent.height();
2664 
2665  // rotation matrix
2666  double r[6];
2667  r[0] = cos( alpha );
2668  r[1] = -sin( alpha );
2669  r[2] = XC * ( 1 - cos( alpha ) ) + YC * sin( alpha );
2670  r[3] = sin( alpha );
2671  r[4] = cos( alpha );
2672  r[5] = - XC * sin( alpha ) + YC * ( 1 - cos( alpha ) );
2673 
2674  // result = rotation x scaling = rotation(scaling(X))
2675  a = r[0] * s[0] + r[1] * s[3];
2676  b = r[0] * s[1] + r[1] * s[4];
2677  c = r[0] * s[2] + r[1] * s[5] + r[2];
2678  d = r[3] * s[0] + r[4] * s[3];
2679  e = r[3] * s[1] + r[4] * s[4];
2680  f = r[3] * s[2] + r[4] * s[5] + r[5];
2681 }
2682 
2684 {
2685  mAtlasMode = mode;
2686 
2687  if ( mode == QgsComposition::AtlasOff )
2688  {
2690  }
2691  else
2692  {
2693  bool atlasHasFeatures = mAtlasComposition.beginRender();
2694  if ( ! atlasHasFeatures )
2695  {
2698  return false;
2699  }
2700  }
2701 
2702  QList<QgsComposerMap*> maps;
2703  composerItems( maps );
2704  for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
2705  {
2706  QgsComposerMap* currentMap = ( *mit );
2707  if ( !currentMap->atlasDriven() )
2708  {
2709  continue;
2710  }
2711  currentMap->toggleAtlasPreview();
2712  }
2713 
2714  update();
2715  return true;
2716 }
2717 
2719 {
2720  double pageWidth = mPageWidth;
2721  double pageHeight = mPageHeight;
2722 
2723  QVariant exprVal;
2724  //in order of precedence - first consider predefined page size
2726  {
2727  QString presetString = exprVal.toString().trimmed();
2728  QgsDebugMsg( QString( "exprVal Paper Preset size :%1" ).arg( presetString ) );
2729  double widthD = 0;
2730  double heightD = 0;
2731  if ( QgsComposerUtils::decodePresetPaperSize( presetString, widthD, heightD ) )
2732  {
2733  pageWidth = widthD;
2734  pageHeight = heightD;
2735  }
2736  }
2737 
2738  //which is overwritten by data defined width/height
2740  {
2741  bool ok;
2742  double widthD = exprVal.toDouble( &ok );
2743  QgsDebugMsg( QString( "exprVal Paper Width:%1" ).arg( widthD ) );
2744  if ( ok )
2745  {
2746  pageWidth = widthD;
2747  }
2748  }
2750  {
2751  bool ok;
2752  double heightD = exprVal.toDouble( &ok );
2753  QgsDebugMsg( QString( "exprVal Paper Height:%1" ).arg( heightD ) );
2754  if ( ok )
2755  {
2756  pageHeight = heightD;
2757  }
2758  }
2759 
2760  //which is finally overwritten by data defined orientation
2762  {
2763  bool ok;
2764  QString orientationString = exprVal.toString().trimmed();
2765  QgsComposition::PaperOrientation orientation = QgsComposerUtils::decodePaperOrientation( orientationString, ok );
2766  QgsDebugMsg( QString( "exprVal Paper Orientation:%1" ).arg( orientationString ) );
2767  if ( ok )
2768  {
2769  double heightD, widthD;
2770  if ( orientation == QgsComposition::Portrait )
2771  {
2772  heightD = qMax( pageHeight, pageWidth );
2773  widthD = qMin( pageHeight, pageWidth );
2774  }
2775  else
2776  {
2777  heightD = qMin( pageHeight, pageWidth );
2778  widthD = qMax( pageHeight, pageWidth );
2779  }
2780  pageWidth = widthD;
2781  pageHeight = heightD;
2782  }
2783  }
2784 
2785  setPaperSize( pageWidth, pageHeight );
2786 }
2787 
2789 {
2790  if ( property == QgsComposerObject::AllProperties || property == QgsComposerObject::NoProperty )
2791  {
2792  //invalid property
2793  return 0;
2794  }
2795 
2796  //find matching QgsDataDefined for property
2797  QMap< QgsComposerObject::DataDefinedProperty, QgsDataDefined* >::const_iterator it = mDataDefinedProperties.find( property );
2798  if ( it != mDataDefinedProperties.constEnd() )
2799  {
2800  return it.value();
2801  }
2802 
2803  //not found
2804  return 0;
2805 }
2806 
2807 void QgsComposition::setDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property, bool active, bool useExpression, const QString &expression, const QString &field )
2808 {
2809  if ( property == QgsComposerObject::AllProperties || property == QgsComposerObject::NoProperty )
2810  {
2811  //invalid property
2812  return;
2813  }
2814 
2815  bool defaultVals = ( !active && !useExpression && expression.isEmpty() && field.isEmpty() );
2816 
2817  if ( mDataDefinedProperties.contains( property ) )
2818  {
2819  QMap< QgsComposerObject::DataDefinedProperty, QgsDataDefined* >::const_iterator it = mDataDefinedProperties.find( property );
2820  if ( it != mDataDefinedProperties.constEnd() )
2821  {
2822  QgsDataDefined* dd = it.value();
2823  dd->setActive( active );
2824  dd->setUseExpression( useExpression );
2825  dd->setExpressionString( expression );
2826  dd->setField( field );
2827  }
2828  }
2829  else if ( !defaultVals )
2830  {
2831  QgsDataDefined* dd = new QgsDataDefined( active, useExpression, expression, field );
2832  mDataDefinedProperties.insert( property, dd );
2833  }
2834 }
2835 
2836 bool QgsComposition::dataDefinedEvaluate( QgsComposerObject::DataDefinedProperty property, QVariant &expressionValue, QMap<QgsComposerObject::DataDefinedProperty, QgsDataDefined *> *dataDefinedProperties )
2837 {
2838  if ( property == QgsComposerObject::NoProperty || property == QgsComposerObject::AllProperties )
2839  {
2840  //invalid property
2841  return false;
2842  }
2843 
2844  //null passed-around QVariant
2845  expressionValue.clear();
2846 
2847  //get fields and feature from atlas
2848  const QgsFeature* currentFeature = 0;
2849  const QgsFields* layerFields = 0;
2850  if ( mAtlasComposition.enabled() )
2851  {
2853  if ( atlasLayer )
2854  {
2855  layerFields = &atlasLayer->pendingFields();
2856  }
2858  {
2859  currentFeature = mAtlasComposition.currentFeature();
2860  }
2861  }
2862 
2863  //evaluate data defined property using current atlas context
2864  QVariant result = dataDefinedValue( property, currentFeature, layerFields, dataDefinedProperties );
2865 
2866  if ( result.isValid() )
2867  {
2868  expressionValue = result;
2869  return true;
2870  }
2871 
2872  return false;
2873 }
2874 
2875 QVariant QgsComposition::dataDefinedValue( QgsComposerObject::DataDefinedProperty property, const QgsFeature *feature, const QgsFields *fields, QMap<QgsComposerObject::DataDefinedProperty, QgsDataDefined *> *dataDefinedProperties )
2876 {
2877  if ( property == QgsComposerObject::AllProperties || property == QgsComposerObject::NoProperty )
2878  {
2879  //invalid property
2880  return QVariant();
2881  }
2882  if ( !dataDefinedProperties->contains( property ) )
2883  {
2884  //missing property
2885  return QVariant();
2886  }
2887 
2888  QgsDataDefined* dd = 0;
2889  QMap< QgsComposerObject::DataDefinedProperty, QgsDataDefined* >::const_iterator it = dataDefinedProperties->find( property );
2890  if ( it != dataDefinedProperties->constEnd() )
2891  {
2892  dd = it.value();
2893  }
2894 
2895  if ( !dd )
2896  {
2897  return QVariant();
2898  }
2899 
2900  if ( !dd->isActive() )
2901  {
2902  return QVariant();
2903  }
2904 
2905  QVariant result = QVariant();
2906  bool useExpression = dd->useExpression();
2907  QString field = dd->field();
2908 
2909  if ( !dd->expressionIsPrepared() )
2910  {
2911  prepareDataDefinedExpression( dd, dataDefinedProperties );
2912  }
2913 
2914  if ( useExpression && dd->expressionIsPrepared() )
2915  {
2916  QgsExpression* expr = dd->expression();
2917 
2918  result = expr->evaluate( feature );
2919  if ( expr->hasEvalError() )
2920  {
2921  QgsDebugMsgLevel( QString( "Evaluate error:" ) + expr->evalErrorString(), 4 );
2922  return QVariant();
2923  }
2924  }
2925  else if ( !useExpression && !field.isEmpty() && fields )
2926  {
2927  if ( !feature )
2928  {
2929  return QVariant();
2930  }
2931  // use direct attribute access instead of evaluating "field" expression (much faster)
2932  int indx = fields->indexFromName( field );
2933  if ( indx != -1 )
2934  {
2935  result = feature->attribute( indx );
2936  }
2937  }
2938  return result;
2939 }
2940 
2941 void QgsComposition::prepareDataDefinedExpression( QgsDataDefined *dd, QMap<QgsComposerObject::DataDefinedProperty, QgsDataDefined *> *dataDefinedProperties ) const
2942 {
2943  QgsVectorLayer* atlasLayer = 0;
2944 
2945  if ( mAtlasComposition.enabled() )
2946  {
2947  atlasLayer = mAtlasComposition.coverageLayer();
2948  }
2949 
2950  //if specific QgsDataDefined passed, prepare it
2951  //otherwise prepare all QgsDataDefineds
2952  if ( dd )
2953  {
2954  dd->prepareExpression( atlasLayer );
2955  }
2956  else
2957  {
2958  QMap< QgsComposerObject::DataDefinedProperty, QgsDataDefined* >::const_iterator it = dataDefinedProperties->constBegin();
2959  for ( ; it != dataDefinedProperties->constEnd(); ++it )
2960  {
2961  it.value()->prepareExpression( atlasLayer );
2962  }
2963  }
2964 }
2965 
2967 {
2969 }
2970 
2971 void QgsComposition::relativeResizeRect( QRectF& rectToResize, const QRectF& boundsBefore, const QRectF& boundsAfter )
2972 {
2973  QgsComposerUtils::relativeResizeRect( rectToResize, boundsBefore, boundsAfter );
2974 }
2975 
2976 double QgsComposition::relativePosition( double position, double beforeMin, double beforeMax, double afterMin, double afterMax )
2977 {
2978  return QgsComposerUtils::relativePosition( position, beforeMin, beforeMax, afterMin, afterMax );
2979 }
bool positionLock() const
Returns whether position lock for mouse drags is enabled returns true if item is locked for mouse mov...
Class for parsing and evaluation of expressions (formerly called "search strings").
Definition: qgsexpression.h:89
void beginPrint(QPrinter &printer, const bool evaluateDDPageSize=false)
Prepare the printer for printing.
static void relativeResizeRect(QRectF &rectToResize, const QRectF &boundsBefore, const QRectF &boundsAfter)
Resizes a QRectF relative to a resized bounding rectangle.
QgsComposition::PlotStyle mPlotStyle
Item representing the paper.
Definition: qgspaperitem.h:40
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
A scale bar item that can be added to a map composition.
QUndoStack * undoStack()
Returns pointer to undo/redo command storage.
QgsComposerItem * composerItemAt(const QPointF &position, const bool ignoreLocked=false) const
Returns the topmost composer item at a specified position.
void unlockAllItems()
Unlock all items.
void setActive(bool active)
QMap< QgsComposerObject::DataDefinedProperty, QgsDataDefined * > mDataDefinedProperties
Map of current data defined properties to QgsDataDefined for the composition.
void loadDefaults()
Loads default composer settings.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
double paperWidth() const
Returns width of paper item.
bool writeXML(QDomElement &composerElem, QDomDocument &doc)
Writes settings to xml (paper dimension)
virtual bool writeXML(QDomElement &elem, QDomDocument &doc) const
Stores item state in DOM element.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
Sets state from Dom document.
QgsComposerItem * getComposerItemAbove(QgsComposerItem *item) const
Finds the next composer item above an item.
QGraphicsView * graphicsView() const
A container class for data source field mapping or expression.
int boundingRectOfSelectedItems(QRectF &bRect)
Returns the bounding rectangle of the selected items in scene coordinates.
An item that draws an arrow between to points.
void addItemToZList(QgsComposerItem *item)
Adds item to z list.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
sets state from Dom document
void composerArrowAdded(QgsComposerArrow *arrow)
Is emitted when new composer arrow has been added to the view.
QgsExpression * expression()
void setPageStyleSymbol(QgsFillSymbolV2 *symbol)
Note: added in version 2.1.
void assignFreeId()
Sets mId to a number not yet used in the composition.
QVariant evaluate(const QgsFeature *f=NULL)
Evaluate the feature and return the result.
QString field() const
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
sets state from Dom document
virtual void beginItemCommand(const QString &text)
void computeWorldFileParameters(double &a, double &b, double &c, double &d, double &e, double &f) const
Compute world file parameters.
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:194
GridStyle
Style to draw the snapping grid.
#define QgsDebugMsg(str)
Definition: qgslogger.h:36
void alignSelectedItemsTop()
void rebuildZList()
Rebuilds the z-order list, based on the current stacking of items in the composition.
void composerPictureAdded(QgsComposerPicture *picture)
Is emitted when a new composer picture has been added.
static double relativePosition(const double position, const double beforeMin, const double beforeMax, const double afterMin, const double afterMax)
Returns a scaled position given a before and after range.
int pageNumberForPoint(const QPointF &position) const
Returns the page number corresponding to a point in the composition.
QgsDataDefined * dataDefinedProperty(const QgsComposerObject::DataDefinedProperty property)
Returns a reference to the data defined settings for one of the composition's data defined properties...
QPointF minPointFromXml(const QDomElement &elem) const
Calculates the item minimum position from an xml string.
static QgsFillSymbolV2 * createSimple(const QgsStringMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties. ...
void cache()
Create cache image.
int zOrderListSize() const
Returns the size of the z-order list, which includes items which may have been removed from the compo...
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
Reads the properties specific to an attribute table from xml.
static void readDataDefinedPropertyMap(const QDomElement &itemElem, QMap< QgsComposerObject::DataDefinedProperty, QString > *dataDefinedNames, QMap< QgsComposerObject::DataDefinedProperty, QgsDataDefined * > *dataDefinedProperties)
Reads all data defined properties from xml.
QList< const QgsComposerMap * > composerMapItems() const
Returns pointers to all composer maps in the scene.
void addComposerScaleBar(QgsComposerScaleBar *scaleBar)
Adds scale bar to the graphics scene and advices composer to create a widget for it (through signal) ...
A item that forms part of a map composition.
void setSelectedItem(QgsComposerItem *item)
Clears any selected items and sets an item as the current selection.
void pushAddRemoveCommand(QgsComposerItem *item, const QString &text, const QgsAddRemoveItemCommand::State state=QgsAddRemoveItemCommand::Added)
Convenience function to create a QgsAddRemoveItemCommand, connect its signals and push it to the undo...
void removeItemFromZList(QgsComposerItem *item)
Removes item from z list.
QUndoStack * mUndoStack
bool enabled() const
Returns whether the atlas generation is enabled.
QPointF snapPointToGrid(const QPointF &scenePoint) const
Snaps a scene coordinate point to grid.
void updateBounds()
Updates the scene bounds of the composition.
Container of fields for a vector layer.
Definition: qgsfield.h:163
A container for grouping several QgsComposerItems.
QList< QgsComposerMapOverview * > mapOverviews() const
void paperSizeChanged()
void sendItemAddedSignal(QgsComposerItem *item)
Casts object to the proper subclass type and calls corresponding itemAdded signal.
virtual void setSelected(bool s)
Set selected, selected item should be highlighted.
void savePreviousState()
Saves current item state as previous state.
QImage printPageAsRaster(int page)
print composer page to image If the image does not fit into memory, a null image is returned ...
A composer command that merges together with other commands having the same context (=id)...
bool moveItemToBottom(QgsComposerItem *item)
bool mPrintAsRaster
Flag if map should be printed as a raster (via QImage).
void setCreateUndoCommands(bool enabled)
void prepareDataDefinedExpression(QgsDataDefined *dd, QMap< QgsComposerObject::DataDefinedProperty, QgsDataDefined * > *dataDefinedProperties) const
Prepares the expression for a data defined property, using the current atlas layer if set...
GridStyle mGridStyle
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
sets state from Dom document
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:113
void beginPrintAsPDF(QPrinter &printer, const QString &file)
Prepare the printer for printing in a PDF.
QList< QgsPaperItem * > mPages
A non GUI class for rendering a map layer set onto a QPainter.
void composerScaleBarAdded(QgsComposerScaleBar *scalebar)
Is emitted when new composer scale bar has been added.
void moveSelectedItemsToBottom()
static void writeDataDefinedPropertyMap(QDomElement &itemElem, QDomDocument &doc, const QMap< QgsComposerObject::DataDefinedProperty, QString > *dataDefinedNames, const QMap< QgsComposerObject::DataDefinedProperty, QgsDataDefined * > *dataDefinedProperties)
Writes data defined properties to xml.
bool reorderItemDown(QgsComposerItem *item)
Moves an item down the z-order list.
void alignSelectedItemsHCenter()
double spaceBetweenPages() const
void doPrint(QPrinter &printer, QPainter &painter, bool startNewPage=false)
Print on a preconfigured printer.
bool loadFromTemplate(const QDomDocument &doc, QMap< QString, QString > *substitutionMap=0, bool addUndoCommands=false)
Load a template document.
void setStatusMessage(const QString &message)
Sets the status bar message for the composer window.
QMap< QString, QString > QgsStringMap
Definition: qgis.h:416
void composerMapAdded(QgsComposerMap *map)
Is emitted when new composer map has been added to the view.
int numPages() const
Note: added in version 1.9.
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:324
static Q_DECL_DEPRECATED double relativePosition(double position, double beforeMin, double beforeMax, double afterMin, double afterMax)
Returns a scaled position given a before and after range.
void setGridVisible(const bool b)
void alignSelectedItemsVCenter()
double x() const
Definition: qgspoint.h:110
DataDefinedProperty
Data defined properties for different item types.
void endRender()
Ends the rendering.
A composer class that displays svg files or raster format (jpg, png, ...)
void readXML(const QDomElement &elem, const QDomDocument &doc)
Reads general atlas settings from xml.
QSet< QgsComposerItem * > items()
bool isDrawing() const
True if a draw is already in progress.
void composerLegendAdded(QgsComposerLegend *legend)
Is emitted when a new composer legend has been added.
void setItemPosition(double x, double y, ItemPositionMode itemPoint=UpperLeft, int page=-1)
Moves the item to a new position (in canvas coordinates)
The QgsMapSettings class contains configuration for rendering of the map.
QList< QgsComposerItem * > * zOrderList()
Returns the item z-order list.
virtual int type() const
return correct graphics item type.
void addComposerShape(QgsComposerShape *shape)
Adds a composer shape to the graphics scene and advices composer to create a widget for it (through s...
void setGridPen(const QPen &p)
static QDomElement saveSymbol(QString symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
void setUseExpression(bool use)
QgsComposerItem * getComposerItemBelow(QgsComposerItem *item) const
QString uuid() const
Get item identification name.
void setNumPages(const int pages)
Note: added in version 1.9.
void refreshItemsTriggered()
Is emitted when item in the composition must be refreshed.
bool beginRender()
Begins the rendering.
void setSnapLinesVisible(const bool visible)
Hides / shows custom snap lines.
int itemPageNumber(const QgsComposerItem *) const
Returns on which page number (0-based) is displayed an item.
static QgsComposition::PaperOrientation decodePaperOrientation(const QString orientationString, bool &ok)
Decodes a string representing a paper orientation.
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:199
void cancelCommand()
Deletes current command.
void toggleAtlasPreview()
Called when atlas preview is toggled, to force map item to update its extent and redraw.
void setSnapGridOffsetX(const double offset)
bool mGenerateWorldFile
Flag if a world file should be generated on raster export.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:37
bool containsChange() const
Returns true if previous state and after state are valid and different.
int pageNumberAt(const QPointF &position) const
Returns the page number (0-based) given a coordinate.
void setUseSymbolV2(bool useSymbolV2)
Controls whether the shape should be drawn using a QgsFillSymbolV2.
void endCommand()
Saves end state of item and pushes command to the undo history.
void itemRemoved(QgsComposerItem *)
Is emitted when a composer item has been removed from the scene.
int printResolution() const
void updatePagePos(double newPageWidth, double newPageHeight)
Moves the item so that it retains its relative position on the page when the paper size changes...
void setField(const QString &field)
QSet< QgsComposerMultiFrame * > mMultiFrames
List multiframe objects.
void clear()
Clears all items from z-order list and resets the model.
void removeSnapLine(QGraphicsLineItem *line)
Remove custom snap line (and delete the object)
void alignSelectedItemsRight()
QRectF compositionBounds() const
Calculates the bounds of all non-gui items in the composition.
Abstract base class for composer entries with the ability to distribute the content to several frames...
double mSnapGridOffsetX
#define M_PI
const QgsComposerItem * getComposerItemByUuid(const QString theUuid) const
Returns a composer item given its unique identifier.
void removeComposerItem(QgsComposerItem *item, const bool createCommand=true, const bool removeGroupItems=true)
Remove item from the graphics scene.
static bool decodePresetPaperSize(const QString presetString, double &width, double &height)
Decodes a string representing a preset page size.
QgsComposerItemCommand * mActiveItemCommand
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
Sets state from DOM document.
void moveSelectedItemsToTop()
int frameCount() const
Return the number of frames associated with this multiframeset.
int mPrintResolution
Dpi for printout.
A composer command that merges together with other commands having the same context (=id) for multi f...
double mapRotation(QgsComposerObject::PropertyValueType valueType=QgsComposerObject::EvaluatedValue) const
Returns the rotation used for drawing the map within the composer item.
void setSnapGridResolution(const double r)
QgsFeature * currentFeature()
Returns the current atlas feature.
void removeMultiFrame(QgsComposerMultiFrame *multiFrame)
Removes multi frame (but does not delete it)
Object representing map window.
Frame for html, table, text which can be divided onto several frames.
bool readXML(const QDomElement &compositionElem, const QDomDocument &doc)
Reads settings from xml file.
bool useExpression() const
int indexFromName(const QString &name) const
Look up field's index from name. Returns -1 on error.
Definition: qgsfield.h:227
QgsComposerMouseHandles * mSelectionHandles
QgsRectangle * currentMapExtent()
Returns a pointer to the current map extent, which is either the original user specified extent or th...
void addItemsFromXML(const QDomElement &elem, const QDomDocument &doc, QMap< QgsComposerMap *, int > *mapsToRestore=0, bool addUndoCommands=false, QPointF *pos=0, bool pasteInPlace=false)
Add items from XML representation to the graphics scene (for project file reading, pasting items from clipboard)
void refreshItems()
Forces items in the composition to refresh.
void setUpdatesEnabled(bool enabled)
Sets whether updates to the composer map are enabled.
QgsComposerItem * getComposerItemAbove(QgsComposerItem *item) const
Q_DECL_DEPRECATED int pixelFontSize(double pointSize) const
Returns the mm font size for a font that has point size set.
void refreshDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property=QgsComposerObject::AllProperties)
Refreshes a data defined property for the composition by reevaluating the property's value and redraw...
PreviewMode previewMode() const
QVariant dataDefinedValue(QgsComposerObject::DataDefinedProperty property, const QgsFeature *feature, const QgsFields *fields, QMap< QgsComposerObject::DataDefinedProperty, QgsDataDefined * > *dataDefinedProperties)
Evaluates a data defined property and returns the calculated value.
void nPagesChanged()
void removeItem(QgsComposerItem *item)
Removes an item from the z-order list.
void updateZValues(const bool addUndoCommands=true)
Reset z-values of items based on position in z list.
void updateSettings()
Refreshes the composition when composer related options change.
void saveAfterState()
Saves current item state as after state.
bool setAtlasMode(const QgsComposition::AtlasMode mode)
Sets the current atlas mode of the composition.
double mSpaceBetweenPages
A model for items attached to a composition.
bool dataDefinedEvaluate(QgsComposerObject::DataDefinedProperty property, QVariant &expressionValue, QMap< QgsComposerObject::DataDefinedProperty, QgsDataDefined * > *dataDefinedProperties)
Evaluate a data defined property and return the calculated value.
static QString encodeStringForXML(const QString &str)
QString file
Definition: qgssvgcache.cpp:76
bool mSnapToGrid
Parameters for snap to grid function.
void setPositionLock(const bool lock)
Locks / unlocks the item position for mouse drags.
void setPrintResolution(const int dpi)
bool print(QPrinter &printer, const bool evaluateDDPageSize=false)
Convenience function that prepares the printer and prints.
void composerTableAdded(QgsComposerAttributeTable *table)
Is emitted when a new composer table has been added.
QList< QgsPaperItem * > pages()
Return pages in the correct order.
void refreshZList()
Rebuilds the z order list by adding any item which are present in the composition but missing from th...
int id() const
Get identification number.
QgsComposition::AtlasMode mAtlasMode
void composerShapeAdded(QgsComposerShape *shape)
Is emitted when a new composer shape has been added.
bool exportAsPDF(const QString &file)
Convenience function that prepares the printer for printing in PDF and prints.
void lockSelectedItems()
Lock the selected items.
void setGridStyle(const GridStyle s)
A composer command class for adding / removing composer items.
const QgsComposerItem * getComposerItemById(const QString theId) const
Returns a composer item given its text identifier.
void selectNextByZOrder(const ZValueDirection direction)
void statusMsgChanged(QString message)
Is emitted when the composition has an updated status bar message for the composer window...
void clearSnapLines()
Removes all snap lines.
A table class that displays a vector attribute table.
bool reorderItemUp(QgsComposerItem *item)
Moves an item up the z-order list.
bool mAlignmentSnap
Parameters for alignment snap.
void prepareAllDataDefinedExpressions()
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:230
QgsComposerItem * getComposerItemBelow(QgsComposerItem *item) const
Finds the next composer item below an item.
Undo command to undo/redo all composer item related changes.
void connectAddRemoveCommandSignals(QgsAddRemoveItemCommand *c)
void setDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property, bool active, bool useExpression, const QString &expression, const QString &field)
Sets parameters for a data defined property for the composition.
A composer items that draws common shapes (ellipse, triangle, rectangle)
virtual void endItemCommand()
void readXMLMapSettings(const QDomElement &elem, const QDomDocument &doc)
Reads old (pre 2.2) map related atlas settings from xml.
double mSnapGridOffsetY
QgsComposerMap * mWorldFileMap
Composer map to use for the world file generation.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
sets state from Dom document
bool prepareExpression(QgsVectorLayer *layer)
bool expressionIsPrepared() const
void addComposerHtmlFrame(QgsComposerHtml *html, QgsComposerFrame *frame)
Adds composer html frame and advices composer to create a widget for it (through signal) ...
AtlasMode
Composition atlas modes.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:362
QPointF positionOnPage(const QPointF &position) const
Returns the position within a page of a point in the composition.
void addComposerMap(QgsComposerMap *map, const bool setDefaultPreviewStyle=true)
Adds map to the graphics scene and advices composer to create a widget for it (through signal) ...
void alignSelectedItemsBottom()
static void fixEngineFlags(QPaintEngine *engine)
void alignSelectedItemsLeft()
QList< QGraphicsLineItem * > mSnapLines
Arbitraty snap lines (horizontal and vertical)
QGraphicsLineItem * nearestSnapLine(const bool horizontal, const double x, const double y, const double tolerance, QList< QPair< QgsComposerItem *, QgsComposerItem::ItemPositionMode > > &snappedItems) const
Get nearest snap line.
double paperHeight() const
Returns height of paper item.
QMap< QgsComposerObject::DataDefinedProperty, QString > mDataDefinedNames
Map of data defined properties for the composition to string name to use when exporting composition t...
QgsComposerMultiFrameCommand * mActiveMultiFrameCommand
static double pointsToMM(const double pointSize)
Returns the size in mm corresponding to a font point size.
QgsAtlasComposition mAtlasComposition
The atlas composition object.
void selectedItemChanged(QgsComposerItem *selected)
Is emitted when selected item changed.
void renderPage(QPainter *p, int page)
Render a page to a paint device.
double y() const
Definition: qgspoint.h:118
A label that can be placed onto a map composition.
void setUseAdvancedEffects(const bool effectsEnabled)
Used to enable or disable advanced effects such as blend modes in a composition.
void setEffectsEnabled(const bool effectsEnabled)
Sets whether effects (eg blend modes) are enabled for the item.
void composerLabelAdded(QgsComposerLabel *label)
Is emitted when new composer label has been added to the view.
void addComposerPicture(QgsComposerPicture *picture)
Adds picture to the graphics scene and advices composer to create a widget for it (through signal) ...
QgsAtlasComposition & atlasComposition()
void composerHtmlFrameAdded(QgsComposerHtml *html, QgsComposerFrame *frame)
Is emitted when a new composer html has been added to the view.
static Q_DECL_DEPRECATED void relativeResizeRect(QRectF &rectToResize, const QRectF &boundsBefore, const QRectF &boundsAfter)
Resizes a QRectF relative to the change from boundsBefore to boundsAfter.
void addComposerTable(QgsComposerAttributeTable *table)
Adds a composer table to the graphics scene and advices composer to create a widget for it (through s...
Handles drawing of selection outlines and mouse handles.
static QgsSymbolV2 * loadSymbol(QDomElement &element)
Q_DECL_DEPRECATED const QgsComposerHtml * getComposerHtmlByItem(QgsComposerItem *item) const
Returns the composer html with specified id (a string as named in the composer user interface item pr...
bool atlasDriven() const
Returns whether the map extent is set to follow the current atlas feature.
QgsVectorLayer * coverageLayer() const
Returns the coverage layer used for the atlas features.
const QgsFields & pendingFields() const
returns field list in the to-be-committed state
void setItemRemoved(QgsComposerItem *item)
Marks an item as removed from the composition.
static void setSpecialColumn(const QString &name, QVariant value)
Assign a special column.
Q_DECL_DEPRECATED double pointFontSize(int pixelSize) const
Does the inverse calculation and returns points for mm.
QGraphicsLineItem * addSnapLine()
Add a custom snap line (can be horizontal or vertical)
void composerItems(QList< T * > &itemList)
Return composer items of a specific type.
void printResolutionChanged()
Is emitted when the compositions print resolution changes.
PlotStyle
Plot type.
const QgsComposerMap * getComposerMapById(const int id) const
Returns the composer map with specified id.
void setPreviewMode(PreviewMode m)
double width() const
Width of the rectangle.
Definition: qgsrectangle.h:204
bool raiseItem(QgsComposerItem *item)
QgsComposerMultiFrame * multiFrame() const
void setSnapToGridEnabled(const bool b)
bool reorderItemToTop(QgsComposerItem *item)
Moves an item to the top of the z-order list.
bool mUseAdvancedEffects
Flag if advanced visual effects such as blend modes should be used.
QList< QgsComposerItem * > selectedComposerItems()
Represents a vector layer which manages a vector based data sets.
void deleteAndRemoveMultiFrames()
void move(double dx, double dy)
Moves item in canvas coordinates.
double mSnapGridResolution
A legend that can be placed onto a map composition.
void addComposerLabel(QgsComposerLabel *label)
Adds label to the graphics scene and advices composer to create a widget for it (through signal) ...
double xMinimum() const
Get the x minimum value (left side of rectangle)
Definition: qgsrectangle.h:189
void addMultiFrame(QgsComposerMultiFrame *multiFrame)
Adds multiframe.
void addItemAtTop(QgsComposerItem *item)
Adds an item to the top of the composition z stack.
int max(int a, int b)
Definition: util.h:87
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:214
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
sets state from Dom document
QgsComposerModel * mItemsModel
QString evalErrorString() const
Returns evaluation error.
void setExpressionString(const QString &expr)
bool isActive() const
bool lowerItem(QgsComposerItem *item)
void addComposerArrow(QgsComposerArrow *arrow)
Adds an arrow item to the graphics scene and advices composer to create a widget for it (through sign...
bool reorderItemToBottom(QgsComposerItem *item)
Moves an item to the bottom of the z-order list.
bool moveItemToTop(QgsComposerItem *item)
void loadSettings()
Loads composer settings which may change, eg grid color.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
sets state from Dom document
void setPaperSize(const double width, const double height)
Changes size of paper item.
void addComposerLegend(QgsComposerLegend *legend)
Adds legend to the graphics scene and advices composer to create a widget for it (through signal) ...
bool containsChange() const
Returns true if previous state and after state are valid and different.
void createDefaultPageStyleSymbol()
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:209
QgsFillSymbolV2 * mPageStyleSymbol
Drawing style for page.
void setSnapGridOffsetY(const double offset)
bool readXML(const QDomElement &itemElem, const QDomDocument &doc, bool ignoreFrames=false)
void beginCommand(QgsComposerItem *item, const QString &commandText, const QgsComposerMergeCommand::Context c=QgsComposerMergeCommand::Unknown)
Allocates new item command and saves initial state in it.
void dirty(bool b)
Definition: qgsproject.cpp:396
#define tr(sourceText)
QList< QGraphicsLineItem * > * snapLines()
Returns pointer to snap lines collection.
void beginMultiFrameCommand(QgsComposerMultiFrame *multiFrame, const QString &text, const QgsComposerMultiFrameMergeCommand::Context c=QgsComposerMultiFrameMergeCommand::Unknown)
static double mmToPoints(const double mmSize)
Returns the size in mm corresponding to a font point size.
QString id() const
Get item's id (which is not necessarly unique)