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