1 /* This file is part of the KDE project
2 * Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
3 * Copyright (C) 2007 Jan Hambrecht <jaham@gmx.net>
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
14 *
15 * You should have received a copy of the GNU Library General Public License
16 * along with this library; see the file COPYING.LIB. If not, write to
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19 */
20 #include "KoShapeContainer.h"
21 #include "KoShapeContainer_p.h"
22 #include "KoShapeContainerModel.h"
23 #include "KoShapeStrokeModel.h"
24 #include "SimpleShapeContainerModel.h"
25 #include "KoShapeSavingContext.h"
26
27 #include <QPointF>
28 #include <QPainter>
29 #include <QPainterPath>
30
31 #include "kis_painting_tweaks.h"
32 #include "kis_assert.h"
33
Private(KoShapeContainer * q)34 KoShapeContainer::Private::Private(KoShapeContainer *q)
35 : shapeInterface(q)
36 , model(0)
37 {
38 }
39
~Private()40 KoShapeContainer::Private::~Private()
41 {
42 delete model;
43 }
44
Private(const KoShapeContainer::Private & rhs,KoShapeContainer * q)45 KoShapeContainer::Private::Private(const KoShapeContainer::Private &rhs, KoShapeContainer *q)
46 : shapeInterface(q)
47 , model(0)
48 {
49 Q_UNUSED(rhs);
50 }
51
KoShapeContainer(KoShapeContainerModel * model)52 KoShapeContainer::KoShapeContainer(KoShapeContainerModel *model)
53 : KoShape()
54 , d(new Private(this))
55 {
56 d->model = model;
57 }
58
KoShapeContainer(const KoShapeContainer & rhs)59 KoShapeContainer::KoShapeContainer(const KoShapeContainer &rhs)
60 : KoShape(rhs)
61 , d(new Private(*(rhs.d.data()), this))
62 {
63 }
64
~KoShapeContainer()65 KoShapeContainer::~KoShapeContainer()
66 {
67 if (d->model) {
68 d->model->deleteOwnedShapes();
69 }
70 }
71
addShape(KoShape * shape)72 void KoShapeContainer::addShape(KoShape *shape)
73 {
74 shape->setParent(this);
75 }
76
removeShape(KoShape * shape)77 void KoShapeContainer::removeShape(KoShape *shape)
78 {
79 shape->setParent(0);
80 }
81
shapeCount() const82 int KoShapeContainer::shapeCount() const
83 {
84 if (d->model == 0)
85 return 0;
86 return d->model->count();
87 }
88
setClipped(const KoShape * child,bool clipping)89 void KoShapeContainer::setClipped(const KoShape *child, bool clipping)
90 {
91 if (d->model == 0)
92 return;
93 d->model->setClipped(child, clipping);
94 }
95
setInheritsTransform(const KoShape * shape,bool inherit)96 void KoShapeContainer::setInheritsTransform(const KoShape *shape, bool inherit)
97 {
98 if (d->model == 0)
99 return;
100 d->model->setInheritsTransform(shape, inherit);
101 }
102
inheritsTransform(const KoShape * shape) const103 bool KoShapeContainer::inheritsTransform(const KoShape *shape) const
104 {
105 if (d->model == 0)
106 return false;
107 return d->model->inheritsTransform(shape);
108 }
109
paint(QPainter & painter,KoShapePaintingContext & paintcontext) const110 void KoShapeContainer::paint(QPainter &painter, KoShapePaintingContext &paintcontext) const
111 {
112 // Shape container paints only its internal component part. All the children are rendered
113 // by the shape manager itself
114
115 painter.save();
116 paintComponent(painter, paintcontext);
117 painter.restore();
118 }
119
shapeChanged(ChangeType type,KoShape * shape)120 void KoShapeContainer::shapeChanged(ChangeType type, KoShape* shape)
121 {
122 Q_UNUSED(shape);
123 if (d->model == 0)
124 return;
125 if (!(type == RotationChanged || type == ScaleChanged || type == ShearChanged
126 || type == SizeChanged || type == PositionChanged || type == GenericMatrixChange))
127 return;
128 d->model->containerChanged(this, type);
129 Q_FOREACH (KoShape *shape, d->model->shapes())
130 shape->notifyChanged();
131 }
132
isClipped(const KoShape * child) const133 bool KoShapeContainer::isClipped(const KoShape *child) const
134 {
135 if (d->model == 0) // throw exception??
136 return false;
137 return d->model->isClipped(child);
138 }
139
update() const140 void KoShapeContainer::update() const
141 {
142 KoShape::update();
143 if (d->model)
144 Q_FOREACH (KoShape *shape, d->model->shapes())
145 shape->update();
146 }
147
shapes() const148 QList<KoShape*> KoShapeContainer::shapes() const
149 {
150 if (d->model == 0)
151 return QList<KoShape*>();
152
153 return d->model->shapes();
154 }
155
model() const156 KoShapeContainerModel *KoShapeContainer::model() const
157 {
158 return d->model;
159 }
160
setModel(KoShapeContainerModel * model)161 void KoShapeContainer::setModel(KoShapeContainerModel *model)
162 {
163 d->model = model;
164 }
165
setModelInit(KoShapeContainerModel * model)166 void KoShapeContainer::setModelInit(KoShapeContainerModel *model)
167 {
168 setModel(model);
169 // HACK ALERT: the shapes are copied inside the model,
170 // but we still need to connect the to the
171 // hierarchy here!
172 if (d->model) {
173 Q_FOREACH (KoShape *shape, d->model->shapes()) {
174 if (shape) { // Note: shape can be 0 because not all shapes
175 // implement cloneShape, e.g. the text shape.
176 shape->setParent(this);
177 }
178 }
179 }
180 }
181
shapeInterface()182 KoShapeContainer::ShapeInterface *KoShapeContainer::shapeInterface()
183 {
184 return &d->shapeInterface;
185 }
186
ShapeInterface(KoShapeContainer * _q)187 KoShapeContainer::ShapeInterface::ShapeInterface(KoShapeContainer *_q)
188 : q(_q)
189 {
190 }
191
addShape(KoShape * shape)192 void KoShapeContainer::ShapeInterface::addShape(KoShape *shape)
193 {
194 KoShapeContainer::Private * const d = q->d.data();
195
196 KIS_SAFE_ASSERT_RECOVER_RETURN(shape);
197
198 if (shape->parent() == q && q->shapes().contains(shape)) {
199 return;
200 }
201
202 // TODO add a method to create a default model depending on the shape container
203 if (!d->model) {
204 d->model = new SimpleShapeContainerModel();
205 }
206
207 if (shape->parent() && shape->parent() != q) {
208 shape->parent()->shapeInterface()->removeShape(shape);
209 }
210
211 d->model->add(shape);
212 d->model->shapeHasBeenAddedToHierarchy(shape, q);
213 }
214
removeShape(KoShape * shape)215 void KoShapeContainer::ShapeInterface::removeShape(KoShape *shape)
216 {
217 KoShapeContainer::Private * const d = q->d.data();
218
219 KIS_SAFE_ASSERT_RECOVER_RETURN(shape);
220 KIS_SAFE_ASSERT_RECOVER_RETURN(d->model);
221 KIS_SAFE_ASSERT_RECOVER_RETURN(d->model->shapes().contains(shape));
222
223 d->model->shapeToBeRemovedFromHierarchy(shape, q);
224 d->model->remove(shape);
225
226 KoShapeContainer *grandparent = q->parent();
227 if (grandparent) {
228 grandparent->model()->childChanged(q, KoShape::ChildChanged);
229 }
230 }
231