Warning, file /office/calligra/libs/textlayout/KoTextShapeData.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2006, 2009-2010 Thomas Zander <zander@kde.org>
0003  * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
0004  * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
0005  * Copyright (C) 2011 C. Boemann <cbo@boemann.dk>
0006  *
0007  * This library is free software; you can redistribute it and/or
0008  * modify it under the terms of the GNU Library General Public
0009  * License as published by the Free Software Foundation; either
0010  * version 2 of the License, or (at your option) any later version.
0011  *
0012  * This library is distributed in the hope that it will be useful,
0013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015  * Library General Public License for more details.
0016  *
0017  * You should have received a copy of the GNU Library General Public License
0018  * along with this library; see the file COPYING.LIB.  If not, write to
0019  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0020  * Boston, MA 02110-1301, USA.
0021  */
0022 
0023 #include "KoTextShapeData.h"
0024 
0025 #include <KoTextShapeDataBase.h>
0026 #include <KoTextShapeDataBase_p.h>
0027 #include "KoTextDocument.h"
0028 #include <KoTextEditor.h>
0029 #include "styles/KoStyleManager.h"
0030 #include "styles/KoParagraphStyle.h"
0031 
0032 #include <KoTextLayoutRootArea.h>
0033 
0034 #include <QTextDocument>
0035 #include <QTextBlock>
0036 #include <QTextCursor>
0037 
0038 #include <KoGenStyle.h>
0039 #include <KoOdfLoadingContext.h>
0040 #include <KoShapeLoadingContext.h>
0041 #include <KoShapeSavingContext.h>
0042 #include <KoDocumentRdfBase.h>
0043 #include <KoStyleStack.h>
0044 #include <KoShape.h>
0045 #include <KoUnit.h>
0046 
0047 #include <KoXmlNS.h>
0048 
0049 #include "KoTextPage.h"
0050 
0051 #include "opendocument/KoTextLoader.h"
0052 #include "opendocument/KoTextWriter.h"
0053 
0054 #include <TextLayoutDebug.h>
0055 
0056 class KoTextShapeDataPrivate : public KoTextShapeDataBasePrivate
0057 {
0058 public:
0059     KoTextShapeDataPrivate()
0060             : ownsDocument(true)
0061             , topPadding(0)
0062             , leftPadding(0)
0063             , rightPadding(0)
0064             , bottomPadding(0)
0065             , direction(KoText::AutoDirection)
0066             , textpage(0)
0067             , rootArea(0)
0068             , paragraphStyle(0)
0069     {
0070     }
0071 
0072     ~KoTextShapeDataPrivate() override
0073     {
0074         if (ownsDocument) {
0075             delete document;
0076         }
0077         delete textpage;
0078         delete paragraphStyle;
0079     }
0080 
0081     bool ownsDocument;
0082     qreal topPadding;
0083     qreal leftPadding;
0084     qreal rightPadding;
0085     qreal bottomPadding;
0086     KoText::Direction direction;
0087     KoTextPage *textpage;
0088     KoTextLayoutRootArea *rootArea;
0089     KoParagraphStyle *paragraphStyle; // the paragraph style of the shape (part of the graphic style)
0090 };
0091 
0092 
0093 KoTextShapeData::KoTextShapeData()
0094     : KoTextShapeDataBase(*(new KoTextShapeDataPrivate()))
0095 {
0096     setDocument(new QTextDocument, true);
0097 }
0098 
0099 KoTextShapeData::~KoTextShapeData()
0100 {
0101 }
0102 
0103 void KoTextShapeData::setDocument(QTextDocument *document, bool transferOwnership)
0104 {
0105     Q_D(KoTextShapeData);
0106     Q_ASSERT(document);
0107     if (d->ownsDocument && document != d->document) {
0108         delete d->document;
0109     }
0110     d->ownsDocument = transferOwnership;
0111 
0112     // The following avoids the normal case where the glyph metrices are rounded to integers and
0113     // hinted to the screen by freetype, which you of course don't want for WYSIWYG
0114     if (! document->useDesignMetrics())
0115         document->setUseDesignMetrics(true);
0116 
0117     KoTextDocument kodoc(document);
0118 
0119     if (document->isEmpty() && !document->firstBlock().blockFormat().hasProperty(KoParagraphStyle::StyleId)) { // apply app default style for first parag
0120         KoStyleManager *sm = kodoc.styleManager();
0121         if (sm) {
0122             KoParagraphStyle *defaultStyle = sm->defaultParagraphStyle();
0123             if (defaultStyle) {
0124                 QTextBlock block = document->begin();
0125                 defaultStyle->applyStyle(block);
0126             }
0127         }
0128     }
0129 
0130     // After setting the document (even if not changing it) we need to explicitly set the root area
0131     // to 0. Otherwise crashes may occur when inserting textshape in words (or resetting document)
0132     d->rootArea = 0;
0133 
0134     if (d->document == document)
0135         return;
0136     d->document = document;
0137 
0138     if (kodoc.textEditor() == 0)
0139         kodoc.setTextEditor(new KoTextEditor(d->document));
0140 }
0141 
0142 qreal KoTextShapeData::documentOffset() const
0143 {
0144     Q_D(const KoTextShapeData);
0145     if (d->rootArea) {
0146         KoBorder *border = d->rootArea->associatedShape()->border();
0147         if (border) {
0148             return d->rootArea->top() - topPadding() - border->borderWidth(KoBorder::TopBorder);
0149         } else {
0150             return d->rootArea->top() - topPadding();
0151         }
0152     } else {
0153         return 0.0;
0154     }
0155 }
0156 
0157 void KoTextShapeData::setDirty()
0158 {
0159     Q_D(KoTextShapeData);
0160     if (d->rootArea) {
0161         d->rootArea->setDirty();
0162     }
0163 }
0164 
0165 
0166 bool KoTextShapeData::isDirty() const
0167 {
0168     Q_D(const KoTextShapeData);
0169     if (d->rootArea) {
0170         return d->rootArea->isDirty();
0171     }
0172     return true;
0173 }
0174 
0175 void KoTextShapeData::setPageDirection(KoText::Direction direction)
0176 {
0177     Q_D(KoTextShapeData);
0178     d->direction = direction;
0179 }
0180 
0181 KoText::Direction KoTextShapeData::pageDirection() const
0182 {
0183     Q_D(const KoTextShapeData);
0184     return d->direction;
0185 }
0186 
0187 void KoTextShapeData::setRootArea(KoTextLayoutRootArea *rootArea)
0188 {
0189     Q_D(KoTextShapeData);
0190     d->rootArea = rootArea;
0191 }
0192 
0193 KoTextLayoutRootArea *KoTextShapeData::rootArea()
0194 {
0195     Q_D(const KoTextShapeData);
0196     return d->rootArea;
0197 }
0198 
0199 void KoTextShapeData::setLeftPadding(qreal padding)
0200 {
0201     Q_D(KoTextShapeData);
0202     d->leftPadding = padding;
0203 }
0204 
0205 qreal KoTextShapeData::leftPadding() const
0206 {
0207     Q_D(const KoTextShapeData);
0208     return d->leftPadding;
0209 }
0210 
0211 void KoTextShapeData::setTopPadding(qreal padding)
0212 {
0213     Q_D(KoTextShapeData);
0214     d->topPadding = padding;
0215 }
0216 
0217 qreal KoTextShapeData::topPadding() const
0218 {
0219     Q_D(const KoTextShapeData);
0220     return d->topPadding;
0221 }
0222 
0223 void KoTextShapeData::setRightPadding(qreal padding)
0224 {
0225     Q_D(KoTextShapeData);
0226     d->rightPadding = padding;
0227 }
0228 
0229 qreal KoTextShapeData::rightPadding() const
0230 {
0231     Q_D(const KoTextShapeData);
0232     return d->rightPadding;
0233 }
0234 
0235 void KoTextShapeData::setBottomPadding(qreal padding)
0236 {
0237     Q_D(KoTextShapeData);
0238     d->bottomPadding = padding;
0239 }
0240 
0241 qreal KoTextShapeData::bottomPadding() const
0242 {
0243     Q_D(const KoTextShapeData);
0244     return d->bottomPadding;
0245 }
0246 
0247 void KoTextShapeData::setPadding(qreal padding)
0248 {
0249     setLeftPadding(padding);
0250     setTopPadding(padding);
0251     setRightPadding(padding);
0252     setBottomPadding(padding);
0253 }
0254 
0255 bool KoTextShapeData::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context, KoDocumentRdfBase *rdfData, KoShape *shape)
0256 {
0257     Q_UNUSED(rdfData);
0258     KoTextLoader loader(context, shape);
0259 
0260     QTextCursor cursor(document());
0261     loader.loadBody(element, cursor);   // now let's load the body from the ODF KoXmlElement.
0262     KoTextEditor *editor = KoTextDocument(document()).textEditor();
0263     if (editor) { // at one point we have to get the position from the odf doc instead.
0264         editor->setPosition(0);
0265     }
0266 
0267     return true;
0268 }
0269 
0270 void KoTextShapeData::saveOdf(KoShapeSavingContext &context, KoDocumentRdfBase *rdfData, int from, int to) const
0271 {
0272     Q_D(const KoTextShapeData);
0273 
0274     KoTextWriter::saveOdf(context, rdfData, d->document, from, to);
0275 }
0276 
0277 void KoTextShapeData::loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context)
0278 {
0279     Q_D(KoTextShapeData);
0280     // load the (text) style of the frame
0281     const KoXmlElement *style = 0;
0282     if (element.hasAttributeNS(KoXmlNS::draw, "style-name")) {
0283         style = context.odfLoadingContext().stylesReader().findStyle(
0284                     element.attributeNS(KoXmlNS::draw, "style-name"), "graphic",
0285                     context.odfLoadingContext().useStylesAutoStyles());
0286         if (!style) {
0287             warnTextLayout << "graphic style not found:" << element.attributeNS(KoXmlNS::draw, "style-name");
0288         }
0289     }
0290     if (element.hasAttributeNS(KoXmlNS::presentation, "style-name")) {
0291         style = context.odfLoadingContext().stylesReader().findStyle(
0292                     element.attributeNS(KoXmlNS::presentation, "style-name"), "presentation",
0293                     context.odfLoadingContext().useStylesAutoStyles());
0294         if (!style) {
0295             warnTextLayout << "presentation style not found:" << element.attributeNS(KoXmlNS::presentation, "style-name");
0296         }
0297     }
0298 
0299 
0300     if (style) {
0301         KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
0302         styleStack.save();
0303         context.odfLoadingContext().addStyles(style, style->attributeNS(KoXmlNS::style, "family", "graphic").toLocal8Bit().constData());   // Load all parents
0304         styleStack.setTypeProperties("graphic");
0305         // Spacing (padding)
0306         const QString paddingLeft(styleStack.property(KoXmlNS::fo, "padding-left" ));
0307         if (!paddingLeft.isEmpty()) {
0308             setLeftPadding(KoUnit::parseValue(paddingLeft));
0309         }
0310         const QString paddingRight(styleStack.property(KoXmlNS::fo, "padding-right" ));
0311         if (!paddingRight.isEmpty()) {
0312             setRightPadding(KoUnit::parseValue(paddingRight));
0313         }
0314         const QString paddingTop(styleStack.property(KoXmlNS::fo, "padding-top" ));
0315         if (!paddingTop.isEmpty()) {
0316             setTopPadding(KoUnit::parseValue(paddingTop));
0317         }
0318         const QString paddingBottom(styleStack.property(KoXmlNS::fo, "padding-bottom" ));
0319         if (!paddingBottom.isEmpty()) {
0320             setBottomPadding(KoUnit::parseValue(paddingBottom));
0321         }
0322         const QString padding(styleStack.property(KoXmlNS::fo, "padding"));
0323         if (!padding.isEmpty()) {
0324             setPadding(KoUnit::parseValue(padding));
0325         }
0326         styleStack.restore();
0327 
0328         QString family = style->attributeNS(KoXmlNS::style, "family", "graphic");
0329         KoParagraphStyle *defaultStyle = 0;
0330         const KoXmlElement *dstyle = context.odfLoadingContext().stylesReader().defaultStyle(family);
0331         if (dstyle) {
0332             defaultStyle = new KoParagraphStyle();
0333             defaultStyle->loadOdf(dstyle, context);
0334         }
0335         // graphic styles don't support inheritance yet therefor some additional work is needed here.
0336         QList<KoParagraphStyle *> paragraphStyles;
0337         while (style) {
0338             KoParagraphStyle *pStyle = new KoParagraphStyle();
0339             pStyle->loadOdf(style, context);
0340             if (!paragraphStyles.isEmpty()) {
0341                 paragraphStyles.last()->setParentStyle(pStyle);
0342             }
0343             paragraphStyles.append(pStyle);
0344             QString family = style->attributeNS(KoXmlNS::style, "family", "graphic");
0345             style = context.odfLoadingContext().stylesReader().findStyle(
0346                     style->attributeNS(KoXmlNS::style, "parent-style-name"), family.toLocal8Bit().constData(),
0347                     context.odfLoadingContext().useStylesAutoStyles());
0348         }
0349         // rather than setting default style and apply to block we just set a final parent
0350         paragraphStyles.last()->setParentStyle(defaultStyle);
0351 
0352         QTextDocument *document = this->document();
0353         QTextCursor cursor(document);
0354         QTextBlockFormat format;
0355         paragraphStyles.first()->applyStyle(format);
0356         cursor.setBlockFormat(format);
0357         QTextCharFormat cformat;
0358         paragraphStyles.first()->KoCharacterStyle::applyStyle(cformat);
0359         cursor.setCharFormat(cformat);
0360         cursor.setBlockCharFormat(cformat);
0361 
0362         d->paragraphStyle = new KoParagraphStyle(format, cformat);
0363         qDeleteAll(paragraphStyles);
0364         delete defaultStyle;
0365     }
0366 }
0367 
0368 void KoTextShapeData::saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const
0369 {
0370     if ((leftPadding() == rightPadding()) && (topPadding() == bottomPadding()) && (rightPadding() == topPadding())) {
0371         style.addPropertyPt("fo:padding", leftPadding(), KoGenStyle::GraphicType);
0372     } else {
0373         if (leftPadding()) {
0374             style.addPropertyPt("fo:padding-left", leftPadding(), KoGenStyle::GraphicType);
0375         }
0376         if (rightPadding()) {
0377             style.addPropertyPt("fo:padding-right", rightPadding(), KoGenStyle::GraphicType);
0378         }
0379         if (topPadding()) {
0380             style.addPropertyPt("fo:padding-top", topPadding(), KoGenStyle::GraphicType);
0381         }
0382         if (bottomPadding()) {
0383             style.addPropertyPt("fo:padding-bottom", bottomPadding(), KoGenStyle::GraphicType);
0384         }
0385     }
0386 
0387     Q_D(const KoTextShapeData);
0388     if (d->paragraphStyle) {
0389         d->paragraphStyle->saveOdf(style, context);
0390     }
0391 }