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