Warning, file /office/calligra/libs/flake/KoShapeGroup.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 Thomas Zander <zander@kde.org>
0003  * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
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 "KoShapeGroup.h"
0022 #include "KoShapeContainerModel.h"
0023 #include "KoShapeContainer_p.h"
0024 #include "KoShapeLayer.h"
0025 #include "SimpleShapeContainerModel.h"
0026 #include "KoShapeSavingContext.h"
0027 #include "KoShapeLoadingContext.h"
0028 #include "KoXmlWriter.h"
0029 #include "KoXmlReader.h"
0030 #include "KoShapeRegistry.h"
0031 #include "KoShapeStrokeModel.h"
0032 #include "KoShapeShadow.h"
0033 #include "KoInsets.h"
0034 
0035 #include <FlakeDebug.h>
0036 
0037 #include <QPainter>
0038 
0039 #include <algorithm>
0040 
0041 class ShapeGroupContainerModel : public SimpleShapeContainerModel
0042 {
0043 public:
0044     ShapeGroupContainerModel(KoShapeGroup *group) : m_group(group) {}
0045     ~ShapeGroupContainerModel() override {}
0046 
0047     void add(KoShape *child) override
0048     {
0049         SimpleShapeContainerModel::add(child);
0050         m_group->invalidateSizeCache();
0051     }
0052 
0053     void remove(KoShape *child) override
0054     {
0055         SimpleShapeContainerModel::remove(child);
0056         m_group->invalidateSizeCache();
0057     }
0058 
0059     void childChanged(KoShape *shape, KoShape::ChangeType type) override
0060     {
0061         SimpleShapeContainerModel::childChanged(shape, type);
0062         //debugFlake << type;
0063         switch (type) {
0064         case KoShape::PositionChanged:
0065         case KoShape::RotationChanged:
0066         case KoShape::ScaleChanged:
0067         case KoShape::ShearChanged:
0068         case KoShape::SizeChanged:
0069         case KoShape::GenericMatrixChange:
0070         case KoShape::ParameterChanged:
0071         case KoShape::ClipPathChanged :
0072             m_group->invalidateSizeCache();
0073             break;
0074         default:
0075             break;
0076         }
0077     }
0078 
0079 private: // members
0080     KoShapeGroup * m_group;
0081 };
0082 
0083 class KoShapeGroupPrivate : public KoShapeContainerPrivate
0084 {
0085 public:
0086     KoShapeGroupPrivate(KoShapeGroup *q)
0087     : KoShapeContainerPrivate(q)
0088     {
0089         model = new ShapeGroupContainerModel(q);
0090     }
0091 
0092     ~KoShapeGroupPrivate() override
0093     {
0094     }
0095 
0096     mutable bool sizeCached;
0097 };
0098 
0099 KoShapeGroup::KoShapeGroup()
0100         : KoShapeContainer(*(new KoShapeGroupPrivate(this)))
0101 {
0102     setSize(QSizeF(0, 0));
0103 }
0104 
0105 KoShapeGroup::~KoShapeGroup()
0106 {
0107 }
0108 
0109 void KoShapeGroup::paintComponent(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &)
0110 {
0111     Q_UNUSED(painter);
0112     Q_UNUSED(converter);
0113 }
0114 
0115 bool KoShapeGroup::hitTest(const QPointF &position) const
0116 {
0117     Q_UNUSED(position);
0118     return false;
0119 }
0120 
0121 QSizeF KoShapeGroup::size() const
0122 {
0123     Q_D(const KoShapeGroup);
0124     //debugFlake << "size" << d->size;
0125     if (!d->sizeCached) {
0126         QRectF bound;
0127         foreach(KoShape *shape, shapes()) {
0128             if (bound.isEmpty())
0129                 bound = shape->transformation().mapRect(shape->outlineRect());
0130             else
0131                 bound |= shape->transformation().mapRect(shape->outlineRect());
0132         }
0133         d->size = bound.size();
0134         d->sizeCached = true;
0135         debugFlake << "recalculated size" << d->size;
0136     }
0137 
0138     return d->size;
0139 }
0140 
0141 QRectF KoShapeGroup::boundingRect() const
0142 {
0143     bool first = true;
0144     QRectF groupBound;
0145     foreach(KoShape* shape, shapes()) {
0146         if (first) {
0147             groupBound = shape->boundingRect();
0148             first = false;
0149         } else {
0150             groupBound = groupBound.united(shape->boundingRect());
0151         }
0152     }
0153 
0154     if (shadow()) {
0155         KoInsets insets;
0156         shadow()->insets(insets);
0157         groupBound.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
0158     }
0159     return groupBound;
0160 }
0161 
0162 void KoShapeGroup::saveOdf(KoShapeSavingContext & context) const
0163 {
0164     context.xmlWriter().startElement("draw:g");
0165     saveOdfAttributes(context, (OdfMandatories ^ (OdfLayer | OdfZIndex)) | OdfAdditionalAttributes);
0166     context.xmlWriter().addAttributePt("svg:y", position().y());
0167 
0168     QList<KoShape*> shapes = this->shapes();
0169     std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
0170 
0171     foreach(KoShape* shape, shapes) {
0172         shape->saveOdf(context);
0173     }
0174 
0175     saveOdfCommonChildElements(context);
0176     context.xmlWriter().endElement();
0177 }
0178 
0179 bool KoShapeGroup::loadOdf(const KoXmlElement & element, KoShapeLoadingContext &context)
0180 {
0181     Q_D(KoShapeGroup);
0182     loadOdfAttributes(element, context, OdfMandatories | OdfStyle | OdfAdditionalAttributes | OdfCommonChildElements);
0183 
0184     KoXmlElement child;
0185     QHash<KoShapeLayer*, int> usedLayers;
0186     forEachElement(child, element) {
0187         KoShape * shape = KoShapeRegistry::instance()->createShapeFromOdf(child, context);
0188         if (shape) {
0189             KoShapeLayer *layer = dynamic_cast<KoShapeLayer*>(shape->parent());
0190             if (layer) {
0191                 usedLayers[layer]++;
0192             }
0193             addShape(shape);
0194         }
0195     }
0196     KoShapeLayer *parent = 0;
0197     int maxUseCount = 0;
0198     // find most used layer and use this as parent for the group
0199     for (QHash<KoShapeLayer*, int>::const_iterator it(usedLayers.constBegin()); it != usedLayers.constEnd(); ++it) {
0200         if (it.value() > maxUseCount) {
0201             maxUseCount = it.value();
0202             parent = it.key();
0203         }
0204     }
0205     setParent(parent);
0206 
0207     QRectF bound;
0208     bool boundInitialized = false;
0209     foreach(KoShape * shape, shapes()) {
0210         if (! boundInitialized) {
0211             bound = shape->boundingRect();
0212             boundInitialized = true;
0213         } else
0214             bound = bound.united(shape->boundingRect());
0215     }
0216 
0217     setSize(bound.size());
0218     d->sizeCached = true;
0219     setPosition(bound.topLeft());
0220 
0221     foreach(KoShape * shape, shapes())
0222         shape->setAbsolutePosition(shape->absolutePosition() - bound.topLeft());
0223 
0224     return true;
0225 }
0226 
0227 void KoShapeGroup::shapeChanged(ChangeType type, KoShape *shape)
0228 {
0229     Q_UNUSED(shape);
0230     KoShapeContainer::shapeChanged(type, shape);
0231     switch (type) {
0232     case KoShape::StrokeChanged:
0233     {
0234         KoShapeStrokeModel *str = stroke();
0235         if (str) {
0236             if (str->deref())
0237                 delete str;
0238             setStroke(0);
0239         }
0240         break;
0241     }
0242     default:
0243         break;
0244     }
0245 }
0246 
0247 void KoShapeGroup::invalidateSizeCache()
0248 {
0249     Q_D(KoShapeGroup);
0250     d->sizeCached = false;
0251 }
0252