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