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