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 "KWRootAreaProviderBase.h"
0023 #include "KWPageManager.h"
0024 #include "KWDocument.h"
0025 #include "KWView.h"
0026 #include "frames/KWTextFrameSet.h"
0027 #include "frames/KWCopyShape.h"
0028 
0029 #include <KoTextLayoutRootArea.h>
0030 #include <KoShape.h>
0031 #include <KoShapeContainer.h>
0032 #include <KoShapeFactoryBase.h>
0033 #include <KoTextShapeData.h>
0034 #include <KoTextDocumentLayout.h>
0035 #include <KoTextLayoutObstruction.h>
0036 #include <KoShapeAnchor.h>
0037 
0038 
0039 KWRootAreaProviderBase::KWRootAreaProviderBase(KWTextFrameSet *textFrameSet)
0040     : KoTextLayoutRootAreaProvider()
0041     , m_textFrameSet(textFrameSet)
0042 {
0043 }
0044 
0045 void KWRootAreaProviderBase::doPostLayout(KoTextLayoutRootArea *rootArea, bool /*isNewRootArea*/)
0046 {
0047     KoShape *shape = rootArea->associatedShape();
0048     if (!shape) {
0049         return;
0050     }
0051 
0052     KoTextShapeData *data = qobject_cast<KoTextShapeData*>(shape->userData());
0053     Q_ASSERT(data);
0054 
0055     QRectF updateRect = shape->outlineRect();
0056 
0057     QSizeF newSize = shape->size()
0058                     - QSizeF(data->leftPadding() + data->rightPadding(),
0059                              data->topPadding() + data->bottomPadding());
0060 
0061     KoBorder *border = shape->border();
0062 
0063     if (border) {
0064         newSize -= QSizeF(border->borderWidth(KoBorder::LeftBorder) + border->borderWidth(KoBorder::RightBorder), border->borderWidth(KoBorder::TopBorder) + border->borderWidth(KoBorder::BottomBorder));
0065     }
0066 
0067     if (data->resizeMethod() == KoTextShapeData::AutoGrowWidthAndHeight
0068         ||data->resizeMethod() == KoTextShapeData::AutoGrowHeight) {
0069 
0070         newSize.setHeight(rootArea->bottom() - rootArea->top());
0071 
0072         // adjust size to have at least the defined minimum height
0073         Q_ASSERT(frameSet()->shapeCount() > 0);
0074         KoShape *firstShape = frameSet()->shapes().first();
0075         if (firstShape->minimumHeight() > newSize.height())
0076             newSize.setHeight(firstShape->minimumHeight());
0077     }
0078     if (data->resizeMethod() == KoTextShapeData::AutoGrowWidthAndHeight
0079         ||data->resizeMethod() == KoTextShapeData::AutoGrowWidth) {
0080         newSize.setWidth(rootArea->right() - rootArea->left());
0081     }
0082 
0083     newSize += QSizeF(data->leftPadding() + data->rightPadding(),
0084                       data->topPadding() + data->bottomPadding());
0085     if (border) {
0086         newSize += QSizeF(border->borderWidth(KoBorder::LeftBorder) + border->borderWidth(KoBorder::RightBorder), border->borderWidth(KoBorder::TopBorder) + border->borderWidth(KoBorder::BottomBorder));
0087     }
0088 
0089     if (newSize != rootArea->associatedShape()->size()) {
0090         rootArea->associatedShape()->setSize(newSize);
0091 
0092         // transfer the new size to the copy-shapes
0093         foreach(KWCopyShape *cs, frameSet()->copyShapes()) {
0094             cs->setSize(newSize);
0095         }
0096     }
0097 
0098     updateRect |= rootArea->associatedShape()->outlineRect();
0099     rootArea->associatedShape()->update(updateRect);
0100 }
0101 
0102 void KWRootAreaProviderBase::updateAll()
0103 {
0104     foreach (KoShape *shape, frameSet()->shapes()) {
0105         shape->update();
0106     }
0107 }
0108 
0109 QRectF KWRootAreaProviderBase::suggestRect(KoTextLayoutRootArea *rootArea)
0110 {
0111     KoShape *shape = rootArea->associatedShape();
0112     if (!shape) { // no shape => nothing to draw => no space needed
0113         return QRectF(0., 0., 0.,0.);
0114     }
0115 
0116     KoTextShapeData *data = qobject_cast<KoTextShapeData*>(shape->userData());
0117     Q_ASSERT(data);
0118 
0119     QRectF rect(QPointF(), shape->size());
0120     rect.adjust(data->leftPadding(), data->topPadding(), -data->rightPadding(), - data->bottomPadding());
0121 
0122     KoBorder *border = shape->border();
0123     if (border) {
0124         rect.adjust(border->borderWidth(KoBorder::LeftBorder),  border->borderWidth(KoBorder::TopBorder),
0125               -border->borderWidth(KoBorder::RightBorder), - border->borderWidth(KoBorder::BottomBorder));
0126     }
0127 
0128     rect.setWidth(qMax(rect.width(), qreal(1.0)));
0129     rect.setHeight(qMax(rect.height(), qreal(1.0)));
0130     if (data->resizeMethod() == KoTextShapeData::AutoGrowWidthAndHeight || data->resizeMethod() == KoTextShapeData::AutoGrowHeight) {
0131         rect.setHeight(1E6);
0132     }
0133 
0134     if (data->resizeMethod() == KoTextShapeData::AutoGrowWidthAndHeight
0135         || data->resizeMethod() == KoTextShapeData::AutoGrowWidth) {
0136         // By setting this we make sure the textlayout librar does 2 internal runs. Once to
0137         // figure out how much width is needed, second to do a normal layout using that calculated width
0138         rootArea->setNoWrap(1E6);
0139     }
0140 
0141     return rect;
0142 }
0143 
0144 QList<KoTextLayoutObstruction *> KWRootAreaProviderBase::relevantObstructions(KoTextLayoutRootArea *rootArea)
0145 {
0146     QList<KoTextLayoutObstruction*> obstructions;
0147     Q_ASSERT(rootArea);
0148 
0149     KoShape *currentShape = rootArea->associatedShape();
0150 
0151     if(!currentShape) {
0152         return obstructions;
0153     }
0154 
0155     // let's convert into canvas/KWDocument coords
0156     QRectF rect = currentShape->boundingRect();
0157 
0158     //TODO would probably be faster if we could use the RTree of the shape manager
0159     foreach (KWFrameSet *fs, frameSet()->wordsDocument()->frameSets()) {
0160         if (fs  == frameSet()) {
0161             continue; // we don't collide with ourselves
0162         }
0163 
0164         if (KWTextFrameSet *tfs = dynamic_cast<KWTextFrameSet*>(fs)) {
0165             if (tfs->textFrameSetType() != Words::OtherTextFrameSet) {
0166                 continue; // we don't collide with headers, footers and main-text.
0167             }
0168         }
0169 
0170         foreach (KoShape *shape, fs->shapes()) {
0171             if (shape == currentShape) {
0172                 continue;
0173             }
0174             if (! shape->isVisible(true)) {
0175                 continue;
0176             }
0177             if (shape->anchor() && shape->anchor()->anchorType() != KoShapeAnchor::AnchorPage) {
0178                 continue;
0179             }
0180             if (shape->textRunAroundSide() == KoShape::RunThrough) {
0181                 continue;
0182             }
0183             if (shape->zIndex() <= currentShape->zIndex()) {
0184                 continue;
0185             }
0186             if (! rect.intersects(shape->boundingRect())) {
0187                 continue;
0188             }
0189             bool isChild = false;
0190             KoShape *parent = shape->parent();
0191             while (parent && !isChild) {
0192                 if (parent == currentShape) {
0193                     isChild = true;
0194                 }
0195                 parent = parent->parent();
0196             }
0197             if (isChild) {
0198                 continue;
0199             }
0200             QTransform matrix = shape->absoluteTransformation(0);
0201             matrix = matrix * currentShape->absoluteTransformation(0).inverted();
0202             matrix.translate(0, rootArea->top());
0203             KoTextLayoutObstruction *obstruction = new KoTextLayoutObstruction(shape, matrix);
0204             obstructions.append(obstruction);
0205         }
0206     }
0207 
0208     return obstructions;
0209 }