QGIS API Documentation  2.12.0-Lyon
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 : [email protected]
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 "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...
80  mPlotStyle = QgsComposition::Preview;
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;
91  mPagesVisible = true;
92  mSnapGridResolution = 0;
93  mSnapGridOffsetX = 0;
94  mSnapGridOffsetY = 0;
95  mAlignmentSnap = true;
96  mGuidesVisible = true;
97  mSmartGuides = true;
98  mSnapTolerance = 0;
99  mBoundingBoxesVisible = true;
100  mSelectionHandles = 0;
101  mActiveItemCommand = 0;
102  mActiveMultiFrameCommand = 0;
103  mAtlasMode = QgsComposition::AtlasOff;
104  mPreventCursorChange = false;
105  mItemsModel = 0;
106  mUndoStack = new QUndoStack();
107 
108  mResizeToContentsMarginTop = 0;
109  mResizeToContentsMarginRight = 0;
110  mResizeToContentsMarginBottom = 0;
111  mResizeToContentsMarginLeft = 0;
112 
113  //data defined strings
114  mDataDefinedNames.insert( QgsComposerObject::PresetPaperSize, QString( "dataDefinedPaperSize" ) );
115  mDataDefinedNames.insert( QgsComposerObject::PaperWidth, QString( "dataDefinedPaperWidth" ) );
116  mDataDefinedNames.insert( QgsComposerObject::PaperHeight, QString( "dataDefinedPaperHeight" ) );
117  mDataDefinedNames.insert( QgsComposerObject::NumPages, QString( "dataDefinedNumPages" ) );
118  mDataDefinedNames.insert( QgsComposerObject::PaperOrientation, QString( "dataDefinedPaperOrientation" ) );
119 
120  //connect to atlas toggling on/off and coverage layer and feature changes
121  //to update data defined values
122  connect( &mAtlasComposition, SIGNAL( toggled( bool ) ), this, SLOT( refreshDataDefinedProperty() ) );
123  connect( &mAtlasComposition, SIGNAL( coverageLayerChanged( QgsVectorLayer* ) ), this, SLOT( refreshDataDefinedProperty() ) );
124  connect( &mAtlasComposition, SIGNAL( featureChanged( QgsFeature* ) ), this, SLOT( refreshDataDefinedProperty() ) );
125  //also, refreshing composition triggers a recalculation of data defined properties
126  connect( this, SIGNAL( refreshItemsTriggered() ), this, SLOT( refreshDataDefinedProperty() ) );
127  //toggling atlas or changing coverage layer requires data defined expressions to be reprepared
128  connect( &mAtlasComposition, SIGNAL( toggled( bool ) ), this, SLOT( prepareAllDataDefinedExpressions() ) );
129  connect( &mAtlasComposition, SIGNAL( coverageLayerChanged( QgsVectorLayer* ) ), this, SLOT( prepareAllDataDefinedExpressions() ) );
130 
131  setBackgroundBrush( QColor( 215, 215, 215 ) );
132  createDefaultPageStyleSymbol();
133 
134  addPaperItem();
135 
136  updateBounds();
137 
138  //add mouse selection handles to composition, and initially hide
139  mSelectionHandles = new QgsComposerMouseHandles( this );
140  addItem( mSelectionHandles );
141  mSelectionHandles->hide();
142  mSelectionHandles->setZValue( 500 );
143 
144  mPrintResolution = 300; //hardcoded default
145 
146  //load default composition settings
147  loadDefaults();
148  loadSettings();
149 
150  mItemsModel = new QgsComposerModel( this );
151 }
152 
153 
154 /*
155 QgsComposition::QgsComposition()
156  : QGraphicsScene( 0 )
157  , mMapRenderer( 0 )
158  , mPlotStyle( QgsComposition::Preview )
159  , mPageWidth( 297 )
160  , mPageHeight( 210 )
161  , mSpaceBetweenPages( 10 )
162  , mPageStyleSymbol( 0 )
163  , mPrintAsRaster( false )
164  , mGenerateWorldFile( false )
165  , mWorldFileMap( 0 )
166  , mUseAdvancedEffects( true )
167  , mSnapToGrid( false )
168  , mGridVisible( false )
169  , mSnapGridResolution( 0 )
170  , mSnapGridTolerance( 0 )
171  , mSnapGridOffsetX( 0 )
172  , mSnapGridOffsetY( 0 )
173  , mAlignmentSnap( true )
174  , mGuidesVisible( true )
175  , mSmartGuides( true )
176  , mAlignmentSnapTolerance( 0 )
177  , mSelectionHandles( 0 )
178  , mActiveItemCommand( 0 )
179  , mActiveMultiFrameCommand( 0 )
180  , mAtlasComposition( this )
181  , mAtlasMode( QgsComposition::AtlasOff )
182  , mPreventCursorChange( false )
183  , mItemsModel( 0 )
184 {
185  //load default composition settings
186  loadDefaults();
187  loadSettings();
188  mItemsModel = new QgsComposerModel( this );
189 }*/
190 
192 {
193  removePaperItems();
194  deleteAndRemoveMultiFrames();
195 
196  // make sure that all composer items are removed before
197  // this class is deconstructed - to avoid segfaults
198  // when composer items access in destructor composition that isn't valid anymore
199  QList<QGraphicsItem*> itemList = items();
200  qDeleteAll( itemList );
201 
202  // clear pointers to QgsDataDefined objects
203  qDeleteAll( mDataDefinedProperties );
204  mDataDefinedProperties.clear();
205 
206  //order is important here - we need to delete model last so that all items have already
207  //been deleted. Deleting the undo stack will also delete any items which have been
208  //removed from the scene, so this needs to be done before deleting the model
209  delete mUndoStack;
210 
211  delete mActiveItemCommand;
212  delete mActiveMultiFrameCommand;
213  delete mPageStyleSymbol;
214  delete mItemsModel;
215 }
216 
217 void QgsComposition::loadDefaults()
218 {
219  QSettings settings;
220  mSnapGridResolution = settings.value( "/Composer/defaultSnapGridResolution", 10.0 ).toDouble();
221  mSnapGridOffsetX = settings.value( "/Composer/defaultSnapGridOffsetX", 0 ).toDouble();
222  mSnapGridOffsetY = settings.value( "/Composer/defaultSnapGridOffsetY", 0 ).toDouble();
223  mSnapTolerance = settings.value( "/Composer/defaultSnapTolerancePixels", 5 ).toInt();
224 }
225 
227 {
228  setSceneRect( compositionBounds( false, 0.05 ) );
229 }
230 
232 {
233  emit refreshItemsTriggered();
234  //force a redraw on all maps
236  composerItems( maps );
238  for ( ; mapIt != maps.end(); ++mapIt )
239  {
240  ( *mapIt )->cache();
241  ( *mapIt )->update();
242  }
243 }
244 
246 {
248  if ( item )
249  {
250  item->setSelected( true );
251  emit selectedItemChanged( item );
252  }
253 }
254 
256 {
257  //we can't use QGraphicsScene::clearSelection, as that emits no signals
258  //and we don't know which items are being unselected
259  //accordingly, we can't inform the composition model of selection changes
260  //instead, do the clear selection manually...
261  QList<QGraphicsItem *> selectedItemList = selectedItems();
262  QList<QGraphicsItem *>::iterator itemIter = selectedItemList.begin();
263 
264  for ( ; itemIter != selectedItemList.end(); ++itemIter )
265  {
266  QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem *>( *itemIter );
267  if ( composerItem )
268  {
269  composerItem->setSelected( false );
270  }
271  }
272 }
273 
275 {
276  const QgsExpressionContext* evalContext = context;
278  if ( !evalContext )
279  {
280  scopedContext.reset( createExpressionContext() );
281  evalContext = scopedContext.data();
282  }
283 
284  //updates data defined properties and redraws composition to match
285  if ( property == QgsComposerObject::NumPages || property == QgsComposerObject::AllProperties )
286  {
287  setNumPages( numPages() );
288  }
289  if ( property == QgsComposerObject::PaperWidth || property == QgsComposerObject::PaperHeight ||
292  {
293  refreshPageSize( evalContext );
294  }
295 }
296 
297 QRectF QgsComposition::compositionBounds( bool ignorePages, double margin ) const
298 {
299  //start with an empty rectangle
300  QRectF bounds;
301 
302  //add all QgsComposerItems and QgsPaperItems which are in the composition
303  QList<QGraphicsItem *> itemList = items();
304  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
305  for ( ; itemIt != itemList.end(); ++itemIt )
306  {
307  const QgsComposerItem* composerItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
308  const QgsPaperItem* paperItem = dynamic_cast<const QgsPaperItem*>( *itemIt );
309  if (( composerItem && ( !paperItem || !ignorePages ) ) )
310  {
311  //expand bounds with current item's bounds
312  if ( bounds.isValid() )
313  bounds = bounds.united(( *itemIt )->sceneBoundingRect() );
314  else
315  bounds = ( *itemIt )->sceneBoundingRect();
316  }
317  }
318 
319  if ( bounds.isValid() && margin > 0.0 )
320  {
321  //finally, expand bounds out by specified margin of page size
322  bounds.adjust( -mPageWidth * margin, -mPageWidth * margin, mPageWidth * margin, mPageWidth * margin );
323  }
324 
325  return bounds;
326 }
327 
328 QRectF QgsComposition::pageItemBounds( int pageNumber, bool visibleOnly ) const
329 {
330  //start with an empty rectangle
331  QRectF bounds;
332 
333  //add all QgsComposerItems on page
334  QList<QGraphicsItem *> itemList = items();
335  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
336  for ( ; itemIt != itemList.end(); ++itemIt )
337  {
338  const QgsComposerItem* composerItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
339  const QgsPaperItem* paperItem = dynamic_cast<const QgsPaperItem*>( *itemIt );
340  if ( composerItem && !paperItem && itemPageNumber( composerItem ) == pageNumber )
341  {
342  if ( visibleOnly && !composerItem->isVisible() )
343  continue;
344 
345  //expand bounds with current item's bounds
346  if ( bounds.isValid() )
347  bounds = bounds.united(( *itemIt )->sceneBoundingRect() );
348  else
349  bounds = ( *itemIt )->sceneBoundingRect();
350  }
351  }
352 
353  return bounds;
354 }
355 
356 void QgsComposition::setPaperSize( const double width, const double height, bool keepRelativeItemPosition )
357 {
358  if ( width == mPageWidth && height == mPageHeight )
359  {
360  return;
361  }
362 
363  if ( keepRelativeItemPosition )
364  {
365  //update item positions
366  QList<QGraphicsItem *> itemList = items();
367  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
368  for ( ; itemIt != itemList.end(); ++itemIt )
369  {
370  QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem *>( *itemIt );
371  if ( composerItem )
372  {
373  composerItem->updatePagePos( width, height );
374  }
375  }
376  }
377 
378  //update guide positions and size
380  QList< QGraphicsLineItem* >::iterator guideIt = guides->begin();
381  double totalHeight = ( height + spaceBetweenPages() ) * ( numPages() - 1 ) + height;
382  for ( ; guideIt != guides->end(); ++guideIt )
383  {
384  QLineF line = ( *guideIt )->line();
385  if ( line.dx() == 0 )
386  {
387  //vertical line, change height of line
388  ( *guideIt )->setLine( line.x1(), 0, line.x1(), totalHeight );
389  }
390  else
391  {
392  //horizontal line
393  if ( keepRelativeItemPosition )
394  {
395  //move to new vertical position and change width of line
396  QPointF curPagePos = positionOnPage( line.p1() );
397  int curPage = pageNumberForPoint( line.p1() ) - 1;
398  double newY = curPage * ( height + spaceBetweenPages() ) + curPagePos.y();
399  ( *guideIt )->setLine( 0, newY, width, newY );
400  }
401  else
402  {
403  //just resize guide to new page size
404  ( *guideIt )->setLine( 0, line.y1(), width, line.y1() );
405  }
406  }
407  }
408 
409  mPageWidth = width;
410  mPageHeight = height;
411  double currentY = 0;
412  for ( int i = 0; i < mPages.size(); ++i )
413  {
414  mPages.at( i )->setSceneRect( QRectF( 0, currentY, width, height ) );
415  currentY += ( height + mSpaceBetweenPages );
416  }
417  QgsProject::instance()->dirty( true );
418  updateBounds();
419  emit paperSizeChanged();
420 }
421 
423 {
424  return mPageHeight;
425 }
426 
428 {
429  return mPageWidth;
430 }
431 
432 void QgsComposition::resizePageToContents( double marginTop, double marginRight, double marginBottom, double marginLeft )
433 {
434  //calculate current bounds
435  QRectF bounds = compositionBounds( true, 0.0 );
436 
437  setNumPages( 1 );
438  double newWidth = bounds.width() + marginLeft + marginRight;
439  double newHeight = bounds.height() + marginTop + marginBottom;
440  setPaperSize( newWidth, newHeight, false );
441 
442  //also move all items so that top-left of bounds is at marginLeft, marginTop
443  double diffX = marginLeft - bounds.left();
444  double diffY = marginTop - bounds.top();
445 
446  QList<QGraphicsItem *> itemList = items();
447  Q_FOREACH ( QGraphicsItem* item, itemList )
448  {
449  QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem *>( item );
450  if ( composerItem )
451  {
452  const QgsPaperItem* paperItem = dynamic_cast<const QgsPaperItem*>( item );
453 
454  if ( !paperItem )
455  composerItem->move( diffX, diffY );
456  }
457  }
458 
459  //also move guides
460  Q_FOREACH ( QGraphicsLineItem* guide, mSnapLines )
461  {
462  QLineF line = guide->line();
463  if ( line.dx() == 0 )
464  {
465  //vertical line
466  guide->setLine( line.x1() + diffX, 0, line.x1() + diffX, newHeight );
467  }
468  else
469  {
470  //horizontal line
471  guide->setLine( 0, line.y1() + diffY, newWidth, line.y1() + diffY );
472  }
473  }
474 }
475 
476 void QgsComposition::setResizeToContentsMargins( double marginTop, double marginRight, double marginBottom, double marginLeft )
477 {
478  mResizeToContentsMarginTop = marginTop;
479  mResizeToContentsMarginRight = marginRight;
480  mResizeToContentsMarginBottom = marginBottom;
481  mResizeToContentsMarginLeft = marginLeft;
482 }
483 
484 void QgsComposition::resizeToContentsMargins( double& marginTop, double& marginRight, double& marginBottom, double& marginLeft ) const
485 {
486  marginTop = mResizeToContentsMarginTop;
487  marginRight = mResizeToContentsMarginRight;
488  marginBottom = mResizeToContentsMarginBottom;
489  marginLeft = mResizeToContentsMarginLeft;
490 }
491 
492 void QgsComposition::setNumPages( const int pages )
493 {
494  int currentPages = numPages();
495  int desiredPages = pages;
496 
497  //data defined num pages set?
498  QVariant exprVal;
500  if ( dataDefinedEvaluate( QgsComposerObject::NumPages, exprVal, *context.data(), &mDataDefinedProperties ) )
501  {
502  bool ok = false;
503  int pagesD = exprVal.toInt( &ok );
504  QgsDebugMsg( QString( "exprVal NumPages:%1" ).arg( pagesD ) );
505  if ( ok )
506  {
507  desiredPages = pagesD;
508  }
509  }
510 
511  int diff = desiredPages - currentPages;
512  if ( diff >= 0 )
513  {
514  for ( int i = 0; i < diff; ++i )
515  {
516  addPaperItem();
517  }
518  }
519  else
520  {
521  diff = -diff;
522  for ( int i = 0; i < diff; ++i )
523  {
524  delete mPages.last();
525  mPages.removeLast();
526  }
527  }
528 
529  //update vertical guide height
531  QList< QGraphicsLineItem* >::iterator guideIt = guides->begin();
532  double totalHeight = ( mPageHeight + spaceBetweenPages() ) * ( pages - 1 ) + mPageHeight;
533  for ( ; guideIt != guides->end(); ++guideIt )
534  {
535  QLineF line = ( *guideIt )->line();
536  if ( line.dx() == 0 )
537  {
538  //vertical line, change height of line
539  ( *guideIt )->setLine( line.x1(), 0, line.x1(), totalHeight );
540  }
541  }
542 
543  QgsProject::instance()->dirty( true );
544  updateBounds();
545 
546  emit nPagesChanged();
547 }
548 
550 {
551  return mPages.size();
552 }
553 
554 bool QgsComposition::pageIsEmpty( const int page ) const
555 {
556  //get all items on page
558  //composerItemsOnPage uses 0-based page numbering
559  composerItemsOnPage( items, page - 1 );
560 
561  //loop through and check for non-paper items
563  for ( ; itemIt != items.constEnd(); ++itemIt )
564  {
565  //is item a paper item?
566  QgsPaperItem* paper = dynamic_cast<QgsPaperItem*>( *itemIt );
567  if ( !paper )
568  {
569  //item is not a paper item, so we have other items on the page
570  return false;
571  }
572  }
573  //no non-paper items
574  return true;
575 }
576 
577 bool QgsComposition::shouldExportPage( const int page ) const
578 {
579  if ( page > numPages() || page < 1 )
580  {
581  //page number out of range
582  return false;
583  }
584 
585  //check all frame items on page
587  //composerItemsOnPage uses 0 based page numbering
588  composerItemsOnPage( frames, page - 1 );
590  for ( ; frameIt != frames.constEnd(); ++frameIt )
591  {
592  if (( *frameIt )->hidePageIfEmpty() && ( *frameIt )->isEmpty() )
593  {
594  //frame is set to hide page if empty, and frame is empty, so we don't want to export this page
595  return false;
596  }
597  }
598  return true;
599 }
600 
602 {
603  delete mPageStyleSymbol;
604  mPageStyleSymbol = static_cast<QgsFillSymbolV2*>( symbol->clone() );
605  QgsProject::instance()->dirty( true );
606 }
607 
608 void QgsComposition::createDefaultPageStyleSymbol()
609 {
610  delete mPageStyleSymbol;
611  QgsStringMap properties;
612  properties.insert( "color", "white" );
613  properties.insert( "style", "solid" );
614  properties.insert( "style_border", "no" );
615  properties.insert( "joinstyle", "miter" );
616  mPageStyleSymbol = QgsFillSymbolV2::createSimple( properties );
617 }
618 
620 {
621  double y;
622  if ( position.y() > ( mPages.size() - 1 ) * ( paperHeight() + spaceBetweenPages() ) )
623  {
624  //y coordinate is greater then the end of the last page, so return distance between
625  //top of last page and y coordinate
626  y = position.y() - ( mPages.size() - 1 ) * ( paperHeight() + spaceBetweenPages() );
627  }
628  else
629  {
630  //y coordinate is less then the end of the last page
631  y = fmod( position.y(), ( paperHeight() + spaceBetweenPages() ) );
632  }
633  return QPointF( position.x(), y );
634 }
635 
636 int QgsComposition::pageNumberForPoint( const QPointF & position ) const
637 {
638  int pageNumber = qFloor( position.y() / ( paperHeight() + spaceBetweenPages() ) ) + 1;
639  pageNumber = pageNumber < 1 ? 1 : pageNumber;
640  pageNumber = pageNumber > mPages.size() ? mPages.size() : pageNumber;
641  return pageNumber;
642 }
643 
645 {
646  emit statusMsgChanged( message );
647 }
648 
649 QgsComposerItem* QgsComposition::composerItemAt( const QPointF & position, const bool ignoreLocked ) const
650 {
651  return composerItemAt( position, 0, ignoreLocked );
652 }
653 
654 QgsComposerItem* QgsComposition::composerItemAt( const QPointF & position, const QgsComposerItem* belowItem, const bool ignoreLocked ) const
655 {
656  //get a list of items which intersect the specified position, in descending z order
657  QList<QGraphicsItem*> itemList;
658  itemList = items( position, Qt::IntersectsItemShape, Qt::DescendingOrder );
659  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
660 
661  bool foundBelowItem = false;
662  for ( ; itemIt != itemList.end(); ++itemIt )
663  {
664  QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem *>( *itemIt );
665  QgsPaperItem* paperItem = dynamic_cast<QgsPaperItem*>( *itemIt );
666  if ( composerItem && !paperItem )
667  {
668  // If we are not checking for a an item below a specified item, or if we've
669  // already found that item, then we've found our target
670  if (( ! belowItem || foundBelowItem ) && ( !ignoreLocked || !composerItem->positionLock() ) )
671  {
672  return composerItem;
673  }
674  else
675  {
676  if ( composerItem == belowItem )
677  {
678  //Target item is next in list
679  foundBelowItem = true;
680  }
681  }
682  }
683  }
684  return 0;
685 }
686 
687 int QgsComposition::pageNumberAt( const QPointF& position ) const
688 {
689  return position.y() / ( paperHeight() + spaceBetweenPages() );
690 }
691 
693 {
694  return pageNumberAt( QPointF( item->pos().x(), item->pos().y() ) );
695 }
696 
698 {
699  QList<QgsComposerItem*> composerItemList;
700 
701  QList<QGraphicsItem *> graphicsItemList = selectedItems();
702  QList<QGraphicsItem *>::iterator itemIter = graphicsItemList.begin();
703 
704  for ( ; itemIter != graphicsItemList.end(); ++itemIter )
705  {
706  QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem *>( *itemIter );
707  if ( composerItem && ( includeLockedItems || !composerItem->positionLock() ) )
708  {
709  composerItemList.push_back( composerItem );
710  }
711  }
712 
713  return composerItemList;
714 }
715 
717 {
718  QList<const QgsComposerMap*> resultList;
719 
720  QList<QGraphicsItem *> itemList = items();
721  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
722  for ( ; itemIt != itemList.end(); ++itemIt )
723  {
724  const QgsComposerMap* composerMap = dynamic_cast<const QgsComposerMap *>( *itemIt );
725  if ( composerMap )
726  {
727  resultList.push_back( composerMap );
728  }
729  }
730 
731  return resultList;
732 }
733 
735 {
736  QList<QGraphicsItem *> itemList = items();
737  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
738  for ( ; itemIt != itemList.end(); ++itemIt )
739  {
740  const QgsComposerMap* composerMap = dynamic_cast<const QgsComposerMap *>( *itemIt );
741  if ( composerMap )
742  {
743  if ( composerMap->id() == id )
744  {
745  return composerMap;
746  }
747  }
748  }
749  return 0;
750 }
751 
753 {
754  // an html item will be a composer frame and if it is we can try to get
755  // its multiframe parent and then try to cast that to a composer html
756  const QgsComposerFrame* composerFrame =
757  dynamic_cast<const QgsComposerFrame *>( item );
758  if ( composerFrame )
759  {
760  const QgsComposerMultiFrame * mypMultiFrame = composerFrame->multiFrame();
761  const QgsComposerHtml* composerHtml =
762  dynamic_cast<const QgsComposerHtml *>( mypMultiFrame );
763  if ( composerHtml )
764  {
765  return composerHtml;
766  }
767  }
768  return 0;
769 }
770 
772 {
773  QList<QGraphicsItem *> itemList = items();
774  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
775  for ( ; itemIt != itemList.end(); ++itemIt )
776  {
777  const QgsComposerItem* mypItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
778  if ( mypItem )
779  {
780  if ( mypItem->id() == theId )
781  {
782  return mypItem;
783  }
784  }
785  }
786  return 0;
787 }
788 
789 #if 0
790 const QgsComposerItem* QgsComposition::getComposerItemByUuid( QString theUuid, bool inAllComposers ) const
791 {
792  //This does not work since it seems impossible to get the QgisApp::instance() from here... Is there a workaround ?
794 
795  if ( inAllComposers )
796  {
797  composers = QgisApp::instance()->printComposers();
798  }
799  else
800  {
801  composers.insert( this )
802  }
803 
805  for ( ; it != composers.constEnd(); ++it )
806  {
807  QList<QGraphicsItem *> itemList = ( *it )->items();
808  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
809  for ( ; itemIt != itemList.end(); ++itemIt )
810  {
811  const QgsComposerItem* mypItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
812  if ( mypItem )
813  {
814  if ( mypItem->uuid() == theUuid )
815  {
816  return mypItem;
817  }
818  }
819  }
820  }
821 
822  return 0;
823 }
824 #endif
825 
827 {
828  QList<QGraphicsItem *> itemList = items();
829  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
830  for ( ; itemIt != itemList.end(); ++itemIt )
831  {
832  const QgsComposerItem* mypItem = dynamic_cast<const QgsComposerItem *>( *itemIt );
833  if ( mypItem )
834  {
835  if ( mypItem->uuid() == theUuid )
836  {
837  return mypItem;
838  }
839  }
840  }
841 
842  return 0;
843 }
844 
846 {
847  mPrintResolution = dpi;
848  emit printResolutionChanged();
849  QgsProject::instance()->dirty( true );
850 }
851 
852 void QgsComposition::setUseAdvancedEffects( const bool effectsEnabled )
853 {
854  mUseAdvancedEffects = effectsEnabled;
855 
856  //toggle effects for all composer items
857  QList<QGraphicsItem*> itemList = items();
859  for ( ; itemIt != itemList.constEnd(); ++itemIt )
860  {
861  QgsComposerItem* composerItem = dynamic_cast<QgsComposerItem*>( *itemIt );
862  if ( composerItem )
863  {
864  composerItem->setEffectsEnabled( effectsEnabled );
865  }
866  }
867 }
868 
869 int QgsComposition::pixelFontSize( double pointSize ) const
870 {
871  return qRound( QgsComposerUtils::pointsToMM( pointSize ) ); //round to nearest mm
872 }
873 
874 double QgsComposition::pointFontSize( int pixelSize ) const
875 {
876  return QgsComposerUtils::mmToPoints( pixelSize );
877 }
878 
880 {
881  if ( composerElem.isNull() )
882  {
883  return false;
884  }
885 
886  QDomElement compositionElem = doc.createElement( "Composition" );
887  compositionElem.setAttribute( "paperWidth", QString::number( mPageWidth ) );
888  compositionElem.setAttribute( "paperHeight", QString::number( mPageHeight ) );
889  compositionElem.setAttribute( "numPages", mPages.size() );
890 
891  QDomElement pageStyleElem = QgsSymbolLayerV2Utils::saveSymbol( QString(), mPageStyleSymbol, doc );
892  compositionElem.appendChild( pageStyleElem );
893 
894  //snapping
895  if ( mSnapToGrid )
896  {
897  compositionElem.setAttribute( "snapping", "1" );
898  }
899  else
900  {
901  compositionElem.setAttribute( "snapping", "0" );
902  }
903  if ( mGridVisible )
904  {
905  compositionElem.setAttribute( "gridVisible", "1" );
906  }
907  else
908  {
909  compositionElem.setAttribute( "gridVisible", "0" );
910  }
911  compositionElem.setAttribute( "snapGridResolution", QString::number( mSnapGridResolution ) );
912  compositionElem.setAttribute( "snapGridOffsetX", QString::number( mSnapGridOffsetX ) );
913  compositionElem.setAttribute( "snapGridOffsetY", QString::number( mSnapGridOffsetY ) );
914 
915  compositionElem.setAttribute( "showPages", mPagesVisible );
916 
917  //custom snap lines
919  for ( ; snapLineIt != mSnapLines.constEnd(); ++snapLineIt )
920  {
921  QDomElement snapLineElem = doc.createElement( "SnapLine" );
922  QLineF line = ( *snapLineIt )->line();
923  snapLineElem.setAttribute( "x1", QString::number( line.x1() ) );
924  snapLineElem.setAttribute( "y1", QString::number( line.y1() ) );
925  snapLineElem.setAttribute( "x2", QString::number( line.x2() ) );
926  snapLineElem.setAttribute( "y2", QString::number( line.y2() ) );
927  compositionElem.appendChild( snapLineElem );
928  }
929 
930  compositionElem.setAttribute( "printResolution", mPrintResolution );
931  compositionElem.setAttribute( "printAsRaster", mPrintAsRaster );
932 
933  compositionElem.setAttribute( "generateWorldFile", mGenerateWorldFile ? 1 : 0 );
934  if ( mGenerateWorldFile && mWorldFileMap )
935  {
936  compositionElem.setAttribute( "worldFileMap", mWorldFileMap->id() );
937  }
938 
939  compositionElem.setAttribute( "alignmentSnap", mAlignmentSnap ? 1 : 0 );
940  compositionElem.setAttribute( "guidesVisible", mGuidesVisible ? 1 : 0 );
941  compositionElem.setAttribute( "smartGuides", mSmartGuides ? 1 : 0 );
942  compositionElem.setAttribute( "snapTolerancePixels", mSnapTolerance );
943 
944  compositionElem.setAttribute( "resizeToContentsMarginTop", mResizeToContentsMarginTop );
945  compositionElem.setAttribute( "resizeToContentsMarginRight", mResizeToContentsMarginRight );
946  compositionElem.setAttribute( "resizeToContentsMarginBottom", mResizeToContentsMarginBottom );
947  compositionElem.setAttribute( "resizeToContentsMarginLeft", mResizeToContentsMarginLeft );
948 
949  //save items except paper items and frame items (they are saved with the corresponding multiframe)
950  QList<QGraphicsItem*> itemList = items();
952  for ( ; itemIt != itemList.constEnd(); ++itemIt )
953  {
954  const QgsComposerItem* composerItem = dynamic_cast<const QgsComposerItem*>( *itemIt );
955  if ( composerItem )
956  {
957  if ( composerItem->type() != QgsComposerItem::ComposerPaper && composerItem->type() != QgsComposerItem::ComposerFrame )
958  {
959  composerItem->writeXML( compositionElem, doc );
960  }
961  }
962  }
963 
964  //save multiframes
965  QSet<QgsComposerMultiFrame*>::const_iterator multiFrameIt = mMultiFrames.constBegin();
966  for ( ; multiFrameIt != mMultiFrames.constEnd(); ++multiFrameIt )
967  {
968  ( *multiFrameIt )->writeXML( compositionElem, doc );
969  }
970  composerElem.appendChild( compositionElem );
971 
972  //data defined properties
973  QgsComposerUtils::writeDataDefinedPropertyMap( compositionElem, doc, &mDataDefinedNames, &mDataDefinedProperties );
974 
975  //custom properties
976  mCustomProperties.writeXml( compositionElem, doc );
977 
978  return true;
979 }
980 
981 bool QgsComposition::readXML( const QDomElement& compositionElem, const QDomDocument& doc )
982 {
983  Q_UNUSED( doc );
984  if ( compositionElem.isNull() )
985  {
986  return false;
987  }
988 
989  //create pages
990  bool widthConversionOk, heightConversionOk;
991  mPageWidth = compositionElem.attribute( "paperWidth" ).toDouble( &widthConversionOk );
992  mPageHeight = compositionElem.attribute( "paperHeight" ).toDouble( &heightConversionOk );
993  emit paperSizeChanged();
994  int numPages = compositionElem.attribute( "numPages", "1" ).toInt();
995 
996  QDomElement pageStyleSymbolElem = compositionElem.firstChildElement( "symbol" );
997  if ( !pageStyleSymbolElem.isNull() )
998  {
999  delete mPageStyleSymbol;
1000  mPageStyleSymbol = QgsSymbolLayerV2Utils::loadSymbol<QgsFillSymbolV2>( pageStyleSymbolElem );
1001  }
1002 
1003  if ( widthConversionOk && heightConversionOk )
1004  {
1005  removePaperItems();
1006  for ( int i = 0; i < numPages; ++i )
1007  {
1008  addPaperItem();
1009  }
1010  }
1011 
1012  //snapping
1013  mSnapToGrid = compositionElem.attribute( "snapping", "0" ).toInt() == 0 ? false : true;
1014  mGridVisible = compositionElem.attribute( "gridVisible", "0" ).toInt() == 0 ? false : true;
1015 
1016  mSnapGridResolution = compositionElem.attribute( "snapGridResolution" ).toDouble();
1017  mSnapGridOffsetX = compositionElem.attribute( "snapGridOffsetX" ).toDouble();
1018  mSnapGridOffsetY = compositionElem.attribute( "snapGridOffsetY" ).toDouble();
1019 
1020  mAlignmentSnap = compositionElem.attribute( "alignmentSnap", "1" ).toInt() == 0 ? false : true;
1021  mGuidesVisible = compositionElem.attribute( "guidesVisible", "1" ).toInt() == 0 ? false : true;
1022  mSmartGuides = compositionElem.attribute( "smartGuides", "1" ).toInt() == 0 ? false : true;
1023  mSnapTolerance = compositionElem.attribute( "snapTolerancePixels", "10" ).toInt();
1024 
1025  mResizeToContentsMarginTop = compositionElem.attribute( "resizeToContentsMarginTop", "0" ).toDouble();
1026  mResizeToContentsMarginRight = compositionElem.attribute( "resizeToContentsMarginRight", "0" ).toDouble();
1027  mResizeToContentsMarginBottom = compositionElem.attribute( "resizeToContentsMarginBottom", "0" ).toDouble();
1028  mResizeToContentsMarginLeft = compositionElem.attribute( "resizeToContentsMarginLeft", "0" ).toDouble();
1029 
1030  //custom snap lines
1031  QDomNodeList snapLineNodes = compositionElem.elementsByTagName( "SnapLine" );
1032  for ( int i = 0; i < snapLineNodes.size(); ++i )
1033  {
1034  QDomElement snapLineElem = snapLineNodes.at( i ).toElement();
1035  QGraphicsLineItem* snapItem = addSnapLine();
1036  double x1 = snapLineElem.attribute( "x1" ).toDouble();
1037  double y1 = snapLineElem.attribute( "y1" ).toDouble();
1038  double x2 = snapLineElem.attribute( "x2" ).toDouble();
1039  double y2 = snapLineElem.attribute( "y2" ).toDouble();
1040  snapItem->setLine( x1, y1, x2, y2 );
1041  }
1042 
1043  mPagesVisible = ( compositionElem.attribute( "showPages", "1" ) != "0" );
1044  mPrintAsRaster = compositionElem.attribute( "printAsRaster" ).toInt();
1045  mPrintResolution = compositionElem.attribute( "printResolution", "300" ).toInt();
1046 
1047  mGenerateWorldFile = compositionElem.attribute( "generateWorldFile", "0" ).toInt() == 1 ? true : false;
1048 
1049  //data defined properties
1050  QgsComposerUtils::readDataDefinedPropertyMap( compositionElem, &mDataDefinedNames, &mDataDefinedProperties );
1051 
1052  //custom properties
1053  mCustomProperties.readXml( compositionElem );
1054 
1055  updatePaperItems();
1056 
1057  updateBounds();
1058 
1059  return true;
1060 }
1061 
1062 bool QgsComposition::loadFromTemplate( const QDomDocument& doc, QMap<QString, QString>* substitutionMap, bool addUndoCommands, const bool clearComposition )
1063 {
1064  if ( clearComposition )
1065  {
1066  deleteAndRemoveMultiFrames();
1067 
1068  //delete all non paper items and emit itemRemoved signal
1069  QList<QGraphicsItem *> itemList = items();
1070  QList<QGraphicsItem *>::iterator itemIter = itemList.begin();
1071  for ( ; itemIter != itemList.end(); ++itemIter )
1072  {
1073  QgsComposerItem* cItem = dynamic_cast<QgsComposerItem*>( *itemIter );
1074  QgsPaperItem* pItem = dynamic_cast<QgsPaperItem*>( *itemIter );
1075  if ( cItem && !pItem )
1076  {
1077  removeItem( cItem );
1078  emit itemRemoved( cItem );
1079  delete cItem;
1080  }
1081  }
1082  mItemsModel->clear();
1083 
1084  removePaperItems();
1085  mUndoStack->clear();
1086  }
1087 
1088  QDomDocument importDoc;
1089  if ( substitutionMap )
1090  {
1091  QString xmlString = doc.toString();
1092  QMap<QString, QString>::const_iterator sIt = substitutionMap->constBegin();
1093  for ( ; sIt != substitutionMap->constEnd(); ++sIt )
1094  {
1095  xmlString = xmlString.replace( "[" + sIt.key() + "]", encodeStringForXML( sIt.value() ) );
1096  }
1097 
1098  QString errorMsg;
1099  int errorLine, errorColumn;
1100  if ( !importDoc.setContent( xmlString, &errorMsg, &errorLine, &errorColumn ) )
1101  {
1102  return false;
1103  }
1104  }
1105  else
1106  {
1107  importDoc = doc;
1108  }
1109 
1110  //read general settings
1111  QDomElement atlasElem;
1112  if ( clearComposition )
1113  {
1114  QDomElement compositionElem = importDoc.documentElement().firstChildElement( "Composition" );
1115  if ( compositionElem.isNull() )
1116  {
1117  return false;
1118  }
1119 
1120  bool ok = readXML( compositionElem, importDoc );
1121  if ( !ok )
1122  {
1123  return false;
1124  }
1125 
1126  // read atlas parameters - must be done before adding items
1127  atlasElem = importDoc.documentElement().firstChildElement( "Atlas" );
1128  atlasComposition().readXML( atlasElem, importDoc );
1129  }
1130 
1131  // remove all uuid attributes since we don't want duplicates UUIDS
1132  QDomNodeList composerItemsNodes = importDoc.elementsByTagName( "ComposerItem" );
1133  for ( int i = 0; i < composerItemsNodes.count(); ++i )
1134  {
1135  QDomNode composerItemNode = composerItemsNodes.at( i );
1136  if ( composerItemNode.isElement() )
1137  {
1138  composerItemNode.toElement().setAttribute( "templateUuid", composerItemNode.toElement().attribute( "uuid" ) );
1139  composerItemNode.toElement().removeAttribute( "uuid" );
1140  }
1141  }
1142 
1143  //addItemsFromXML
1144  addItemsFromXML( importDoc.documentElement(), importDoc, 0, addUndoCommands, 0 );
1145 
1146  //read atlas map parameters (for pre 2.2 templates)
1147  //this can only be done after items have been added
1148  if ( clearComposition )
1149  {
1150  atlasComposition().readXMLMapSettings( atlasElem, importDoc );
1151  }
1152  return true;
1153 }
1154 
1155 QPointF QgsComposition::minPointFromXml( const QDomElement& elem ) const
1156 {
1157  double minX = std::numeric_limits<double>::max();
1158  double minY = std::numeric_limits<double>::max();
1159  QDomNodeList composerItemList = elem.elementsByTagName( "ComposerItem" );
1160  for ( int i = 0; i < composerItemList.size(); ++i )
1161  {
1162  QDomElement currentComposerItemElem = composerItemList.at( i ).toElement();
1163  double x, y;
1164  bool xOk, yOk;
1165  x = currentComposerItemElem.attribute( "x" ).toDouble( &xOk );
1166  y = currentComposerItemElem.attribute( "y" ).toDouble( &yOk );
1167  if ( !xOk || !yOk )
1168  {
1169  continue;
1170  }
1171  minX = qMin( minX, x );
1172  minY = qMin( minY, y );
1173  }
1174  if ( minX < std::numeric_limits<double>::max() )
1175  {
1176  return QPointF( minX, minY );
1177  }
1178  else
1179  {
1180  return QPointF( 0, 0 );
1181  }
1182 }
1183 
1185  bool addUndoCommands, QPointF* pos, bool pasteInPlace )
1186 {
1187  QPointF* pasteInPlacePt = 0;
1188 
1189  //if we are adding items to a composition which already contains items, we need to make sure
1190  //these items are placed at the top of the composition and that zValues are not duplicated
1191  //so, calculate an offset which needs to be added to the zValue of created items
1192  int zOrderOffset = mItemsModel->zOrderListSize();
1193 
1194  QPointF pasteShiftPos;
1195  QgsComposerItem* lastPastedItem = 0;
1196  if ( pos )
1197  {
1198  //If we are placing items relative to a certain point, then calculate how much we need
1199  //to shift the items by so that they are placed at this point
1200  //First, calculate the minimum position from the xml
1201  QPointF minItemPos = minPointFromXml( elem );
1202  //next, calculate how much each item needs to be shifted from its original position
1203  //so that it's placed at the correct relative position
1204  pasteShiftPos = *pos - minItemPos;
1205 
1206  //since we are pasting items, clear the existing selection
1207  setAllUnselected();
1208 
1209  if ( pasteInPlace )
1210  {
1211  pasteInPlacePt = new QPointF( 0, pageNumberAt( *pos ) * ( mPageHeight + mSpaceBetweenPages ) );
1212  }
1213  }
1214  QDomNodeList composerLabelList = elem.elementsByTagName( "ComposerLabel" );
1215  for ( int i = 0; i < composerLabelList.size(); ++i )
1216  {
1217  QDomElement currentComposerLabelElem = composerLabelList.at( i ).toElement();
1218  QgsComposerLabel* newLabel = new QgsComposerLabel( this );
1219  newLabel->readXML( currentComposerLabelElem, doc );
1220  if ( pos )
1221  {
1222  if ( pasteInPlacePt )
1223  {
1224  newLabel->setItemPosition( newLabel->pos().x(), fmod( newLabel->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1225  newLabel->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1226  }
1227  else
1228  {
1229  newLabel->move( pasteShiftPos.x(), pasteShiftPos.y() );
1230  }
1231  newLabel->setSelected( true );
1232  lastPastedItem = newLabel;
1233  }
1234  addComposerLabel( newLabel );
1235  newLabel->setZValue( newLabel->zValue() + zOrderOffset );
1236  if ( addUndoCommands )
1237  {
1238  pushAddRemoveCommand( newLabel, tr( "Label added" ) );
1239  }
1240  }
1241  // map
1242  QDomNodeList composerMapList = elem.elementsByTagName( "ComposerMap" );
1243  for ( int i = 0; i < composerMapList.size(); ++i )
1244  {
1245  QDomElement currentComposerMapElem = composerMapList.at( i ).toElement();
1246  QgsComposerMap* newMap = new QgsComposerMap( this );
1247 
1248  if ( mapsToRestore )
1249  {
1250  newMap->setUpdatesEnabled( false );
1251  }
1252 
1253  newMap->readXML( currentComposerMapElem, doc );
1254  newMap->assignFreeId();
1255 
1256  if ( mapsToRestore )
1257  {
1258  mapsToRestore->insert( newMap, ( int )( newMap->previewMode() ) );
1260  newMap->setUpdatesEnabled( true );
1261  }
1262  addComposerMap( newMap, false );
1263  newMap->setZValue( newMap->zValue() + zOrderOffset );
1264  if ( pos )
1265  {
1266  if ( pasteInPlace )
1267  {
1268  newMap->setItemPosition( newMap->pos().x(), fmod( newMap->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1269  newMap->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1270  }
1271  else
1272  {
1273  newMap->move( pasteShiftPos.x(), pasteShiftPos.y() );
1274  }
1275  newMap->setSelected( true );
1276  lastPastedItem = newMap;
1277  }
1278 
1279  if ( addUndoCommands )
1280  {
1281  pushAddRemoveCommand( newMap, tr( "Map added" ) );
1282  }
1283  }
1284  //now that all map items have been created, re-connect overview map signals
1286  composerItems( maps );
1287  for ( QList<QgsComposerMap*>::iterator mit = maps.begin(); mit != maps.end(); ++mit )
1288  {
1289  QgsComposerMap* map = ( *mit );
1290  if ( map )
1291  {
1292  QList<QgsComposerMapOverview* > overviews = map->overviews()->asList();
1293  QList<QgsComposerMapOverview* >::iterator overviewIt = overviews.begin();
1294  for ( ; overviewIt != overviews.end(); ++overviewIt )
1295  {
1296  ( *overviewIt )->connectSignals();
1297  }
1298  }
1299  }
1300 
1301  // arrow
1302  QDomNodeList composerArrowList = elem.elementsByTagName( "ComposerArrow" );
1303  for ( int i = 0; i < composerArrowList.size(); ++i )
1304  {
1305  QDomElement currentComposerArrowElem = composerArrowList.at( i ).toElement();
1306  QgsComposerArrow* newArrow = new QgsComposerArrow( this );
1307  newArrow->readXML( currentComposerArrowElem, doc );
1308  if ( pos )
1309  {
1310  if ( pasteInPlace )
1311  {
1312  newArrow->setItemPosition( newArrow->pos().x(), fmod( newArrow->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1313  newArrow->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1314  }
1315  else
1316  {
1317  newArrow->move( pasteShiftPos.x(), pasteShiftPos.y() );
1318  }
1319  newArrow->setSelected( true );
1320  lastPastedItem = newArrow;
1321  }
1322  addComposerArrow( newArrow );
1323  newArrow->setZValue( newArrow->zValue() + zOrderOffset );
1324  if ( addUndoCommands )
1325  {
1326  pushAddRemoveCommand( newArrow, tr( "Arrow added" ) );
1327  }
1328  }
1329  // scalebar
1330  QDomNodeList composerScaleBarList = elem.elementsByTagName( "ComposerScaleBar" );
1331  for ( int i = 0; i < composerScaleBarList.size(); ++i )
1332  {
1333  QDomElement currentComposerScaleBarElem = composerScaleBarList.at( i ).toElement();
1334  QgsComposerScaleBar* newScaleBar = new QgsComposerScaleBar( this );
1335  newScaleBar->readXML( currentComposerScaleBarElem, doc );
1336  if ( pos )
1337  {
1338  if ( pasteInPlace )
1339  {
1340  newScaleBar->setItemPosition( newScaleBar->pos().x(), fmod( newScaleBar->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1341  newScaleBar->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1342  }
1343  else
1344  {
1345  newScaleBar->move( pasteShiftPos.x(), pasteShiftPos.y() );
1346  }
1347  newScaleBar->setSelected( true );
1348  lastPastedItem = newScaleBar;
1349  }
1350  addComposerScaleBar( newScaleBar );
1351  newScaleBar->setZValue( newScaleBar->zValue() + zOrderOffset );
1352  if ( addUndoCommands )
1353  {
1354  pushAddRemoveCommand( newScaleBar, tr( "Scale bar added" ) );
1355  }
1356  }
1357  // shape
1358  QDomNodeList composerShapeList = elem.elementsByTagName( "ComposerShape" );
1359  for ( int i = 0; i < composerShapeList.size(); ++i )
1360  {
1361  QDomElement currentComposerShapeElem = composerShapeList.at( i ).toElement();
1362  QgsComposerShape* newShape = new QgsComposerShape( this );
1363  newShape->readXML( currentComposerShapeElem, doc );
1364  //new shapes should default to symbol v2
1365  newShape->setUseSymbolV2( true );
1366  if ( pos )
1367  {
1368  if ( pasteInPlace )
1369  {
1370  newShape->setItemPosition( newShape->pos().x(), fmod( newShape->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1371  newShape->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1372  }
1373  else
1374  {
1375  newShape->move( pasteShiftPos.x(), pasteShiftPos.y() );
1376  }
1377  newShape->setSelected( true );
1378  lastPastedItem = newShape;
1379  }
1380  addComposerShape( newShape );
1381  newShape->setZValue( newShape->zValue() + zOrderOffset );
1382  if ( addUndoCommands )
1383  {
1384  pushAddRemoveCommand( newShape, tr( "Shape added" ) );
1385  }
1386  }
1387  // picture
1388  QDomNodeList composerPictureList = elem.elementsByTagName( "ComposerPicture" );
1389  for ( int i = 0; i < composerPictureList.size(); ++i )
1390  {
1391  QDomElement currentComposerPictureElem = composerPictureList.at( i ).toElement();
1392  QgsComposerPicture* newPicture = new QgsComposerPicture( this );
1393  newPicture->readXML( currentComposerPictureElem, doc );
1394  if ( pos )
1395  {
1396  if ( pasteInPlace )
1397  {
1398  newPicture->setItemPosition( newPicture->pos().x(), fmod( newPicture->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1399  newPicture->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1400  }
1401  else
1402  {
1403  newPicture->move( pasteShiftPos.x(), pasteShiftPos.y() );
1404  }
1405  newPicture->setSelected( true );
1406  lastPastedItem = newPicture;
1407  }
1408  addComposerPicture( newPicture );
1409  newPicture->setZValue( newPicture->zValue() + zOrderOffset );
1410  if ( addUndoCommands )
1411  {
1412  pushAddRemoveCommand( newPicture, tr( "Picture added" ) );
1413  }
1414  }
1415  // legend
1416  QDomNodeList composerLegendList = elem.elementsByTagName( "ComposerLegend" );
1417  for ( int i = 0; i < composerLegendList.size(); ++i )
1418  {
1419  QDomElement currentComposerLegendElem = composerLegendList.at( i ).toElement();
1420  QgsComposerLegend* newLegend = new QgsComposerLegend( this );
1421  newLegend->readXML( currentComposerLegendElem, doc );
1422  if ( pos )
1423  {
1424  if ( pasteInPlace )
1425  {
1426  newLegend->setItemPosition( newLegend->pos().x(), fmod( newLegend->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1427  newLegend->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1428  }
1429  else
1430  {
1431  newLegend->move( pasteShiftPos.x(), pasteShiftPos.y() );
1432  }
1433  newLegend->setSelected( true );
1434  lastPastedItem = newLegend;
1435  }
1436  addComposerLegend( newLegend );
1437  newLegend->setZValue( newLegend->zValue() + zOrderOffset );
1438  if ( addUndoCommands )
1439  {
1440  pushAddRemoveCommand( newLegend, tr( "Legend added" ) );
1441  }
1442  }
1443  // table
1444  QDomNodeList composerTableList = elem.elementsByTagName( "ComposerAttributeTable" );
1445  for ( int i = 0; i < composerTableList.size(); ++i )
1446  {
1447  QDomElement currentComposerTableElem = composerTableList.at( i ).toElement();
1448  QgsComposerAttributeTable* newTable = new QgsComposerAttributeTable( this );
1449  newTable->readXML( currentComposerTableElem, doc );
1450  if ( pos )
1451  {
1452  if ( pasteInPlace )
1453  {
1454  newTable->setItemPosition( newTable->pos().x(), fmod( newTable->pos().y(), ( paperHeight() + spaceBetweenPages() ) ) );
1455  newTable->move( pasteInPlacePt->x(), pasteInPlacePt->y() );
1456  }
1457  else
1458  {
1459  newTable->move( pasteShiftPos.x(), pasteShiftPos.y() );
1460  }
1461  newTable->setSelected( true );
1462  lastPastedItem = newTable;
1463  }
1464  addComposerTable( newTable );
1465  newTable->setZValue( newTable->zValue() + zOrderOffset );
1466  if ( addUndoCommands )
1467  {
1468  pushAddRemoveCommand( newTable, tr( "Table added" ) );
1469  }
1470  }
1471  // html
1472  //TODO - fix this. pasting multiframe frame items has no effect
1473  QDomNodeList composerHtmlList = elem.elementsByTagName( "ComposerHtml" );
1474  for ( int i = 0; i < composerHtmlList.size(); ++i )
1475  {
1476  QDomElement currentHtmlElem = composerHtmlList.at( i ).toElement();
1477  QgsComposerHtml* newHtml = new QgsComposerHtml( this, false );
1478  newHtml->readXML( currentHtmlElem, doc );
1479  newHtml->setCreateUndoCommands( true );
1480  this->addMultiFrame( newHtml );
1481 
1482  //offset z values for frames
1483  //TODO - fix this after fixing html item paste
1484  /*for ( int frameIdx = 0; frameIdx < newHtml->frameCount(); ++frameIdx )
1485  {
1486  QgsComposerFrame * frame = newHtml->frame( frameIdx );
1487  frame->setZValue( frame->zValue() + zOrderOffset );
1488  }*/
1489  }
1490  QDomNodeList composerAttributeTableV2List = elem.elementsByTagName( "ComposerAttributeTableV2" );
1491  for ( int i = 0; i < composerAttributeTableV2List.size(); ++i )
1492  {
1493  QDomElement currentTableElem = composerAttributeTableV2List.at( i ).toElement();
1494  QgsComposerAttributeTableV2* newTable = new QgsComposerAttributeTableV2( this, false );
1495  newTable->readXML( currentTableElem, doc );
1496  newTable->setCreateUndoCommands( true );
1497  this->addMultiFrame( newTable );
1498 
1499  //offset z values for frames
1500  //TODO - fix this after fixing html item paste
1501  /*for ( int frameIdx = 0; frameIdx < newHtml->frameCount(); ++frameIdx )
1502  {
1503  QgsComposerFrame * frame = newHtml->frame( frameIdx );
1504  frame->setZValue( frame->zValue() + zOrderOffset );
1505  }*/
1506  }
1507 
1508  // groups (must be last as it references uuids of above items)
1509  //TODO - pasted groups lose group properties, since the uuids of group items
1510  //changes
1511  QDomNodeList groupList = elem.elementsByTagName( "ComposerItemGroup" );
1512  for ( int i = 0; i < groupList.size(); ++i )
1513  {
1514  QDomElement groupElem = groupList.at( i ).toElement();
1515  QgsComposerItemGroup *newGroup = new QgsComposerItemGroup( this );
1516  newGroup->readXML( groupElem, doc );
1517  addItem( newGroup );
1518  }
1519 
1520  //Since this function adds items grouped by type, and each item is added to end of
1521  //z order list in turn, it will now be inconsistent with the actual order of items in the scene.
1522  //Make sure z order list matches the actual order of items in the scene.
1523  mItemsModel->rebuildZList();
1524 
1525  if ( lastPastedItem )
1526  {
1527  emit selectedItemChanged( lastPastedItem );
1528  }
1529 
1530  delete pasteInPlacePt;
1531  pasteInPlacePt = 0;
1532 
1533 }
1534 
1536 {
1537  if ( !item )
1538  {
1539  return;
1540  }
1541 
1542  //model handles changes to z list
1543  mItemsModel->addItemAtTop( item );
1544 }
1545 
1547 {
1548  if ( !item )
1549  {
1550  return;
1551  }
1552 
1553  //model handles changes to z list
1554  mItemsModel->removeItem( item );
1555 }
1556 
1558 {
1560  QList<QgsComposerItem*>::iterator it = selectedItems.begin();
1561  bool itemsRaised = false;
1562  for ( ; it != selectedItems.end(); ++it )
1563  {
1564  itemsRaised = itemsRaised | raiseItem( *it );
1565  }
1566 
1567  if ( !itemsRaised )
1568  {
1569  //no change
1570  return;
1571  }
1572 
1573  //update all positions
1574  updateZValues();
1575  update();
1576 }
1577 
1579 {
1580  //model handles reordering items
1581  return mItemsModel->reorderItemUp( item );
1582 }
1583 
1585 {
1586  return mItemsModel->getComposerItemAbove( item );
1587 }
1588 
1590 {
1591  return mItemsModel->getComposerItemBelow( item );
1592 }
1593 
1595 {
1596  QgsComposerItem* previousSelectedItem = 0;
1598  if ( selectedItems.size() > 0 )
1599  {
1600  previousSelectedItem = selectedItems.at( 0 );
1601  }
1602 
1603  if ( !previousSelectedItem )
1604  {
1605  return;
1606  }
1607 
1608  //select item with target z value
1609  QgsComposerItem* selectedItem = 0;
1610  switch ( direction )
1611  {
1613  selectedItem = getComposerItemBelow( previousSelectedItem );
1614  break;
1616  selectedItem = getComposerItemAbove( previousSelectedItem );
1617  break;
1618  }
1619 
1620  if ( !selectedItem )
1621  {
1622  return;
1623  }
1624 
1625  //ok, found a good target item
1626  setAllUnselected();
1627  selectedItem->setSelected( true );
1628  emit selectedItemChanged( selectedItem );
1629 }
1630 
1632 {
1634  QList<QgsComposerItem*>::iterator it = selectedItems.begin();
1635  bool itemsLowered = false;
1636  for ( ; it != selectedItems.end(); ++it )
1637  {
1638  itemsLowered = itemsLowered | lowerItem( *it );
1639  }
1640 
1641  if ( !itemsLowered )
1642  {
1643  //no change
1644  return;
1645  }
1646 
1647  //update all positions
1648  updateZValues();
1649  update();
1650 }
1651 
1653 {
1654  //model handles reordering items
1655  return mItemsModel->reorderItemDown( item );
1656 }
1657 
1659 {
1661  QList<QgsComposerItem*>::iterator it = selectedItems.begin();
1662  bool itemsRaised = false;
1663  for ( ; it != selectedItems.end(); ++it )
1664  {
1665  itemsRaised = itemsRaised | moveItemToTop( *it );
1666  }
1667 
1668  if ( !itemsRaised )
1669  {
1670  //no change
1671  return;
1672  }
1673 
1674  //update all positions
1675  updateZValues();
1676  update();
1677 }
1678 
1680 {
1681  //model handles reordering items
1682  return mItemsModel->reorderItemToTop( item );
1683 }
1684 
1686 {
1688  QList<QgsComposerItem*>::iterator it = selectedItems.begin();
1689  bool itemsLowered = false;
1690  for ( ; it != selectedItems.end(); ++it )
1691  {
1692  itemsLowered = itemsLowered | moveItemToBottom( *it );
1693  }
1694 
1695  if ( !itemsLowered )
1696  {
1697  //no change
1698  return;
1699  }
1700 
1701  //update all positions
1702  updateZValues();
1703  update();
1704 }
1705 
1707 {
1708  //model handles reordering items
1709  return mItemsModel->reorderItemToBottom( item );
1710 }
1711 
1713 {
1715  if ( selectedItems.size() < 2 )
1716  {
1717  return;
1718  }
1719 
1720  QRectF selectedItemBBox;
1721  if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
1722  {
1723  return;
1724  }
1725 
1726  double minXCoordinate = selectedItemBBox.left();
1727 
1728  //align items left to minimum x coordinate
1729  QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items left" ) );
1730  QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
1731  for ( ; align_it != selectedItems.end(); ++align_it )
1732  {
1733  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
1734  subcommand->savePreviousState();
1735  ( *align_it )->setPos( minXCoordinate, ( *align_it )->pos().y() );
1736  subcommand->saveAfterState();
1737  }
1738  mUndoStack->push( parentCommand );
1739  QgsProject::instance()->dirty( true );
1740 }
1741 
1743 {
1745  if ( selectedItems.size() < 2 )
1746  {
1747  return;
1748  }
1749 
1750  QRectF selectedItemBBox;
1751  if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
1752  {
1753  return;
1754  }
1755 
1756  double averageXCoord = ( selectedItemBBox.left() + selectedItemBBox.right() ) / 2.0;
1757 
1758  //place items
1759  QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items horizontal center" ) );
1760  QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
1761  for ( ; align_it != selectedItems.end(); ++align_it )
1762  {
1763  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
1764  subcommand->savePreviousState();
1765  ( *align_it )->setPos( averageXCoord - ( *align_it )->rect().width() / 2.0, ( *align_it )->pos().y() );
1766  subcommand->saveAfterState();
1767  }
1768  mUndoStack->push( parentCommand );
1769  QgsProject::instance()->dirty( true );
1770 }
1771 
1773 {
1775  if ( selectedItems.size() < 2 )
1776  {
1777  return;
1778  }
1779 
1780  QRectF selectedItemBBox;
1781  if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
1782  {
1783  return;
1784  }
1785 
1786  double maxXCoordinate = selectedItemBBox.right();
1787 
1788  //align items right to maximum x coordinate
1789  QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items right" ) );
1790  QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
1791  for ( ; align_it != selectedItems.end(); ++align_it )
1792  {
1793  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
1794  subcommand->savePreviousState();
1795  ( *align_it )->setPos( maxXCoordinate - ( *align_it )->rect().width(), ( *align_it )->pos().y() );
1796  subcommand->saveAfterState();
1797  }
1798  mUndoStack->push( parentCommand );
1799  QgsProject::instance()->dirty( true );
1800 }
1801 
1803 {
1805  if ( selectedItems.size() < 2 )
1806  {
1807  return;
1808  }
1809 
1810  QRectF selectedItemBBox;
1811  if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
1812  {
1813  return;
1814  }
1815 
1816  double minYCoordinate = selectedItemBBox.top();
1817 
1818  QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items top" ) );
1819  QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
1820  for ( ; align_it != selectedItems.end(); ++align_it )
1821  {
1822  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
1823  subcommand->savePreviousState();
1824  ( *align_it )->setPos(( *align_it )->pos().x(), minYCoordinate );
1825  subcommand->saveAfterState();
1826  }
1827  mUndoStack->push( parentCommand );
1828  QgsProject::instance()->dirty( true );
1829 }
1830 
1832 {
1834  if ( selectedItems.size() < 2 )
1835  {
1836  return;
1837  }
1838 
1839  QRectF selectedItemBBox;
1840  if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
1841  {
1842  return;
1843  }
1844 
1845  double averageYCoord = ( selectedItemBBox.top() + selectedItemBBox.bottom() ) / 2.0;
1846  QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items vertical center" ) );
1847  QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
1848  for ( ; align_it != selectedItems.end(); ++align_it )
1849  {
1850  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
1851  subcommand->savePreviousState();
1852  ( *align_it )->setPos(( *align_it )->pos().x(), averageYCoord - ( *align_it )->rect().height() / 2 );
1853  subcommand->saveAfterState();
1854  }
1855  mUndoStack->push( parentCommand );
1856  QgsProject::instance()->dirty( true );
1857 }
1858 
1860 {
1862  if ( selectedItems.size() < 2 )
1863  {
1864  return;
1865  }
1866 
1867  QRectF selectedItemBBox;
1868  if ( boundingRectOfSelectedItems( selectedItemBBox ) != 0 )
1869  {
1870  return;
1871  }
1872 
1873  double maxYCoord = selectedItemBBox.bottom();
1874  QUndoCommand* parentCommand = new QUndoCommand( tr( "Aligned items bottom" ) );
1875  QList<QgsComposerItem*>::iterator align_it = selectedItems.begin();
1876  for ( ; align_it != selectedItems.end(); ++align_it )
1877  {
1878  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *align_it, "", parentCommand );
1879  subcommand->savePreviousState();
1880  ( *align_it )->setPos(( *align_it )->pos().x(), maxYCoord - ( *align_it )->rect().height() );
1881  subcommand->saveAfterState();
1882  }
1883  mUndoStack->push( parentCommand );
1884  QgsProject::instance()->dirty( true );
1885 }
1886 
1888 {
1889  QUndoCommand* parentCommand = new QUndoCommand( tr( "Items locked" ) );
1891  QList<QgsComposerItem*>::iterator itemIter = selectionList.begin();
1892  for ( ; itemIter != selectionList.end(); ++itemIter )
1893  {
1894  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( *itemIter, "", parentCommand );
1895  subcommand->savePreviousState();
1896  ( *itemIter )->setPositionLock( true );
1897  subcommand->saveAfterState();
1898  }
1899 
1900  setAllUnselected();
1901  mUndoStack->push( parentCommand );
1902  QgsProject::instance()->dirty( true );
1903 }
1904 
1906 {
1907  //unlock all items in composer
1908 
1909  QUndoCommand* parentCommand = new QUndoCommand( tr( "Items unlocked" ) );
1910 
1911  //first, clear the selection
1912  setAllUnselected();
1913 
1914  QList<QGraphicsItem *> itemList = items();
1915  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
1916  for ( ; itemIt != itemList.end(); ++itemIt )
1917  {
1918  QgsComposerItem* mypItem = dynamic_cast<QgsComposerItem *>( *itemIt );
1919  if ( mypItem && mypItem->positionLock() )
1920  {
1921  QgsComposerItemCommand* subcommand = new QgsComposerItemCommand( mypItem, "", parentCommand );
1922  subcommand->savePreviousState();
1923  mypItem->setPositionLock( false );
1924  //select unlocked items, same behaviour as illustrator
1925  mypItem->setSelected( true );
1926  emit selectedItemChanged( mypItem );
1927  subcommand->saveAfterState();
1928  }
1929  }
1930  mUndoStack->push( parentCommand );
1931  QgsProject::instance()->dirty( true );
1932 }
1933 
1935 {
1936  if ( items.size() < 2 )
1937  {
1938  //not enough items for a group
1939  return 0;
1940  }
1941 
1942  QgsComposerItemGroup* itemGroup = new QgsComposerItemGroup( this );
1943 
1944  QList<QgsComposerItem*>::iterator itemIter = items.begin();
1945  for ( ; itemIter != items.end(); ++itemIter )
1946  {
1947  itemGroup->addItem( *itemIter );
1948  }
1949 
1950  addItem( itemGroup );
1951  return itemGroup;
1952 }
1953 
1955 {
1956  QList<QgsComposerItem *> ungroupedItems;
1957  if ( !group )
1958  {
1959  return ungroupedItems;
1960  }
1961 
1962  QSet<QgsComposerItem*> groupedItems = group->items();
1963  QSet<QgsComposerItem*>::iterator itemIt = groupedItems.begin();
1964  for ( ; itemIt != groupedItems.end(); ++itemIt )
1965  {
1966  ungroupedItems << ( *itemIt );
1967  }
1968 
1969  group->removeItems();
1970  removeComposerItem( group, false, false );
1971 
1972  emit itemRemoved( group );
1973  delete( group );
1974 
1975  return ungroupedItems;
1976 }
1977 
1978 void QgsComposition::updateZValues( const bool addUndoCommands )
1979 {
1980  int counter = mItemsModel->zOrderListSize();
1982  QgsComposerItem* currentItem = 0;
1983 
1984  QUndoCommand* parentCommand = 0;
1985  if ( addUndoCommands )
1986  {
1987  parentCommand = new QUndoCommand( tr( "Item z-order changed" ) );
1988  }
1989  for ( ; it != mItemsModel->zOrderList()->constEnd(); ++it )
1990  {
1991  currentItem = *it;
1992  if ( currentItem )
1993  {
1994  QgsComposerItemCommand* subcommand = 0;
1995  if ( addUndoCommands )
1996  {
1997  subcommand = new QgsComposerItemCommand( *it, "", parentCommand );
1998  subcommand->savePreviousState();
1999  }
2000  currentItem->setZValue( counter );
2001  if ( addUndoCommands )
2002  {
2003  subcommand->saveAfterState();
2004  }
2005  }
2006  --counter;
2007  }
2008  if ( addUndoCommands )
2009  {
2010  mUndoStack->push( parentCommand );
2011  QgsProject::instance()->dirty( true );
2012  }
2013 }
2014 
2016 {
2017  //model handles changes to item z order list
2018  mItemsModel->rebuildZList();
2019 
2020  //Finally, rebuild the zValue of all items to remove any duplicate zValues and make sure there's
2021  //no missing zValues.
2022  updateZValues( false );
2023 }
2024 
2026 {
2027  if ( !mSnapToGrid || mSnapGridResolution <= 0 || !graphicsView() )
2028  {
2029  return scenePoint;
2030  }
2031 
2032  //y offset to current page
2033  int pageNr = ( int )( scenePoint.y() / ( mPageHeight + mSpaceBetweenPages ) );
2034  double yOffset = pageNr * ( mPageHeight + mSpaceBetweenPages );
2035  double yPage = scenePoint.y() - yOffset; //y-coordinate relative to current page
2036 
2037  //snap x coordinate
2038  int xRatio = ( int )(( scenePoint.x() - mSnapGridOffsetX ) / mSnapGridResolution + 0.5 );
2039  int yRatio = ( int )(( yPage - mSnapGridOffsetY ) / mSnapGridResolution + 0.5 );
2040 
2041  double xSnapped = xRatio * mSnapGridResolution + mSnapGridOffsetX;
2042  double ySnapped = yRatio * mSnapGridResolution + mSnapGridOffsetY + yOffset;
2043 
2044  //convert snap tolerance from pixels to mm
2045  double viewScaleFactor = graphicsView()->transform().m11();
2046  double alignThreshold = mSnapTolerance / viewScaleFactor;
2047 
2048  if ( fabs( xSnapped - scenePoint.x() ) > alignThreshold )
2049  {
2050  //snap distance is outside of tolerance
2051  xSnapped = scenePoint.x();
2052  }
2053  if ( fabs( ySnapped - scenePoint.y() ) > alignThreshold )
2054  {
2055  //snap distance is outside of tolerance
2056  ySnapped = scenePoint.y();
2057  }
2058 
2059  return QPointF( xSnapped, ySnapped );
2060 }
2061 
2063 {
2064  QGraphicsLineItem* item = new QGraphicsLineItem();
2065  QPen linePen( Qt::SolidLine );
2066  linePen.setColor( Qt::red );
2067  // use a pen width of 0, since this activates a cosmetic pen
2068  // which doesn't scale with the composer and keeps a constant size
2069  linePen.setWidthF( 0 );
2070  item->setPen( linePen );
2071  item->setZValue( 100 );
2072  item->setVisible( mGuidesVisible );
2073  addItem( item );
2074  mSnapLines.push_back( item );
2075  return item;
2076 }
2077 
2079 {
2080  removeItem( line );
2081  mSnapLines.removeAll( line );
2082  delete line;
2083 }
2084 
2086 {
2087  QList< QGraphicsLineItem* >::iterator it = mSnapLines.begin();
2088  for ( ; it != mSnapLines.end(); ++it )
2089  {
2090  removeItem(( *it ) );
2091  delete( *it );
2092  }
2093  mSnapLines.clear();
2094 }
2095 
2096 void QgsComposition::setSnapLinesVisible( const bool visible )
2097 {
2098  mGuidesVisible = visible;
2099  QList< QGraphicsLineItem* >::iterator it = mSnapLines.begin();
2100  for ( ; it != mSnapLines.end(); ++it )
2101  {
2102  if ( visible )
2103  {
2104  ( *it )->show();
2105  }
2106  else
2107  {
2108  ( *it )->hide();
2109  }
2110  }
2111 }
2112 
2114 {
2115  mPagesVisible = visible;
2116  update();
2117 }
2118 
2119 QGraphicsLineItem* QgsComposition::nearestSnapLine( const bool horizontal, const double x, const double y, const double tolerance,
2121 {
2122  double minSqrDist = DBL_MAX;
2123  QGraphicsLineItem* item = 0;
2124  double currentXCoord = 0;
2125  double currentYCoord = 0;
2126  double currentSqrDist = 0;
2127  double sqrTolerance = tolerance * tolerance;
2128 
2129  snappedItems.clear();
2130 
2132  for ( ; it != mSnapLines.constEnd(); ++it )
2133  {
2134  bool itemHorizontal = qgsDoubleNear(( *it )->line().y2() - ( *it )->line().y1(), 0 );
2135  if ( horizontal && itemHorizontal )
2136  {
2137  currentYCoord = ( *it )->line().y1();
2138  currentSqrDist = ( y - currentYCoord ) * ( y - currentYCoord );
2139  }
2140  else if ( !horizontal && !itemHorizontal )
2141  {
2142  currentXCoord = ( *it )->line().x1();
2143  currentSqrDist = ( x - currentXCoord ) * ( x - currentXCoord );
2144  }
2145  else
2146  {
2147  continue;
2148  }
2149 
2150  if ( currentSqrDist < minSqrDist && currentSqrDist < sqrTolerance )
2151  {
2152  item = *it;
2153  minSqrDist = currentSqrDist;
2154  }
2155  }
2156 
2157  double itemTolerance = 0.0000001;
2158  if ( item )
2159  {
2160  //go through all the items to find items snapped to this snap line
2161  QList<QGraphicsItem *> itemList = items();
2162  QList<QGraphicsItem *>::iterator itemIt = itemList.begin();
2163  for ( ; itemIt != itemList.end(); ++itemIt )
2164  {
2165  QgsComposerItem* currentItem = dynamic_cast<QgsComposerItem*>( *itemIt );
2166  if ( !currentItem || currentItem->type() == QgsComposerItem::ComposerPaper )
2167  {
2168  continue;
2169  }
2170 
2171  if ( horizontal )
2172  {
2173  if ( qgsDoubleNear( currentYCoord, currentItem->pos().y() + currentItem->rect().top(), itemTolerance ) )
2174  {
2175  snappedItems.append( qMakePair( currentItem, QgsComposerItem::UpperMiddle ) );
2176  }
2177  else if ( qgsDoubleNear( currentYCoord, currentItem->pos().y() + currentItem->rect().center().y(), itemTolerance ) )
2178  {
2179  snappedItems.append( qMakePair( currentItem, QgsComposerItem::Middle ) );
2180  }
2181  else if ( qgsDoubleNear( currentYCoord, currentItem->pos().y() + currentItem->rect().bottom(), itemTolerance ) )
2182  {
2183  snappedItems.append( qMakePair( currentItem, QgsComposerItem::LowerMiddle ) );
2184  }
2185  }
2186  else
2187  {
2188  if ( qgsDoubleNear( currentXCoord, currentItem->pos().x(), itemTolerance ) )
2189  {
2190  snappedItems.append( qMakePair( currentItem, QgsComposerItem::MiddleLeft ) );
2191  }
2192  else if ( qgsDoubleNear( currentXCoord, currentItem->pos().x() + currentItem->rect().center().x(), itemTolerance ) )
2193  {
2194  snappedItems.append( qMakePair( currentItem, QgsComposerItem::Middle ) );
2195  }
2196  else if ( qgsDoubleNear( currentXCoord, currentItem->pos().x() + currentItem->rect().width(), itemTolerance ) )
2197  {
2198  snappedItems.append( qMakePair( currentItem, QgsComposerItem::MiddleRight ) );
2199  }
2200  }
2201  }
2202  }
2203 
2204  return item;
2205 }
2206 
2207 int QgsComposition::boundingRectOfSelectedItems( QRectF& bRect )
2208 {
2210  if ( selectedItems.size() < 1 )
2211  {
2212  return 1;
2213  }
2214 
2215  //set the box to the first item
2216  QgsComposerItem* currentItem = selectedItems.at( 0 );
2217  double minX = currentItem->pos().x();
2218  double minY = currentItem->pos().y();
2219  double maxX = minX + currentItem->rect().width();
2220  double maxY = minY + currentItem->rect().height();
2221 
2222  double currentMinX, currentMinY, currentMaxX, currentMaxY;
2223 
2224  for ( int i = 1; i < selectedItems.size(); ++i )
2225  {
2226  currentItem = selectedItems.at( i );
2227  currentMinX = currentItem->pos().x();
2228  currentMinY = currentItem->pos().y();
2229  currentMaxX = currentMinX + currentItem->rect().width();
2230  currentMaxY = currentMinY + currentItem->rect().height();
2231 
2232  if ( currentMinX < minX )
2233  minX = currentMinX;
2234  if ( currentMaxX > maxX )
2235  maxX = currentMaxX;
2236  if ( currentMinY < minY )
2237  minY = currentMinY;
2238  if ( currentMaxY > maxY )
2239  maxY = currentMaxY;
2240  }
2241 
2242  bRect.setTopLeft( QPointF( minX, minY ) );
2243  bRect.setBottomRight( QPointF( maxX, maxY ) );
2244  return 0;
2245 }
2246 
2248 {
2249  mSnapToGrid = b;
2250  updatePaperItems();
2251 }
2252 
2254 {
2255  mGridVisible = b;
2256  updatePaperItems();
2257 }
2258 
2260 {
2261  mSnapGridResolution = r;
2262  updatePaperItems();
2263 }
2264 
2265 void QgsComposition::setSnapGridOffsetX( const double offset )
2266 {
2267  mSnapGridOffsetX = offset;
2268  updatePaperItems();
2269 }
2270 
2271 void QgsComposition::setSnapGridOffsetY( const double offset )
2272 {
2273  mSnapGridOffsetY = offset;
2274  updatePaperItems();
2275 }
2276 
2278 {
2279  mGridPen = p;
2280  //make sure grid is drawn using a zero-width cosmetic pen
2281  mGridPen.setWidthF( 0 );
2282  updatePaperItems();
2283 }
2284 
2286 {
2287  mGridStyle = s;
2288  updatePaperItems();
2289 }
2290 
2291 void QgsComposition::setBoundingBoxesVisible( const bool boundsVisible )
2292 {
2293  mBoundingBoxesVisible = boundsVisible;
2294 
2295  if ( mSelectionHandles )
2296  {
2297  mSelectionHandles->update();
2298  }
2299 }
2300 
2302 {
2303  //load new composer setting values
2304  loadSettings();
2305  //update any paper items to reflect new settings
2306  updatePaperItems();
2307 }
2308 
2309 void QgsComposition::loadSettings()
2310 {
2311  //read grid style, grid color and pen width from settings
2312  QSettings s;
2313 
2314  QString gridStyleString;
2315  gridStyleString = s.value( "/Composer/gridStyle", "Dots" ).toString();
2316 
2317  int gridRed, gridGreen, gridBlue, gridAlpha;
2318  gridRed = s.value( "/Composer/gridRed", 190 ).toInt();
2319  gridGreen = s.value( "/Composer/gridGreen", 190 ).toInt();
2320  gridBlue = s.value( "/Composer/gridBlue", 190 ).toInt();
2321  gridAlpha = s.value( "/Composer/gridAlpha", 100 ).toInt();
2322  QColor gridColor = QColor( gridRed, gridGreen, gridBlue, gridAlpha );
2323 
2324  mGridPen.setColor( gridColor );
2325  mGridPen.setWidthF( 0 );
2326 
2327  if ( gridStyleString == "Dots" )
2328  {
2329  mGridStyle = Dots;
2330  }
2331  else if ( gridStyleString == "Crosses" )
2332  {
2333  mGridStyle = Crosses;
2334  }
2335  else
2336  {
2337  mGridStyle = Solid;
2338  }
2339 }
2340 
2342 {
2343  delete mActiveItemCommand;
2344  if ( !item )
2345  {
2346  mActiveItemCommand = 0;
2347  return;
2348  }
2349 
2351  {
2352  mActiveItemCommand = new QgsComposerItemCommand( item, commandText );
2353  }
2354  else
2355  {
2356  mActiveItemCommand = new QgsComposerMergeCommand( c, item, commandText );
2357  }
2358  mActiveItemCommand->savePreviousState();
2359 }
2360 
2362 {
2363  if ( mActiveItemCommand )
2364  {
2365  mActiveItemCommand->saveAfterState();
2366  if ( mActiveItemCommand->containsChange() ) //protect against empty commands
2367  {
2368  mUndoStack->push( mActiveItemCommand );
2369  QgsProject::instance()->dirty( true );
2370  }
2371  else
2372  {
2373  delete mActiveItemCommand;
2374  }
2375  mActiveItemCommand = 0;
2376  }
2377 }
2378 
2380 {
2381  delete mActiveItemCommand;
2382  mActiveItemCommand = 0;
2383 }
2384 
2386 {
2387  delete mActiveMultiFrameCommand;
2388 
2389  if ( !multiFrame )
2390  {
2391  mActiveMultiFrameCommand = 0;
2392  return;
2393  }
2394 
2396  {
2397  mActiveMultiFrameCommand = new QgsComposerMultiFrameCommand( multiFrame, text );
2398  }
2399  else
2400  {
2401  mActiveMultiFrameCommand = new QgsComposerMultiFrameMergeCommand( c, multiFrame, text );
2402  }
2403  mActiveMultiFrameCommand->savePreviousState();
2404 }
2405 
2407 {
2408  if ( mActiveMultiFrameCommand )
2409  {
2410  mActiveMultiFrameCommand->saveAfterState();
2411  if ( mActiveMultiFrameCommand->containsChange() )
2412  {
2413  mUndoStack->push( mActiveMultiFrameCommand );
2414  QgsProject::instance()->dirty( true );
2415  }
2416  else
2417  {
2418  delete mActiveMultiFrameCommand;
2419  }
2420  mActiveMultiFrameCommand = 0;
2421  }
2422 }
2423 
2425 {
2426  delete mActiveMultiFrameCommand;
2427  mActiveMultiFrameCommand = 0;
2428 }
2429 
2431 {
2432  mMultiFrames.insert( multiFrame );
2433 
2434  updateBounds();
2435 }
2436 
2438 {
2439  mMultiFrames.remove( multiFrame );
2440 
2441  updateBounds();
2442 }
2443 
2445 {
2446  addItem( arrow );
2447 
2448  updateBounds();
2449  connect( arrow, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2450 
2451  emit composerArrowAdded( arrow );
2452 }
2453 
2455 {
2456  addItem( label );
2457 
2458  updateBounds();
2459  connect( label, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2460 
2461  emit composerLabelAdded( label );
2462 }
2463 
2464 void QgsComposition::addComposerMap( QgsComposerMap* map, const bool setDefaultPreviewStyle )
2465 {
2466  addItem( map );
2467  if ( setDefaultPreviewStyle )
2468  {
2469  //set default preview mode to cache. Must be done here between adding composer map to scene and emiting signal
2471  }
2472 
2473  if ( map->previewMode() != QgsComposerMap::Rectangle )
2474  {
2475  map->cache();
2476  }
2477 
2478  updateBounds();
2479  connect( map, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2480 
2481  emit composerMapAdded( map );
2482 }
2483 
2485 {
2486  addItem( scaleBar );
2487 
2488  updateBounds();
2489  connect( scaleBar, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2490 
2491  emit composerScaleBarAdded( scaleBar );
2492 }
2493 
2495 {
2496  addItem( legend );
2497 
2498  updateBounds();
2499  connect( legend, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2500 
2501  emit composerLegendAdded( legend );
2502 }
2503 
2505 {
2506  addItem( picture );
2507 
2508  updateBounds();
2509  connect( picture, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2510 
2511  emit composerPictureAdded( picture );
2512 }
2513 
2515 {
2516  addItem( shape );
2517 
2518  updateBounds();
2519  connect( shape, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2520 
2521  emit composerShapeAdded( shape );
2522 }
2523 
2525 {
2526  addItem( table );
2527 
2528  updateBounds();
2529  connect( table, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2530 
2531  emit composerTableAdded( table );
2532 }
2533 
2535 {
2536  addItem( frame );
2537 
2538  updateBounds();
2539  connect( frame, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2540 
2541  emit composerHtmlFrameAdded( html, frame );
2542 }
2543 
2545 {
2546  addItem( frame );
2547 
2548  updateBounds();
2549  connect( frame, SIGNAL( sizeChanged() ), this, SLOT( updateBounds() ) );
2550 
2551  emit composerTableFrameAdded( table, frame );
2552 }
2553 
2554 void QgsComposition::removeComposerItem( QgsComposerItem* item, const bool createCommand, const bool removeGroupItems )
2555 {
2556  QgsComposerMap* map = dynamic_cast<QgsComposerMap *>( item );
2557 
2558  if ( !map || !map->isDrawing() ) //don't delete a composer map while it draws
2559  {
2560  mItemsModel->setItemRemoved( item );
2561  removeItem( item );
2562 
2563  QgsComposerItemGroup* itemGroup = dynamic_cast<QgsComposerItemGroup*>( item );
2564  if ( itemGroup && removeGroupItems )
2565  {
2566  //add add/remove item command for every item in the group
2567  QUndoCommand* parentCommand = new QUndoCommand( tr( "Remove item group" ) );
2568 
2569  QSet<QgsComposerItem*> groupedItems = itemGroup->items();
2570  QSet<QgsComposerItem*>::iterator it = groupedItems.begin();
2571  for ( ; it != groupedItems.end(); ++it )
2572  {
2573  QgsAddRemoveItemCommand* subcommand = new QgsAddRemoveItemCommand( QgsAddRemoveItemCommand::Removed, *it, this, "", parentCommand );
2574  connectAddRemoveCommandSignals( subcommand );
2575  emit itemRemoved( *it );
2576  }
2577 
2578  undoStack()->push( parentCommand );
2579  emit itemRemoved( itemGroup );
2580  delete itemGroup;
2581  }
2582  else
2583  {
2584  bool frameItem = ( item->type() == QgsComposerItem::ComposerFrame );
2585  QgsComposerMultiFrame* multiFrame = 0;
2586  if ( createCommand )
2587  {
2588  if ( frameItem ) //multiframe tracks item changes
2589  {
2590  multiFrame = static_cast<QgsComposerFrame*>( item )->multiFrame();
2591  item->beginItemCommand( tr( "Frame deleted" ) );
2592  emit itemRemoved( item );
2593  item->endItemCommand();
2594  }
2595  else
2596  {
2597  emit itemRemoved( item );
2598  pushAddRemoveCommand( item, tr( "Item deleted" ), QgsAddRemoveItemCommand::Removed );
2599  }
2600  }
2601  else
2602  {
2603  emit itemRemoved( item );
2604  }
2605 
2606  //check if there are frames left. If not, remove the multi frame
2607  if ( frameItem && multiFrame )
2608  {
2609  if ( multiFrame->frameCount() < 1 )
2610  {
2611  removeMultiFrame( multiFrame );
2612  if ( createCommand )
2613  {
2615  multiFrame, this, tr( "Multiframe removed" ) );
2616  undoStack()->push( command );
2617  }
2618  else
2619  {
2620  delete multiFrame;
2621  }
2622  }
2623  }
2624  }
2625  }
2626 
2627  updateBounds();
2628 }
2629 
2631 {
2632  QgsAddRemoveItemCommand* c = new QgsAddRemoveItemCommand( state, item, this, text );
2633  connectAddRemoveCommandSignals( c );
2634  undoStack()->push( c );
2635  QgsProject::instance()->dirty( true );
2636 }
2637 
2638 void QgsComposition::connectAddRemoveCommandSignals( QgsAddRemoveItemCommand* c )
2639 {
2640  if ( !c )
2641  {
2642  return;
2643  }
2644 
2645  QObject::connect( c, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SIGNAL( itemRemoved( QgsComposerItem* ) ) );
2646  QObject::connect( c, SIGNAL( itemAdded( QgsComposerItem* ) ), this, SLOT( sendItemAddedSignal( QgsComposerItem* ) ) );
2647 }
2648 
2650 {
2651  //cast and send proper signal
2652  item->setSelected( true );
2653  QgsComposerArrow* arrow = dynamic_cast<QgsComposerArrow*>( item );
2654  if ( arrow )
2655  {
2656  emit composerArrowAdded( arrow );
2657  emit selectedItemChanged( arrow );
2658  return;
2659  }
2660  QgsComposerLabel* label = dynamic_cast<QgsComposerLabel*>( item );
2661  if ( label )
2662  {
2663  emit composerLabelAdded( label );
2664  emit selectedItemChanged( label );
2665  return;
2666  }
2667  QgsComposerMap* map = dynamic_cast<QgsComposerMap*>( item );
2668  if ( map )
2669  {
2670  emit composerMapAdded( map );
2671  emit selectedItemChanged( map );
2672  return;
2673  }
2674  QgsComposerScaleBar* scalebar = dynamic_cast<QgsComposerScaleBar*>( item );
2675  if ( scalebar )
2676  {
2677  emit composerScaleBarAdded( scalebar );
2678  emit selectedItemChanged( scalebar );
2679  return;
2680  }
2681  QgsComposerLegend* legend = dynamic_cast<QgsComposerLegend*>( item );
2682  if ( legend )
2683  {
2684  emit composerLegendAdded( legend );
2685  emit selectedItemChanged( legend );
2686  return;
2687  }
2688  QgsComposerPicture* picture = dynamic_cast<QgsComposerPicture*>( item );
2689  if ( picture )
2690  {
2691  emit composerPictureAdded( picture );
2692  emit selectedItemChanged( picture );
2693  return;
2694  }
2695  QgsComposerShape* shape = dynamic_cast<QgsComposerShape*>( item );
2696  if ( shape )
2697  {
2698  emit composerShapeAdded( shape );
2699  emit selectedItemChanged( shape );
2700  return;
2701  }
2702  QgsComposerAttributeTable* table = dynamic_cast<QgsComposerAttributeTable*>( item );
2703  if ( table )
2704  {
2705  emit composerTableAdded( table );
2706  emit selectedItemChanged( table );
2707  return;
2708  }
2709  QgsComposerFrame* frame = dynamic_cast<QgsComposerFrame*>( item );
2710  if ( frame )
2711  {
2712  //emit composerFrameAdded( multiframe, frame, );
2713  QgsComposerMultiFrame* mf = frame->multiFrame();
2714  QgsComposerHtml* html = dynamic_cast<QgsComposerHtml*>( mf );
2715  if ( html )
2716  {
2717  emit composerHtmlFrameAdded( html, frame );
2718  }
2719  QgsComposerAttributeTableV2* table = dynamic_cast<QgsComposerAttributeTableV2*>( mf );
2720  if ( table )
2721  {
2722  emit composerTableFrameAdded( table, frame );
2723  }
2724  emit selectedItemChanged( frame );
2725  return;
2726  }
2727 }
2728 
2729 void QgsComposition::updatePaperItems()
2730 {
2731  QList< QgsPaperItem* >::iterator paperIt = mPages.begin();
2732  for ( ; paperIt != mPages.end(); ++paperIt )
2733  {
2734  ( *paperIt )->update();
2735  }
2736 }
2737 
2738 void QgsComposition::addPaperItem()
2739 {
2740  double paperHeight = this->paperHeight();
2741  double paperWidth = this->paperWidth();
2742  double currentY = paperHeight * mPages.size() + mPages.size() * mSpaceBetweenPages; //add 10mm visible space between pages
2743  QgsPaperItem* paperItem = new QgsPaperItem( 0, currentY, paperWidth, paperHeight, this ); //default size A4
2744  paperItem->setBrush( Qt::white );
2745  addItem( paperItem );
2746  paperItem->setZValue( 0 );
2747  mPages.push_back( paperItem );
2748 }
2749 
2750 void QgsComposition::removePaperItems()
2751 {
2752  qDeleteAll( mPages );
2753  mPages.clear();
2754 }
2755 
2756 void QgsComposition::deleteAndRemoveMultiFrames()
2757 {
2758  QSet<QgsComposerMultiFrame*>::iterator multiFrameIt = mMultiFrames.begin();
2759  for ( ; multiFrameIt != mMultiFrames.end(); ++multiFrameIt )
2760  {
2761  delete *multiFrameIt;
2762  }
2763  mMultiFrames.clear();
2764 }
2765 
2766 void QgsComposition::beginPrintAsPDF( QPrinter& printer, const QString& file )
2767 {
2768  printer.setOutputFileName( file );
2769  // setOutputFormat should come after setOutputFileName, which auto-sets format to QPrinter::PdfFormat.
2770  // [LS] This should be QPrinter::NativeFormat for Mac, otherwise fonts are not embed-able
2771  // and text is not searchable; however, there are several bugs with <= Qt 4.8.5, 5.1.1, 5.2.0:
2772  // https://bugreports.qt-project.org/browse/QTBUG-10094 - PDF font embedding fails
2773  // https://bugreports.qt-project.org/browse/QTBUG-33583 - PDF output converts text to outline
2774  // Also an issue with PDF paper size using QPrinter::NativeFormat on Mac (always outputs portrait letter-size)
2775  printer.setOutputFormat( QPrinter::PdfFormat );
2776 
2777  refreshPageSize();
2778  //must set orientation to portrait before setting paper size, otherwise size will be flipped
2779  //for landscape sized outputs (#11352)
2780  printer.setOrientation( QPrinter::Portrait );
2781  printer.setPaperSize( QSizeF( paperWidth(), paperHeight() ), QPrinter::Millimeter );
2782 
2783  // TODO: add option for this in Composer
2784  // May not work on Windows or non-X11 Linux. Works fine on Mac using QPrinter::NativeFormat
2785  //printer.setFontEmbeddingEnabled( true );
2786 
2788 }
2789 
2791 {
2792  QPrinter printer;
2793  beginPrintAsPDF( printer, file );
2794  return print( printer );
2795 }
2796 
2797 void QgsComposition::doPrint( QPrinter& printer, QPainter& p, bool startNewPage )
2798 {
2799  if ( ddPageSizeActive() )
2800  {
2801  //set the page size again so that data defined page size takes effect
2802  refreshPageSize();
2803  //must set orientation to portrait before setting paper size, otherwise size will be flipped
2804  //for landscape sized outputs (#11352)
2805  printer.setOrientation( QPrinter::Portrait );
2806  printer.setPaperSize( QSizeF( paperWidth(), paperHeight() ), QPrinter::Millimeter );
2807  }
2808 
2809  //QgsComposition starts page numbering at 0
2810  int fromPage = ( printer.fromPage() < 1 ) ? 0 : printer.fromPage() - 1;
2811  int toPage = ( printer.toPage() < 1 ) ? numPages() - 1 : printer.toPage() - 1;
2812 
2813  bool pageExported = false;
2814  if ( mPrintAsRaster )
2815  {
2816  for ( int i = fromPage; i <= toPage; ++i )
2817  {
2818  if ( !shouldExportPage( i + 1 ) )
2819  {
2820  continue;
2821  }
2822  if (( pageExported && i > fromPage ) || startNewPage )
2823  {
2824  printer.newPage();
2825  }
2826 
2827  QImage image = printPageAsRaster( i );
2828  if ( !image.isNull() )
2829  {
2830  QRectF targetArea( 0, 0, image.width(), image.height() );
2831  p.drawImage( targetArea, image, targetArea );
2832  }
2833  pageExported = true;
2834  }
2835  }
2836 
2837  if ( !mPrintAsRaster )
2838  {
2839  for ( int i = fromPage; i <= toPage; ++i )
2840  {
2841  if ( !shouldExportPage( i + 1 ) )
2842  {
2843  continue;
2844  }
2845  if (( pageExported && i > fromPage ) || startNewPage )
2846  {
2847  printer.newPage();
2848  }
2849  renderPage( &p, i );
2850  pageExported = true;
2851  }
2852  }
2853 }
2854 
2855 void QgsComposition::beginPrint( QPrinter &printer, const bool evaluateDDPageSize )
2856 {
2857  //set resolution based on composer setting
2858  printer.setFullPage( true );
2859  printer.setColorMode( QPrinter::Color );
2860 
2861  //set user-defined resolution
2862  printer.setResolution( printResolution() );
2863 
2864  if ( evaluateDDPageSize && ddPageSizeActive() )
2865  {
2866  //set data defined page size
2867  refreshPageSize();
2868  //must set orientation to portrait before setting paper size, otherwise size will be flipped
2869  //for landscape sized outputs (#11352)
2870  printer.setOrientation( QPrinter::Portrait );
2871  printer.setPaperSize( QSizeF( paperWidth(), paperHeight() ), QPrinter::Millimeter );
2872  }
2873 }
2874 
2875 bool QgsComposition::print( QPrinter &printer, const bool evaluateDDPageSize )
2876 {
2877  beginPrint( printer, evaluateDDPageSize );
2878  QPainter p;
2879  bool ready = p.begin( &printer );
2880  if ( !ready )
2881  {
2882  //error beginning print
2883  return false;
2884  }
2885  doPrint( printer, p );
2886  p.end();
2887  return true;
2888 }
2889 
2890 QImage QgsComposition::printPageAsRaster( int page, const QSize& imageSize, int dpi )
2891 {
2892  int resolution = mPrintResolution;
2893  if ( imageSize.isValid() )
2894  {
2895  //output size in pixels specified, calculate resolution using average of
2896  //derived x/y dpi
2897  resolution = ( imageSize.width() / mPageWidth
2898  + imageSize.height() / mPageHeight ) / 2.0 * 25.4;
2899  }
2900  else if ( dpi > 0 )
2901  {
2902  //dpi overridden by function parameters
2903  resolution = dpi;
2904  }
2905 
2906  int width = imageSize.isValid() ? imageSize.width()
2907  : ( int )( resolution * mPageWidth / 25.4 );
2908  int height = imageSize.isValid() ? imageSize.height()
2909  : ( int )( resolution * mPageHeight / 25.4 );
2910 
2911  QImage image( QSize( width, height ), QImage::Format_ARGB32 );
2912  if ( !image.isNull() )
2913  {
2914  image.setDotsPerMeterX( resolution / 25.4 * 1000 );
2915  image.setDotsPerMeterY( resolution / 25.4 * 1000 );
2916  image.fill( 0 );
2917  QPainter imagePainter( &image );
2918  renderPage( &imagePainter, page );
2919  if ( !imagePainter.isActive() ) return QImage();
2920  }
2921  return image;
2922 }
2923 
2924 QImage QgsComposition::renderRectAsRaster( const QRectF& rect, const QSize& imageSize, int dpi )
2925 {
2926  int resolution = mPrintResolution;
2927  if ( imageSize.isValid() )
2928  {
2929  //output size in pixels specified, calculate resolution using average of
2930  //derived x/y dpi
2931  resolution = ( imageSize.width() / rect.width()
2932  + imageSize.height() / rect.height() ) / 2.0 * 25.4;
2933  }
2934  else if ( dpi > 0 )
2935  {
2936  //dpi overridden by function parameters
2937  resolution = dpi;
2938  }
2939 
2940  int width = imageSize.isValid() ? imageSize.width()
2941  : ( int )( resolution * rect.width() / 25.4 );
2942  int height = imageSize.isValid() ? imageSize.height()
2943  : ( int )( resolution * rect.height() / 25.4 );
2944 
2945  QImage image( QSize( width, height ), QImage::Format_ARGB32 );
2946  if ( !image.isNull() )
2947  {
2948  image.setDotsPerMeterX( resolution / 25.4 * 1000 );
2949  image.setDotsPerMeterY( resolution / 25.4 * 1000 );
2950  image.fill( Qt::transparent );
2951  QPainter imagePainter( &image );
2952  renderRect( &imagePainter, rect );
2953  if ( !imagePainter.isActive() ) return QImage();
2954  }
2955  return image;
2956 }
2957 
2959 {
2960  if ( mPages.size() <= page )
2961  {
2962  return;
2963  }
2964 
2965  QgsPaperItem* paperItem = mPages[page];
2966  if ( !paperItem )
2967  {
2968  return;
2969  }
2970 
2971  QRectF paperRect = QRectF( paperItem->pos().x(), paperItem->pos().y(), paperItem->rect().width(), paperItem->rect().height() );
2972  renderRect( p, paperRect );
2973 }
2974 
2976 {
2977  QPaintDevice* paintDevice = p->device();
2978  if ( !paintDevice )
2979  {
2980  return;
2981  }
2982 
2983  QgsComposition::PlotStyle savedPlotStyle = mPlotStyle;
2984  mPlotStyle = QgsComposition::Print;
2985 
2986  setSnapLinesVisible( false );
2987  //hide background before rendering
2988  setBackgroundBrush( Qt::NoBrush );
2989  render( p, QRectF( 0, 0, paintDevice->width(), paintDevice->height() ), rect );
2990  //show background after rendering
2991  setBackgroundBrush( QColor( 215, 215, 215 ) );
2992  setSnapLinesVisible( true );
2993 
2994  mPlotStyle = savedPlotStyle;
2995 }
2996 
2997 QString QgsComposition::encodeStringForXML( const QString& str )
2998 {
2999  QString modifiedStr( str );
3000  modifiedStr.replace( "&", "&amp;" );
3001  modifiedStr.replace( "\"", "&quot;" );
3002  modifiedStr.replace( "'", "&apos;" );
3003  modifiedStr.replace( "<", "&lt;" );
3004  modifiedStr.replace( ">", "&gt;" );
3005  return modifiedStr;
3006 }
3007 
3008 QGraphicsView *QgsComposition::graphicsView() const
3009 {
3010  //try to find current view attached to composition
3011  QList<QGraphicsView*> viewList = views();
3012  if ( viewList.size() > 0 )
3013  {
3014  return viewList.at( 0 );
3015  }
3016 
3017  //no view attached to composition
3018  return 0;
3019 }
3020 
3021 void QgsComposition::computeWorldFileParameters( double& a, double& b, double& c, double& d, double& e, double& f ) const
3022 {
3023  if ( !mWorldFileMap )
3024  {
3025  return;
3026  }
3027 
3028  int pageNumber = mWorldFileMap->page() - 1;
3029  double pageY = pageNumber * ( mPageHeight + mSpaceBetweenPages );
3030  QRectF pageRect( 0, pageY, mPageWidth, mPageHeight );
3031  computeWorldFileParameters( pageRect, a, b, c, d, e, f );
3032 }
3033 
3034 void QgsComposition::computeWorldFileParameters( const QRectF& exportRegion, double& a, double& b, double& c, double& d, double& e, double& f ) const
3035 {
3036  // World file parameters : affine transformation parameters from pixel coordinates to map coordinates
3037 
3038  if ( !mWorldFileMap )
3039  {
3040  return;
3041  }
3042 
3043  double destinationHeight = exportRegion.height();
3044  double destinationWidth = exportRegion.width();
3045 
3046  QRectF mapItemSceneRect = mWorldFileMap->mapRectToScene( mWorldFileMap->rect() );
3047  QgsRectangle mapExtent = *mWorldFileMap->currentMapExtent();
3048 
3049  double alpha = mWorldFileMap->mapRotation() / 180 * M_PI;
3050 
3051  double xRatio = mapExtent.width() / mapItemSceneRect.width();
3052  double yRatio = mapExtent.height() / mapItemSceneRect.height();
3053 
3054  double xCenter = mapExtent.center().x();
3055  double yCenter = mapExtent.center().y();
3056 
3057  // get the extent (in map units) for the region
3058  QPointF mapItemPos = mWorldFileMap->pos();
3059  //adjust item position so it is relative to export region
3060  mapItemPos.rx() -= exportRegion.left();
3061  mapItemPos.ry() -= exportRegion.top();
3062 
3063  double xmin = mapExtent.xMinimum() - mapItemPos.x() * xRatio;
3064  double ymax = mapExtent.yMaximum() + mapItemPos.y() * yRatio;
3065  QgsRectangle paperExtent( xmin, ymax - destinationHeight * yRatio, xmin + destinationWidth * xRatio, ymax );
3066 
3067  double X0 = paperExtent.xMinimum();
3068  double Y0 = paperExtent.yMinimum();
3069 
3070  int widthPx = ( int )( printResolution() * destinationWidth / 25.4 );
3071  int heightPx = ( int )( printResolution() * destinationHeight / 25.4 );
3072 
3073  double Ww = paperExtent.width() / widthPx;
3074  double Hh = paperExtent.height() / heightPx;
3075 
3076  // scaling matrix
3077  double s[6];
3078  s[0] = Ww;
3079  s[1] = 0;
3080  s[2] = X0;
3081  s[3] = 0;
3082  s[4] = -Hh;
3083  s[5] = Y0 + paperExtent.height();
3084 
3085  // rotation matrix
3086  double r[6];
3087  r[0] = cos( alpha );
3088  r[1] = -sin( alpha );
3089  r[2] = xCenter * ( 1 - cos( alpha ) ) + yCenter * sin( alpha );
3090  r[3] = sin( alpha );
3091  r[4] = cos( alpha );
3092  r[5] = - xCenter * sin( alpha ) + yCenter * ( 1 - cos( alpha ) );
3093 
3094  // result = rotation x scaling = rotation(scaling(X))
3095  a = r[0] * s[0] + r[1] * s[3];
3096  b = r[0] * s[1] + r[1] * s[4];
3097  c = r[0] * s[2] + r[1] * s[5] + r[2];
3098  d = r[3] * s[0] + r[4] * s[3];
3099  e = r[3] * s[1] + r[4] * s[4];
3100  f = r[3] * s[2] + r[4] * s[5] + r[5];
3101 }
3102 
3104 {
3105  mAtlasMode = mode;
3106 
3107  if ( mode == QgsComposition::AtlasOff )
3108  {
3109  mAtlasComposition.endRender();
3110  }
3111  else
3112  {
3113  bool atlasHasFeatures = mAtlasComposition.beginRender();
3114  if ( ! atlasHasFeatures )
3115  {
3116  mAtlasMode = QgsComposition::AtlasOff;
3117  mAtlasComposition.endRender();
3118  return false;
3119  }
3120  }
3121 
3122  update();
3123  return true;
3124 }
3125 
3126 bool QgsComposition::ddPageSizeActive() const
3127 {
3128  //check if any data defined page settings are active
3129  return dataDefinedActive( QgsComposerObject::PresetPaperSize, &mDataDefinedProperties ) ||
3130  dataDefinedActive( QgsComposerObject::PaperWidth, &mDataDefinedProperties ) ||
3131  dataDefinedActive( QgsComposerObject::PaperHeight, &mDataDefinedProperties ) ||
3132  dataDefinedActive( QgsComposerObject::PaperOrientation, &mDataDefinedProperties );
3133 }
3134 
3135 void QgsComposition::refreshPageSize( const QgsExpressionContext* context )
3136 {
3137  const QgsExpressionContext* evalContext = context;
3139  if ( !evalContext )
3140  {
3141  scopedContext.reset( createExpressionContext() );
3142  evalContext = scopedContext.data();
3143  }
3144 
3145  double pageWidth = mPageWidth;
3146  double pageHeight = mPageHeight;
3147 
3148  QVariant exprVal;
3149  //in order of precedence - first consider predefined page size
3150  if ( dataDefinedEvaluate( QgsComposerObject::PresetPaperSize, exprVal, *evalContext, &mDataDefinedProperties ) )
3151  {
3152  QString presetString = exprVal.toString().trimmed();
3153  QgsDebugMsg( QString( "exprVal Paper Preset size :%1" ).arg( presetString ) );
3154  double widthD = 0;
3155  double heightD = 0;
3156  if ( QgsComposerUtils::decodePresetPaperSize( presetString, widthD, heightD ) )
3157  {
3158  pageWidth = widthD;
3159  pageHeight = heightD;
3160  }
3161  }
3162 
3163  //which is overwritten by data defined width/height
3164  if ( dataDefinedEvaluate( QgsComposerObject::PaperWidth, exprVal, *evalContext, &mDataDefinedProperties ) )
3165  {
3166  bool ok;
3167  double widthD = exprVal.toDouble( &ok );
3168  QgsDebugMsg( QString( "exprVal Paper Width:%1" ).arg( widthD ) );
3169  if ( ok )
3170  {
3171  pageWidth = widthD;
3172  }
3173  }
3174  if ( dataDefinedEvaluate( QgsComposerObject::PaperHeight, exprVal, *evalContext, &mDataDefinedProperties ) )
3175  {
3176  bool ok;
3177  double heightD = exprVal.toDouble( &ok );
3178  QgsDebugMsg( QString( "exprVal Paper Height:%1" ).arg( heightD ) );
3179  if ( ok )
3180  {
3181  pageHeight = heightD;
3182  }
3183  }
3184 
3185  //which is finally overwritten by data defined orientation
3186  if ( dataDefinedEvaluate( QgsComposerObject::PaperOrientation, exprVal, *evalContext, &mDataDefinedProperties ) )
3187  {
3188  bool ok;
3189  QString orientationString = exprVal.toString().trimmed();
3190  QgsComposition::PaperOrientation orientation = QgsComposerUtils::decodePaperOrientation( orientationString, ok );
3191  QgsDebugMsg( QString( "exprVal Paper Orientation:%1" ).arg( orientationString ) );
3192  if ( ok )
3193  {
3194  double heightD, widthD;
3195  if ( orientation == QgsComposition::Portrait )
3196  {
3197  heightD = qMax( pageHeight, pageWidth );
3198  widthD = qMin( pageHeight, pageWidth );
3199  }
3200  else
3201  {
3202  heightD = qMin( pageHeight, pageWidth );
3203  widthD = qMax( pageHeight, pageWidth );
3204  }
3205  pageWidth = widthD;
3206  pageHeight = heightD;
3207  }
3208  }
3209 
3210  setPaperSize( pageWidth, pageHeight );
3211 }
3212 
3214 {
3215  if ( property == QgsComposerObject::AllProperties || property == QgsComposerObject::NoProperty )
3216  {
3217  //invalid property
3218  return 0;
3219  }
3220 
3221  //find matching QgsDataDefined for property
3223  if ( it != mDataDefinedProperties.constEnd() )
3224  {
3225  return it.value();
3226  }
3227 
3228  //not found
3229  return 0;
3230 }
3231 
3232 void QgsComposition::setDataDefinedProperty( const QgsComposerObject::DataDefinedProperty property, bool active, bool useExpression, const QString &expression, const QString &field )
3233 {
3234  if ( property == QgsComposerObject::AllProperties || property == QgsComposerObject::NoProperty )
3235  {
3236  //invalid property
3237  return;
3238  }
3239 
3240  bool defaultVals = ( !active && !useExpression && expression.isEmpty() && field.isEmpty() );
3241 
3242  if ( mDataDefinedProperties.contains( property ) )
3243  {
3245  if ( it != mDataDefinedProperties.constEnd() )
3246  {
3247  QgsDataDefined* dd = it.value();
3248  dd->setActive( active );
3249  dd->setExpressionString( expression );
3250  dd->setField( field );
3251  dd->setUseExpression( useExpression );
3252  }
3253  }
3254  else if ( !defaultVals )
3255  {
3256  QgsDataDefined* dd = new QgsDataDefined( active, useExpression, expression, field );
3257  mDataDefinedProperties.insert( property, dd );
3258  }
3259 }
3260 
3261 void QgsComposition::setCustomProperty( const QString& key, const QVariant& value )
3262 {
3263  mCustomProperties.setValue( key, value );
3264 }
3265 
3266 QVariant QgsComposition::customProperty( const QString& key, const QVariant& defaultValue ) const
3267 {
3268  return mCustomProperties.value( key, defaultValue );
3269 }
3270 
3272 {
3273  mCustomProperties.remove( key );
3274 }
3275 
3277 {
3278  return mCustomProperties.keys();
3279 }
3280 
3281 bool QgsComposition::dataDefinedEvaluate( QgsComposerObject::DataDefinedProperty property, QVariant &expressionValue,
3282  const QgsExpressionContext& context,
3284 {
3285  if ( property == QgsComposerObject::NoProperty || property == QgsComposerObject::AllProperties )
3286  {
3287  //invalid property
3288  return false;
3289  }
3290 
3291  //null passed-around QVariant
3292  expressionValue.clear();
3293 
3294  //get fields and feature from atlas
3295  QgsFeature currentFeature;
3296  QgsFields layerFields;
3297  bool useFeature = false;
3298  if ( mAtlasComposition.enabled() )
3299  {
3300  QgsVectorLayer* atlasLayer = mAtlasComposition.coverageLayer();
3301  if ( atlasLayer )
3302  {
3303  layerFields = atlasLayer->fields();
3304  }
3305  if ( mAtlasMode != QgsComposition::AtlasOff )
3306  {
3307  useFeature = true;
3308  currentFeature = mAtlasComposition.feature();
3309  }
3310  }
3311 
3312  //evaluate data defined property using current atlas context
3313  QVariant result = dataDefinedValue( property, useFeature ? &currentFeature : 0, layerFields, context, dataDefinedProperties );
3314 
3315  if ( result.isValid() )
3316  {
3317  expressionValue = result;
3318  return true;
3319  }
3320 
3321  return false;
3322 }
3323 
3324 bool QgsComposition::dataDefinedActive( const QgsComposerObject::DataDefinedProperty property, const QMap<QgsComposerObject::DataDefinedProperty, QgsDataDefined *> *dataDefinedProperties ) const
3325 {
3326  if ( property == QgsComposerObject::AllProperties || property == QgsComposerObject::NoProperty )
3327  {
3328  //invalid property
3329  return false;
3330  }
3331  if ( !dataDefinedProperties->contains( property ) )
3332  {
3333  //missing property
3334  return false;
3335  }
3336 
3337  QgsDataDefined* dd = 0;
3339  if ( it != dataDefinedProperties->constEnd() )
3340  {
3341  dd = it.value();
3342  }
3343 
3344  if ( !dd )
3345  {
3346  return false;
3347  }
3348 
3349  //found the data defined property, return whether it is active
3350  return dd->isActive();
3351 }
3352 
3353 QVariant QgsComposition::dataDefinedValue( QgsComposerObject::DataDefinedProperty property, const QgsFeature *feature, const QgsFields& fields, const QgsExpressionContext& context, QMap<QgsComposerObject::DataDefinedProperty, QgsDataDefined *> *dataDefinedProperties ) const
3354 {
3355  if ( property == QgsComposerObject::AllProperties || property == QgsComposerObject::NoProperty )
3356  {
3357  //invalid property
3358  return QVariant();
3359  }
3360  if ( !dataDefinedProperties->contains( property ) )
3361  {
3362  //missing property
3363  return QVariant();
3364  }
3365 
3366  QgsDataDefined* dd = 0;
3368  if ( it != dataDefinedProperties->constEnd() )
3369  {
3370  dd = it.value();
3371  }
3372 
3373  if ( !dd )
3374  {
3375  return QVariant();
3376  }
3377 
3378  if ( !dd->isActive() )
3379  {
3380  return QVariant();
3381  }
3382 
3383  QVariant result = QVariant();
3384  bool useExpression = dd->useExpression();
3385  QString field = dd->field();
3386 
3387  if ( !dd->expressionIsPrepared() )
3388  {
3389  prepareDataDefinedExpression( dd, dataDefinedProperties, context );
3390  }
3391 
3392  if ( useExpression && dd->expressionIsPrepared() )
3393  {
3394  QgsExpression* expr = dd->expression();
3395 
3396  result = expr->evaluate( &context );
3397  if ( expr->hasEvalError() )
3398  {
3399  QgsDebugMsgLevel( QString( "Evaluate error:" ) + expr->evalErrorString(), 4 );
3400  return QVariant();
3401  }
3402  }
3403  else if ( !useExpression && !field.isEmpty() )
3404  {
3405  if ( !feature )
3406  {
3407  return QVariant();
3408  }
3409  // use direct attribute access instead of evaluating "field" expression (much faster)
3410  int indx = fields.indexFromName( field );
3411  if ( indx != -1 )
3412  {
3413  result = feature->attribute( indx );
3414  }
3415  }
3416  return result;
3417 }
3418 
3419 void QgsComposition::prepareDataDefinedExpression( QgsDataDefined *dd, QMap<QgsComposerObject::DataDefinedProperty, QgsDataDefined *> *dataDefinedProperties,
3420  const QgsExpressionContext& context ) const
3421 {
3422  //if specific QgsDataDefined passed, prepare it
3423  //otherwise prepare all QgsDataDefineds
3424  if ( dd )
3425  {
3426  dd->prepareExpression( context );
3427  }
3428  else
3429  {
3431  for ( ; it != dataDefinedProperties->constEnd(); ++it )
3432  {
3433  it.value()->prepareExpression( context );
3434  }
3435  }
3436 }
3437 
3439 {
3440  QgsExpressionContext* context = new QgsExpressionContext();
3444  if ( mAtlasComposition.enabled() )
3445  {
3446  context->appendScope( QgsExpressionContextUtils::atlasScope( &mAtlasComposition ) );
3447  }
3448  return context;
3449 }
3450 
3451 void QgsComposition::prepareAllDataDefinedExpressions()
3452 {
3454  prepareDataDefinedExpression( 0, &mDataDefinedProperties, *context.data() );
3455 }
3456 
3457 void QgsComposition::relativeResizeRect( QRectF& rectToResize, const QRectF& boundsBefore, const QRectF& boundsAfter )
3458 {
3459  QgsComposerUtils::relativeResizeRect( rectToResize, boundsBefore, boundsAfter );
3460 }
3461 
3462 double QgsComposition::relativePosition( double position, double beforeMin, double beforeMax, double afterMin, double afterMax )
3463 {
3464  return QgsComposerUtils::relativePosition( position, beforeMin, beforeMax, afterMin, afterMax );
3465 }
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:92
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.
Item representing the paper.
Definition: qgspaperitem.h:40
bool hasEvalError() const
Returns true if an error occurred when evaluating last input.
void clear()
A scale bar item that can be added to a map composition.
QUndoStack * undoStack()
Returns pointer to undo/redo command storage.
QDomNodeList elementsByTagName(const QString &tagname) const
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)
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from Dom document.
A rectangle specified with double values.
Definition: qgsrectangle.h:35
double paperWidth() const
Width of paper item.
bool isValid() const
void setDotsPerMeterX(int x)
void setDotsPerMeterY(int y)
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.
void setAllUnselected()
Clears any selected items in the composition.
QgsComposerItem * getComposerItemAbove(QgsComposerItem *item) const
Finds the next composer item above an item.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from Dom document.
int width() const
A container class for data source field mapping or expression.
bool end()
bool contains(const Key &key) const
Q_DECL_DEPRECATED QVariant evaluate(const QgsFeature *f)
Evaluate the feature and return the result.
An item that draws an arrow between to points.
QLineF line() const
QgsComposerMapOverviewStack * overviews()
Returns the map item's overview stack, which is used to control how overviews are drawn over the map'...
void render(QPainter *painter, const QRectF &target, const QRectF &source, Qt::AspectRatioMode aspectRatioMode)
void setResolution(int dpi)
QDomNode appendChild(const QDomNode &newChild)
void addItemToZList(QgsComposerItem *item)
Adds item to z list.
void readXml(const QDomNode &parentNode, const QString &keyStartsWith=QString())
Read store contents from XML.
void composerArrowAdded(QgsComposerArrow *arrow)
Is emitted when new composer arrow has been added to the view.
void setBoundingBoxesVisible(const bool boundsVisible)
Sets whether selection bounding boxes should be shown in the composition.
void push_back(const T &value)
QList< QGraphicsItem * > selectedItems() const
void setPageStyleSymbol(QgsFillSymbolV2 *symbol)
Note: added in version 2.1.
static QgsExpressionContextScope * atlasScope(const QgsAtlasComposition *atlas)
Creates a new scope which contains variables and functions relating to a QgsAtlasComposition.
void assignFreeId()
Sets mId to a number not yet used in the composition.
void setOutputFileName(const QString &fileName)
QString field() const
Get the field which this QgsDataDefined represents.
QString attribute(const QString &name, const QString &defValue) const
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.
void setResizeToContentsMargins(double marginTop, double marginRight, double marginBottom, double marginLeft)
Sets the resize to contents margins.
double yMaximum() const
Get the y maximum value (top side of rectangle)
Definition: qgsrectangle.h:196
#define QgsDebugMsg(str)
Definition: qgslogger.h:33
QgsFields fields() const
Returns the list of fields of this layer.
QList< QGraphicsItem * > items() const
void alignSelectedItemsTop()
void clear()
void rebuildZList()
Rebuilds the z-order list, based on the current stacking of items in the composition.
QString toString(int indent) const
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...
void removeItems() override
Removes the items but does not delete them.
bool isElement() const
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...
const_iterator constBegin() const
const T & at(int i) const
QgsComposerItemGroup * groupItems(QList< QgsComposerItem * > items)
Creates a new group from a list of composer items and adds it to the composition. ...
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 setBackgroundBrush(const QBrush &brush)
void setSelectedItem(QgsComposerItem *item)
Clears any selected items and sets an item as the current selection.
void setPagesVisible(bool visible)
Sets whether the page items should be visible in the composition.
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.
static QDomElement saveSymbol(const QString &symbolName, QgsSymbolV2 *symbol, QDomDocument &doc)
bool enabled() const
Returns whether the atlas generation is enabled.
void setSceneRect(const QRectF &rect)
QPointF snapPointToGrid(const QPointF &scenePoint) const
Snaps a scene coordinate point to grid.
QgsExpression * expression()
void updateBounds()
Updates the scene bounds of the composition.
Container of fields for a vector layer.
Definition: qgsfield.h:177
A container for grouping several QgsComposerItems.
void resizeToContentsMargins(double &marginTop, double &marginRight, double &marginBottom, double &marginLeft) const
Returns the resize to contents margins.
void paperSizeChanged()
void sendItemAddedSignal(QgsComposerItem *item)
Casts object to the proper subclass type and calls corresponding itemAdded signal.
qreal top() const
QgsFeature feature() const
Returns the current atlas feature.
virtual void setSelected(bool s)
Set selected, selected item should be highlighted.
void savePreviousState()
Saves current item state as previous state.
const QgsComposerItem * getComposerItemByUuid(const QString &theUuid) const
Returns a composer item given its unique identifier.
A composer command that merges together with other commands having the same context (=id)...
QDomElement documentElement() const
bool moveItemToBottom(QgsComposerItem *item)
void setCreateUndoCommands(bool enabled)
Sets whether undo commands should be created for interactions with the multiframe.
DataDefinedProperty
Data defined properties for different item types.
bool isNull() const
QVariant customProperty(const QString &key, const QVariant &defaultValue=QVariant()) const
Read a custom property from the composition.
const_iterator insert(const T &value)
The feature class encapsulates a single feature including its id, geometry and a list of field/values...
Definition: qgsfeature.h:176
void beginPrintAsPDF(QPrinter &printer, const QString &file)
Prepare the printer for printing in a PDF.
A non GUI class for rendering a map layer set onto a QPainter.
qreal height() const
QRectF mapRectToScene(const QRectF &rect) const
void composerScaleBarAdded(QgsComposerScaleBar *scalebar)
Is emitted when new composer scale bar has been added.
void moveSelectedItemsToBottom()
void clear()
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 toDouble(bool *ok) const
double spaceBetweenPages() const
Returns the vertical space between pages in a composer view.
void doPrint(QPrinter &printer, QPainter &painter, bool startNewPage=false)
Print on a preconfigured printer.
void setPaperSize(double width, double height, bool keepRelativeItemPosition=true)
Changes size of paper item.
void setStatusMessage(const QString &message)
Sets the status bar message for the composer window.
QString tr(const char *sourceText, const char *disambiguation, int n)
void remove(const QString &key)
Remove a key (entry) from the store.
void composerMapAdded(QgsComposerMap *map)
Is emitted when new composer map has been added to the view.
int numPages() const
Returns the number of pages in the composition.
qreal left() const
void adjust(qreal dx1, qreal dy1, qreal dx2, qreal dy2)
bool qgsDoubleNear(double a, double b, double epsilon=4 *DBL_EPSILON)
Definition: qgis.h:268
virtual bool readXML(const QDomElement &itemElem, const QDomDocument &doc, bool ignoreFrames=false) override
Reads the properties specific to an attribute table from xml.
void update(const QRectF &rect)
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()
bool shouldExportPage(const int page) const
Returns whether a specified page number should be included in exports of the composition.
double x() const
Get the x value of the point.
Definition: qgspoint.h:126
qreal dx() const
A table that displays attributes from a vector layer.
void composerItemsOnPage(QList< T * > &itemList, const int pageNumber) const
Return composer items of a specific type on a specified page.
void endRender()
Ends the rendering.
int size() const
QRectF pageItemBounds(int pageNumber, bool visibleOnly=false) const
Returns the bounding box of the items contained on a specified page.
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()
void reset(T *other)
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 setCustomProperty(const QString &key, const QVariant &value)
Set a custom property for the composition.
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.
int width() const
double ANALYSIS_EXPORT max(double x, double y)
Returns the maximum of two doubles or the first argument if both are equal.
QDomElement toElement() const
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)
QVariant value(const QString &key, const QVariant &defaultValue=QVariant()) const
Return value for the given key. If the key is not stored, default value will be used.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Reads the properties specific to an attribute table from xml.
qreal bottom() const
void setUseExpression(bool use)
Controls if the field or the expression part is active.
QgsComposerItem * getComposerItemBelow(QgsComposerItem *item) const
QTransform transform() const
QString uuid() const
Get item identification name.
qreal zValue() const
qreal y1() const
qreal y2() const
QPointF pos() const
void setNumPages(const int pages)
Sets the number of pages for the composition.
int count() const
qreal x1() const
qreal x2() const
QString number(int n, int base)
void refreshItemsTriggered()
Is emitted when item in the composition must be refreshed.
qreal x() const
qreal y() const
QPointF p1() const
bool beginRender()
Begins the rendering.
void setValue(const QString &key, const QVariant &value)
Add an entry to the store. If the entry with the keys exists already, it will be overwritten.
static QgsExpressionContextScope * globalScope()
Creates a new scope which contains variables and functions relating to the global QGIS context...
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.
int toInt(bool *ok) const
double yMinimum() const
Get the y minimum value (bottom side of rectangle)
Definition: qgsrectangle.h:201
void removeItem(QGraphicsItem *item)
void cancelCommand()
Deletes current command.
void fill(uint pixelValue)
PlotStyle
Plot type.
void setSnapGridOffsetX(const double offset)
QImage printPageAsRaster(int page, const QSize &imageSize=QSize(), int dpi=0)
Renders a composer page to an image.
#define QgsDebugMsgLevel(str, level)
Definition: qgslogger.h:34
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
GridStyle
Style to draw the snapping grid.
void updatePagePos(double newPageWidth, double newPageHeight)
Moves the item so that it retains its relative position on the page when the paper size changes...
int width() const
void setAttribute(const QString &name, const QString &value)
void setField(const QString &field)
Set the field name which this QgsDataDefined represents.
void clear()
Clears all items from z-order list and resets the model.
QList< QGraphicsView * > views() const
void removeSnapLine(QGraphicsLineItem *line)
Remove custom snap line (and delete the object)
qreal m11() const
void addItem(QgsComposerItem *item) override
Adds an item to the group.
int toInt(bool *ok, int base) const
void alignSelectedItemsRight()
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
QDomNodeList elementsByTagName(const QString &tagname) const
QStringList keys() const
Return list of stored keys.
Abstract base class for composer items with the ability to distribute the content to several frames (...
bool isEmpty() const
void resizePageToContents(double marginTop=0.0, double marginRight=0.0, double marginBottom=0.0, double marginLeft=0.0)
Resizes the composition page to fit the current contents of the composition.
int removeAll(const T &value)
QString trimmed() const
const_iterator constEnd() const
void setLine(const QLineF &line)
void addComposerTableFrame(QgsComposerAttributeTableV2 *table, QgsComposerFrame *frame)
Adds composer tablev2 frame and advises composer to create a widget for it (through signal) ...
#define M_PI
QPaintDevice * device() const
QList< QgsComposerItem * > ungroupItems(QgsComposerItemGroup *group)
Ungroups items by removing them from an item group and removing the group from the composition...
void cancelMultiFrameCommand()
Deletes current multi frame command.
void setWidthF(qreal width)
void removeComposerItem(QgsComposerItem *item, const bool createCommand=true, const bool removeGroupItems=true)
Remove item from the graphics scene.
QPointF center() const
QRectF compositionBounds(bool ignorePages=false, double margin=0.0) const
Calculates the bounds of all non-gui items in the composition.
const_iterator constEnd() const
void removeCustomProperty(const QString &key)
Remove a custom property from the composition.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from Dom document.
QRectF united(const QRectF &rectangle) const
bool loadFromTemplate(const QDomDocument &doc, QMap< QString, QString > *substitutionMap=0, bool addUndoCommands=false, const bool clearComposition=true)
Load a template document.
void setPaperSize(PaperSize newPaperSize)
void moveSelectedItemsToTop()
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from Dom document.
int frameCount() const
Returns the number of frames associated with this multiframe.
void setColor(const QColor &color)
QStringList customProperties() const
Return list of keys stored in custom properties for composition.
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)
bool pageIsEmpty(const int page) const
Returns whether a page is empty, ie, it contains no items except for the background paper item...
virtual QPaintEngine * paintEngine() const
void setPen(const QPen &pen)
const QgsComposerItem * getComposerItemById(const QString &theId) const
Returns a composer item given its text identifier.
void removeMultiFrame(QgsComposerMultiFrame *multiFrame)
Removes multi frame (but does not delete it)
Object representing map window.
Frame item for a composer multiframe item.
bool readXML(const QDomElement &compositionElem, const QDomDocument &doc)
Reads settings from xml file.
bool useExpression() const
Returns if the field or the expression part is active.
int indexFromName(const QString &name) const
Look up field's index from name. Returns -1 on error.
Definition: qgsfield.cpp:364
bool isActive() const
T * data() const
virtual QgsSymbolV2 * clone() const override
iterator end()
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from Dom document.
QgsRectangle * currentMapExtent()
Returns a pointer to the current map extent, which is either the original user specified extent or th...
QgsExpressionContext * createExpressionContext() const
Creates an expression context relating to the compositions's current state.
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.
qreal right() const
void setUpdatesEnabled(bool enabled)
Sets whether updates to the composer map are enabled.
iterator begin()
void clear()
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 setFullPage(bool fp)
PreviewMode previewMode() const
void setLine(qreal x1, qreal y1, qreal x2, qreal y2)
void nPagesChanged()
void removeItem(QgsComposerItem *item)
Removes an item from the z-order list.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from Dom document.
void setTopLeft(const QPointF &position)
void updateSettings()
Refreshes the composition when composer related options change.
void saveAfterState()
Saves current item state as after state.
const_iterator constBegin() const
static bool decodePresetPaperSize(const QString &presetString, double &width, double &height)
Decodes a string representing a preset page size.
bool setAtlasMode(const QgsComposition::AtlasMode mode)
Sets the current atlas mode of the composition.
AtlasMode
Composition atlas modes.
bool isNull() const
bool newPage()
void setPositionLock(const bool lock)
Locks / unlocks the item position for mouse drags.
void setOrientation(Orientation orientation)
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.
const Key key(const T &value) const
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.
bool isValid() const
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.
QString & replace(int position, int n, QChar after)
void setGridStyle(const GridStyle s)
A composer command class for adding / removing composer items.
void selectNextByZOrder(const ZValueDirection direction)
void statusMsgChanged(QString message)
Is emitted when the composition has an updated status bar message for the composer window...
QVariant value(const QString &key, const QVariant &defaultValue) const
bool isVisible() const
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.
void drawImage(const QRectF &target, const QImage &image, const QRectF &source, QFlags< Qt::ImageConversionFlag > flags)
qreal width() const
QVariant attribute(const QString &name) const
Lookup attribute value from attribute name.
Definition: qgsfeature.cpp:238
QgsComposerItem * getComposerItemBelow(QgsComposerItem *item) const
Finds the next composer item below an item.
bool remove(const T &value)
Undo command to undo/redo all composer item related changes.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from Dom document.
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)
void writeXml(QDomNode &parentNode, QDomDocument &doc) const
Write store contents to XML.
virtual void endItemCommand()
void readXMLMapSettings(const QDomElement &elem, const QDomDocument &doc)
Reads old (pre 2.2) map related atlas settings from xml.
Q_DECL_DEPRECATED bool prepareExpression(QgsVectorLayer *layer)
Prepares the expression using a vector layer.
bool expressionIsPrepared() const
Returns whether the data defined object's expression is prepared.
void addComposerHtmlFrame(QgsComposerHtml *html, QgsComposerFrame *frame)
Adds composer html frame and advises composer to create a widget for it (through signal) ...
iterator end()
void appendScope(QgsExpressionContextScope *scope)
Appends a scope to the end of the context.
QList< QgsComposerMapOverview * > asList() const
Returns a list of QgsComposerMapOverviews contained by the stack.
static QgsProject * instance()
access to canonical QgsProject instance
Definition: qgsproject.cpp:353
QDomElement firstChildElement(const QString &tagName) const
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) ...
T & last()
void alignSelectedItemsBottom()
static void fixEngineFlags(QPaintEngine *engine)
void update(qreal x, qreal y, qreal w, qreal h)
void renderRect(QPainter *p, const QRectF &rect)
Renders a portion of the composition to a paint device.
void alignSelectedItemsLeft()
int height() const
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.
qreal & rx()
qreal & ry()
void removeLast()
double paperHeight() const
Height of paper item.
static double pointsToMM(const double pointSize)
Returns the size in mm corresponding to a font point size.
int page() const
Gets the page the item is currently on.
void selectedItemChanged(QgsComposerItem *selected)
Is emitted when selected item changed.
void renderPage(QPainter *p, int page)
Renders a full page to a paint device.
void setVisible(bool visible)
double y() const
Get the y value of the point.
Definition: qgspoint.h:134
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.
bool isValid() const
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.
qreal height() const
int height() const
void addComposerPicture(QgsComposerPicture *picture)
Adds picture to the graphics scene and advices composer to create a widget for it (through signal) ...
QgsAtlasComposition & atlasComposition()
double toDouble(bool *ok) const
void composerHtmlFrameAdded(QgsComposerHtml *html, QgsComposerFrame *frame)
Is emitted when a new composer html has been added to the view.
iterator insert(const Key &key, const T &value)
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...
void removeAttribute(const QString &name)
Handles drawing of selection outlines and mouse handles.
void composerTableFrameAdded(QgsComposerAttributeTableV2 *table, QgsComposerFrame *frame)
Is emitted when a new composer table frame has been added to the view.
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...
QgsVectorLayer * coverageLayer() const
Returns the coverage layer used for the atlas features.
void setItemRemoved(QgsComposerItem *item)
Marks an item as removed from the composition.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets state from DOM document.
static QgsExpressionContextScope * projectScope()
Creates a new scope which contains variables and functions relating to the current QGIS project...
void setBrush(const QBrush &brush)
friend class QgsComposerModel
int size() const
int height() const
bool readXML(const QDomElement &itemElem, const QDomDocument &doc, bool ignoreFrames=false) override
Reads multiframe state information from a DOM element.
const_iterator constEnd() const
Q_DECL_DEPRECATED double pointFontSize(int pixelSize) const
Does the inverse calculation and returns points for mm.
int fromPage() const
QGraphicsLineItem * addSnapLine()
Add a custom snap line (can be horizontal or vertical)
QDomElement createElement(const QString &tagName)
void clear()
void composerItems(QList< T * > &itemList)
Return composer items of a specific type.
const_iterator constBegin() const
void printResolutionChanged()
Is emitted when the compositions print resolution changes.
void setColorMode(ColorMode newColorMode)
void addItem(QGraphicsItem *item)
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:206
bool raiseItem(QgsComposerItem *item)
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QgsComposerMultiFrame * multiFrame() const
Returns the parent multiframe for the frame.
void setSnapToGridEnabled(const bool b)
bool reorderItemToTop(QgsComposerItem *item)
Moves an item to the top of the z-order list.
void setOutputFormat(OutputFormat format)
Represents a vector layer which manages a vector based data sets.
bool begin(QPaintDevice *device)
void setBottomRight(const QPointF &position)
void move(double dx, double dy)
Moves item in canvas coordinates.
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:191
QString toString() const
void setZValue(qreal z)
void addMultiFrame(QgsComposerMultiFrame *multiFrame)
Adds multiframe.
void addItemAtTop(QgsComposerItem *item)
Adds an item to the top of the composition z stack.
QgsPoint center() const
Center point of the rectangle.
Definition: qgsrectangle.h:216
QString evalErrorString() const
Returns evaluation error.
void setExpressionString(const QString &expr)
Sets the expression for this QgsDataDefined.
bool isActive() const
iterator find(const Key &key)
iterator begin()
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 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.
Q_DECL_DEPRECATED QgsComposition(QgsMapRenderer *mapRenderer)
static QgsComposition::PaperOrientation decodePaperOrientation(const QString &orientationString, bool &ok)
Decodes a string representing a paper orientation.
void push(QUndoCommand *cmd)
double height() const
Height of the rectangle.
Definition: qgsrectangle.h:211
virtual int type() const override
Return correct graphics item type.
qreal width() const
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
QDomNode at(int index) const
QRectF rect() const
int toPage() const
void setSnapGridOffsetY(const double offset)
void refreshDataDefinedProperty(const QgsComposerObject::DataDefinedProperty property=QgsComposerObject::AllProperties, const QgsExpressionContext *context=0)
Refreshes a data defined property for the composition by reevaluating the property's value and redraw...
const T value(const Key &key) const
void beginCommand(QgsComposerItem *item, const QString &commandText, const QgsComposerMergeCommand::Context c=QgsComposerMergeCommand::Unknown)
Allocates new item command and saves initial state in it.
QList< QgsComposerItem * > selectedComposerItems(const bool includeLockedItems=true)
Returns list of selected composer items.
void dirty(bool b)
Definition: qgsproject.cpp:382
static QgsExpressionContextScope * compositionScope(const QgsComposition *composition)
Creates a new scope which contains variables and functions relating to a QgsComposition.
QList< QGraphicsLineItem * > * snapLines()
Returns pointer to snap lines collection.
QImage renderRectAsRaster(const QRectF &rect, const QSize &imageSize=QSize(), int dpi=0)
Renders a portion of the composition to an image.
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)