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