Warning, file /office/calligra/libs/flake/KoShapeContainer.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-2010 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 #include "KoShapeContainer.h"
0021 #include "KoShapeContainer_p.h"
0022 #include "KoShapeContainerModel.h"
0023 #include "KoShapeStrokeModel.h"
0024 #include "KoShapeContainerDefaultModel.h"
0025 #include "KoShapeSavingContext.h"
0026 
0027 #include <QPointF>
0028 #include <QPainter>
0029 #include <QPainterPath>
0030 
0031 #include <algorithm>
0032 
0033 KoShapeContainerPrivate::KoShapeContainerPrivate(KoShapeContainer *q)
0034     : KoShapePrivate(q),
0035     model(0)
0036 {
0037 }
0038 
0039 KoShapeContainerPrivate::~KoShapeContainerPrivate()
0040 {
0041     delete model;
0042 }
0043 
0044 KoShapeContainer::KoShapeContainer(KoShapeContainerModel *model)
0045         : KoShape(*(new KoShapeContainerPrivate(this)))
0046 {
0047     Q_D(KoShapeContainer);
0048     d->model = model;
0049 }
0050 
0051 KoShapeContainer::KoShapeContainer(KoShapeContainerPrivate &dd)
0052     : KoShape(dd)
0053 {
0054 }
0055 
0056 KoShapeContainer::~KoShapeContainer()
0057 {
0058     Q_D(KoShapeContainer);
0059     if (d->model) {
0060         foreach(KoShape *shape, d->model->shapes()) {
0061             delete shape;
0062         }
0063     }
0064 }
0065 
0066 void KoShapeContainer::addShape(KoShape *shape)
0067 {
0068     Q_D(KoShapeContainer);
0069     Q_ASSERT(shape);
0070     if (shape->parent() == this && shapes().contains(shape))
0071         return;
0072     // TODO add a method to create a default model depending on the shape container
0073     if (d->model == 0)
0074         d->model = new KoShapeContainerDefaultModel();
0075     if (shape->parent() && shape->parent() != this)
0076         shape->parent()->removeShape(shape);
0077     d->model->add(shape);
0078     shape->setParent(this);
0079 }
0080 
0081 void KoShapeContainer::removeShape(KoShape *shape)
0082 {
0083     Q_D(KoShapeContainer);
0084     Q_ASSERT(shape);
0085     if (d->model == 0)
0086         return;
0087     d->model->remove(shape);
0088     shape->setParent(0);
0089 
0090     KoShapeContainer * grandparent = parent();
0091     if (grandparent) {
0092         grandparent->model()->childChanged(this, KoShape::ChildChanged);
0093     }
0094 }
0095 
0096 void KoShapeContainer::removeAllShapes()
0097 {
0098     Q_D(KoShapeContainer);
0099     if (d->model == 0)
0100         return;
0101     for(int i = d->model->shapes().count() - 1; i >= 0; --i) {
0102         KoShape *shape = d->model->shapes().at(i);
0103         d->model->remove(shape);
0104         shape->setParent(0);
0105     }
0106 
0107     KoShapeContainer * grandparent = parent();
0108     if (grandparent) {
0109         grandparent->model()->childChanged(this, KoShape::ChildChanged);
0110     }
0111 }
0112 
0113 int  KoShapeContainer::shapeCount() const
0114 {
0115     Q_D(const KoShapeContainer);
0116     if (d->model == 0)
0117         return 0;
0118     return d->model->count();
0119 }
0120 
0121 bool KoShapeContainer::isChildLocked(const KoShape *child) const
0122 {
0123     Q_D(const KoShapeContainer);
0124     if (d->model == 0)
0125         return false;
0126     return d->model->isChildLocked(child);
0127 }
0128 
0129 KoShape::AllowedInteractions KoShapeContainer::allowedInteractions(const KoShape *child) const
0130 {
0131     Q_D(const KoShapeContainer);
0132     KoShape::AllowedInteractions state;
0133     if (!d->model) {
0134         return child->allowedInteractions(false);
0135     }
0136     return d->model->allowedInteractions(child);
0137 }
0138 
0139 void KoShapeContainer::setClipped(const KoShape *child, bool clipping)
0140 {
0141     Q_D(KoShapeContainer);
0142     if (d->model == 0)
0143         return;
0144     d->model->setClipped(child, clipping);
0145 }
0146 
0147 void KoShapeContainer::setInheritsTransform(const KoShape *shape, bool inherit)
0148 {
0149     Q_D(KoShapeContainer);
0150     if (d->model == 0)
0151         return;
0152     d->model->setInheritsTransform(shape, inherit);
0153 }
0154 
0155 bool KoShapeContainer::inheritsTransform(const KoShape *shape) const
0156 {
0157     Q_D(const KoShapeContainer);
0158     if (d->model == 0)
0159         return false;
0160     return d->model->inheritsTransform(shape);
0161 }
0162 
0163 void KoShapeContainer::paint(QPainter &painter, const KoViewConverter &converter, KoShapePaintingContext &paintcontext)
0164 {
0165     Q_D(KoShapeContainer);
0166     painter.save();
0167     paintComponent(painter, converter, paintcontext);
0168     painter.restore();
0169     if (d->model == 0 || d->model->count() == 0)
0170         return;
0171 
0172     QList<KoShape*> sortedObjects = d->model->shapes();
0173     std::sort(sortedObjects.begin(), sortedObjects.end(), KoShape::compareShapeZIndex);
0174 
0175     // Do the following to revert the absolute transformation of the container
0176     // that is re-applied in shape->absoluteTransformation() later on. The transformation matrix
0177     // of the container has already been applied once before this function is called.
0178     QTransform baseMatrix = absoluteTransformation(&converter).inverted() * painter.transform();
0179 
0180     // clip the children to the parent outline.
0181     QTransform m;
0182     qreal zoomX, zoomY;
0183     converter.zoom(&zoomX, &zoomY);
0184     m.scale(zoomX, zoomY);
0185     painter.setClipPath(m.map(outline()), Qt::IntersectClip);
0186 
0187     QRectF toPaintRect = converter.viewToDocument(painter.clipRegion().boundingRect());
0188     toPaintRect = transform().mapRect(toPaintRect);
0189     // We'll use this clipRect to see if our child shapes lie within it.
0190     // Because shape->boundingRect() uses absoluteTransformation(0) we'll
0191     // use that as well to have the same (absolute) reference transformation
0192     // of our and the child's bounding boxes.
0193     QTransform absTrans = absoluteTransformation(0);
0194     QRectF clipRect = absTrans.map(outline()).boundingRect();
0195 
0196 
0197     foreach(KoShape *shape, sortedObjects) {
0198         //debugFlake <<"KoShapeContainer::painting shape:" << shape->shapeId() <<"," << shape->boundingRect();
0199         if (!shape->isVisible())
0200             continue;
0201         if (!isClipped(shape))  // the shapeManager will have to draw those, or else we can't do clipRects
0202             continue;
0203         // don't try to draw a child shape that is not in the clipping rect of the painter.
0204         if (!clipRect.intersects(shape->boundingRect()))
0205 
0206             continue;
0207 
0208         painter.save();
0209         painter.setTransform(shape->absoluteTransformation(&converter) * baseMatrix);
0210         shape->paint(painter, converter, paintcontext);
0211         painter.restore();
0212         if (shape->stroke()) {
0213             painter.save();
0214             painter.setTransform(shape->absoluteTransformation(&converter) * baseMatrix);
0215             shape->stroke()->paint(shape, painter, converter);
0216             painter.restore();
0217         }
0218     }
0219 }
0220 
0221 void KoShapeContainer::shapeChanged(ChangeType type, KoShape* shape)
0222 {
0223     Q_UNUSED(shape);
0224     Q_D(KoShapeContainer);
0225     if (d->model == 0)
0226         return;
0227     if (!(type == RotationChanged || type == ScaleChanged || type == ShearChanged
0228             || type == SizeChanged || type == PositionChanged || type == GenericMatrixChange))
0229         return;
0230     d->model->containerChanged(this, type);
0231     foreach(KoShape *shape, d->model->shapes())
0232         shape->notifyChanged();
0233 }
0234 
0235 bool KoShapeContainer::isClipped(const KoShape *child) const
0236 {
0237     Q_D(const KoShapeContainer);
0238     if (d->model == 0) // throw exception??
0239         return false;
0240     return d->model->isClipped(child);
0241 }
0242 
0243 void KoShapeContainer::update() const
0244 {
0245     Q_D(const KoShapeContainer);
0246     KoShape::update();
0247     if (d->model)
0248         foreach(KoShape *shape, d->model->shapes())
0249             shape->update();
0250 }
0251 
0252 QList<KoShape*> KoShapeContainer::shapes() const
0253 {
0254     Q_D(const KoShapeContainer);
0255     if (d->model == 0)
0256         return QList<KoShape*>();
0257 
0258     return d->model->shapes();
0259 }
0260 
0261 KoShapeContainerModel *KoShapeContainer::model() const
0262 {
0263     Q_D(const KoShapeContainer);
0264     return d->model;
0265 }