QGIS API Documentation  2.5.0-Master
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties 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 
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 }
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 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.
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 removeComposerItem(QgsComposerItem *item, const bool createCommand=true, const bool removeGroupItems=true)
Remove item from the graphics scene.
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)
#define tr(sourceText)