File indexing completed on 2024-05-12 16:37:13

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2010-2015 C. Boemann <cbo@boemann.dk>
0003  * Copyright (C) 2006,2011 Sebastian Sauer <mail@dipe.org>
0004  * Copyright (C) 2006-2007, 2010 Thomas Zander <zander@kde.org>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  */
0021 
0022 #include "KWRootAreaProvider.h"
0023 #include "KWPageManager.h"
0024 #include "KWDocument.h"
0025 #include "KWView.h"
0026 #include "KWPage.h"
0027 #include "frames/KWCopyShape.h"
0028 #include "frames/KWTextFrameSet.h"
0029 #include "frames/KWFrameLayout.h"
0030 
0031 #include <KoTextLayoutRootArea.h>
0032 #include <KoShape.h>
0033 #include <KoShapeContainer.h>
0034 #include <KoShapeFactoryBase.h>
0035 #include <KoTextShapeData.h>
0036 #include <KoTextDocumentLayout.h>
0037 #include <KoTextLayoutObstruction.h>
0038 #include <KoSelection.h>
0039 #include <KoCanvasBase.h>
0040 #include <KoShapeAnchor.h>
0041 #include <KoColumns.h>
0042 
0043 #include <QTimer>
0044 #include <WordsDebug.h>
0045 
0046 class KWTextLayoutRootArea : public KoTextLayoutRootArea
0047 {
0048     public:
0049         KWTextLayoutRootArea(KoTextDocumentLayout *documentLayout, KWTextFrameSet *frameSet, int pageNumber) : KoTextLayoutRootArea(documentLayout), m_frameSet(frameSet), m_pageNumber(pageNumber) {
0050             //debugWords;
0051         }
0052         ~KWTextLayoutRootArea() override {
0053             //debugWords;
0054         }
0055         virtual bool layout(FrameIterator *cursor) {
0056             //debugWords << "pageNumber=" << m_pageNumber << "frameSetType=" << Words::frameSetTypeName(m_frameSet->textFrameSetType()) << "isDirty=" << isDirty();
0057             bool ok = KoTextLayoutRootArea::layout(cursor);
0058             return ok;
0059         }
0060         KWTextFrameSet *m_frameSet;
0061         int m_pageNumber;
0062 };
0063 
0064 KWRootAreaProvider::KWRootAreaProvider(KWTextFrameSet *textFrameSet)
0065     : KWRootAreaProviderBase(textFrameSet)
0066 {
0067 }
0068 
0069 KWRootAreaProvider::~KWRootAreaProvider()
0070 {
0071     qDeleteAll(m_rootAreaCache);
0072     m_rootAreaCache.clear();
0073     qDeleteAll(m_pages);
0074     m_pages.clear();
0075 }
0076 
0077 void KWRootAreaProvider::clearPages(int pageNumber)
0078 {
0079     if (pageNumber > pages().count()) {
0080         return;
0081     }
0082 
0083     KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout*>(frameSet()->document()->documentLayout());
0084     Q_ASSERT(lay);
0085     int prevPageIndex = pageNumber - 2;
0086     do {
0087         KWRootAreaPage *prevPage = prevPageIndex >= 0 && prevPageIndex < pages().count() ? pages()[prevPageIndex] : 0;
0088         if (prevPage) {
0089             if (prevPage->rootAreas.isEmpty()) {
0090                 --prevPageIndex;
0091                 continue; // this page doesn't have any root-areas so try the next previous page
0092             }
0093             QList<KoTextLayoutRootArea *> rootAreas = prevPage->rootAreas;
0094             foreach(KoTextLayoutRootArea *area, rootAreas) {
0095                 releaseAllAfter(area);
0096                 lay->removeRootArea(area);
0097             }
0098         } else {
0099             releaseAllAfter(0);
0100             lay->removeRootArea(0);
0101         }
0102     } while(false);
0103 }
0104 
0105 void KWRootAreaProvider::addDependentProvider(KWRootAreaProviderBase *provider, int pageNumber)
0106 {
0107     debugWords;
0108     KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout*>(provider->frameSet()->document()->documentLayout());
0109     Q_ASSERT(lay);
0110     lay->setContinuousLayout(false); // to abort the current layout-loop
0111     lay->setBlockLayout(true); // to prevent a new layout-loop from being started
0112 
0113     m_dependentProviders.append(QPair<KWRootAreaProviderBase *, int>(provider, pageNumber));
0114 }
0115 
0116 void KWRootAreaProvider::setPageDirty(int pageNumber)
0117 {
0118     if (pageNumber - 1 < m_pages.count()) {
0119         KWRootAreaPage *page = m_pages[pageNumber - 1];
0120         foreach(KoTextLayoutRootArea *rootArea, page->rootAreas) {
0121             rootArea->setDirty(); // be sure the root-areas from the page are relayouted
0122         }
0123     }
0124 }
0125 
0126 void KWRootAreaProvider::handleDependentProviders(int pageNumber)
0127 {
0128     QList<KoTextDocumentLayout *> layouts;
0129     for(int i = m_dependentProviders.count() - 1; i >= 0; --i) {
0130         QPair<KWRootAreaProviderBase *, int> p = m_dependentProviders[i];
0131         if (p.second > pageNumber) { // only handle providers which would continue layouting at the page we just processed
0132             continue;
0133         }
0134         m_dependentProviders.removeAt(i); // this one is handled now
0135         p.first->setPageDirty(pageNumber);
0136         KoTextDocumentLayout *lay = dynamic_cast<KoTextDocumentLayout*>(p.first->frameSet()->document()->documentLayout());
0137         Q_ASSERT(lay);
0138         if (!layouts.contains(lay)) {
0139             layouts.append(lay);
0140         }
0141     }
0142 
0143     foreach(KoTextDocumentLayout *lay, layouts) {
0144         lay->setContinuousLayout(true); // to not abort the current layout-loop any longer
0145         lay->setBlockLayout(false); // allow layouting again
0146         lay->layout(); // continue layouting but don't schedule so we are sure it's done instantly
0147     }
0148 }
0149 
0150 KoTextLayoutRootArea* KWRootAreaProvider::provideNext(KoTextDocumentLayout *documentLayout, const RootAreaConstraint &constraints)
0151 {
0152     KWDocument *kwdoc = frameSet()->wordsDocument();
0153     KWPageManager *pageManager = kwdoc->pageManager();
0154     Q_ASSERT(pageManager);
0155 
0156     int pageNumber = 1;
0157     KWRootAreaPage *rootAreaPage = m_pages.isEmpty() ? 0 : m_pages.last();
0158     int requiredRootAreaCount = 1;
0159     if (rootAreaPage && frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
0160         Q_ASSERT(rootAreaPage->page.isValid());
0161         Q_ASSERT(rootAreaPage->page.pageStyle().isValid());
0162         requiredRootAreaCount = rootAreaPage->page.pageStyle().columns().count;
0163         if (constraints.newPageForced) {
0164             requiredRootAreaCount = 1;
0165         }
0166     }
0167     if (rootAreaPage && rootAreaPage->rootAreas.count() < requiredRootAreaCount) {
0168         pageNumber = m_pages.count(); // the root-area is still on the same page
0169     } else {
0170         pageNumber = m_pages.count() + 1; // the root-area is the first on a new page
0171 
0172         if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
0173             // Create missing KWPage's (they will also create a KWFrame and TextShape per page)
0174             for(int i = pageManager->pageCount(); i < pageNumber; ++i) {
0175                 KWPage page = kwdoc->appendPage(constraints.masterPageName);
0176                 Q_ASSERT(page.isValid());
0177                 if (constraints.visiblePageNumber >= 0)
0178                     page.setVisiblePageNumber(constraints.visiblePageNumber);
0179             }
0180         } else if (pageNumber > pageManager->pageCount()) {
0181             if (Words::isHeaderFooter(frameSet())) {
0182                 // Headers and footers are special in that they continue with every page what is why they depend on the mainframe.
0183                 KWRootAreaProvider *provider = (KWRootAreaProvider *)kwdoc->frameLayout()->mainFrameSet()->rootAreaProvider();
0184                 provider->addDependentProvider(this, pageNumber);
0185             }
0186             return 0; // not ready to layout this yet
0187         }
0188 
0189         KWPage page = pageManager->page(pageNumber);
0190         Q_ASSERT(page.isValid());
0191         if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
0192             if (constraints.visiblePageNumber >= 0)
0193                 page.setVisiblePageNumber(constraints.visiblePageNumber);
0194             else
0195                 page.setVisiblePageNumber(0);
0196         }
0197         rootAreaPage = new KWRootAreaPage(page);
0198         m_pages.append(rootAreaPage);
0199     }
0200 
0201     debugWords << "pageNumber=" << pageNumber <<  "frameSet=" << Words::frameSetTypeName(frameSet()->textFrameSetType());
0202     if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
0203         handleDependentProviders(pageNumber);
0204     }
0205     // Determinate the frames that are on the page. Note that the KWFrameLayout only knows
0206     // about header, footer and the mainframes but not about all other framesets.
0207     QList<KoShape *> shapes;
0208 
0209     if (frameSet()->type() == Words::OtherFrameSet || frameSet()->textFrameSetType() == Words::OtherTextFrameSet) {
0210         if (KoShape *s = frameSet()->shapes().value(pageNumber - 1))
0211             shapes = QList<KoShape *>() << s;
0212     } else {
0213         shapes = kwdoc->frameLayout()->sequencedShapesOn(frameSet(), pageNumber);
0214     }
0215 
0216     // position OtherFrameSet's which are anchored to this page
0217     if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
0218         foreach(KWFrameSet* fs, kwdoc->frameSets()) {
0219             KWTextFrameSet *tfs = dynamic_cast<KWTextFrameSet*>(fs);
0220             if (tfs && tfs->textFrameSetType() != Words::OtherTextFrameSet)
0221                 continue;
0222             foreach (KWFrame *frame, fs->frames()) {
0223                 KoShape *shape = frame->shape();
0224                 int anchoredPageNumber = shape->anchor() ? shape->anchor()->pageNumber() : -1;
0225                 if (anchoredPageNumber == pageNumber) {
0226                     qreal oldOffset = frame->anchoredFrameOffset();
0227                     qreal newOffset = rootAreaPage->page.offsetInDocument();
0228                     if (!qFuzzyCompare(1 + oldOffset, 1 + newOffset)) {
0229                         frame->setAnchoredFrameOffset(newOffset);
0230                         QPointF pos(shape->position().x(), newOffset - oldOffset + shape->position().y());
0231                         shape->setPosition(pos);
0232                     }
0233 
0234                     // During load we make page anchored shapes invisible, because otherwise
0235                     // they leave empty rects in the text if there is run-around
0236                     // now is the time to make them visible again
0237                     shape->setVisible(true);
0238 
0239                     QPointF delta;
0240                     KWFrameLayout::proposeShapeMove(shape, delta, rootAreaPage->page);
0241                     shape->setPosition(shape->position() + delta);
0242                }
0243             }
0244         }
0245     } else {
0246         if (!documentLayout->referencedLayout()) {
0247             KoTextDocumentLayout *reflay = dynamic_cast<KoTextDocumentLayout*>(kwdoc->frameLayout()->mainFrameSet()->document()->documentLayout());
0248             documentLayout->setReferencedLayout(reflay);
0249         }
0250     }
0251 
0252     KoShape *shape = rootAreaPage->rootAreas.count() < shapes.count() ? shapes[rootAreaPage->rootAreas.count()] : 0;
0253 
0254     KWTextLayoutRootArea *area = new KWTextLayoutRootArea(documentLayout, frameSet(), pageNumber);
0255     if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
0256         if (rootAreaPage->page.pageStyle().columns().count > 1) {
0257             area->setAcceptsColumnBreak(true);
0258         }
0259         area->setAcceptsPageBreak(true);
0260     }
0261 
0262     if (shape) { // Not every KoTextLayoutRootArea has a KoShape for display purposes.
0263         //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());
0264         KoTextShapeData *data = qobject_cast<KoTextShapeData*>(shape->userData());
0265         if (data) {
0266             data->setRootArea(area);
0267             area->setAssociatedShape(shape);
0268         } else {
0269             warnWords << "shape has no KoTextShapeData";
0270         }
0271         if ((!shape->anchor()) || shape->anchor()->anchorType() == KoShapeAnchor::AnchorPage) {
0272             area->setPage(new KWPage(rootAreaPage->page));
0273         }
0274     }
0275 
0276     if (frameSet()->type() != Words::OtherFrameSet && frameSet()->textFrameSetType() != Words::OtherTextFrameSet) {
0277         // Only header, footer and main-frames have an own KoTextPage. All other frames are embedded into them and inherit the KoTextPage from them.
0278         area->setPage(new KWPage(rootAreaPage->page));
0279         area->setLayoutEnvironmentResctictions(true, false);
0280     } else {
0281         area->setLayoutEnvironmentResctictions(true, true);
0282     }
0283 
0284     m_pageHash[area] = rootAreaPage;
0285     rootAreaPage->rootAreas.append(area);
0286 
0287     return area;
0288 }
0289 
0290 KoTextLayoutRootArea *KWRootAreaProvider::provide(KoTextDocumentLayout* documentLayout, const RootAreaConstraint& constraints, int requestedPosition, bool *isNewArea)
0291 {
0292     KWPageManager *pageManager = frameSet()->wordsDocument()->pageManager();
0293     Q_ASSERT(pageManager);
0294     if (pageManager->pageCount() == 0) // not ready yet (may happen e.g. on loading a document)
0295         return 0;
0296 
0297     QString reallyNeededPageStyle = constraints.masterPageName;
0298     int visiblePageNumber = constraints.visiblePageNumber;
0299     bool newPageForced = constraints.newPageForced;
0300     if (m_rootAreaCache.size() > requestedPosition)
0301     {
0302         KoTextLayoutRootArea *rootArea = m_rootAreaCache[requestedPosition];
0303         Q_ASSERT(rootArea);
0304 
0305         if (frameSet()->textFrameSetType() != Words::MainTextFrameSet)
0306         {
0307             // No constraints except for the main frame set
0308             *isNewArea = false;
0309             return rootArea;
0310         }
0311 
0312         KWRootAreaPage *rootAreaPage = m_pageHash.value(rootArea);
0313         Q_ASSERT(rootAreaPage);
0314 
0315         if (constraints.visiblePageNumber >= 0)
0316             rootAreaPage->page.setVisiblePageNumber(constraints.visiblePageNumber);
0317         else
0318             rootAreaPage->page.setVisiblePageNumber(0);
0319 
0320         QString reallyNeededPageStyle = constraints.masterPageName;
0321         if (reallyNeededPageStyle.isNull())
0322         {
0323             // We must work using the previous pages...
0324             if (requestedPosition == 0)
0325             {
0326                 reallyNeededPageStyle = pageManager->defaultPageStyle().name();
0327             }
0328             else
0329             {
0330                 KWRootAreaPage *previousAreaPage = m_pageHash.value(m_rootAreaCache[requestedPosition - 1]);
0331                 reallyNeededPageStyle = previousAreaPage->page.pageStyle().nextStyleName();
0332                 if (reallyNeededPageStyle.isNull())
0333                     reallyNeededPageStyle = previousAreaPage->page.pageStyle().name();
0334             }
0335         }
0336 
0337         if (rootAreaPage->page.masterPageName() != reallyNeededPageStyle)
0338         {
0339             //TODO : recycle pages in order to save us a lot of effort and reduce risks of flickering, especially with very long documents
0340             releaseAllAfter(rootArea);
0341         }
0342         else
0343         {
0344             *isNewArea = false;
0345             return rootArea;
0346         }
0347     }
0348 
0349     // We are interested in the first KoTextLayoutRootArea that has a shape associated for display
0350     // purposes. This can mean that multiple KoTextLayoutRootArea are created but only selected
0351     // ones that should be layouted and displayed are passed on to the textlayout-library.
0352     // This is only done for headers and footers cause they are continuous whereas for example
0353     // Words::OtherFrameSet and Words::OtherTextFrameSet framesets may not have the correct position
0354     // or not shape assigned at this point but later.
0355     RootAreaConstraint realConstraints;
0356     realConstraints.masterPageName = reallyNeededPageStyle;
0357     realConstraints.visiblePageNumber = visiblePageNumber;
0358     realConstraints.newPageForced = newPageForced;
0359     KoTextLayoutRootArea *area = 0;
0360     do {
0361         area = provideNext(documentLayout, realConstraints);
0362         if (m_rootAreaCache.size() <= requestedPosition)
0363             m_rootAreaCache.append(area);
0364     } while(Words::isHeaderFooter(frameSet()) && area && !area->associatedShape());
0365 
0366     Q_ASSERT(m_rootAreaCache.size() > requestedPosition);
0367 
0368     if (area == 0 && (frameSet()->textFrameSetType() != Words::MainTextFrameSet) && requestedPosition == 0)
0369         m_rootAreaCache.clear();
0370     *isNewArea = true;
0371 
0372     return area;
0373 }
0374 
0375 // afterThis==nullptr means delete everything
0376 void KWRootAreaProvider::releaseAllAfter(KoTextLayoutRootArea *afterThis)
0377 {
0378     int afterIndex = -1;
0379     if (afterThis) {
0380         if (!m_pageHash.contains(afterThis))
0381             return;
0382         KWRootAreaPage *page = m_pageHash.value(afterThis);
0383         afterIndex = m_pages.indexOf(page);
0384         Q_ASSERT(afterIndex >= 0);
0385 
0386         int newSize = m_rootAreaCache.indexOf(afterThis) + 1;
0387         while (m_rootAreaCache.size() != newSize)
0388         {
0389             KoTextLayoutRootArea *oldArea = m_rootAreaCache.takeLast();
0390             delete(oldArea);
0391         }
0392     }
0393 
0394     debugWords << "afterPageNumber=" << afterIndex+1;
0395 
0396     bool atLeastOnePageRemoved = false;
0397     KWPageManager *pageManager = frameSet()->wordsDocument()->pageManager();
0398     if (afterIndex >= 0) {
0399         for(int i = m_pages.count() - 1; i > afterIndex; --i) {
0400             KWRootAreaPage *page = m_pages.takeLast();
0401             foreach(KoTextLayoutRootArea *area, page->rootAreas)
0402                 m_pageHash.remove(area);
0403             delete page;
0404 
0405             if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
0406                 pageManager->removePage(i+1);
0407                 atLeastOnePageRemoved = true;
0408             }
0409         }
0410 
0411         // FIXME
0412         for(int i = m_dependentProviders.count() - 1; i >= 0; --i) {
0413             QPair<KWRootAreaProviderBase *, int> p = m_dependentProviders[i];
0414             if (p.second >= afterIndex)
0415                 m_dependentProviders.removeAt(i);
0416         }
0417     } else {
0418         //atLeastOnePageRemoved = !m_pages.isEmpty();
0419         qDeleteAll(m_pages);
0420         qDeleteAll(m_rootAreaCache);
0421         m_pages.clear();
0422         m_pageHash.clear();
0423         m_rootAreaCache.clear();
0424 
0425         /*FIXME that would result in flickering :-/
0426         for(int i = pageManager->pageCount(); i >= 1; --i)
0427             pageManager->removePage(i);
0428         */
0429 
0430         /*FIXME
0431         m_dependentProviders.clear();
0432         */
0433     }
0434      if (atLeastOnePageRemoved)
0435          frameSet()->wordsDocument()->firePageSetupChanged();
0436 }
0437 
0438 void KWRootAreaProvider::doPostLayout(KoTextLayoutRootArea *rootArea, bool isNewRootArea)
0439 {
0440     KWDocument *kwdoc = const_cast<KWDocument*>(frameSet()->wordsDocument());
0441     KWPageManager *pageManager = kwdoc->pageManager();
0442     Q_ASSERT(pageManager);
0443 
0444     if (frameSet()->textFrameSetType() != Words::MainTextFrameSet) {
0445         if (m_pages.count() > pageManager->pageCount()) {
0446             // we need to wait for the mainFrameSet to finish till we are able to continue
0447             KWRootAreaProvider *provider = (KWRootAreaProvider *)kwdoc->frameLayout()->mainFrameSet()->rootAreaProvider();
0448             provider->addDependentProvider(this, m_pages.count());
0449         }
0450     }
0451 
0452     KoShape *shape = rootArea->associatedShape();
0453     if (!shape)
0454         return;
0455 
0456     KWPage page = pageManager->page(shape);
0457     Q_ASSERT(page.isValid());
0458     KoTextShapeData *data = qobject_cast<KoTextShapeData*>(shape->userData());
0459     Q_ASSERT(data);
0460     bool isHeaderFooter = Words::isHeaderFooter(frameSet());
0461 
0462     debugWords << "pageNumber=" << page.pageNumber() << "frameSetType=" << Words::frameSetTypeName(frameSet()->textFrameSetType()) << "isNewRootArea=" << isNewRootArea << "rootArea=" << rootArea << "isDirty=" << rootArea->isDirty();
0463 
0464     QRectF updateRect = shape->outlineRect();
0465 
0466     QSizeF newSize = shape->size()
0467                     - QSizeF(data->leftPadding() + data->rightPadding(),
0468                              data->topPadding() + data->bottomPadding());
0469 
0470     KoBorder *border = shape->border();
0471 
0472     if (border) {
0473         newSize -= QSizeF(border->borderWidth(KoBorder::LeftBorder) + border->borderWidth(KoBorder::RightBorder), border->borderWidth(KoBorder::TopBorder) + border->borderWidth(KoBorder::BottomBorder));
0474     }
0475 
0476     if (isHeaderFooter
0477         ||data->resizeMethod() == KoTextShapeData::AutoGrowWidthAndHeight
0478         ||data->resizeMethod() == KoTextShapeData::AutoGrowHeight) {
0479 
0480         newSize.setHeight(rootArea->bottom() - rootArea->top());
0481 
0482         if (frameSet()->type() == Words::OtherFrameSet || frameSet()->textFrameSetType() == Words::OtherTextFrameSet) {
0483             // adjust size to have at least the defined minimum height
0484             Q_ASSERT(frameSet()->shapeCount() > 0);
0485             KoShape *firstShape = frameSet()->shapes().first();
0486             if (firstShape->minimumHeight() > newSize.height())
0487                 newSize.setHeight(firstShape->minimumHeight());
0488         }
0489     }
0490     if (data->resizeMethod() == KoTextShapeData::AutoGrowWidthAndHeight
0491         ||data->resizeMethod() == KoTextShapeData::AutoGrowWidth) {
0492         newSize.setWidth(rootArea->right() - rootArea->left());
0493     }
0494 
0495     // To make sure footnotes always end up at the bottom of the main area we need to set this
0496     if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
0497         rootArea->setBottom(rootArea->top() + newSize.height());
0498     }
0499 
0500     newSize += QSizeF(data->leftPadding() + data->rightPadding(),
0501                       data->topPadding() + data->bottomPadding());
0502     if (border) {
0503         newSize += QSizeF(border->borderWidth(KoBorder::LeftBorder) + border->borderWidth(KoBorder::RightBorder), border->borderWidth(KoBorder::TopBorder) + border->borderWidth(KoBorder::BottomBorder));
0504     }
0505 
0506     if (newSize != rootArea->associatedShape()->size()) {
0507         rootArea->associatedShape()->setSize(newSize);
0508 
0509         // transfer the new size to the copy-shapes
0510         foreach(KWCopyShape *cs, frameSet()->copyShapes()) {
0511             cs->setSize(newSize);
0512         }
0513 
0514         if (isHeaderFooter) {
0515             // adjust the minimum shape height for headers and footer
0516             Q_ASSERT(frameSet()->shapeCount() > 0);
0517             KoShape *firstShape = frameSet()->shapes().first();
0518             if (firstShape->minimumHeight() != newSize.height()) {
0519                 firstShape->setMinimumHeight(newSize.height());
0520 
0521                 // transfer the new minimumFrameHeight to the copy-shapes too
0522                 foreach(KWCopyShape *cs, frameSet()->copyShapes()) {
0523                     cs->setMinimumHeight(newSize.height());
0524                 }
0525                 // cause the header/footer's height changed we have to relayout the whole page
0526                 frameSet()->wordsDocument()->frameLayout()->layoutFramesOnPage(page.pageNumber());
0527             }
0528         }
0529     }
0530 
0531 
0532     updateRect |= rootArea->associatedShape()->outlineRect();
0533     rootArea->associatedShape()->update(updateRect);
0534 
0535     if (frameSet()->textFrameSetType() == Words::MainTextFrameSet) {
0536         handleDependentProviders(page.pageNumber());
0537     }
0538 
0539 }