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