File indexing completed on 2024-05-19 04:24:55
0001 /* This file is part of the KDE project 0002 * SPDX-FileCopyrightText: 2006-2010 Thomas Zander <zander@kde.org> 0003 * SPDX-FileCopyrightText: 2007 Jan Hambrecht <jaham@gmx.net> 0004 * 0005 * SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 #include "KoShapeContainer.h" 0008 #include "KoShapeContainer_p.h" 0009 #include "KoShapeContainerModel.h" 0010 #include "KoShapeStrokeModel.h" 0011 #include "SimpleShapeContainerModel.h" 0012 #include "KoShapeSavingContext.h" 0013 0014 #include <QPointF> 0015 #include <QPainter> 0016 #include <QPainterPath> 0017 0018 #include "kis_painting_tweaks.h" 0019 #include "kis_assert.h" 0020 0021 KoShapeContainer::Private::Private(KoShapeContainer *q) 0022 : shapeInterface(q) 0023 , model(0) 0024 { 0025 } 0026 0027 KoShapeContainer::Private::~Private() 0028 { 0029 delete model; 0030 } 0031 0032 KoShapeContainer::Private::Private(const KoShapeContainer::Private &rhs, KoShapeContainer *q) 0033 : shapeInterface(q) 0034 , model(0) 0035 { 0036 Q_UNUSED(rhs); 0037 } 0038 0039 KoShapeContainer::KoShapeContainer(KoShapeContainerModel *model) 0040 : KoShape() 0041 , d(new Private(this)) 0042 { 0043 d->model = model; 0044 } 0045 0046 KoShapeContainer::KoShapeContainer(const KoShapeContainer &rhs) 0047 : KoShape(rhs) 0048 , d(new Private(*(rhs.d.data()), this)) 0049 { 0050 } 0051 0052 KoShapeContainer::~KoShapeContainer() 0053 { 0054 if (d->model) { 0055 d->model->deleteOwnedShapes(); 0056 } 0057 } 0058 0059 void KoShapeContainer::addShape(KoShape *shape) 0060 { 0061 shape->setParent(this); 0062 } 0063 0064 void KoShapeContainer::removeShape(KoShape *shape) 0065 { 0066 shape->setParent(0); 0067 } 0068 0069 int KoShapeContainer::shapeCount() const 0070 { 0071 if (d->model == 0) 0072 return 0; 0073 return d->model->count(); 0074 } 0075 0076 void KoShapeContainer::setClipped(const KoShape *child, bool clipping) 0077 { 0078 if (d->model == 0) 0079 return; 0080 d->model->setClipped(child, clipping); 0081 } 0082 0083 void KoShapeContainer::setInheritsTransform(const KoShape *shape, bool inherit) 0084 { 0085 if (d->model == 0) 0086 return; 0087 d->model->setInheritsTransform(shape, inherit); 0088 } 0089 0090 bool KoShapeContainer::inheritsTransform(const KoShape *shape) const 0091 { 0092 if (d->model == 0) 0093 return false; 0094 return d->model->inheritsTransform(shape); 0095 } 0096 0097 void KoShapeContainer::paint(QPainter &painter) const 0098 { 0099 // Shape container paints only its internal component part. All the children are rendered 0100 // by the shape manager itself 0101 0102 painter.save(); 0103 paintComponent(painter); 0104 painter.restore(); 0105 } 0106 0107 void KoShapeContainer::shapeChanged(ChangeType type, KoShape* shape) 0108 { 0109 Q_UNUSED(shape); 0110 if (d->model == 0) 0111 return; 0112 if (!(type == RotationChanged || type == ScaleChanged || type == ShearChanged 0113 || type == SizeChanged || type == PositionChanged || type == GenericMatrixChange)) 0114 return; 0115 d->model->containerChanged(this, type); 0116 Q_FOREACH (KoShape *shape, d->model->shapes()) 0117 shape->notifyChanged(); 0118 } 0119 0120 bool KoShapeContainer::isClipped(const KoShape *child) const 0121 { 0122 if (d->model == 0) // throw exception?? 0123 return false; 0124 return d->model->isClipped(child); 0125 } 0126 0127 void KoShapeContainer::update() const 0128 { 0129 KoShape::update(); 0130 if (d->model) { 0131 Q_FOREACH (KoShape *shape, d->model->shapes()) { 0132 shape->update(); 0133 } 0134 } 0135 } 0136 0137 QList<KoShape*> KoShapeContainer::shapes() const 0138 { 0139 if (d->model == 0) 0140 return QList<KoShape*>(); 0141 0142 return d->model->shapes(); 0143 } 0144 0145 KoShapeContainerModel *KoShapeContainer::model() const 0146 { 0147 return d->model; 0148 } 0149 0150 void KoShapeContainer::setModel(KoShapeContainerModel *model) 0151 { 0152 d->model = model; 0153 } 0154 0155 void KoShapeContainer::setModelInit(KoShapeContainerModel *model) 0156 { 0157 setModel(model); 0158 // HACK ALERT: the shapes are copied inside the model, 0159 // but we still need to connect the to the 0160 // hierarchy here! 0161 if (d->model) { 0162 Q_FOREACH (KoShape *shape, d->model->shapes()) { 0163 if (shape) { // Note: shape can be 0 because not all shapes 0164 // implement cloneShape, e.g. the text shape. 0165 shape->setParent(this); 0166 } 0167 } 0168 } 0169 } 0170 0171 KoShapeContainer::ShapeInterface *KoShapeContainer::shapeInterface() 0172 { 0173 return &d->shapeInterface; 0174 } 0175 0176 KoShapeContainer::ShapeInterface::ShapeInterface(KoShapeContainer *_q) 0177 : q(_q) 0178 { 0179 } 0180 0181 void KoShapeContainer::ShapeInterface::addShape(KoShape *shape) 0182 { 0183 KoShapeContainer::Private * const d = q->d.data(); 0184 0185 KIS_SAFE_ASSERT_RECOVER_RETURN(shape); 0186 0187 if (shape->parent() == q && q->shapes().contains(shape)) { 0188 return; 0189 } 0190 0191 // TODO add a method to create a default model depending on the shape container 0192 if (!d->model) { 0193 d->model = new SimpleShapeContainerModel(); 0194 } 0195 0196 if (shape->parent() && shape->parent() != q) { 0197 shape->parent()->shapeInterface()->removeShape(shape); 0198 } 0199 0200 d->model->add(shape); 0201 d->model->shapeHasBeenAddedToHierarchy(shape, q); 0202 } 0203 0204 void KoShapeContainer::ShapeInterface::removeShape(KoShape *shape) 0205 { 0206 KoShapeContainer::Private * const d = q->d.data(); 0207 0208 KIS_SAFE_ASSERT_RECOVER_RETURN(shape); 0209 KIS_SAFE_ASSERT_RECOVER_RETURN(d->model); 0210 KIS_SAFE_ASSERT_RECOVER_RETURN(d->model->shapes().contains(shape)); 0211 0212 d->model->shapeToBeRemovedFromHierarchy(shape, q); 0213 d->model->remove(shape); 0214 0215 KoShapeContainer *grandparent = q->parent(); 0216 if (grandparent) { 0217 grandparent->model()->childChanged(q, KoShape::ChildChanged); 0218 } 0219 }