1 /* This file is part of the KDE project
2 * Copyright (C) 2010-2015 C. Boemann <cbo@boemann.dk>
3 * Copyright (C) 2006,2011 Sebastian Sauer <mail@dipe.org>
4 * Copyright (C) 2006-2007, 2010 Thomas Zander <zander@kde.org>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #include "KWRootAreaProvider.h"
23 #include "KWPageManager.h"
24 #include "KWDocument.h"
25 #include "KWView.h"
26 #include "KWPage.h"
27 #include "frames/KWCopyShape.h"
28 #include "frames/KWTextFrameSet.h"
29 #include "frames/KWFrameLayout.h"
30
31 #include <KoTextLayoutRootArea.h>
32 #include <KoShape.h>
33 #include <KoShapeContainer.h>
34 #include <KoShapeFactoryBase.h>
35 #include <KoTextShapeData.h>
36 #include <KoTextDocumentLayout.h>
37 #include <KoTextLayoutObstruction.h>
38 #include <KoSelection.h>
39 #include <KoCanvasBase.h>
40 #include <KoShapeAnchor.h>
41 #include <KoColumns.h>
42
43 #include <QTimer>
44 #include <WordsDebug.h>
45
46 class KWTextLayoutRootArea : public KoTextLayoutRootArea
47 {
48 public:
KWTextLayoutRootArea(KoTextDocumentLayout * documentLayout,KWTextFrameSet * frameSet,int pageNumber)49 KWTextLayoutRootArea(KoTextDocumentLayout *documentLayout, KWTextFrameSet *frameSet, int pageNumber) : KoTextLayoutRootArea(documentLayout), m_frameSet(frameSet), m_pageNumber(pageNumber) {
50 //debugWords;
51 }
~KWTextLayoutRootArea()52 ~KWTextLayoutRootArea() override {
53 //debugWords;
54 }
layout(FrameIterator * cursor)55 virtual bool layout(FrameIterator *cursor) {
56 //debugWords << "pageNumber=" << m_pageNumber << "frameSetType=" << Words::frameSetTypeName(m_frameSet->textFrameSetType()) << "isDirty=" << isDirty();
57 bool ok = KoTextLayoutRootArea::layout(cursor);
58 return ok;
59 }
60 KWTextFrameSet *m_frameSet;
61 int m_pageNumber;
62 };
63
KWRootAreaProvider(KWTextFrameSet * textFrameSet)64 KWRootAreaProvider::KWRootAreaProvider(KWTextFrameSet *textFrameSet)
65 : KWRootAreaProviderBase(textFrameSet)
66 {
67 }
68
~KWRootAreaProvider()69 KWRootAreaProvider::~KWRootAreaProvider()
70 {
71 qDeleteAll(m_rootAreaCache);
72 m_rootAreaCache.clear();
73 qDeleteAll(m_pages);
74 m_pages.clear();
75 }
76
clearPages(int pageNumber)77 void KWRootAreaProvider::clearPages(int pageNumber)
78 {
79 if (pageNumber > pages().count()) {
80 return;
81 }
82
83 KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout*>(frameSet()->document()->documentLayout());
84 Q_ASSERT(lay);
85 int prevPageIndex = pageNumber - 2;
86 do {
87 KWRootAreaPage *prevPage = prevPageIndex >= 0 && prevPageIndex < pages().count() ? pages()[prevPageIndex] : 0;
88 if (prevPage) {
89 if (prevPage->rootAreas.isEmpty()) {
90 --prevPageIndex;
91 continue; // this page doesn't have any root-areas so try the next previous page
92 }
93 QList<KoTextLayoutRootArea *> rootAreas = prevPage->rootAreas;
94 foreach(KoTextLayoutRootArea *area, rootAreas) {
95 releaseAllAfter(area);
96 lay->removeRootArea(area);
97 }
98 } else {
99 releaseAllAfter(0);
100 lay->removeRootArea(0);
101 }
102 } while(false);
103 }
104
addDependentProvider(KWRootAreaProviderBase * provider,int pageNumber)105 void KWRootAreaProvider::addDependentProvider(KWRootAreaProviderBase *provider, int pageNumber)
106 {
107 debugWords;
108 KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout*>(provider->frameSet()->document()->documentLayout());
109 Q_ASSERT(lay);
110 lay->setContinuousLayout(false); // to abort the current layout-loop
111 lay->setBlockLayout(true); // to prevent a new layout-loop from being started
112
113 m_dependentProviders.append(QPair<KWRootAreaProviderBase *, int>(provider, pageNumber));
114 }
115
setPageDirty(int pageNumber)116 void KWRootAreaProvider::setPageDirty(int pageNumber)
117 {
118 if (pageNumber - 1 < m_pages.count()) {
119 KWRootAreaPage *page = m_pages[pageNumber - 1];
120 foreach(KoTextLayoutRootArea *rootArea, page->rootAreas) {
121 rootArea->setDirty(); // be sure the root-areas from the page are relayouted
122 }
123 }
124 }
125
handleDependentProviders(int pageNumber)126 void KWRootAreaProvider::handleDependentProviders(int pageNumber)
127 {
128 QList<KoTextDocumentLayout *> layouts;
129 for(int i = m_dependentProviders.count() - 1; i >= 0; --i) {
130 QPair<KWRootAreaProviderBase *, int> p = m_dependentProviders[i];
131 if (p.second > pageNumber) { // only handle providers which would continue layouting at the page we just processed
132 continue;
133 }
134 m_dependentProviders.removeAt(i); // this one is handled now
135 p.first->setPageDirty(pageNumber);
136 KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout*>(p.first->frameSet()->document()->documentLayout());
137 Q_ASSERT(lay);
138 if (!layouts.contains(lay)) {
139 layouts.append(lay);
140 }
141 }
142
143 foreach(KoTextDocumentLayout *lay, layouts) {
144 lay->setContinuousLayout(true); // to not abort the current layout-loop any longer
145 lay->setBlockLayout(false); // allow layouting again
146 lay->layout(); // continue layouting but don't schedule so we are sure it's done instantly
147 }
148 }
149
provideNext(KoTextDocumentLayout * documentLayout,const RootAreaConstraint & constraints)150 KoTextLayoutRootArea* KWRootAreaProvider::provideNext(KoTextDocumentLayout *documentLayout, const RootAreaConstraint &constraints)
151 {
152 KWDocument *kwdoc = frameSet()->wordsDocument();
153 KWPageManager *pageManager = kwdoc->pageManager();
154 Q_ASSERT(pageManager);
155
156 int pageNumber = 1;
157 KWRootAreaPage *rootAreaPage = m_pages.isEmpty() ? 0 : m_pages.last();
158 int requiredRootAreaCount = 1;
159 if (rootAreaPage && frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
160 Q_ASSERT(rootAreaPage->page.isValid());
161 Q_ASSERT(rootAreaPage->page.pageStyle().isValid());
162 requiredRootAreaCount = rootAreaPage->page.pageStyle().columns().count;
163 if (constraints.newPageForced) {
164 requiredRootAreaCount = 1;
165 }
166 }
167 if (rootAreaPage && rootAreaPage->rootAreas.count() < requiredRootAreaCount) {
168 pageNumber = m_pages.count(); // the root-area is still on the same page
169 } else {
170 pageNumber = m_pages.count() + 1; // the root-area is the first on a new page
171
172 if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
173 // Create missing KWPage's (they will also create a KWFrame and TextShape per page)
174 for(int i = pageManager->pageCount(); i < pageNumber; ++i) {
175 KWPage page = kwdoc->appendPage(constraints.masterPageName);
176 Q_ASSERT(page.isValid());
177 if (constraints.visiblePageNumber >= 0)
178 page.setVisiblePageNumber(constraints.visiblePageNumber);
179 }
180 } else if (pageNumber > pageManager->pageCount()) {
181 if (Words::isHeaderFooter(frameSet())) {
182 // Headers and footers are special in that they continue with every page what is why they depend on the mainframe.
183 KWRootAreaProvider *provider = (KWRootAreaProvider *)kwdoc->frameLayout()->mainFrameSet()->rootAreaProvider();
184 provider->addDependentProvider(this, pageNumber);
185 }
186 return 0; // not ready to layout this yet
187 }
188
189 KWPage page = pageManager->page(pageNumber);
190 Q_ASSERT(page.isValid());
191 if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
192 if (constraints.visiblePageNumber >= 0)
193 page.setVisiblePageNumber(constraints.visiblePageNumber);
194 else
195 page.setVisiblePageNumber(0);
196 }
197 rootAreaPage = new KWRootAreaPage(page);
198 m_pages.append(rootAreaPage);
199 }
200
201 debugWords << "pageNumber=" << pageNumber << "frameSet=" << Words::frameSetTypeName(frameSet()->textFrameSetType());
202 if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
203 handleDependentProviders(pageNumber);
204 }
205 // Determinate the frames that are on the page. Note that the KWFrameLayout only knows
206 // about header, footer and the mainframes but not about all other framesets.
207 QList<KoShape *> shapes;
208
209 if (frameSet()->type() == Words::OtherFrameSet || frameSet()->textFrameSetType() == Words::OtherTextFrameSet) {
210 if (KoShape *s = frameSet()->shapes().value(pageNumber - 1))
211 shapes = QList<KoShape *>() << s;
212 } else {
213 shapes = kwdoc->frameLayout()->sequencedShapesOn(frameSet(), pageNumber);
214 }
215
216 // position OtherFrameSet's which are anchored to this page
217 if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
218 foreach(KWFrameSet* fs, kwdoc->frameSets()) {
219 KWTextFrameSet *tfs = dynamic_cast<KWTextFrameSet*>(fs);
220 if (tfs && tfs->textFrameSetType() != Words::OtherTextFrameSet)
221 continue;
222 foreach (KWFrame *frame, fs->frames()) {
223 KoShape *shape = frame->shape();
224 int anchoredPageNumber = shape->anchor() ? shape->anchor()->pageNumber() : -1;
225 if (anchoredPageNumber == pageNumber) {
226 qreal oldOffset = frame->anchoredFrameOffset();
227 qreal newOffset = rootAreaPage->page.offsetInDocument();
228 if (!qFuzzyCompare(1 + oldOffset, 1 + newOffset)) {
229 frame->setAnchoredFrameOffset(newOffset);
230 QPointF pos(shape->position().x(), newOffset - oldOffset + shape->position().y());
231 shape->setPosition(pos);
232 }
233
234 // During load we make page anchored shapes invisible, because otherwise
235 // they leave empty rects in the text if there is run-around
236 // now is the time to make them visible again
237 shape->setVisible(true);
238
239 QPointF delta;
240 KWFrameLayout::proposeShapeMove(shape, delta, rootAreaPage->page);
241 shape->setPosition(shape->position() + delta);
242 }
243 }
244 }
245 } else {
246 if (!documentLayout->referencedLayout()) {
247 KoTextDocumentLayout *reflay = dynamic_cast<KoTextDocumentLayout*>(kwdoc->frameLayout()->mainFrameSet()->document()->documentLayout());
248 documentLayout->setReferencedLayout(reflay);
249 }
250 }
251
252 KoShape *shape = rootAreaPage->rootAreas.count() < shapes.count() ? shapes[rootAreaPage->rootAreas.count()] : 0;
253
254 KWTextLayoutRootArea *area = new KWTextLayoutRootArea(documentLayout, frameSet(), pageNumber);
255 if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
256 if (rootAreaPage->page.pageStyle().columns().count > 1) {
257 area->setAcceptsColumnBreak(true);
258 }
259 area->setAcceptsPageBreak(true);
260 }
261
262 if (shape) { // Not every KoTextLayoutRootArea has a KoShape for display purposes.
263 //Q_ASSERT_X(pageNumber == pageManager->page(shape).pageNumber(), __FUNCTION__, QString("KWPageManager is out-of-sync, pageNumber=%1 vs pageNumber=%2 with offset=%3 vs offset=%4 on frameSetType=%5").arg(pageNumber).arg(pageManager->page(shape).pageNumber()).arg(shape->absolutePosition().y()).arg(pageManager->page(shape).offsetInDocument()).arg(Words::frameSetTypeName(frameSet()->textFrameSetType())).toLocal8Bit());
264 KoTextShapeData *data = qobject_cast<KoTextShapeData*>(shape->userData());
265 if (data) {
266 data->setRootArea(area);
267 area->setAssociatedShape(shape);
268 } else {
269 warnWords << "shape has no KoTextShapeData";
270 }
271 if ((!shape->anchor()) || shape->anchor()->anchorType() == KoShapeAnchor::AnchorPage) {
272 area->setPage(new KWPage(rootAreaPage->page));
273 }
274 }
275
276 if (frameSet()->type() != Words::OtherFrameSet && frameSet()->textFrameSetType() != Words::OtherTextFrameSet) {
277 // Only header, footer and main-frames have an own KoTextPage. All other frames are embedded into them and inherit the KoTextPage from them.
278 area->setPage(new KWPage(rootAreaPage->page));
279 area->setLayoutEnvironmentResctictions(true, false);
280 } else {
281 area->setLayoutEnvironmentResctictions(true, true);
282 }
283
284 m_pageHash[area] = rootAreaPage;
285 rootAreaPage->rootAreas.append(area);
286
287 return area;
288 }
289
provide(KoTextDocumentLayout * documentLayout,const RootAreaConstraint & constraints,int requestedPosition,bool * isNewArea)290 KoTextLayoutRootArea *KWRootAreaProvider::provide(KoTextDocumentLayout* documentLayout, const RootAreaConstraint& constraints, int requestedPosition, bool *isNewArea)
291 {
292 KWPageManager *pageManager = frameSet()->wordsDocument()->pageManager();
293 Q_ASSERT(pageManager);
294 if (pageManager->pageCount() == 0) // not ready yet (may happen e.g. on loading a document)
295 return 0;
296
297 QString reallyNeededPageStyle = constraints.masterPageName;
298 int visiblePageNumber = constraints.visiblePageNumber;
299 bool newPageForced = constraints.newPageForced;
300 if (m_rootAreaCache.size() > requestedPosition)
301 {
302 KoTextLayoutRootArea *rootArea = m_rootAreaCache[requestedPosition];
303 Q_ASSERT(rootArea);
304
305 if (frameSet()->textFrameSetType() != Words::MainTextFrameSet)
306 {
307 // No constraints except for the main frame set
308 *isNewArea = false;
309 return rootArea;
310 }
311
312 KWRootAreaPage *rootAreaPage = m_pageHash.value(rootArea);
313 Q_ASSERT(rootAreaPage);
314
315 if (constraints.visiblePageNumber >= 0)
316 rootAreaPage->page.setVisiblePageNumber(constraints.visiblePageNumber);
317 else
318 rootAreaPage->page.setVisiblePageNumber(0);
319
320 QString reallyNeededPageStyle = constraints.masterPageName;
321 if (reallyNeededPageStyle.isNull())
322 {
323 // We must work using the previous pages...
324 if (requestedPosition == 0)
325 {
326 reallyNeededPageStyle = pageManager->defaultPageStyle().name();
327 }
328 else
329 {
330 KWRootAreaPage *previousAreaPage = m_pageHash.value(m_rootAreaCache[requestedPosition - 1]);
331 reallyNeededPageStyle = previousAreaPage->page.pageStyle().nextStyleName();
332 if (reallyNeededPageStyle.isNull())
333 reallyNeededPageStyle = previousAreaPage->page.pageStyle().name();
334 }
335 }
336
337 if (rootAreaPage->page.masterPageName() != reallyNeededPageStyle)
338 {
339 //TODO : recycle pages in order to save us a lot of effort and reduce risks of flickering, especially with very long documents
340 releaseAllAfter(rootArea);
341 }
342 else
343 {
344 *isNewArea = false;
345 return rootArea;
346 }
347 }
348
349 // We are interested in the first KoTextLayoutRootArea that has a shape associated for display
350 // purposes. This can mean that multiple KoTextLayoutRootArea are created but only selected
351 // ones that should be layouted and displayed are passed on to the textlayout-library.
352 // This is only done for headers and footers cause they are continuous whereas for example
353 // Words::OtherFrameSet and Words::OtherTextFrameSet framesets may not have the correct position
354 // or not shape assigned at this point but later.
355 RootAreaConstraint realConstraints;
356 realConstraints.masterPageName = reallyNeededPageStyle;
357 realConstraints.visiblePageNumber = visiblePageNumber;
358 realConstraints.newPageForced = newPageForced;
359 KoTextLayoutRootArea *area = 0;
360 do {
361 area = provideNext(documentLayout, realConstraints);
362 if (m_rootAreaCache.size() <= requestedPosition)
363 m_rootAreaCache.append(area);
364 } while(Words::isHeaderFooter(frameSet()) && area && !area->associatedShape());
365
366 Q_ASSERT(m_rootAreaCache.size() > requestedPosition);
367
368 if (area == 0 && (frameSet()->textFrameSetType() != Words::MainTextFrameSet) && requestedPosition == 0)
369 m_rootAreaCache.clear();
370 *isNewArea = true;
371
372 return area;
373 }
374
375 // afterThis==nullptr means delete everything
releaseAllAfter(KoTextLayoutRootArea * afterThis)376 void KWRootAreaProvider::releaseAllAfter(KoTextLayoutRootArea *afterThis)
377 {
378 int afterIndex = -1;
379 if (afterThis) {
380 if (!m_pageHash.contains(afterThis))
381 return;
382 KWRootAreaPage *page = m_pageHash.value(afterThis);
383 afterIndex = m_pages.indexOf(page);
384 Q_ASSERT(afterIndex >= 0);
385
386 int newSize = m_rootAreaCache.indexOf(afterThis) + 1;
387 while (m_rootAreaCache.size() != newSize)
388 {
389 KoTextLayoutRootArea *oldArea = m_rootAreaCache.takeLast();
390 delete(oldArea);
391 }
392 }
393
394 debugWords << "afterPageNumber=" << afterIndex+1;
395
396 bool atLeastOnePageRemoved = false;
397 KWPageManager *pageManager = frameSet()->wordsDocument()->pageManager();
398 if (afterIndex >= 0) {
399 for(int i = m_pages.count() - 1; i > afterIndex; --i) {
400 KWRootAreaPage *page = m_pages.takeLast();
401 foreach(KoTextLayoutRootArea *area, page->rootAreas)
402 m_pageHash.remove(area);
403 delete page;
404
405 if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
406 pageManager->removePage(i+1);
407 atLeastOnePageRemoved = true;
408 }
409 }
410
411 // FIXME
412 for(int i = m_dependentProviders.count() - 1; i >= 0; --i) {
413 QPair<KWRootAreaProviderBase *, int> p = m_dependentProviders[i];
414 if (p.second >= afterIndex)
415 m_dependentProviders.removeAt(i);
416 }
417 } else {
418 //atLeastOnePageRemoved = !m_pages.isEmpty();
419 qDeleteAll(m_pages);
420 qDeleteAll(m_rootAreaCache);
421 m_pages.clear();
422 m_pageHash.clear();
423 m_rootAreaCache.clear();
424
425 /*FIXME that would result in flickering :-/
426 for(int i = pageManager->pageCount(); i >= 1; --i)
427 pageManager->removePage(i);
428 */
429
430 /*FIXME
431 m_dependentProviders.clear();
432 */
433 }
434 if (atLeastOnePageRemoved)
435 frameSet()->wordsDocument()->firePageSetupChanged();
436 }
437
doPostLayout(KoTextLayoutRootArea * rootArea,bool isNewRootArea)438 void KWRootAreaProvider::doPostLayout(KoTextLayoutRootArea *rootArea, bool isNewRootArea)
439 {
440 KWDocument *kwdoc = const_cast<KWDocument*>(frameSet()->wordsDocument());
441 KWPageManager *pageManager = kwdoc->pageManager();
442 Q_ASSERT(pageManager);
443
444 if (frameSet()->textFrameSetType() != Words::MainTextFrameSet) {
445 if (m_pages.count() > pageManager->pageCount()) {
446 // we need to wait for the mainFrameSet to finish till we are able to continue
447 KWRootAreaProvider *provider = (KWRootAreaProvider *)kwdoc->frameLayout()->mainFrameSet()->rootAreaProvider();
448 provider->addDependentProvider(this, m_pages.count());
449 }
450 }
451
452 KoShape *shape = rootArea->associatedShape();
453 if (!shape)
454 return;
455
456 KWPage page = pageManager->page(shape);
457 Q_ASSERT(page.isValid());
458 KoTextShapeData *data = qobject_cast<KoTextShapeData*>(shape->userData());
459 Q_ASSERT(data);
460 bool isHeaderFooter = Words::isHeaderFooter(frameSet());
461
462 debugWords << "pageNumber=" << page.pageNumber() << "frameSetType=" << Words::frameSetTypeName(frameSet()->textFrameSetType()) << "isNewRootArea=" << isNewRootArea << "rootArea=" << rootArea << "isDirty=" << rootArea->isDirty();
463
464 QRectF updateRect = shape->outlineRect();
465
466 QSizeF newSize = shape->size()
467 - QSizeF(data->leftPadding() + data->rightPadding(),
468 data->topPadding() + data->bottomPadding());
469
470 KoBorder *border = shape->border();
471
472 if (border) {
473 newSize -= QSizeF(border->borderWidth(KoBorder::LeftBorder) + border->borderWidth(KoBorder::RightBorder), border->borderWidth(KoBorder::TopBorder) + border->borderWidth(KoBorder::BottomBorder));
474 }
475
476 if (isHeaderFooter
477 ||data->resizeMethod() == KoTextShapeData::AutoGrowWidthAndHeight
478 ||data->resizeMethod() == KoTextShapeData::AutoGrowHeight) {
479
480 newSize.setHeight(rootArea->bottom() - rootArea->top());
481
482 if (frameSet()->type() == Words::OtherFrameSet || frameSet()->textFrameSetType() == Words::OtherTextFrameSet) {
483 // adjust size to have at least the defined minimum height
484 Q_ASSERT(frameSet()->shapeCount() > 0);
485 KoShape *firstShape = frameSet()->shapes().first();
486 if (firstShape->minimumHeight() > newSize.height())
487 newSize.setHeight(firstShape->minimumHeight());
488 }
489 }
490 if (data->resizeMethod() == KoTextShapeData::AutoGrowWidthAndHeight
491 ||data->resizeMethod() == KoTextShapeData::AutoGrowWidth) {
492 newSize.setWidth(rootArea->right() - rootArea->left());
493 }
494
495 // To make sure footnotes always end up at the bottom of the main area we need to set this
496 if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
497 rootArea->setBottom(rootArea->top() + newSize.height());
498 }
499
500 newSize += QSizeF(data->leftPadding() + data->rightPadding(),
501 data->topPadding() + data->bottomPadding());
502 if (border) {
503 newSize += QSizeF(border->borderWidth(KoBorder::LeftBorder) + border->borderWidth(KoBorder::RightBorder), border->borderWidth(KoBorder::TopBorder) + border->borderWidth(KoBorder::BottomBorder));
504 }
505
506 if (newSize != rootArea->associatedShape()->size()) {
507 rootArea->associatedShape()->setSize(newSize);
508
509 // transfer the new size to the copy-shapes
510 foreach(KWCopyShape *cs, frameSet()->copyShapes()) {
511 cs->setSize(newSize);
512 }
513
514 if (isHeaderFooter) {
515 // adjust the minimum shape height for headers and footer
516 Q_ASSERT(frameSet()->shapeCount() > 0);
517 KoShape *firstShape = frameSet()->shapes().first();
518 if (firstShape->minimumHeight() != newSize.height()) {
519 firstShape->setMinimumHeight(newSize.height());
520
521 // transfer the new minimumFrameHeight to the copy-shapes too
522 foreach(KWCopyShape *cs, frameSet()->copyShapes()) {
523 cs->setMinimumHeight(newSize.height());
524 }
525 // cause the header/footer's height changed we have to relayout the whole page
526 frameSet()->wordsDocument()->frameLayout()->layoutFramesOnPage(page.pageNumber());
527 }
528 }
529 }
530
531
532 updateRect |= rootArea->associatedShape()->outlineRect();
533 rootArea->associatedShape()->update(updateRect);
534
535 if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
536 handleDependentProviders(page.pageNumber());
537 }
538
539 }
540