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