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 }