QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
qgscomposermultiframe.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscomposermultiframe.cpp
3  ------------------------------------------------------------
4  begin : July 2012
5  copyright : (C) 2012 by Marco Hugentobler
6  email : marco dot hugentobler at sourcepole dot ch
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgscomposermultiframe.h"
17 #include "qgscomposerframe.h"
18 #include "qgscomposition.h"
19 #include <QtCore>
20 
22  QgsComposerObject( c ),
23  mResizeMode( UseExistingFrames ),
24  mCreateUndoCommands( createUndoCommands ),
25  mIsRecalculatingSize( false )
26 {
27  mComposition->addMultiFrame( this );
28  connect( mComposition, SIGNAL( nPagesChanged() ), this, SLOT( handlePageChange() ) );
29 }
30 
32  QgsComposerObject( 0 ),
33  mResizeMode( UseExistingFrames ),
34  mIsRecalculatingSize( false )
35 {
36 }
37 
39 {
40  deleteFrames();
41 }
42 
44 {
45  if ( mode != mResizeMode )
46  {
47  mResizeMode = mode;
49  emit changed();
50  }
51 }
52 
54 {
55  if ( mFrameItems.size() < 1 )
56  {
57  return;
58  }
59 
60  QSizeF size = totalSize();
61  double totalHeight = size.height();
62 
63  if ( totalHeight < 1 )
64  {
65  return;
66  }
67 
68  double currentY = 0;
69  double currentHeight = 0;
70  QgsComposerFrame* currentItem = 0;
71 
72  for ( int i = 0; i < mFrameItems.size(); ++i )
73  {
74  if ( mResizeMode != RepeatOnEveryPage && currentY >= totalHeight )
75  {
76  if ( mResizeMode == RepeatUntilFinished || mResizeMode == ExtendToNextPage ) //remove unneeded frames in extent mode
77  {
78  for ( int j = mFrameItems.size(); j > i; --j )
79  {
80  removeFrame( j - 1 );
81  }
82  return;
83  }
84  }
85 
86  currentItem = mFrameItems.value( i );
87  currentHeight = currentItem->rect().height();
89  {
90  currentItem->setContentSection( QRectF( 0, 0, currentItem->rect().width(), currentHeight ) );
91  }
92  else
93  {
94  currentHeight = findNearbyPageBreak( currentY + currentHeight ) - currentY;
95  currentItem->setContentSection( QRectF( 0, currentY, currentItem->rect().width(), currentHeight ) );
96  }
97  currentItem->update();
98  currentY += currentHeight;
99  }
100 
101  //at end of frames but there is still content left. Add other pages if ResizeMode ==
103  {
104  while (( mResizeMode == RepeatOnEveryPage ) || currentY < totalHeight )
105  {
106  //find out on which page the lower left point of the last frame is
107  int page = qFloor(( currentItem->pos().y() + currentItem->rect().height() ) / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() ) ) + 1;
108 
110  {
111  if ( page >= mComposition->numPages() )
112  {
113  break;
114  }
115  }
116  else
117  {
118  //add an extra page if required
119  if ( mComposition->numPages() < ( page + 1 ) )
120  {
121  mComposition->setNumPages( page + 1 );
122  }
123  }
124 
125  double frameHeight = 0;
127  {
128  frameHeight = currentItem->rect().height();
129  }
130  else //mResizeMode == ExtendToNextPage
131  {
132  frameHeight = ( currentY + mComposition->paperHeight() ) > totalHeight ? totalHeight - currentY : mComposition->paperHeight();
133  }
134 
135  double newFrameY = page * ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
137  {
138  newFrameY += currentItem->pos().y() - ( page - 1 ) * ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
139  }
140 
141  //create new frame
142  QgsComposerFrame* newFrame = createNewFrame( currentItem,
143  QPointF( currentItem->pos().x(), newFrameY ),
144  QSizeF( currentItem->rect().width(), frameHeight ) );
145 
147  {
148  newFrame->setContentSection( QRectF( 0, 0, newFrame->rect().width(), newFrame->rect().height() ) );
149  currentY += frameHeight;
150  }
151  else
152  {
153  double contentHeight = findNearbyPageBreak( currentY + newFrame->rect().height() ) - currentY;
154  newFrame->setContentSection( QRectF( 0, currentY, newFrame->rect().width(), contentHeight ) );
155  currentY += contentHeight;
156  }
157 
158  currentItem = newFrame;
159  }
160  }
161 }
162 
164 {
165  if ( !currentFrame )
166  {
167  return 0;
168  }
169 
170  QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, pos.x(),
171  pos.y(), size.width(), size.height() );
172 
173  //copy some settings from the parent frame
174  newFrame->setBackgroundColor( currentFrame->backgroundColor() );
175  newFrame->setBackgroundEnabled( currentFrame->hasBackground() );
176  newFrame->setBlendMode( currentFrame->blendMode() );
177  newFrame->setFrameEnabled( currentFrame->hasFrame() );
178  newFrame->setFrameJoinStyle( currentFrame->frameJoinStyle() );
179  newFrame->setFrameOutlineWidth( currentFrame->frameOutlineWidth() );
180  newFrame->setOpacity( currentFrame->opacity() );
181 
182  addFrame( newFrame, false );
183 
184  return newFrame;
185 }
186 
188 {
189  QgsComposerFrame* frame = dynamic_cast<QgsComposerFrame*>( item );
190  if ( !frame )
191  {
192  return;
193  }
194  int index = mFrameItems.indexOf( frame );
195  if ( index == -1 )
196  {
197  return;
198  }
199  mFrameItems.removeAt( index );
200  if ( mFrameItems.size() > 0 )
201  {
203  {
204  //removing a frame forces the multi frame to UseExistingFrames resize mode
205  //otherwise the frame may not actually be removed, leading to confusing ui behaviour
207  emit changed();
208  }
210  }
211 }
212 
214 {
215  if ( mComposition->numPages() < 1 )
216  {
217  return;
218  }
219 
221  {
222  return;
223  }
224 
225  //remove items beginning on non-existing pages
226  for ( int i = mFrameItems.size() - 1; i >= 0; --i )
227  {
229  int page = frame->pos().y() / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
230  if ( page > ( mComposition->numPages() - 1 ) )
231  {
232  removeFrame( i );
233  }
234  }
235 
236  //page number of the last item
237  QgsComposerFrame* lastFrame = mFrameItems.last();
238  int lastItemPage = lastFrame->pos().y() / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
239 
240  for ( int i = lastItemPage + 1; i < mComposition->numPages(); ++i )
241  {
242  //copy last frame to current page
243  QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, lastFrame->pos().x(),
244  lastFrame->pos().y() + mComposition->paperHeight() + mComposition->spaceBetweenPages(),
245  lastFrame->rect().width(), lastFrame->rect().height() );
246  addFrame( newFrame, false );
247  lastFrame = newFrame;
248  }
249 
251  update();
252 }
253 
255 {
256  if ( i >= mFrameItems.count() )
257  {
258  return;
259  }
260 
261  QgsComposerFrame* frameItem = mFrameItems[i];
262  if ( mComposition )
263  {
264  mIsRecalculatingSize = true;
265  mComposition->removeComposerItem( frameItem );
266  mIsRecalculatingSize = false;
267  }
268  mFrameItems.removeAt( i );
269 }
270 
272 {
273  QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
274  for ( ; frameIt != mFrameItems.end(); ++frameIt )
275  {
276  ( *frameIt )->update();
277  }
278 }
279 
281 {
282  ResizeMode bkResizeMode = mResizeMode;
284  QObject::disconnect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( handleFrameRemoval( QgsComposerItem* ) ) );
285  QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
286  for ( ; frameIt != mFrameItems.end(); ++frameIt )
287  {
288  mComposition->removeComposerItem( *frameIt, false );
289  delete *frameIt;
290  }
291  QObject::connect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( handleFrameRemoval( QgsComposerItem* ) ) );
292  mFrameItems.clear();
293  mResizeMode = bkResizeMode;
294 }
295 
297 {
298  if ( i >= mFrameItems.size() )
299  {
300  return 0;
301  }
302  return mFrameItems.at( i );
303 }
304 
305 bool QgsComposerMultiFrame::_writeXML( QDomElement& elem, QDomDocument& doc, bool ignoreFrames ) const
306 {
307  elem.setAttribute( "resizeMode", mResizeMode );
308  if ( !ignoreFrames )
309  {
310  QList<QgsComposerFrame*>::const_iterator frameIt = mFrameItems.constBegin();
311  for ( ; frameIt != mFrameItems.constEnd(); ++frameIt )
312  {
313  ( *frameIt )->writeXML( elem, doc );
314  }
315  }
316  QgsComposerObject::writeXML( elem, doc );
317  return true;
318 }
319 
320 bool QgsComposerMultiFrame::_readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames )
321 {
322  QgsComposerObject::readXML( itemElem, doc );
323 
324  mResizeMode = ( ResizeMode )itemElem.attribute( "resizeMode", "0" ).toInt();
325  if ( !ignoreFrames )
326  {
327  QDomNodeList frameList = itemElem.elementsByTagName( "ComposerFrame" );
328  for ( int i = 0; i < frameList.size(); ++i )
329  {
330  QDomElement frameElem = frameList.at( i ).toElement();
331  QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, 0, 0, 0, 0 );
332  newFrame->readXML( frameElem, doc );
333  addFrame( newFrame );
334  }
335  }
336  return true;
337 }
void recalculateFrameSizes()
Recalculates the portion of the multiframe item which is shown in each of it's component frames...
static unsigned index
virtual bool writeXML(QDomElement &elem, QDomDocument &doc) const
Stores item state in DOM element.
A base class for objects which belong to a map composition.
Qt::PenJoinStyle frameJoinStyle() const
Returns the join style used for drawing the item's frame.
virtual double findNearbyPageBreak(double yPos)
Finds the optimal position to break a frame at.
A item that forms part of a map composition.
ResizeMode resizeMode() const
void setFrameEnabled(const bool drawFrame)
Set whether this item has a frame drawn around it or not.
virtual QSizeF totalSize() const =0
QColor backgroundColor() const
Gets the background color for this item.
double spaceBetweenPages() const
void setBlendMode(const QPainter::CompositionMode blendMode)
Sets the item's composition blending mode.
int numPages() const
Note: added in version 1.9.
double frameOutlineWidth() const
Returns the frame's outline width.
bool _readXML(const QDomElement &itemElem, const QDomDocument &doc, bool ignoreFrames=false)
void setNumPages(const int pages)
Note: added in version 1.9.
void setFrameJoinStyle(const Qt::PenJoinStyle style)
Sets join style used when drawing the item's frame.
virtual void addFrame(QgsComposerFrame *frame, bool recalcFrameSizes=true)=0
QgsComposerFrame * createNewFrame(QgsComposerFrame *currentFrame, QPointF pos, QSizeF size)
Creates a new frame and adds it to the multi frame and composition.
QList< QgsComposerFrame * > mFrameItems
bool _writeXML(QDomElement &elem, QDomDocument &doc, bool ignoreFrames=false) const
void setBackgroundEnabled(const bool drawBackground)
Set whether this item has a Background drawn around it or not.
Graphics scene for map printing.
void handlePageChange()
Adapts to changed number of pages if resize type is RepeatOnEveryPage.
Frame for html, table, text which can be divided onto several frames.
virtual void setFrameOutlineWidth(const double outlineWidth)
Sets frame outline width.
QgsComposition * mComposition
void deleteFrames()
Removes and deletes all frames from mComposition.
void setBackgroundColor(const QColor &backgroundColor)
Sets the background color for this item.
QPainter::CompositionMode blendMode() const
Returns the item's composition blending mode.
virtual bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
Sets item state from DOM element.
bool hasFrame() const
Whether this item has a frame or not.
void setResizeMode(ResizeMode mode)
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
Sets item state from DOM element.
double paperHeight() const
Returns height of paper item.
bool hasBackground() const
Whether this item has a Background or not.
QgsComposerFrame * frame(int i) const
void setContentSection(const QRectF &section)
Sets the part of this frame (relative to the total multiframe extent in mm)
double size
Definition: qgssvgcache.cpp:77
void addMultiFrame(QgsComposerMultiFrame *multiFrame)
Adds multiframe.
void handleFrameRemoval(QgsComposerItem *item)
Called before a frame is going to be removed (update frame list)
void removeComposerItem(QgsComposerItem *item, const bool createCommand=true)
Remove item from the graphics scene.