Warning, file /office/calligra/libs/flake/KoTosContainer.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) 2010 Thomas Zander <zander@kde.org>
0003  * Copyright (C) 2010 KO GmbH <boud@kogmbh.com>
0004  * Copyright (C) 2010 Thorsten Zachmann <zachmann@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 "KoTosContainer.h"
0023 
0024 #include "KoTosContainer_p.h"
0025 #include "KoShapeRegistry.h"
0026 #include "KoShapeFactoryBase.h"
0027 #include "KoShapeLoadingContext.h"
0028 #include "KoTextShapeDataBase.h"
0029 #include "KoTosContainerModel.h"
0030 #include "KoStyleStack.h"
0031 #include "KoOdfLoadingContext.h"
0032 #include "KoXmlNS.h"
0033 #include "KoGenStyle.h"
0034 
0035 #include <FlakeDebug.h>
0036 
0037 #include <QTextCursor>
0038 #include <QTextDocument>
0039 
0040 KoTosContainerPrivate::KoTosContainerPrivate(KoShapeContainer *q)
0041     : KoShapeContainerPrivate(q)
0042     , resizeBehavior(KoTosContainer::IndependentSizes)
0043 {
0044 }
0045 
0046 KoTosContainerPrivate::~KoTosContainerPrivate()
0047 {
0048 }
0049 
0050 
0051 KoTosContainer::KoTosContainer()
0052     : KoShapeContainer(*(new KoTosContainerPrivate(this)))
0053 {
0054 }
0055 
0056 KoTosContainer::~KoTosContainer()
0057 {
0058     delete textShape();
0059 }
0060 
0061 KoTosContainer::KoTosContainer(KoTosContainerPrivate &dd)
0062     : KoShapeContainer(dd)
0063 {
0064 }
0065 
0066 void KoTosContainer::paintComponent(QPainter &, const KoViewConverter &, KoShapePaintingContext &)
0067 {
0068 }
0069 
0070 bool KoTosContainer::loadText(const KoXmlElement &element, KoShapeLoadingContext &context)
0071 {
0072     Q_D(const KoTosContainer);
0073 
0074     KoXmlElement child;
0075     forEachElement(child, element) {
0076         // only recreate the text shape if there's something to be loaded
0077         if (child.localName() == "p" || child.localName() == "list") {
0078 
0079             KoShape *textShape = createTextShape(context.documentResourceManager());
0080             if (!textShape) {
0081                 return false;
0082             }
0083             //apply the style properties to the loaded text
0084             setTextAlignment(d->alignment);
0085 
0086             // In the case of text on shape, we cannot ask the text shape to load
0087             // the odf, since it expects a complete document with style info and
0088             // everything, so we have to use the KoTextShapeData object instead.
0089             KoTextShapeDataBase *shapeData = qobject_cast<KoTextShapeDataBase*>(textShape->userData());
0090             Q_ASSERT(shapeData);
0091             shapeData->loadStyle(element, context);
0092             bool loadOdf = shapeData->loadOdf(element, context);
0093 
0094             return loadOdf;
0095         }
0096     }
0097     return true;
0098 }
0099 
0100 void KoTosContainer::loadStyle(const KoXmlElement &element, KoShapeLoadingContext &context)
0101 {
0102     Q_D(KoTosContainer);
0103 
0104     KoShapeContainer::loadStyle(element, context);
0105 
0106     KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
0107     styleStack.setTypeProperties("graphic");
0108 
0109     QString verticalAlign(styleStack.property(KoXmlNS::draw, "textarea-vertical-align"));
0110     Qt::Alignment vAlignment(Qt::AlignTop);
0111     if (verticalAlign == "bottom") {
0112         vAlignment = Qt::AlignBottom;
0113     } else if (verticalAlign == "justify") {
0114         // not yet supported
0115         vAlignment = Qt::AlignVCenter;
0116     } else if (verticalAlign == "middle") {
0117         vAlignment = Qt::AlignVCenter;
0118     }
0119 
0120     QString horizontalAlign(styleStack.property(KoXmlNS::draw, "textarea-horizontal-align"));
0121     Qt::Alignment hAlignment(Qt::AlignLeft);
0122     if (horizontalAlign == "center") {
0123         hAlignment = Qt::AlignCenter;
0124     } else if (horizontalAlign == "justify") {
0125         // not yet supported
0126         hAlignment = Qt::AlignCenter;
0127     } else if (horizontalAlign == "right") {
0128         hAlignment = Qt::AlignRight;
0129     }
0130 
0131     d->alignment = vAlignment | hAlignment;
0132 }
0133 
0134 QString KoTosContainer::saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const
0135 {
0136     Qt::Alignment alignment = textAlignment();
0137     QString verticalAlignment = "top";
0138     Qt::Alignment vAlignment(alignment & Qt::AlignVertical_Mask);
0139     if (vAlignment == Qt::AlignBottom) {
0140         verticalAlignment = "bottom";
0141     } else if (vAlignment == Qt::AlignVCenter || vAlignment == Qt::AlignCenter) {
0142         verticalAlignment = "middle";
0143     }
0144 
0145     style.addProperty("draw:textarea-vertical-align", verticalAlignment);
0146 
0147     QString horizontalAlignment = "left";
0148     Qt::Alignment hAlignment(alignment & Qt::AlignHorizontal_Mask);
0149     if (hAlignment == Qt::AlignCenter || hAlignment == Qt::AlignHCenter) {
0150         horizontalAlignment = "center";
0151     } else if (hAlignment == Qt::AlignJustify) {
0152         horizontalAlignment = "justify";
0153     } else if (hAlignment == Qt::AlignRight) {
0154         horizontalAlignment = "right";
0155     }
0156 
0157     style.addProperty("draw:textarea-horizontal-align", horizontalAlignment);
0158     // FIXME set these dependent on flags
0159     style.addProperty("draw:auto-grow-height", "false");
0160     style.addProperty("draw:auto-grow-width", "false");
0161 
0162     return KoShapeContainer::saveStyle(style, context);
0163 }
0164 
0165 void KoTosContainer::saveText(KoShapeSavingContext &context) const
0166 {
0167     KoShape *textShape = this->textShape();
0168     if (!textShape) {
0169         return;
0170     }
0171     // In the case of text on shape, we cannot ask the text shape to save
0172     // the odf, since it would save all the frame information as well, which
0173     // is wrong.
0174     // Only save the text shape if it has content.
0175     KoTextShapeDataBase *shapeData = qobject_cast<KoTextShapeDataBase*>(textShape->userData());
0176     if (shapeData && !shapeData->document()->isEmpty()) {
0177         shapeData->saveOdf(context);
0178     }
0179 }
0180 
0181 void KoTosContainer::setPlainText(const QString &text)
0182 {
0183     KoShape *textShape = this->textShape();
0184     if (textShape == 0) {
0185         warnFlake << "No text shape present in KoTosContainer";
0186         return;
0187     }
0188     KoTextShapeDataBase *shapeData = qobject_cast<KoTextShapeDataBase*>(textShape->userData());
0189     Q_ASSERT(shapeData->document());
0190     shapeData->document()->setPlainText(text);
0191 }
0192 
0193 void KoTosContainer::setResizeBehavior(ResizeBehavior resizeBehavior)
0194 {
0195     Q_D(KoTosContainer);
0196     if (d->resizeBehavior == resizeBehavior) {
0197         return;
0198     }
0199     d->resizeBehavior = resizeBehavior;
0200     if (d->model) {
0201         d->model->containerChanged(this, KoShape::SizeChanged);
0202     }
0203 }
0204 
0205 KoTosContainer::ResizeBehavior KoTosContainer::resizeBehavior() const
0206 {
0207     Q_D(const KoTosContainer);
0208     return d->resizeBehavior;
0209 }
0210 
0211 void KoTosContainer::setTextAlignment(Qt::Alignment alignment)
0212 {
0213     Q_D(KoTosContainer);
0214 
0215     KoShape *textShape = this->textShape();
0216     if (textShape == 0) {
0217         warnFlake << "No text shape present in KoTosContainer";
0218         return;
0219     }
0220 
0221     // vertical
0222     KoTextShapeDataBase *shapeData = qobject_cast<KoTextShapeDataBase*>(textShape->userData());
0223     shapeData->setVerticalAlignment(alignment);
0224 
0225     // horizontal
0226     Q_ASSERT(shapeData->document());
0227     QTextBlockFormat bf;
0228     bf.setAlignment(alignment & Qt::AlignHorizontal_Mask);
0229 
0230     QTextCursor cursor(shapeData->document());
0231     cursor.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
0232     cursor.mergeBlockFormat(bf);
0233 
0234     d->alignment = alignment;
0235 }
0236 
0237 Qt::Alignment KoTosContainer::textAlignment() const
0238 {
0239     KoShape *textShape = this->textShape();
0240     if (textShape == 0) {
0241         warnFlake << "No text shape present in KoTosContainer";
0242         return Qt::AlignTop;
0243     }
0244 
0245     // vertical
0246     KoTextShapeDataBase *shapeData = qobject_cast<KoTextShapeDataBase*>(textShape->userData());
0247     // the model makes sure it contains a shape that has a KoTextShapeDataBase set so no need to check that
0248     Qt::Alignment answer = shapeData->verticalAlignment() & Qt::AlignVertical_Mask;
0249 
0250     // horizontal
0251     Q_ASSERT(shapeData->document());
0252     QTextCursor cursor(shapeData->document());
0253     answer = answer | (cursor.blockFormat().alignment() & Qt::AlignHorizontal_Mask);
0254 
0255     return answer;
0256 }
0257 
0258 void KoTosContainer::setPreferredTextRect(const QRectF &rect)
0259 {
0260     Q_D(KoTosContainer);
0261     d->preferredTextRect = rect;
0262     KoShape *textShape = this->textShape();
0263     //debugFlake << rect << textShape << d->resizeBehavior;
0264     if (d->resizeBehavior == TextFollowsPreferredTextRect && textShape) {
0265         //debugFlake << rect;
0266         textShape->setPosition(rect.topLeft());
0267         textShape->setSize(rect.size());
0268     }
0269 }
0270 
0271 QRectF KoTosContainer::preferredTextRect() const
0272 {
0273     Q_D(const KoTosContainer);
0274     return d->preferredTextRect;
0275 }
0276 
0277 KoShape *KoTosContainer::createTextShape(KoDocumentResourceManager *documentResources)
0278 {
0279     if (!documentResources) {
0280         warnFlake << "KoDocumentResourceManager not found";
0281         return 0;
0282     }
0283 
0284     Q_D(KoTosContainer);
0285 
0286     delete textShape();
0287     delete d->model;
0288 
0289     d->model = new KoTosContainerModel();
0290 
0291     QSet<KoShape*> delegates;
0292     delegates << this;
0293     KoShape *textShape = 0;
0294     KoShapeFactoryBase *factory = KoShapeRegistry::instance()->get("TextShapeID");
0295     if (factory) { // not installed, thats too bad, but allowed
0296         textShape = factory->createDefaultShape(documentResources);
0297         Q_ASSERT(textShape); // would be a bug in the text shape;
0298         if (d->resizeBehavior == TextFollowsPreferredTextRect) {
0299             textShape->setSize(d->preferredTextRect.size());
0300         } else {
0301             textShape->setSize(size());
0302         }
0303         if (d->resizeBehavior == TextFollowsPreferredTextRect) {
0304             textShape->setPosition(d->preferredTextRect.topLeft());
0305         } else {
0306             textShape->setPosition(QPointF(0, 0));
0307         }
0308         textShape->setSelectable(false);
0309         textShape->setRunThrough(runThrough());
0310         KoTextShapeDataBase *shapeData = qobject_cast<KoTextShapeDataBase*>(textShape->userData());
0311         Q_ASSERT(shapeData); // would be a bug in kotext
0312         // TODO check if that is correct depending on the resize mode
0313         shapeData->setVerticalAlignment(Qt::AlignVCenter);
0314         addShape(textShape);
0315         // textShape->setZIndex(zIndex() + 1); // not needed as there as the text shape is the only sub shape
0316         delegates << textShape;
0317     } else {
0318         warnFlake << "Text shape factory not found";
0319     }
0320     setToolDelegates(delegates);
0321     return textShape;
0322 }
0323 
0324 KoShape *KoTosContainer::textShape() const
0325 {
0326     const QList<KoShape*> subShapes = shapes();
0327     return subShapes.isEmpty() ? 0 : subShapes.at(0);
0328 }
0329 
0330 void KoTosContainer::shapeChanged(ChangeType type, KoShape *shape)
0331 {
0332     Q_UNUSED(shape);
0333     Q_D(KoTosContainer);
0334     if (d->model == 0) {
0335         return;
0336     }
0337 
0338     if (type == SizeChanged || type == ContentChanged) {
0339         d->model->containerChanged(this, type);
0340     }
0341     // TODO is this needed?
0342 #if 0
0343     foreach(KoShape *shape, d->model->shapes())
0344         shape->notifyChanged();
0345 #endif
0346 }
0347 
0348 void KoTosContainer::setRunThrough(short int runThrough)
0349 {
0350     KoShape::setRunThrough(runThrough);
0351     KoShape *textShape = this->textShape();
0352     if (textShape) {
0353         textShape->setRunThrough(runThrough);
0354     }
0355 }