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