File indexing completed on 2024-05-12 16:34:58

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2010 Thomas Zander <zander@kde.org>
0003  * Copyright (C) 2010 Sebastian Sauer <sebsauer@kdab.com>
0004  *
0005  * This library is free software; you can redistribute it and/or
0006  * modify it under the terms of the GNU Library General Public
0007  * License as published by the Free Software Foundation; either
0008  * version 2 of the License, or (at your option) any later version.
0009  *
0010  * This library is distributed in the hope that it will be useful,
0011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0013  * Library General Public License for more details.
0014  *
0015  * You should have received a copy of the GNU Library General Public License
0016  * along with this library; see the file COPYING.LIB.  If not, write to
0017  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0018  * Boston, MA 02110-1301, USA.
0019  */
0020 
0021 #include "ShrinkToFitShapeContainer.h"
0022 
0023 #include <KoShapeSavingContext.h>
0024 #include <KoTextLayoutRootArea.h>
0025 
0026 ShrinkToFitShapeContainer::ShrinkToFitShapeContainer(KoShape *childShape, KoDocumentResourceManager *documentResources)
0027     : KoShapeContainer(*(new ShrinkToFitShapeContainerPrivate(this, childShape)))
0028 {
0029     Q_UNUSED(documentResources);
0030     Q_D(ShrinkToFitShapeContainer);
0031 
0032     setPosition(childShape->position());
0033     setSize(childShape->size());
0034     setZIndex(childShape->zIndex());
0035     setRunThrough(childShape->runThrough());
0036     rotate(childShape->rotation());
0037     //setTransformation(childShape->transformation());
0038 
0039     if (childShape->parent()) {
0040         childShape->parent()->addShape(this);
0041         childShape->setParent(0);
0042     }
0043 
0044     childShape->setPosition(QPointF(0.0,0.0)); // since its relative to my position, this won't move it
0045     childShape->setSelectable(false); // our ShrinkToFitShapeContainer will handle that from now on
0046 
0047     d->model = new ShrinkToFitShapeContainerModel(this, d);
0048     addShape(childShape);
0049 
0050     QSet<KoShape*> delegates;
0051     delegates << childShape;
0052     setToolDelegates(delegates);
0053 
0054     KoTextShapeData* data = dynamic_cast<KoTextShapeData*>(childShape->userData());
0055     Q_ASSERT(data);
0056     KoTextDocumentLayout *lay = qobject_cast<KoTextDocumentLayout*>(data->document()->documentLayout());
0057     Q_ASSERT(lay);
0058     QObject::connect(lay, SIGNAL(finishedLayout()), static_cast<ShrinkToFitShapeContainerModel*>(d->model), SLOT(finishedLayout()));
0059 }
0060 
0061 ShrinkToFitShapeContainer::~ShrinkToFitShapeContainer()
0062 {
0063 }
0064 
0065 void ShrinkToFitShapeContainer::paintComponent(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &)
0066 {
0067     Q_UNUSED(painter);
0068     Q_UNUSED(converter);
0069     //painter.fillRect(converter.documentToView(QRectF(QPointF(0,0),size())), QBrush(QColor("#ffcccc"))); // for testing
0070 }
0071 
0072 bool ShrinkToFitShapeContainer::loadOdf(const KoXmlElement &element, KoShapeLoadingContext &context)
0073 {
0074     Q_UNUSED(element);
0075     Q_UNUSED(context);
0076     return true;
0077 }
0078 
0079 void ShrinkToFitShapeContainer::saveOdf(KoShapeSavingContext &context) const
0080 {
0081     Q_D(const ShrinkToFitShapeContainer);
0082     d->childShape->saveOdf(context);
0083 }
0084 
0085 ShrinkToFitShapeContainer* ShrinkToFitShapeContainer::wrapShape(KoShape *shape, KoDocumentResourceManager *documentResourceManager)
0086 {
0087     Q_ASSERT(dynamic_cast<KoTextShapeData*>(shape->userData()));
0088     Q_ASSERT(qobject_cast<KoTextDocumentLayout*>(dynamic_cast<KoTextShapeData*>(shape->userData())->document()->documentLayout()));
0089 
0090     return new ShrinkToFitShapeContainer(shape, documentResourceManager);
0091 }
0092 
0093 void ShrinkToFitShapeContainer::tryWrapShape(KoShape *shape, const KoXmlElement &element, KoShapeLoadingContext &context)
0094 {
0095     KoTextShapeData* data = dynamic_cast<KoTextShapeData*>(shape->userData());
0096     if (!data || data->resizeMethod() != KoTextShapeData::ShrinkToFitResize)
0097         return;
0098 
0099     KoShapeContainer *oldParent = shape->parent();
0100     ShrinkToFitShapeContainer *tos = wrapShape(shape, context.documentResourceManager());
0101     if (!tos->loadOdf(element, context)) {
0102         shape->setParent(oldParent);
0103         delete tos;
0104     }
0105 }
0106 
0107 void ShrinkToFitShapeContainer::unwrapShape(KoShape *shape)
0108 {
0109     Q_ASSERT(shape->parent() == this);
0110 
0111     removeShape(shape);
0112     shape->setParent(parent());
0113 
0114     QSet<KoShape*> delegates = toolDelegates();
0115     delegates.remove(shape);
0116     setToolDelegates(delegates);
0117 
0118     shape->setPosition(position());
0119     shape->setSize(size());
0120     shape->rotate(rotation());
0121     shape->setSelectable(true);
0122 }
0123 
0124 ShrinkToFitShapeContainerModel::ShrinkToFitShapeContainerModel(ShrinkToFitShapeContainer *q, ShrinkToFitShapeContainerPrivate *d)
0125     : q(q)
0126     , d(d)
0127     , m_scale(1.0)
0128     , m_dirty(10)
0129     , m_maybeUpdate(false)
0130 {
0131 }
0132 
0133 void ShrinkToFitShapeContainerModel::finishedLayout()
0134 {
0135     m_maybeUpdate = true;
0136     containerChanged(q, KoShape::SizeChanged);
0137     m_maybeUpdate = false;
0138 }
0139 
0140 void ShrinkToFitShapeContainerModel::containerChanged(KoShapeContainer *container, KoShape::ChangeType type)
0141 {
0142     Q_ASSERT(container == q); Q_UNUSED(container);
0143     if (type == KoShape::SizeChanged) {
0144         KoTextShapeData* data = dynamic_cast<KoTextShapeData*>(d->childShape->userData());
0145         Q_ASSERT(data);
0146         KoTextLayoutRootArea *rootArea = data->rootArea();
0147         Q_ASSERT(rootArea);
0148 
0149         QSizeF shapeSize = q->size();
0150         QSizeF documentSize = rootArea->boundingRect().size();
0151         if (m_maybeUpdate &&shapeSize == m_shapeSize && documentSize == m_documentSize) {
0152             m_dirty = 0;
0153             return; // nothing to update
0154         }
0155 
0156         m_shapeSize = shapeSize;
0157         m_documentSize = documentSize;
0158 
0159         if ( documentSize.width() > 0.0 && documentSize.height() > 0.0 ) {
0160             if (m_dirty || !m_maybeUpdate) {
0161                 qreal scaleX = qMin<qreal>(1.0, shapeSize.width() / documentSize.width());
0162                 qreal scaleY = qMin<qreal>(1.0, shapeSize.height() / documentSize.height());
0163                 m_scale = (scaleX+scaleY)/2.0 * 0.95;
0164                 if (m_maybeUpdate && m_dirty)
0165                     --m_dirty;
0166             }
0167         } else {
0168             m_scale = 1.0;
0169             m_dirty = 1;
0170         }
0171 
0172         QSizeF newSize(shapeSize.width() / m_scale, shapeSize.height() / m_scale);
0173         d->childShape->setSize(newSize);
0174 
0175         QTransform m;
0176         m.scale(m_scale, m_scale);
0177         d->childShape->setTransformation(m);
0178     }
0179 }
0180 
0181 bool ShrinkToFitShapeContainerModel::inheritsTransform(const KoShape *child) const
0182 {
0183     Q_ASSERT(child == d->childShape); Q_UNUSED(child);
0184     return true;
0185 }
0186 
0187 bool ShrinkToFitShapeContainerModel::isChildLocked(const KoShape *child) const
0188 {
0189     Q_ASSERT(child == d->childShape); Q_UNUSED(child);
0190     return true;
0191 }
0192 
0193 bool ShrinkToFitShapeContainerModel::isClipped(const KoShape *child) const
0194 {
0195     Q_ASSERT(child == d->childShape); Q_UNUSED(child);
0196     return false;
0197 }