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