QGIS API Documentation  2.9.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  , mCreateUndoCommands( false )
35  , mIsRecalculatingSize( false )
36 {
37 }
38 
40 {
41  deleteFrames();
42 }
43 
44 void QgsComposerMultiFrame::render( QPainter *p, const QRectF &renderExtent )
45 {
46  //base implementation does nothing
47  Q_UNUSED( p );
48  Q_UNUSED( renderExtent );
49 }
50 
51 void QgsComposerMultiFrame::render( QPainter *painter, const QRectF &renderExtent, const int frameIndex )
52 {
53  Q_UNUSED( frameIndex );
54  //base implementation ignores frameIndex
56  render( painter, renderExtent );
58 }
59 
61 {
62  if ( mode != mResizeMode )
63  {
64  mResizeMode = mode;
66  emit changed();
67  }
68 }
69 
71 {
72  if ( mFrameItems.size() < 1 )
73  {
74  return;
75  }
76 
77  QSizeF size = totalSize();
78  double totalHeight = size.height();
79 
80  if ( totalHeight < 1 )
81  {
82  return;
83  }
84 
85  double currentY = 0;
86  double currentHeight = 0;
87  QgsComposerFrame* currentItem = 0;
88 
89  for ( int i = 0; i < mFrameItems.size(); ++i )
90  {
91  if ( mResizeMode != RepeatOnEveryPage && currentY >= totalHeight )
92  {
93  if ( mResizeMode == RepeatUntilFinished || mResizeMode == ExtendToNextPage ) //remove unneeded frames in extent mode
94  {
95  bool removingPages = true;
96  for ( int j = mFrameItems.size(); j > i; --j )
97  {
98  int numPagesBefore = mComposition->numPages();
99  removeFrame( j - 1, removingPages );
100  //if removing the frame didn't also remove the page, then stop removing pages
101  removingPages = removingPages && ( mComposition->numPages() < numPagesBefore );
102  }
103  return;
104  }
105  }
106 
107  currentItem = mFrameItems.value( i );
108  currentHeight = currentItem->rect().height();
110  {
111  currentItem->setContentSection( QRectF( 0, 0, currentItem->rect().width(), currentHeight ) );
112  }
113  else
114  {
115  currentHeight = findNearbyPageBreak( currentY + currentHeight ) - currentY;
116  currentItem->setContentSection( QRectF( 0, currentY, currentItem->rect().width(), currentHeight ) );
117  }
118  currentItem->update();
119  currentY += currentHeight;
120  }
121 
122  //at end of frames but there is still content left. Add other pages if ResizeMode ==
124  {
125  while (( mResizeMode == RepeatOnEveryPage ) || currentY < totalHeight )
126  {
127  //find out on which page the lower left point of the last frame is
128  int page = qFloor(( currentItem->pos().y() + currentItem->rect().height() ) / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() ) ) + 1;
129 
131  {
132  if ( page >= mComposition->numPages() )
133  {
134  break;
135  }
136  }
137  else
138  {
139  //add an extra page if required
140  if ( mComposition->numPages() < ( page + 1 ) )
141  {
142  mComposition->setNumPages( page + 1 );
143  }
144  }
145 
146  double frameHeight = 0;
148  {
149  frameHeight = currentItem->rect().height();
150  }
151  else //mResizeMode == ExtendToNextPage
152  {
153  frameHeight = ( currentY + mComposition->paperHeight() ) > totalHeight ? totalHeight - currentY : mComposition->paperHeight();
154  }
155 
156  double newFrameY = page * ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
158  {
159  newFrameY += currentItem->pos().y() - ( page - 1 ) * ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
160  }
161 
162  //create new frame
163  QgsComposerFrame* newFrame = createNewFrame( currentItem,
164  QPointF( currentItem->pos().x(), newFrameY ),
165  QSizeF( currentItem->rect().width(), frameHeight ) );
166 
168  {
169  newFrame->setContentSection( QRectF( 0, 0, newFrame->rect().width(), newFrame->rect().height() ) );
170  currentY += frameHeight;
171  }
172  else
173  {
174  double contentHeight = findNearbyPageBreak( currentY + newFrame->rect().height() ) - currentY;
175  newFrame->setContentSection( QRectF( 0, currentY, newFrame->rect().width(), contentHeight ) );
176  currentY += contentHeight;
177  }
178 
179  currentItem = newFrame;
180  }
181  }
182 }
183 
185 {
186  if ( mFrameItems.size() < 1 )
187  {
188  //no frames, nothing to do
189  return;
190  }
191 
192  QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
193  for ( ; frameIt != mFrameItems.end(); ++frameIt )
194  {
195  ( *frameIt )->setSceneRect( QRectF(( *frameIt )->scenePos().x(), ( *frameIt )->scenePos().y(),
196  ( *frameIt )->rect().width(), ( *frameIt )->rect().height() ) );
197  }
198 }
199 
201 {
202  if ( !currentFrame )
203  {
204  return 0;
205  }
206 
207  QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, pos.x(),
208  pos.y(), size.width(), size.height() );
209 
210  //copy some settings from the parent frame
211  newFrame->setBackgroundColor( currentFrame->backgroundColor() );
212  newFrame->setBackgroundEnabled( currentFrame->hasBackground() );
213  newFrame->setBlendMode( currentFrame->blendMode() );
214  newFrame->setFrameEnabled( currentFrame->hasFrame() );
215  newFrame->setFrameOutlineColor( currentFrame->frameOutlineColor() );
216  newFrame->setFrameJoinStyle( currentFrame->frameJoinStyle() );
217  newFrame->setFrameOutlineWidth( currentFrame->frameOutlineWidth() );
218  newFrame->setTransparency( currentFrame->transparency() );
219  newFrame->setHideBackgroundIfEmpty( currentFrame->hideBackgroundIfEmpty() );
220 
221  addFrame( newFrame, false );
222 
223  return newFrame;
224 }
225 
227 {
228  return tr( "<frame>" );
229 }
230 
232 {
233  QgsComposerFrame* frame = dynamic_cast<QgsComposerFrame*>( item );
234  if ( !frame )
235  {
236  return;
237  }
238  int index = mFrameItems.indexOf( frame );
239  if ( index == -1 )
240  {
241  return;
242  }
243 
244  mFrameItems.removeAt( index );
245  if ( mFrameItems.size() > 0 )
246  {
247  if ( resizeMode() != QgsComposerMultiFrame::RepeatOnEveryPage && !mIsRecalculatingSize )
248  {
249  //removing a frame forces the multi frame to UseExistingFrames resize mode
250  //otherwise the frame may not actually be removed, leading to confusing ui behaviour
252  emit changed();
254  }
255  }
256 }
257 
259 {
260  if ( mComposition->numPages() < 1 )
261  {
262  return;
263  }
264 
266  {
267  return;
268  }
269 
270  //remove items beginning on non-existing pages
271  for ( int i = mFrameItems.size() - 1; i >= 0; --i )
272  {
274  int page = frame->pos().y() / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
275  if ( page > ( mComposition->numPages() - 1 ) )
276  {
277  removeFrame( i );
278  }
279  }
280 
281  //page number of the last item
282  QgsComposerFrame* lastFrame = mFrameItems.last();
283  int lastItemPage = lastFrame->pos().y() / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
284 
285  for ( int i = lastItemPage + 1; i < mComposition->numPages(); ++i )
286  {
287  //copy last frame to current page
288  QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, lastFrame->pos().x(),
289  lastFrame->pos().y() + mComposition->paperHeight() + mComposition->spaceBetweenPages(),
290  lastFrame->rect().width(), lastFrame->rect().height() );
291  addFrame( newFrame, false );
292  lastFrame = newFrame;
293  }
294 
296  update();
297 }
298 
299 void QgsComposerMultiFrame::removeFrame( int i, const bool removeEmptyPages )
300 {
301  if ( i >= mFrameItems.count() )
302  {
303  return;
304  }
305 
306  QgsComposerFrame* frameItem = mFrameItems[i];
307  if ( mComposition )
308  {
309  mIsRecalculatingSize = true;
310  int pageNumber = frameItem->page();
311  //remove item, but don't create undo command
312  mComposition->removeComposerItem( frameItem, false );
313  //if frame was the only item on the page, remove the page
314  if ( removeEmptyPages && mComposition->pageIsEmpty( pageNumber ) )
315  {
317  }
318  mIsRecalculatingSize = false;
319  }
320  mFrameItems.removeAt( i );
321 }
322 
324 {
325  QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
326  for ( ; frameIt != mFrameItems.end(); ++frameIt )
327  {
328  ( *frameIt )->update();
329  }
330 }
331 
333 {
334  ResizeMode bkResizeMode = mResizeMode;
336  QObject::disconnect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( handleFrameRemoval( QgsComposerItem* ) ) );
337  QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
338  for ( ; frameIt != mFrameItems.end(); ++frameIt )
339  {
340  mComposition->removeComposerItem( *frameIt, false );
341  delete *frameIt;
342  }
343  QObject::connect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( handleFrameRemoval( QgsComposerItem* ) ) );
344  mFrameItems.clear();
345  mResizeMode = bkResizeMode;
346 }
347 
349 {
350  if ( i >= mFrameItems.size() )
351  {
352  return 0;
353  }
354  return mFrameItems.at( i );
355 }
356 
358 {
359  return mFrameItems.indexOf( frame );
360 }
361 
362 bool QgsComposerMultiFrame::_writeXML( QDomElement& elem, QDomDocument& doc, bool ignoreFrames ) const
363 {
364  elem.setAttribute( "resizeMode", mResizeMode );
365  if ( !ignoreFrames )
366  {
367  QList<QgsComposerFrame*>::const_iterator frameIt = mFrameItems.constBegin();
368  for ( ; frameIt != mFrameItems.constEnd(); ++frameIt )
369  {
370  ( *frameIt )->writeXML( elem, doc );
371  }
372  }
373  QgsComposerObject::writeXML( elem, doc );
374  return true;
375 }
376 
377 bool QgsComposerMultiFrame::_readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames )
378 {
379  QgsComposerObject::readXML( itemElem, doc );
380 
381  mResizeMode = ( ResizeMode )itemElem.attribute( "resizeMode", "0" ).toInt();
382  if ( !ignoreFrames )
383  {
384  QDomNodeList frameList = itemElem.elementsByTagName( "ComposerFrame" );
385  for ( int i = 0; i < frameList.size(); ++i )
386  {
387  QDomElement frameElem = frameList.at( i ).toElement();
388  QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, 0, 0, 0, 0 );
389  newFrame->readXML( frameElem, doc );
390  addFrame( newFrame, false );
391  }
392 
393  //TODO - think there should be a recalculateFrameSizes() call here
394  }
395  return true;
396 }
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:441
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:442
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.
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...
bool readXML(const QDomElement &itemElem, const QDomDocument &doc) override
Sets item state from DOM element.
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)