QGIS API Documentation  2.7.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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 
31 QgsComposerMultiFrame::QgsComposerMultiFrame():
32  QgsComposerObject( 0 ),
33  mResizeMode( UseExistingFrames ),
34  mIsRecalculatingSize( false )
35 {
36 }
37 
39 {
40  deleteFrames();
41 }
42 
43 void QgsComposerMultiFrame::render( QPainter *p, const QRectF &renderExtent )
44 {
45  //base implementation does nothing
46  Q_UNUSED( p );
47  Q_UNUSED( renderExtent );
48 }
49 
50 void QgsComposerMultiFrame::render( QPainter *painter, const QRectF &renderExtent, const int frameIndex )
51 {
52  Q_UNUSED( frameIndex );
53  //base implementation ignores frameIndex
55  render( painter, renderExtent );
57 }
58 
60 {
61  if ( mode != mResizeMode )
62  {
63  mResizeMode = mode;
65  emit changed();
66  }
67 }
68 
70 {
71  if ( mFrameItems.size() < 1 )
72  {
73  return;
74  }
75 
76  QSizeF size = totalSize();
77  double totalHeight = size.height();
78 
79  if ( totalHeight < 1 )
80  {
81  return;
82  }
83 
84  double currentY = 0;
85  double currentHeight = 0;
86  QgsComposerFrame* currentItem = 0;
87 
88  for ( int i = 0; i < mFrameItems.size(); ++i )
89  {
90  if ( mResizeMode != RepeatOnEveryPage && currentY >= totalHeight )
91  {
92  if ( mResizeMode == RepeatUntilFinished || mResizeMode == ExtendToNextPage ) //remove unneeded frames in extent mode
93  {
94  bool removingPages = true;
95  for ( int j = mFrameItems.size(); j > i; --j )
96  {
97  int numPagesBefore = mComposition->numPages();
98  removeFrame( j - 1, removingPages );
99  //if removing the frame didn't also remove the page, then stop removing pages
100  removingPages = removingPages && ( mComposition->numPages() < numPagesBefore );
101  }
102  return;
103  }
104  }
105 
106  currentItem = mFrameItems.value( i );
107  currentHeight = currentItem->rect().height();
109  {
110  currentItem->setContentSection( QRectF( 0, 0, currentItem->rect().width(), currentHeight ) );
111  }
112  else
113  {
114  currentHeight = findNearbyPageBreak( currentY + currentHeight ) - currentY;
115  currentItem->setContentSection( QRectF( 0, currentY, currentItem->rect().width(), currentHeight ) );
116  }
117  currentItem->update();
118  currentY += currentHeight;
119  }
120 
121  //at end of frames but there is still content left. Add other pages if ResizeMode ==
123  {
124  while (( mResizeMode == RepeatOnEveryPage ) || currentY < totalHeight )
125  {
126  //find out on which page the lower left point of the last frame is
127  int page = qFloor(( currentItem->pos().y() + currentItem->rect().height() ) / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() ) ) + 1;
128 
130  {
131  if ( page >= mComposition->numPages() )
132  {
133  break;
134  }
135  }
136  else
137  {
138  //add an extra page if required
139  if ( mComposition->numPages() < ( page + 1 ) )
140  {
141  mComposition->setNumPages( page + 1 );
142  }
143  }
144 
145  double frameHeight = 0;
147  {
148  frameHeight = currentItem->rect().height();
149  }
150  else //mResizeMode == ExtendToNextPage
151  {
152  frameHeight = ( currentY + mComposition->paperHeight() ) > totalHeight ? totalHeight - currentY : mComposition->paperHeight();
153  }
154 
155  double newFrameY = page * ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
157  {
158  newFrameY += currentItem->pos().y() - ( page - 1 ) * ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
159  }
160 
161  //create new frame
162  QgsComposerFrame* newFrame = createNewFrame( currentItem,
163  QPointF( currentItem->pos().x(), newFrameY ),
164  QSizeF( currentItem->rect().width(), frameHeight ) );
165 
167  {
168  newFrame->setContentSection( QRectF( 0, 0, newFrame->rect().width(), newFrame->rect().height() ) );
169  currentY += frameHeight;
170  }
171  else
172  {
173  double contentHeight = findNearbyPageBreak( currentY + newFrame->rect().height() ) - currentY;
174  newFrame->setContentSection( QRectF( 0, currentY, newFrame->rect().width(), contentHeight ) );
175  currentY += contentHeight;
176  }
177 
178  currentItem = newFrame;
179  }
180  }
181 }
182 
184 {
185  if ( mFrameItems.size() < 1 )
186  {
187  //no frames, nothing to do
188  return;
189  }
190 
191  QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
192  for ( ; frameIt != mFrameItems.end(); ++frameIt )
193  {
194  ( *frameIt )->setSceneRect( QRectF(( *frameIt )->scenePos().x(), ( *frameIt )->scenePos().y(),
195  ( *frameIt )->rect().width(), ( *frameIt )->rect().height() ) );
196  }
197 }
198 
200 {
201  if ( !currentFrame )
202  {
203  return 0;
204  }
205 
206  QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, pos.x(),
207  pos.y(), size.width(), size.height() );
208 
209  //copy some settings from the parent frame
210  newFrame->setBackgroundColor( currentFrame->backgroundColor() );
211  newFrame->setBackgroundEnabled( currentFrame->hasBackground() );
212  newFrame->setBlendMode( currentFrame->blendMode() );
213  newFrame->setFrameEnabled( currentFrame->hasFrame() );
214  newFrame->setFrameOutlineColor( currentFrame->frameOutlineColor() );
215  newFrame->setFrameJoinStyle( currentFrame->frameJoinStyle() );
216  newFrame->setFrameOutlineWidth( currentFrame->frameOutlineWidth() );
217  newFrame->setTransparency( currentFrame->transparency() );
218  newFrame->setHideBackgroundIfEmpty( currentFrame->hideBackgroundIfEmpty() );
219 
220  addFrame( newFrame, false );
221 
222  return newFrame;
223 }
224 
226 {
227  return tr( "<frame>" );
228 }
229 
231 {
232  QgsComposerFrame* frame = dynamic_cast<QgsComposerFrame*>( item );
233  if ( !frame )
234  {
235  return;
236  }
237  int index = mFrameItems.indexOf( frame );
238  if ( index == -1 )
239  {
240  return;
241  }
242 
243  mFrameItems.removeAt( index );
244  if ( mFrameItems.size() > 0 )
245  {
246  if ( resizeMode() != QgsComposerMultiFrame::RepeatOnEveryPage && !mIsRecalculatingSize )
247  {
248  //removing a frame forces the multi frame to UseExistingFrames resize mode
249  //otherwise the frame may not actually be removed, leading to confusing ui behaviour
251  emit changed();
253  }
254  }
255 }
256 
258 {
259  if ( mComposition->numPages() < 1 )
260  {
261  return;
262  }
263 
265  {
266  return;
267  }
268 
269  //remove items beginning on non-existing pages
270  for ( int i = mFrameItems.size() - 1; i >= 0; --i )
271  {
273  int page = frame->pos().y() / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
274  if ( page > ( mComposition->numPages() - 1 ) )
275  {
276  removeFrame( i );
277  }
278  }
279 
280  //page number of the last item
281  QgsComposerFrame* lastFrame = mFrameItems.last();
282  int lastItemPage = lastFrame->pos().y() / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
283 
284  for ( int i = lastItemPage + 1; i < mComposition->numPages(); ++i )
285  {
286  //copy last frame to current page
287  QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, lastFrame->pos().x(),
288  lastFrame->pos().y() + mComposition->paperHeight() + mComposition->spaceBetweenPages(),
289  lastFrame->rect().width(), lastFrame->rect().height() );
290  addFrame( newFrame, false );
291  lastFrame = newFrame;
292  }
293 
295  update();
296 }
297 
298 void QgsComposerMultiFrame::removeFrame( int i, const bool removeEmptyPages )
299 {
300  if ( i >= mFrameItems.count() )
301  {
302  return;
303  }
304 
305  QgsComposerFrame* frameItem = mFrameItems[i];
306  if ( mComposition )
307  {
308  mIsRecalculatingSize = true;
309  int pageNumber = frameItem->page();
310  //remove item, but don't create undo command
311  mComposition->removeComposerItem( frameItem, false );
312  //if frame was the only item on the page, remove the page
313  if ( removeEmptyPages && mComposition->pageIsEmpty( pageNumber ) )
314  {
316  }
317  mIsRecalculatingSize = false;
318  }
319  mFrameItems.removeAt( i );
320 }
321 
323 {
324  QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
325  for ( ; frameIt != mFrameItems.end(); ++frameIt )
326  {
327  ( *frameIt )->update();
328  }
329 }
330 
332 {
333  ResizeMode bkResizeMode = mResizeMode;
335  QObject::disconnect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( handleFrameRemoval( QgsComposerItem* ) ) );
336  QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
337  for ( ; frameIt != mFrameItems.end(); ++frameIt )
338  {
339  mComposition->removeComposerItem( *frameIt, false );
340  delete *frameIt;
341  }
342  QObject::connect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( handleFrameRemoval( QgsComposerItem* ) ) );
343  mFrameItems.clear();
344  mResizeMode = bkResizeMode;
345 }
346 
348 {
349  if ( i >= mFrameItems.size() )
350  {
351  return 0;
352  }
353  return mFrameItems.at( i );
354 }
355 
357 {
358  return mFrameItems.indexOf( frame );
359 }
360 
361 bool QgsComposerMultiFrame::_writeXML( QDomElement& elem, QDomDocument& doc, bool ignoreFrames ) const
362 {
363  elem.setAttribute( "resizeMode", mResizeMode );
364  if ( !ignoreFrames )
365  {
366  QList<QgsComposerFrame*>::const_iterator frameIt = mFrameItems.constBegin();
367  for ( ; frameIt != mFrameItems.constEnd(); ++frameIt )
368  {
369  ( *frameIt )->writeXML( elem, doc );
370  }
371  }
372  QgsComposerObject::writeXML( elem, doc );
373  return true;
374 }
375 
376 bool QgsComposerMultiFrame::_readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames )
377 {
378  QgsComposerObject::readXML( itemElem, doc );
379 
380  mResizeMode = ( ResizeMode )itemElem.attribute( "resizeMode", "0" ).toInt();
381  if ( !ignoreFrames )
382  {
383  QDomNodeList frameList = itemElem.elementsByTagName( "ComposerFrame" );
384  for ( int i = 0; i < frameList.size(); ++i )
385  {
386  QDomElement frameElem = frameList.at( i ).toElement();
387  QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, 0, 0, 0, 0 );
388  newFrame->readXML( frameElem, doc );
389  addFrame( newFrame, false );
390  }
391 
392  //TODO - think there should be a recalculateFrameSizes() call here
393  }
394  return true;
395 }
virtual 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.
void setHideBackgroundIfEmpty(const bool hideBackgroundIfEmpty)
Sets whether the background and frame border should be hidden if this frame is empty.
Qt::PenJoinStyle frameJoinStyle() const
Returns the join style used for drawing the item's frame.
virtual QString displayName() const
Get multiframe display name.
virtual double findNearbyPageBreak(double yPos)
Finds the optimal position to break a frame at.
A item that forms part of a map composition.
#define Q_NOWARN_DEPRECATED_PUSH
Definition: qgis.h:439
ResizeMode resizeMode() const
Returns the resize mode for the multiframe.
virtual void setFrameEnabled(const bool drawFrame)
Set whether this item has a frame drawn around it or not.
virtual QSizeF totalSize() const =0
Returns the total size of the multiframe's content.
QColor backgroundColor() const
Gets the background color for this item.
double spaceBetweenPages() const
Returns the vertical space between pages in a composer view.
void setBlendMode(const QPainter::CompositionMode blendMode)
Sets the item's composition blending mode.
int numPages() const
Returns the number of pages in the composition.
double frameOutlineWidth() const
Returns the frame's outline width.
bool _readXML(const QDomElement &itemElem, const QDomDocument &doc, bool ignoreFrames=false)
Restores state information about base multiframe object from a DOM element.
void setNumPages(const int pages)
Sets the number of pages for the composition.
void recalculateFrameRects()
Forces a recalculation of all the associated frame's scene rectangles.
QgsComposerMultiFrame(QgsComposition *c, bool createUndoCommands)
Construct a new multiframe item.
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
Adds a frame to the multiframe.
int transparency() const
Returns the item's transparency.
QgsComposerFrame * createNewFrame(QgsComposerFrame *currentFrame, QPointF pos, QSizeF size)
Creates a new frame and adds it to the multi frame and composition.
virtual void setFrameOutlineColor(const QColor &color)
Sets frame outline color.
QList< QgsComposerFrame * > mFrameItems
void removeFrame(int i, const bool removeEmptyPages=false)
Removes a frame from the multiframe.
bool _writeXML(QDomElement &elem, QDomDocument &doc, bool ignoreFrames=false) const
Stores state information about base multiframe object in DOM element.
void removeComposerItem(QgsComposerItem *item, const bool createCommand=true, const bool removeGroupItems=true)
Remove item from the graphics scene.
bool hideBackgroundIfEmpty() const
Returns whether the background and frame border should be hidden if this frame is empty...
void setBackgroundEnabled(const bool drawBackground)
Set whether this item has a Background drawn around it or not.
bool pageIsEmpty(const int page) const
Returns whether a page is empty, ie, it contains no items except for the background paper item...
Graphics scene for map printing.
void handlePageChange()
Adapts to changed number of composition pages if resize type is RepeatOnEveryPage.
Frame item for a composer multiframe item.
QColor frameOutlineColor() const
Returns the frame's outline color.
virtual void setFrameOutlineWidth(const double outlineWidth)
Sets frame outline width.
#define Q_NOWARN_DEPRECATED_POP
Definition: qgis.h:440
QgsComposition * mComposition
void deleteFrames()
Removes and deletes all child frames.
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)
Sets the resize mode for the multiframe, and recalculates frame sizes to match.
bool readXML(const QDomElement &itemElem, const QDomDocument &doc)
Sets item state from DOM element.
virtual Q_DECL_DEPRECATED void render(QPainter *p, const QRectF &renderExtent)
Renders a portion of the multiframe's content into a painter.
double paperHeight() const
Height of paper item.
bool hasBackground() const
Whether this item has a Background or not.
int page() const
Gets the page the item is currently on.
int frameIndex(QgsComposerFrame *frame) const
Returns the index of a frame within the multiframe.
QgsComposerFrame * frame(int i) const
Returns a child frame from the multiframe.
void update()
Forces a redraw of all child frames.
void setContentSection(const QRectF &section)
Sets the visible part of the multiframe's content which is visible within this frame (relative to the...
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.
void setTransparency(const int transparency)
Sets the item's transparency.
void changed()
Emitted when the properties of a multi frame have changed, and the GUI item widget must be updated...
#define tr(sourceText)