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