QGIS API Documentation  2.8.2-Wien
 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 
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 }