File indexing completed on 2024-05-12 15:56:47
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 QList<KoShape*> KoShapeContainer::shapes() const 0136 { 0137 if (d->model == 0) 0138 return QList<KoShape*>(); 0139 0140 return d->model->shapes(); 0141 } 0142 0143 KoShapeContainerModel *KoShapeContainer::model() const 0144 { 0145 return d->model; 0146 } 0147 0148 void KoShapeContainer::setModel(KoShapeContainerModel *model) 0149 { 0150 d->model = model; 0151 } 0152 0153 void KoShapeContainer::setModelInit(KoShapeContainerModel *model) 0154 { 0155 setModel(model); 0156 // HACK ALERT: the shapes are copied inside the model, 0157 // but we still need to connect the to the 0158 // hierarchy here! 0159 if (d->model) { 0160 Q_FOREACH (KoShape *shape, d->model->shapes()) { 0161 if (shape) { // Note: shape can be 0 because not all shapes 0162 // implement cloneShape, e.g. the text shape. 0163 shape->setParent(this); 0164 } 0165 } 0166 } 0167 } 0168 0169 KoShapeContainer::ShapeInterface *KoShapeContainer::shapeInterface() 0170 { 0171 return &d->shapeInterface; 0172 } 0173 0174 KoShapeContainer::ShapeInterface::ShapeInterface(KoShapeContainer *_q) 0175 : q(_q) 0176 { 0177 } 0178 0179 void KoShapeContainer::ShapeInterface::addShape(KoShape *shape) 0180 { 0181 KoShapeContainer::Private * const d = q->d.data(); 0182 0183 KIS_SAFE_ASSERT_RECOVER_RETURN(shape); 0184 0185 if (shape->parent() == q && q->shapes().contains(shape)) { 0186 return; 0187 } 0188 0189 // TODO add a method to create a default model depending on the shape container 0190 if (!d->model) { 0191 d->model = new SimpleShapeContainerModel(); 0192 } 0193 0194 if (shape->parent() && shape->parent() != q) { 0195 shape->parent()->shapeInterface()->removeShape(shape); 0196 } 0197 0198 d->model->add(shape); 0199 d->model->shapeHasBeenAddedToHierarchy(shape, q); 0200 } 0201 0202 void KoShapeContainer::ShapeInterface::removeShape(KoShape *shape) 0203 { 0204 KoShapeContainer::Private * const d = q->d.data(); 0205 0206 KIS_SAFE_ASSERT_RECOVER_RETURN(shape); 0207 KIS_SAFE_ASSERT_RECOVER_RETURN(d->model); 0208 KIS_SAFE_ASSERT_RECOVER_RETURN(d->model->shapes().contains(shape)); 0209 0210 d->model->shapeToBeRemovedFromHierarchy(shape, q); 0211 d->model->remove(shape); 0212 0213 KoShapeContainer *grandparent = q->parent(); 0214 if (grandparent) { 0215 grandparent->model()->childChanged(q, KoShape::ChildChanged); 0216 } 0217 }