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  return tr( "<frame>" );
190 }
191 
193 {
194  QgsComposerFrame* frame = dynamic_cast<QgsComposerFrame*>( item );
195  if ( !frame )
196  {
197  return;
198  }
199  int index = mFrameItems.indexOf( frame );
200  if ( index == -1 )
201  {
202  return;
203  }
204  mFrameItems.removeAt( index );
205  if ( mFrameItems.size() > 0 )
206  {
208  {
209  //removing a frame forces the multi frame to UseExistingFrames resize mode
210  //otherwise the frame may not actually be removed, leading to confusing ui behaviour
212  emit changed();
213  }
215  }
216 }
217 
219 {
220  if ( mComposition->numPages() < 1 )
221  {
222  return;
223  }
224 
226  {
227  return;
228  }
229 
230  //remove items beginning on non-existing pages
231  for ( int i = mFrameItems.size() - 1; i >= 0; --i )
232  {
234  int page = frame->pos().y() / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
235  if ( page > ( mComposition->numPages() - 1 ) )
236  {
237  removeFrame( i );
238  }
239  }
240 
241  //page number of the last item
242  QgsComposerFrame* lastFrame = mFrameItems.last();
243  int lastItemPage = lastFrame->pos().y() / ( mComposition->paperHeight() + mComposition->spaceBetweenPages() );
244 
245  for ( int i = lastItemPage + 1; i < mComposition->numPages(); ++i )
246  {
247  //copy last frame to current page
248  QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, lastFrame->pos().x(),
249  lastFrame->pos().y() + mComposition->paperHeight() + mComposition->spaceBetweenPages(),
250  lastFrame->rect().width(), lastFrame->rect().height() );
251  addFrame( newFrame, false );
252  lastFrame = newFrame;
253  }
254 
256  update();
257 }
258 
260 {
261  if ( i >= mFrameItems.count() )
262  {
263  return;
264  }
265 
266  QgsComposerFrame* frameItem = mFrameItems[i];
267  if ( mComposition )
268  {
269  mIsRecalculatingSize = true;
270  mComposition->removeComposerItem( frameItem );
271  mIsRecalculatingSize = false;
272  }
273  mFrameItems.removeAt( i );
274 }
275 
277 {
278  QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
279  for ( ; frameIt != mFrameItems.end(); ++frameIt )
280  {
281  ( *frameIt )->update();
282  }
283 }
284 
286 {
287  ResizeMode bkResizeMode = mResizeMode;
289  QObject::disconnect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( handleFrameRemoval( QgsComposerItem* ) ) );
290  QList<QgsComposerFrame*>::iterator frameIt = mFrameItems.begin();
291  for ( ; frameIt != mFrameItems.end(); ++frameIt )
292  {
293  mComposition->removeComposerItem( *frameIt, false );
294  delete *frameIt;
295  }
296  QObject::connect( mComposition, SIGNAL( itemRemoved( QgsComposerItem* ) ), this, SLOT( handleFrameRemoval( QgsComposerItem* ) ) );
297  mFrameItems.clear();
298  mResizeMode = bkResizeMode;
299 }
300 
302 {
303  if ( i >= mFrameItems.size() )
304  {
305  return 0;
306  }
307  return mFrameItems.at( i );
308 }
309 
310 bool QgsComposerMultiFrame::_writeXML( QDomElement& elem, QDomDocument& doc, bool ignoreFrames ) const
311 {
312  elem.setAttribute( "resizeMode", mResizeMode );
313  if ( !ignoreFrames )
314  {
315  QList<QgsComposerFrame*>::const_iterator frameIt = mFrameItems.constBegin();
316  for ( ; frameIt != mFrameItems.constEnd(); ++frameIt )
317  {
318  ( *frameIt )->writeXML( elem, doc );
319  }
320  }
321  QgsComposerObject::writeXML( elem, doc );
322  return true;
323 }
324 
325 bool QgsComposerMultiFrame::_readXML( const QDomElement& itemElem, const QDomDocument& doc, bool ignoreFrames )
326 {
327  QgsComposerObject::readXML( itemElem, doc );
328 
329  mResizeMode = ( ResizeMode )itemElem.attribute( "resizeMode", "0" ).toInt();
330  if ( !ignoreFrames )
331  {
332  QDomNodeList frameList = itemElem.elementsByTagName( "ComposerFrame" );
333  for ( int i = 0; i < frameList.size(); ++i )
334  {
335  QDomElement frameElem = frameList.at( i ).toElement();
336  QgsComposerFrame* newFrame = new QgsComposerFrame( mComposition, this, 0, 0, 0, 0 );
337  newFrame->readXML( frameElem, doc );
338  addFrame( newFrame );
339  }
340  }
341  return true;
342 }