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