libs/flake

KoShape.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE project
00002    Copyright (C) 2006 Casper Boemann Rasmussen <cbr@boemann.dk>
00003    Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
00004    Copyright (C) 2006-2008 Thorsten Zachmann <zachmann@kde.org>
00005    Copyright (C) 2007-2009 Jan Hambrecht <jaham@gmx.net>
00006 
00007    This library is free software; you can redistribute it and/or
00008    modify it under the terms of the GNU Library General Public
00009    License as published by the Free Software Foundation; either
00010    version 2 of the License, or (at your option) any later version.
00011 
00012    This library is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015    Library General Public License for more details.
00016 
00017    You should have received a copy of the GNU Library General Public License
00018    along with this library; see the file COPYING.LIB.  If not, write to
00019    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020  * Boston, MA 02110-1301, USA.
00021 */
00022 
00023 #include "KoShape.h"
00024 #include "KoShape_p.h"
00025 #include "KoShapeContainer.h"
00026 #include "KoShapeLayer.h"
00027 #include "KoShapeContainerModel.h"
00028 #include "KoSelection.h"
00029 #include "KoPointerEvent.h"
00030 #include "KoInsets.h"
00031 #include "KoShapeBorderModel.h"
00032 #include "KoShapeBackground.h"
00033 #include "KoColorBackground.h"
00034 #include "KoGradientBackground.h"
00035 #include "KoPatternBackground.h"
00036 #include "KoShapeManager.h"
00037 #include "KoShapeUserData.h"
00038 #include "KoShapeApplicationData.h"
00039 #include "KoShapeSavingContext.h"
00040 #include "KoShapeLoadingContext.h"
00041 #include "KoViewConverter.h"
00042 #include "KoLineBorder.h"
00043 #include "ShapeDeleter_p.h"
00044 #include "KoShapeShadow.h"
00045 #include "KoEventAction.h"
00046 #include "KoEventActionRegistry.h"
00047 #include "KoOdfWorkaround.h"
00048 #include "KoFilterEffectStack.h"
00049 
00050 #include <KoXmlReader.h>
00051 #include <KoXmlWriter.h>
00052 #include <KoXmlNS.h>
00053 #include <KoGenStyle.h>
00054 #include <KoGenStyles.h>
00055 #include <KoUnit.h>
00056 #include <KoOdfStylesReader.h>
00057 #include <KoOdfGraphicStyles.h>
00058 #include <KoOdfLoadingContext.h>
00059 
00060 #include <QPainter>
00061 #include <QVariant>
00062 #include <QPainterPath>
00063 #include <QList>
00064 #include <QMap>
00065 #include <QByteArray>
00066 
00067 #include <kdebug.h>
00068 
00069 #include <limits>
00070 
00071 KoShapePrivate::KoShapePrivate(KoShape *shape)
00072     : size(50, 50),
00073     parent(0),
00074     userData(0),
00075     appData(0),
00076     fill(0),
00077     border(0),
00078     q(shape),
00079     shadow(0),
00080     filterEffectStack(0),
00081     zIndex(0),
00082     visible(true),
00083     printable(true),
00084     geometryProtected(false),
00085     keepAspect(false),
00086     selectable(true),
00087     detectCollision(false),
00088     protectContent(false)
00089 {
00090     connectors.append(QPointF(0.5, 0.0));
00091     connectors.append(QPointF(1.0, 0.5));
00092     connectors.append(QPointF(0.5, 1.0));
00093     connectors.append(QPointF(0.0, 0.5));
00094 }
00095 
00096 KoShapePrivate::~KoShapePrivate()
00097 {
00098     if (parent)
00099         parent->removeChild(q);
00100     foreach(KoShapeManager *manager, shapeManagers) {
00101         manager->remove(q);
00102         manager->removeAdditional(q);
00103     }
00104     delete userData;
00105     delete appData;
00106     if (border && ! border->removeUser())
00107         delete border;
00108     if (shadow && ! shadow->removeUser())
00109         delete shadow;
00110     if (fill && ! fill->removeUser())
00111         delete fill;
00112     if (filterEffectStack && ! filterEffectStack->removeUser())
00113         delete filterEffectStack;
00114     qDeleteAll(eventActions);
00115 }
00116 
00117 void KoShapePrivate::shapeChanged(KoShape::ChangeType type)
00118 {
00119     if (parent)
00120         parent->model()->childChanged(q, type);
00121     q->shapeChanged(type);
00122     foreach(KoShape * shape, dependees)
00123         shape->shapeChanged(type, q);
00124 }
00125 
00126 void KoShapePrivate::updateBorder()
00127 {
00128     if (border == 0)
00129         return;
00130     KoInsets insets;
00131     border->borderInsets(q, insets);
00132     QSizeF inner = q->size();
00133     // update left
00134     q->update(QRectF(-insets.left, -insets.top, insets.left,
00135                 inner.height() + insets.top + insets.bottom));
00136     // update top
00137     q->update(QRectF(-insets.left, -insets.top,
00138                 inner.width() + insets.left + insets.right, insets.top));
00139     // update right
00140     q->update(QRectF(inner.width(), -insets.top, insets.right,
00141                 inner.height() + insets.top + insets.bottom));
00142     // update bottom
00143     q->update(QRectF(-insets.left, inner.height(),
00144                 inner.width() + insets.left + insets.right, insets.bottom));
00145 }
00146 
00147 // ======== KoShape
00148 KoShape::KoShape()
00149         : d_ptr(new KoShapePrivate(this))
00150 {
00151     notifyChanged();
00152 }
00153 
00154 KoShape::KoShape(KoShapePrivate &dd)
00155     : d_ptr(&dd)
00156 {
00157 }
00158 
00159 KoShape::~KoShape()
00160 {
00161     Q_D(KoShape);
00162     d->shapeChanged(Deleted);
00163     delete d_ptr;
00164 }
00165 
00166 void KoShape::paintDecorations(QPainter &painter, const KoViewConverter &converter, const KoCanvasBase *canvas)
00167 {
00168     Q_UNUSED(painter);
00169     Q_UNUSED(converter);
00170     Q_UNUSED(canvas);
00171     /* Since this code is not actually used (kivio is going to be the main user) lets disable instead of fix.
00172         if ( selected )
00173         {
00174             // draw connectors
00175             QPen pen( Qt::blue );
00176             pen.setWidth( 0 );
00177             painter.setPen( pen );
00178             painter.setBrush( Qt::NoBrush );
00179             for ( int i = 0; i < d->connectors.size(); ++i )
00180             {
00181                 QPointF p = converter.documentToView(d->connectors[ i ]);
00182                 painter.drawLine( QPointF( p.x() - 2, p.y() + 2 ), QPointF( p.x() + 2, p.y() - 2 ) );
00183                 painter.drawLine( QPointF( p.x() + 2, p.y() + 2 ), QPointF( p.x() - 2, p.y() - 2 ) );
00184             }
00185         }*/
00186 }
00187 
00188 void KoShape::setScale(qreal sx, qreal sy)
00189 {
00190     Q_D(KoShape);
00191     QPointF pos = position();
00192     QMatrix scaleMatrix;
00193     scaleMatrix.translate(pos.x(), pos.y());
00194     scaleMatrix.scale(sx, sy);
00195     scaleMatrix.translate(-pos.x(), -pos.y());
00196     d->localMatrix = d->localMatrix * scaleMatrix;
00197 
00198     notifyChanged();
00199     d->shapeChanged(ScaleChanged);
00200 }
00201 
00202 void KoShape::rotate(qreal angle)
00203 {
00204     Q_D(KoShape);
00205     QPointF center = d->localMatrix.map(QPointF(0.5 * size().width(), 0.5 * size().height()));
00206     QMatrix rotateMatrix;
00207     rotateMatrix.translate(center.x(), center.y());
00208     rotateMatrix.rotate(angle);
00209     rotateMatrix.translate(-center.x(), -center.y());
00210     d->localMatrix = d->localMatrix * rotateMatrix;
00211 
00212     notifyChanged();
00213     d->shapeChanged(RotationChanged);
00214 }
00215 
00216 void KoShape::setShear(qreal sx, qreal sy)
00217 {
00218     Q_D(KoShape);
00219     QPointF pos = position();
00220     QMatrix shearMatrix;
00221     shearMatrix.translate(pos.x(), pos.y());
00222     shearMatrix.shear(sx, sy);
00223     shearMatrix.translate(-pos.x(), -pos.y());
00224     d->localMatrix = d->localMatrix * shearMatrix;
00225 
00226     notifyChanged();
00227     d->shapeChanged(ShearChanged);
00228 }
00229 
00230 void KoShape::setSize(const QSizeF &newSize)
00231 {
00232     Q_D(KoShape);
00233     QSizeF oldSize(size());
00234     if (oldSize == newSize)
00235         return;
00236 
00237     QMatrix matrix;
00238     oldSize.setHeight(qMax((qreal) 1E-4, oldSize.height())); // avoids devision by zero below
00239     oldSize.setWidth(qMax((qreal) 1E-4, oldSize.width()));
00240     matrix.scale(newSize.width()/oldSize.width(), newSize.height()/oldSize.height());
00241 
00242     KoGradientBackground * g = dynamic_cast<KoGradientBackground*>(d->fill);
00243     if (g) {
00244         g->setMatrix(g->matrix() * matrix);
00245     }
00246     KoLineBorder *l = dynamic_cast<KoLineBorder*>(d->border);
00247     if (l && l->lineBrush().gradient()) {
00248         QBrush brush = l->lineBrush();
00249         brush.setMatrix(brush.matrix() * matrix);
00250         l->setLineBrush(brush);
00251     }
00252 
00253     d->size = newSize;
00254 
00255     notifyChanged();
00256     d->shapeChanged(SizeChanged);
00257 }
00258 
00259 void KoShape::setPosition(const QPointF &newPosition)
00260 {
00261     Q_D(KoShape);
00262     QPointF currentPos = position();
00263     if (newPosition == currentPos)
00264         return;
00265     QMatrix translateMatrix;
00266     translateMatrix.translate(newPosition.x() - currentPos.x(), newPosition.y() - currentPos.y());
00267     d->localMatrix = d->localMatrix * translateMatrix;
00268 
00269     notifyChanged();
00270     d->shapeChanged(PositionChanged);
00271 }
00272 
00273 bool KoShape::hitTest(const QPointF &position) const
00274 {
00275     Q_D(const KoShape);
00276     if (d->parent && d->parent->childClipped(this) && !d->parent->hitTest(position))
00277         return false;
00278 
00279     QPointF point = absoluteTransformation(0).inverted().map(position);
00280     QRectF bb(QPointF(), size());
00281     if (d->border) {
00282         KoInsets insets;
00283         d->border->borderInsets(this, insets);
00284         bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
00285     }
00286     if (bb.contains(point))
00287         return true;
00288 
00289     // if there is no shadow we can as well just leave
00290     if (! d->shadow)
00291         return false;
00292 
00293     // the shadow has an offset to the shape, so we simply
00294     // check if the position minus the shadow offset hits the shape
00295     point = absoluteTransformation(0).inverted().map(position - d->shadow->offset());
00296 
00297     return bb.contains(point);
00298 }
00299 
00300 QRectF KoShape::boundingRect() const
00301 {
00302     Q_D(const KoShape);
00303     QSizeF mySize = size();
00304     QMatrix transform = absoluteTransformation(0);
00305     QRectF bb(QPointF(0, 0), mySize);
00306     if (d->border) {
00307         KoInsets insets;
00308         d->border->borderInsets(this, insets);
00309         bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
00310     }
00311     bb = transform.mapRect(bb);
00312     if (d->shadow) {
00313         KoInsets insets;
00314         d->shadow->insets(this, insets);
00315         bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
00316     }
00317     if (d->filterEffectStack) {
00318         QRectF clipRect = d->filterEffectStack->clipRectForBoundingRect(QRectF(QPointF(), mySize));
00319         bb |= transform.mapRect(clipRect);
00320     }
00321     
00322     return bb;
00323 }
00324 
00325 QMatrix KoShape::absoluteTransformation(const KoViewConverter *converter) const
00326 {
00327     Q_D(const KoShape);
00328     QMatrix matrix;
00329     // apply parents matrix to inherit any transformations done there.
00330     KoShapeContainer * container = d->parent;
00331     if (container) {
00332         if (container->childClipped(this))
00333             matrix = container->absoluteTransformation(0);
00334         else {
00335             QSizeF containerSize = container->size();
00336             QPointF containerPos = container->absolutePosition() - QPointF(0.5 * containerSize.width(), 0.5 * containerSize.height());
00337             if (converter)
00338                 containerPos = converter->documentToView(containerPos);
00339             matrix.translate(containerPos.x(), containerPos.y());
00340         }
00341     }
00342 
00343     if (converter) {
00344         QPointF pos = d->localMatrix.map(QPointF());
00345         QPointF trans = converter->documentToView(pos) - pos;
00346         matrix.translate(trans.x(), trans.y());
00347     }
00348 
00349     return d->localMatrix * matrix;
00350 }
00351 
00352 void KoShape::applyAbsoluteTransformation(const QMatrix &matrix)
00353 {
00354     QMatrix globalMatrix = absoluteTransformation(0);
00355     // the transformation is relative to the global coordinate system
00356     // but we want to change the local matrix, so convert the matrix
00357     // to be relative to the local coordinate system
00358     QMatrix transformMatrix = globalMatrix * matrix * globalMatrix.inverted();
00359     applyTransformation(transformMatrix);
00360 }
00361 
00362 void KoShape::applyTransformation(const QMatrix &matrix)
00363 {
00364     Q_D(KoShape);
00365     d->localMatrix = matrix * d->localMatrix;
00366     notifyChanged();
00367     d->shapeChanged(GenericMatrixChange);
00368 }
00369 
00370 void KoShape::setTransformation(const QMatrix &matrix)
00371 {
00372     Q_D(KoShape);
00373     d->localMatrix = matrix;
00374     notifyChanged();
00375     d->shapeChanged(GenericMatrixChange);
00376 }
00377 
00378 QMatrix KoShape::transformation() const
00379 {
00380     Q_D(const KoShape);
00381     return d->localMatrix;
00382 }
00383 
00384 bool KoShape::compareShapeZIndex(KoShape *s1, KoShape *s2)
00385 {
00386     bool foundCommonParent = false;
00387     KoShape *parentShapeS1 = s1;
00388     KoShape *parentShapeS2 = s2;
00389     int index1 = parentShapeS1->zIndex();
00390     int index2 = parentShapeS2->zIndex();
00391     while (parentShapeS1 && !foundCommonParent) {
00392         parentShapeS2 = s2;
00393         index2 = parentShapeS2->zIndex();
00394         while (parentShapeS2) {
00395             if (parentShapeS2 == parentShapeS1) {
00396                 foundCommonParent = true;
00397                 break;
00398             }
00399             index2 = parentShapeS2->zIndex();
00400             parentShapeS2 = parentShapeS2->parent();
00401         }
00402 
00403         if (!foundCommonParent) {
00404             index1 = parentShapeS1->zIndex();
00405             parentShapeS1 = parentShapeS1->parent();
00406         }
00407     }
00408     if (s1 == parentShapeS2) {
00409         return true;
00410     }
00411     else if (s2 == parentShapeS1) {
00412         return false;
00413     }
00414     return index1 < index2;
00415 }
00416 
00417 void KoShape::setParent(KoShapeContainer *parent)
00418 {
00419     Q_D(KoShape);
00420     if (d->parent == parent)
00421         return;
00422     KoShapeContainer *oldParent = d->parent;
00423     d->parent = 0; // avoids recursive removing
00424     if (oldParent)
00425         oldParent->removeChild(this);
00426     if (parent && parent != this) {
00427         d->parent = parent;
00428         parent->addChild(this);
00429     }
00430     notifyChanged();
00431     d->shapeChanged(ParentChanged);
00432 }
00433 
00434 int KoShape::zIndex() const
00435 {
00436     Q_D(const KoShape);
00437     return d->zIndex;
00438 }
00439 
00440 void KoShape::update() const
00441 {
00442     Q_D(const KoShape);
00443     if (!d->shapeManagers.empty()) {
00444         QRectF rect(boundingRect());
00445         foreach(KoShapeManager * manager, d->shapeManagers)
00446             manager->update(rect, this, true);
00447     }
00448 }
00449 
00450 void KoShape::update(const QRectF &shape) const
00451 {
00452     Q_D(const KoShape);
00453     if (!d->shapeManagers.empty() && isVisible()) {
00454         QRectF rect(absoluteTransformation(0).mapRect(shape));
00455         foreach(KoShapeManager * manager, d->shapeManagers) {
00456             manager->update(rect);
00457         }
00458     }
00459 }
00460 
00461 QPainterPath KoShape::outline() const
00462 {
00463     Q_D(const KoShape);
00464     QPainterPath path;
00465     path.addRect(QRectF(QPointF(0, 0), QSizeF(qMax(d->size.width(), qreal(0.0001)), qMax(d->size.height(), qreal(0.0001)))));
00466     return path;
00467 }
00468 
00469 QPointF KoShape::absolutePosition(KoFlake::Position anchor) const
00470 {
00471     QPointF point;
00472     switch (anchor) {
00473     case KoFlake::TopLeftCorner: break;
00474     case KoFlake::TopRightCorner: point = QPointF(size().width(), 0.0); break;
00475     case KoFlake::BottomLeftCorner: point = QPointF(0.0, size().height()); break;
00476     case KoFlake::BottomRightCorner: point = QPointF(size().width(), size().height()); break;
00477     case KoFlake::CenteredPosition: point = QPointF(size().width() / 2.0, size().height() / 2.0); break;
00478     }
00479     return absoluteTransformation(0).map(point);
00480 }
00481 
00482 void KoShape::setAbsolutePosition(QPointF newPosition, KoFlake::Position anchor)
00483 {
00484     Q_D(KoShape);
00485     QPointF currentAbsPosition = absolutePosition(anchor);
00486     QPointF translate = newPosition - currentAbsPosition;
00487     QMatrix translateMatrix;
00488     translateMatrix.translate(translate.x(), translate.y());
00489     applyAbsoluteTransformation(translateMatrix);
00490     notifyChanged();
00491     d->shapeChanged(PositionChanged);
00492 }
00493 
00494 void KoShape::copySettings(const KoShape *shape)
00495 {
00496     Q_D(KoShape);
00497     d->size = shape->size();
00498     d->connectors.clear();
00499     foreach(const QPointF & point, shape->connectionPoints())
00500         addConnectionPoint(point);
00501     d->zIndex = shape->zIndex();
00502     d->visible = shape->isVisible();
00503 
00504     // Ensure printable is true by default
00505     if (!d->visible)
00506         d->printable = true;
00507     else
00508         d->printable = shape->isPrintable();
00509 
00510     d->geometryProtected = shape->isGeometryProtected();
00511     d->keepAspect = shape->keepAspectRatio();
00512     d->localMatrix = shape->d_ptr->localMatrix;
00513 }
00514 
00515 void KoShape::notifyChanged()
00516 {
00517     Q_D(KoShape);
00518     foreach(KoShapeManager * manager, d->shapeManagers) {
00519         manager->notifyShapeChanged(this);
00520     }
00521 }
00522 
00523 void KoShape::setUserData(KoShapeUserData *userData)
00524 {
00525     Q_D(KoShape);
00526     delete d->userData;
00527     d->userData = userData;
00528 }
00529 
00530 KoShapeUserData *KoShape::userData() const
00531 {
00532     Q_D(const KoShape);
00533     return d->userData;
00534 }
00535 
00536 void KoShape::setApplicationData(KoShapeApplicationData *appData)
00537 {
00538     Q_D(KoShape);
00539     // appdata is deleted by the application.
00540     d->appData = appData;
00541 }
00542 
00543 KoShapeApplicationData *KoShape::applicationData() const
00544 {
00545     Q_D(const KoShape);
00546     return d->appData;
00547 }
00548 
00549 bool KoShape::hasTransparency()
00550 {
00551     Q_D(KoShape);
00552     if (! d->fill)
00553         return true;
00554     else
00555         return d->fill->hasTransparency();
00556 }
00557 
00558 KoInsets KoShape::borderInsets() const
00559 {
00560     Q_D(const KoShape);
00561     KoInsets answer;
00562     if (d->border)
00563         d->border->borderInsets(this, answer);
00564     return answer;
00565 }
00566 
00567 qreal KoShape::rotation() const
00568 {
00569     Q_D(const KoShape);
00570     // try to extract the rotation angle out of the local matrix
00571     // if it is a pure rotation matrix
00572 
00573     // check if the matrix has shearing mixed in
00574     if (fabs(fabs(d->localMatrix.m12()) - fabs(d->localMatrix.m21())) > 1e-10)
00575         return std::numeric_limits<qreal>::quiet_NaN();
00576     // check if the matrix has scaling mixed in
00577     if (fabs(d->localMatrix.m11() - d->localMatrix.m22()) > 1e-10)
00578         return std::numeric_limits<qreal>::quiet_NaN();
00579 
00580     // calculate the angle from the matrix elements
00581     qreal angle = atan2(-d->localMatrix.m21(), d->localMatrix.m11()) * 180.0 / M_PI;
00582     if (angle < 0.0)
00583         angle += 360.0;
00584 
00585     return angle;
00586 }
00587 
00588 QSizeF KoShape::size() const
00589 {
00590     Q_D(const KoShape);
00591     return d->size;
00592 }
00593 
00594 QPointF KoShape::position() const
00595 {
00596     Q_D(const KoShape);
00597     QPointF center(0.5*size().width(), 0.5*size().height());
00598     return d->localMatrix.map(center) - center;
00599     //return d->localMatrix.map( QPointF(0,0) );
00600 }
00601 
00602 void KoShape::addConnectionPoint(const QPointF &point)
00603 {
00604     Q_D(KoShape);
00605     QSizeF s = size();
00606     // convert glue point from shape coordinates to factors of size
00607     d->connectors.append(QPointF(point.x() / s.width(), point.y() / s.height()));
00608 }
00609 
00610 QList<QPointF> KoShape::connectionPoints() const
00611 {
00612     Q_D(const KoShape);
00613     QList<QPointF> points;
00614     QSizeF s = size();
00615     // convert glue points to shape coordinates
00616     foreach(const QPointF & cp, d->connectors)
00617         points.append(QPointF(s.width() * cp.x(), s.height() * cp.y()));
00618 
00619     return points;
00620 }
00621 
00622 void KoShape::addEventAction(KoEventAction * action)
00623 {
00624     Q_D(KoShape);
00625     if (! d->eventActions.contains(action)) {
00626         d->eventActions.append(action);
00627     }
00628 }
00629 
00630 void KoShape::removeEventAction(KoEventAction * action)
00631 {
00632     Q_D(KoShape);
00633     if (d->eventActions.contains(action)) {
00634         d->eventActions.removeAll(action);
00635     }
00636 }
00637 
00638 QList<KoEventAction *> KoShape::eventActions() const
00639 {
00640     Q_D(const KoShape);
00641     return d->eventActions;
00642 }
00643 
00644 void KoShape::setBackground(KoShapeBackground * fill)
00645 {
00646     Q_D(KoShape);
00647     if (d->fill)
00648         d->fill->removeUser();
00649     d->fill = fill;
00650     if (d->fill)
00651         d->fill->addUser();
00652     d->shapeChanged(BackgroundChanged);
00653     notifyChanged();
00654 }
00655 
00656 KoShapeBackground * KoShape::background() const
00657 {
00658     Q_D(const KoShape);
00659     return d->fill;
00660 }
00661 
00662 void KoShape::setZIndex(int zIndex)
00663 {
00664     Q_D(KoShape);
00665     notifyChanged();
00666     d->zIndex = zIndex;
00667 }
00668 
00669 void KoShape::setVisible(bool on)
00670 {
00671     Q_D(KoShape);
00672     d->visible = on;
00673 }
00674 
00675 bool KoShape::isVisible(bool recursive) const
00676 {
00677     Q_D(const KoShape);
00678     if (! recursive)
00679         return d->visible;
00680     if (recursive && ! d->visible)
00681         return false;
00682 
00683     KoShapeContainer * parentShape = parent();
00684     while (parentShape) {
00685         if (! parentShape->isVisible())
00686             return false;
00687         parentShape = parentShape->parent();
00688     }
00689     return true;
00690 }
00691 
00692 void KoShape::setPrintable(bool on)
00693 {
00694     Q_D(KoShape);
00695     d->printable = on;
00696 }
00697 
00698 bool KoShape::isPrintable() const
00699 {
00700     Q_D(const KoShape);
00701     if (d->visible)
00702         return d->printable;
00703     else
00704         return false;
00705 }
00706 
00707 void KoShape::setSelectable(bool selectable)
00708 {
00709     Q_D(KoShape);
00710     d->selectable = selectable;
00711 }
00712 
00713 bool KoShape::isSelectable() const
00714 {
00715     Q_D(const KoShape);
00716     return d->selectable;
00717 }
00718 
00719 void KoShape::setGeometryProtected(bool on)
00720 {
00721     Q_D(KoShape);
00722     d->geometryProtected = on;
00723 }
00724 
00725 bool KoShape::isGeometryProtected() const
00726 {
00727     Q_D(const KoShape);
00728     return d->geometryProtected;
00729 }
00730 
00731 void KoShape::setContentProtected(bool protect)
00732 {
00733     Q_D(KoShape);
00734     d->protectContent = protect;
00735 }
00736 
00737 bool KoShape::isContentProtected() const
00738 {
00739     Q_D(const KoShape);
00740     return d->protectContent;
00741 }
00742 
00743 KoShapeContainer *KoShape::parent() const
00744 {
00745     Q_D(const KoShape);
00746     return d->parent;
00747 }
00748 
00749 void KoShape::setKeepAspectRatio(bool keepAspect)
00750 {
00751     Q_D(KoShape);
00752     d->keepAspect = keepAspect;
00753 }
00754 
00755 bool KoShape::keepAspectRatio() const
00756 {
00757     Q_D(const KoShape);
00758     return d->keepAspect;
00759 }
00760 
00761 QString KoShape::shapeId() const
00762 {
00763     Q_D(const KoShape);
00764     return d->shapeId;
00765 }
00766 
00767 void KoShape::setShapeId(const QString &id)
00768 {
00769     Q_D(KoShape);
00770     d->shapeId = id;
00771 }
00772 
00773 void KoShape::setCollisionDetection(bool detect)
00774 {
00775     Q_D(KoShape);
00776     d->detectCollision = detect;
00777 }
00778 
00779 bool KoShape::collisionDetection()
00780 {
00781     Q_D(KoShape);
00782     return d->detectCollision;
00783 }
00784 
00785 void KoShape::addShapeManager(KoShapeManager * manager)
00786 {
00787     Q_D(KoShape);
00788     d->shapeManagers.insert(manager);
00789 }
00790 
00791 void KoShape::removeShapeManager(KoShapeManager * manager)
00792 {
00793     Q_D(KoShape);
00794     d->shapeManagers.remove(manager);
00795 }
00796 
00797 KoShapeBorderModel *KoShape::border() const
00798 {
00799     Q_D(const KoShape);
00800     return d->border;
00801 }
00802 
00803 void KoShape::setBorder(KoShapeBorderModel *border)
00804 {
00805     Q_D(KoShape);
00806     if (border)
00807         border->addUser();
00808     d->updateBorder();
00809     if (d->border)
00810         d->border->removeUser();
00811     d->border = border;
00812     d->updateBorder();
00813     d->shapeChanged(BorderChanged);
00814     notifyChanged();
00815 }
00816 
00817 void KoShape::setShadow(KoShapeShadow * shadow)
00818 {
00819     Q_D(KoShape);
00820     if (d->shadow)
00821         d->shadow->removeUser();
00822     d->shadow = shadow;
00823     if (d->shadow) {
00824         d->shadow->addUser();
00825         // TODO update changed area
00826     }
00827     d->shapeChanged(ShadowChanged);
00828     notifyChanged();
00829 }
00830 
00831 KoShapeShadow * KoShape::shadow() const
00832 {
00833     Q_D(const KoShape);
00834     return d->shadow;
00835 }
00836 
00837 QMatrix KoShape::matrix() const
00838 {
00839     Q_D(const KoShape);
00840     return d->localMatrix;
00841 }
00842 
00843 void KoShape::removeConnectionPoint(int index)
00844 {
00845     Q_D(KoShape);
00846     if (index < d->connectors.count())
00847         d->connectors.remove(index);
00848 }
00849 
00850 QString KoShape::name() const
00851 {
00852     Q_D(const KoShape);
00853     return d->name;
00854 }
00855 
00856 void KoShape::setName(const QString & name)
00857 {
00858     Q_D(KoShape);
00859     d->name = name;
00860 }
00861 
00862 void KoShape::waitUntilReady(const KoViewConverter &converter, bool asynchronous) const
00863 {
00864     Q_UNUSED(converter);
00865     Q_UNUSED(asynchronous);
00866 }
00867 
00868 void KoShape::deleteLater()
00869 {
00870     Q_D(KoShape);
00871     foreach(KoShapeManager *manager, d->shapeManagers)
00872         manager->remove(this);
00873     d->shapeManagers.clear();
00874     new ShapeDeleter(this);
00875 }
00876 
00877 bool KoShape::isEditable() const
00878 {
00879     Q_D(const KoShape);
00880     if (!d->visible || d->geometryProtected)
00881         return false;
00882 
00883     if (d->parent && d->parent->isChildLocked(this))
00884         return false;
00885 
00886     return true;
00887 }
00888 
00889 // loading & saving methods
00890 QString KoShape::saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const
00891 {
00892     Q_D(const KoShape);
00893     // and fill the style
00894     KoShapeBorderModel * b = border();
00895     if (b) {
00896         b->fillStyle(style, context);
00897     }
00898     else {
00899         style.addProperty( "draw:stroke", "none" );
00900     }
00901     KoShapeShadow * s = shadow();
00902     if (s)
00903         s->fillStyle(style, context);
00904 
00905     KoShapeBackground * bg = background();
00906     if (bg) {
00907         bg->fillStyle(style, context);
00908     }
00909     else {
00910         style.addProperty( "draw:fill", "none" );
00911     }
00912 
00913     if (context.isSet(KoShapeSavingContext::AutoStyleInStyleXml)) {
00914         style.setAutoStyleInStylesDotXml(true);
00915     }
00916 
00917     QString value;
00918     if (isGeometryProtected())
00919         value = "position size";
00920     if (isContentProtected()) {
00921         if (! value.isEmpty())
00922             value += ' ';
00923         value += "content";
00924     }
00925     if (!value.isEmpty())
00926         (const_cast<KoShapePrivate*>(d))->additionalStyleAttributes.insert("style:protect", value);
00927 
00928     QMap<QByteArray, QString>::const_iterator it(d->additionalStyleAttributes.constBegin());
00929     for (; it != d->additionalStyleAttributes.constEnd(); ++it) {
00930         style.addProperty(it.key(), it.value());
00931     }
00932 
00933     return context.mainStyles().lookup(style, context.isSet(KoShapeSavingContext::PresentationShape) ? "pr" : "gr");
00934 }
00935 
00936 void KoShape::loadStyle(const KoXmlElement & element, KoShapeLoadingContext &context)
00937 {
00938     Q_D(KoShape);
00939     
00940     KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
00941     styleStack.save();
00942 
00943     // fill the style stack with the shapes style
00944     if (element.hasAttributeNS(KoXmlNS::draw, "style-name")) {
00945         context.odfLoadingContext().fillStyleStack(element, KoXmlNS::draw, "style-name", "graphic");
00946         styleStack.setTypeProperties("graphic");
00947     } else if (element.hasAttributeNS(KoXmlNS::presentation, "style-name")) {
00948         context.odfLoadingContext().fillStyleStack(element, KoXmlNS::presentation, "style-name", "presentation");
00949         styleStack.setTypeProperties("graphic");
00950     }
00951 
00952     if(d->fill && !d->fill->removeUser()) {
00953         delete d->fill;
00954         d->fill = 0;
00955     }
00956     if(d->border && !d->border->removeUser()) {
00957         delete d->border;
00958         d->border = 0;
00959     }
00960     if(d->shadow && !d->shadow->removeUser()) {
00961         delete d->shadow;
00962         d->shadow = 0;
00963     }
00964     setBackground(loadOdfFill(element, context));
00965     setBorder(loadOdfStroke(element, context));
00966     setShadow(loadOdfShadow(element, context));
00967 
00968     styleStack.restore();
00969 }
00970 
00971 bool KoShape::loadOdfAttributes(const KoXmlElement & element, KoShapeLoadingContext &context, int attributes)
00972 {
00973     Q_D(KoShape);
00974     if (attributes & OdfPosition) {
00975         QPointF pos(position());
00976         if (element.hasAttributeNS(KoXmlNS::svg, "x"))
00977             pos.setX(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "x", QString())));
00978         if (element.hasAttributeNS(KoXmlNS::svg, "y"))
00979             pos.setY(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "y", QString())));
00980         setPosition(pos);
00981     }
00982 
00983     if (attributes & OdfSize) {
00984         QSizeF s(size());
00985         if (element.hasAttributeNS(KoXmlNS::svg, "width"))
00986             s.setWidth(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "width", QString())));
00987         if (element.hasAttributeNS(KoXmlNS::svg, "height"))
00988             s.setHeight(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "height", QString())));
00989         setSize(s);
00990     }
00991 
00992     if (attributes & OdfLayer) {
00993         if (element.hasAttributeNS(KoXmlNS::draw, "layer")) {
00994             KoShapeLayer * layer = context.layer(element.attributeNS(KoXmlNS::draw, "layer"));
00995             if (layer) {
00996                 setParent(layer);
00997             }
00998         }
00999     }
01000 
01001     if (attributes & OdfId) {
01002         if (element.hasAttributeNS(KoXmlNS::draw, "id")) {
01003             QString id = element.attributeNS(KoXmlNS::draw, "id");
01004             if (!id.isNull()) {
01005                 context.addShapeId(this, id);
01006             }
01007         }
01008     }
01009 
01010     if (attributes & OdfZIndex) {
01011         if (element.hasAttributeNS(KoXmlNS::draw, "z-index")) {
01012             setZIndex(element.attributeNS(KoXmlNS::draw, "z-index").toInt());
01013         }
01014         else {
01015             setZIndex(context.zIndex());
01016         }
01017     }
01018 
01019     if (attributes & OdfName) {
01020         if (element.hasAttributeNS(KoXmlNS::draw, "name")) {
01021             setName(element.attributeNS(KoXmlNS::draw, "name"));
01022         }
01023     }
01024 
01025     if (attributes & OdfStyle) {
01026         loadStyle(element, context);
01027     }
01028 
01029     if (attributes & OdfTransformation) {
01030         QString transform = element.attributeNS(KoXmlNS::draw, "transform", QString());
01031         if (! transform.isEmpty())
01032             applyAbsoluteTransformation(parseOdfTransform(transform));
01033     }
01034 
01035     if (attributes & OdfAdditionalAttributes) {
01036         QSet<KoShapeLoadingContext::AdditionalAttributeData> additionalAttributeData = KoShapeLoadingContext::additionalAttributeData();
01037         foreach(const KoShapeLoadingContext::AdditionalAttributeData & attributeData, additionalAttributeData) {
01038             if (element.hasAttributeNS(attributeData.ns, attributeData.tag)) {
01039                 QString value = element.attributeNS(attributeData.ns, attributeData.tag);
01040                 //kDebug(30006) << "load additional attribute" << attributeData.tag << value;
01041                 setAdditionalAttribute(attributeData.name, value);
01042             }
01043         }
01044     }
01045 
01046     if (attributes & OdfCommonChildElements) {
01047         const KoXmlElement eventActionsElement(KoXml::namedItemNS(element, KoXmlNS::office, "event-listeners"));
01048         if (!eventActionsElement.isNull()) {
01049             d->eventActions = KoEventActionRegistry::instance()->createEventActionsFromOdf(eventActionsElement, context);
01050         }
01051         // load glue points (connection points)
01052     }
01053 
01054     return true;
01055 }
01056 
01057 QString KoShape::getStyleProperty(const char *property, const KoXmlElement & element, KoShapeLoadingContext & context)
01058 {
01059     Q_UNUSED(element);
01060     KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
01061     QString value;
01062 
01063     if (styleStack.hasProperty(KoXmlNS::draw, property)) {
01064         value = styleStack.property(KoXmlNS::draw, property);
01065     }
01066 
01067     return value;
01068 }
01069 
01070 KoShapeBackground * KoShape::loadOdfFill(const KoXmlElement & element, KoShapeLoadingContext & context)
01071 {
01072     QString fill = getStyleProperty("fill", element, context);
01073     KoShapeBackground * bg = 0;
01074     if (fill == "solid" || fill == "hatch")
01075         bg = new KoColorBackground();
01076     else if (fill == "gradient")
01077         bg = new KoGradientBackground(new QLinearGradient());
01078     else if (fill == "bitmap")
01079         bg = new KoPatternBackground(context.imageCollection());
01080 
01081     if (! bg)
01082         return 0;
01083 
01084     if (! bg->loadStyle(context.odfLoadingContext(), size())) {
01085         delete bg;
01086         return 0;
01087     }
01088 
01089     return bg;
01090 }
01091 
01092 KoShapeBorderModel * KoShape::loadOdfStroke(const KoXmlElement & element, KoShapeLoadingContext & context)
01093 {
01094     KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
01095     KoOdfStylesReader &stylesReader = context.odfLoadingContext().stylesReader();
01096 
01097     QString stroke = getStyleProperty("stroke", element, context);
01098     if (stroke == "solid" || stroke == "dash") {
01099         QPen pen = KoOdfGraphicStyles::loadOdfStrokeStyle(styleStack, stroke, stylesReader);
01100 
01101         KoLineBorder * border = new KoLineBorder();
01102 
01103         if (styleStack.hasProperty(KoXmlNS::koffice, "stroke-gradient")) {
01104             QString gradientName = styleStack.property(KoXmlNS::koffice, "stroke-gradient");
01105             QBrush brush = KoOdfGraphicStyles::loadOdfGradientStyleByName(stylesReader, gradientName, size());
01106             border->setLineBrush(brush);
01107         } else {
01108             border->setColor(pen.color());
01109         }
01110 
01111 #ifndef NWORKAROUND_ODF_BUGS
01112         KoOdfWorkaround::fixPenWidth(pen, context);
01113 #endif
01114         border->setLineWidth(pen.widthF());
01115         border->setJoinStyle(pen.joinStyle());
01116         border->setLineStyle(pen.style(), pen.dashPattern());
01117 
01118         return border;
01119     } else {
01120         return 0;
01121     }
01122 }
01123 
01124 KoShapeShadow * KoShape::loadOdfShadow(const KoXmlElement & element, KoShapeLoadingContext & context)
01125 {
01126     KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
01127     QString shadowStyle = getStyleProperty("shadow", element, context);
01128     if (shadowStyle == "visible" || shadowStyle == "hidden") {
01129         KoShapeShadow * shadow = new KoShapeShadow();
01130         QColor shadowColor(styleStack.property(KoXmlNS::draw, "shadow-color"));
01131         qreal offsetX = KoUnit::parseValue(styleStack.property(KoXmlNS::draw, "shadow-offset-x"));
01132         qreal offsetY = KoUnit::parseValue(styleStack.property(KoXmlNS::draw, "shadow-offset-y"));
01133         shadow->setOffset(QPointF(offsetX, offsetY));
01134 
01135         QString opacity = styleStack.property(KoXmlNS::draw, "shadow-opacity");
01136         if (! opacity.isEmpty() && opacity.right(1) == "%")
01137             shadowColor.setAlphaF(opacity.left(opacity.length() - 1).toFloat() / 100.0);
01138         shadow->setColor(shadowColor);
01139         shadow->setVisibility(shadowStyle == "visible");
01140 
01141         return shadow;
01142     }
01143     return 0;
01144 }
01145 
01146 QMatrix KoShape::parseOdfTransform(const QString &transform)
01147 {
01148     QMatrix matrix;
01149 
01150     // Split string for handling 1 transform statement at a time
01151     QStringList subtransforms = transform.split(')', QString::SkipEmptyParts);
01152     QStringList::ConstIterator it = subtransforms.constBegin();
01153     QStringList::ConstIterator end = subtransforms.constEnd();
01154     for (; it != end; ++it) {
01155         QStringList subtransform = (*it).split('(', QString::SkipEmptyParts);
01156 
01157         subtransform[0] = subtransform[0].trimmed().toLower();
01158         subtransform[1] = subtransform[1].simplified();
01159         QRegExp reg("[,( ]");
01160         QStringList params = subtransform[1].split(reg, QString::SkipEmptyParts);
01161 
01162         if (subtransform[0].startsWith(';') || subtransform[0].startsWith(','))
01163             subtransform[0] = subtransform[0].right(subtransform[0].length() - 1);
01164 
01165         QString cmd = subtransform[0].toLower();
01166 
01167         if (cmd == "rotate") {
01168             QMatrix rotMatrix;
01169             if (params.count() == 3) {
01170                 qreal x = KoUnit::parseValue(params[1]);
01171                 qreal y = KoUnit::parseValue(params[2]);
01172 
01173                 rotMatrix.translate(x, y);
01174                 // oo2 rotates by radians
01175                 rotMatrix.rotate(-params[0].toDouble()*180.0 / M_PI);
01176                 rotMatrix.translate(-x, -y);
01177             } else {
01178                 // oo2 rotates by radians
01179                 rotMatrix.rotate(-params[0].toDouble()*180.0 / M_PI);
01180             }
01181             matrix = matrix * rotMatrix;
01182         } else if (cmd == "translate") {
01183             QMatrix moveMatrix;
01184             if (params.count() == 2) {
01185                 qreal x = KoUnit::parseValue(params[0]);
01186                 qreal y = KoUnit::parseValue(params[1]);
01187                 moveMatrix.translate(x, y);
01188             } else   // Spec : if only one param given, assume 2nd param to be 0
01189                 moveMatrix.translate(KoUnit::parseValue(params[0]) , 0);
01190             matrix = matrix * moveMatrix;
01191         } else if (cmd == "scale") {
01192             QMatrix scaleMatrix;
01193             if (params.count() == 2)
01194                 scaleMatrix.scale(params[0].toDouble(), params[1].toDouble());
01195             else    // Spec : if only one param given, assume uniform scaling
01196                 scaleMatrix.scale(params[0].toDouble(), params[0].toDouble());
01197             matrix = matrix * scaleMatrix;
01198         } else if (cmd == "skewx") {
01199             QPointF p = absolutePosition(KoFlake::TopLeftCorner);
01200             QMatrix shearMatrix;
01201             shearMatrix.translate(p.x(), p.y());
01202             shearMatrix.shear(tan(-params[0].toDouble()), 0.0F);
01203             shearMatrix.translate(-p.x(), -p.y());
01204             matrix = matrix * shearMatrix;
01205         } else if (cmd == "skewy") {
01206             QPointF p = absolutePosition(KoFlake::TopLeftCorner);
01207             QMatrix shearMatrix;
01208             shearMatrix.translate(p.x(), p.y());
01209             shearMatrix.shear(0.0F, tan(-params[0].toDouble()));
01210             shearMatrix.translate(-p.x(), -p.y());
01211             matrix = matrix * shearMatrix;
01212         } else if (cmd == "matrix") {
01213             QMatrix m;
01214             if (params.count() >= 6)
01215                 m.setMatrix(params[0].toDouble(), params[1].toDouble(), params[2].toDouble(), params[3].toDouble(),
01216                         KoUnit::parseValue(params[4]), KoUnit::parseValue(params[5]));
01217             matrix = matrix * m;
01218         }
01219     }
01220 
01221     return matrix;
01222 }
01223 
01224 void KoShape::saveOdfAttributes(KoShapeSavingContext &context, int attributes) const
01225 {
01226     Q_D(const KoShape);
01227     if (attributes & OdfStyle) {
01228         KoGenStyle style;
01229         // all items that should be written to 'draw:frame' and any other 'draw:' object that inherits this shape
01230         if (context.isSet(KoShapeSavingContext::PresentationShape)) {
01231             style = KoGenStyle(KoGenStyle::StylePresentationAuto, "presentation");
01232             context.xmlWriter().addAttribute("presentation:style-name", saveStyle(style, context));
01233         } else {
01234             style = KoGenStyle(KoGenStyle::StyleGraphicAuto, "graphic");
01235             context.xmlWriter().addAttribute("draw:style-name", saveStyle(style, context));
01236         }
01237     }
01238 
01239     if (attributes & OdfId)  {
01240         if (context.isSet(KoShapeSavingContext::DrawId)) {
01241             context.xmlWriter().addAttribute("draw:id", context.drawId(this));
01242         }
01243     }
01244 
01245     if (attributes & OdfName) {
01246         if (! name().isEmpty())
01247             context.xmlWriter().addAttribute("draw:name", name());
01248     }
01249 
01250     if (attributes & OdfLayer) {
01251         KoShape *parent = d->parent;
01252         while (parent) {
01253             if (dynamic_cast<KoShapeLayer*>(parent)) {
01254                 context.xmlWriter().addAttribute("draw:layer", parent->name());
01255                 break;
01256             }
01257             parent = parent->parent();
01258         }
01259     }
01260 
01261     if (attributes & OdfSize) {
01262         const QSizeF s(size());
01263         context.xmlWriter().addAttributePt("svg:width", s.width());
01264         context.xmlWriter().addAttributePt("svg:height", s.height());
01265     }
01266 
01267     // The position is implicitly stored in the transformation matrix
01268     // if the transformation is saved as well
01269     if ((attributes & OdfPosition) && !(attributes & OdfTransformation)) {
01270         const QPointF p(position() * context.shapeOffset(this));
01271         context.xmlWriter().addAttributePt("svg:x", p.x());
01272         context.xmlWriter().addAttributePt("svg:y", p.y());
01273     }
01274 
01275     if (attributes & OdfTransformation) {
01276         QMatrix matrix = absoluteTransformation(0) * context.shapeOffset(this);
01277         if (! matrix.isIdentity()) {
01278             if (qAbs(matrix.m11() - 1) < 1E-5           // 1
01279                     && qAbs(matrix.m12()) < 1E-5        // 0
01280                     && qAbs(matrix.m21()) < 1E-5        // 0
01281                     && qAbs(matrix.m22() - 1) < 1E-5) { // 1
01282                 context.xmlWriter().addAttribute("svg:x", QString("%1pt").arg(matrix.dx()));
01283                 context.xmlWriter().addAttribute("svg:y", QString("%1pt").arg(matrix.dy()));
01284             } else {
01285                 QString m = QString("matrix(%1 %2 %3 %4 %5pt %6pt)")
01286                             .arg(matrix.m11()).arg(matrix.m12())
01287                             .arg(matrix.m21()).arg(matrix.m22())
01288                             .arg(matrix.dx()) .arg(matrix.dy());
01289                 context.xmlWriter().addAttribute("draw:transform", m);
01290             }
01291         }
01292     }
01293 
01294     if (attributes & OdfViewbox) {
01295         const QSizeF s(size());
01296         QString viewBox = QString("0 0 %1 %2").arg(qRound(s.width())).arg(qRound(s.height()));
01297         context.xmlWriter().addAttribute("svg:viewBox", viewBox);
01298     }
01299 
01300     if (attributes & OdfAdditionalAttributes) {
01301         QMap<QByteArray, QString>::const_iterator it(d->additionalAttributes.constBegin());
01302         for (; it != d->additionalAttributes.constEnd(); ++it) {
01303             context.xmlWriter().addAttribute(it.key(), it.value());
01304         }
01305     }
01306 }
01307 
01308 void KoShape::saveOdfCommonChildElements(KoShapeSavingContext &context) const
01309 {
01310     Q_D(const KoShape);
01311     // save event listeners see ODF 9.2.21 Event Listeners
01312     if (d->eventActions.size() > 0) {
01313         context.xmlWriter().startElement("office:event-listeners");
01314         foreach(KoEventAction * action, d->eventActions) {
01315             action->saveOdf(context);
01316         }
01317         context.xmlWriter().endElement();
01318     }
01319 
01320     // save glue points see ODF 9.2.19 Glue Points
01321 }
01322 
01323 // end loading & saving methods
01324 
01325 void KoShape::init(const QMap<QString, KoDataCenter *> & dataCenterMap)
01326 {
01327     Q_UNUSED(dataCenterMap);
01328 }
01329 
01330 
01331 // static
01332 void KoShape::applyConversion(QPainter &painter, const KoViewConverter &converter)
01333 {
01334     qreal zoomX, zoomY;
01335     converter.zoom(&zoomX, &zoomY);
01336     painter.scale(zoomX, zoomY);
01337 }
01338 
01339 QPointF KoShape::shapeToDocument(const QPointF &point) const
01340 {
01341     return absoluteTransformation(0).map(point);
01342 }
01343 
01344 QRectF KoShape::shapeToDocument(const QRectF &rect) const
01345 {
01346     return absoluteTransformation(0).mapRect(rect);
01347 }
01348 
01349 QPointF KoShape::documentToShape(const QPointF &point) const
01350 {
01351     return absoluteTransformation(0).inverted().map(point);
01352 }
01353 
01354 QRectF KoShape::documentToShape(const QRectF &rect) const
01355 {
01356     return absoluteTransformation(0).inverted().mapRect(rect);
01357 }
01358 
01359 bool KoShape::addDependee(KoShape * shape)
01360 {
01361     Q_D(KoShape);
01362     if (! shape)
01363         return false;
01364 
01365     // refuse to establish a circular dependency
01366     if (shape->hasDependee(this))
01367         return false;
01368 
01369     if (! d->dependees.contains(shape))
01370         d->dependees.append(shape);
01371 
01372     return true;
01373 }
01374 
01375 void KoShape::removeDependee(KoShape * shape)
01376 {
01377     Q_D(KoShape);
01378     int index = d->dependees.indexOf(shape);
01379     if (index >= 0)
01380         d->dependees.removeAt(index);
01381 }
01382 
01383 bool KoShape::hasDependee(KoShape * shape) const
01384 {
01385     Q_D(const KoShape);
01386     return d->dependees.contains(shape);
01387 }
01388 
01389 void KoShape::shapeChanged(ChangeType type, KoShape *shape)
01390 {
01391     Q_UNUSED(type);
01392     Q_UNUSED(shape);
01393 }
01394 
01395 KoSnapData KoShape::snapData() const
01396 {
01397     return KoSnapData();
01398 }
01399 
01400 void KoShape::setAdditionalAttribute(const char * name, const QString & value)
01401 {
01402     Q_D(KoShape);
01403     d->additionalAttributes.insert(name, value);
01404 }
01405 
01406 void KoShape::removeAdditionalAttribute(const char * name)
01407 {
01408     Q_D(KoShape);
01409     d->additionalAttributes.remove(name);
01410 }
01411 
01412 bool KoShape::hasAdditionalAttribute(const char * name) const
01413 {
01414     Q_D(const KoShape);
01415     return d->additionalAttributes.contains(name);
01416 }
01417 
01418 QString KoShape::additionalAttribute(const char * name) const
01419 {
01420     Q_D(const KoShape);
01421     return d->additionalAttributes.value(name);
01422 }
01423 
01424 void KoShape::setAdditionalStyleAttribute(const char * name, const QString & value)
01425 {
01426     Q_D(KoShape);
01427     d->additionalStyleAttributes.insert(name, value);
01428 }
01429 
01430 void KoShape::removeAdditionalStyleAttribute(const char * name)
01431 {
01432     Q_D(KoShape);
01433     d->additionalStyleAttributes.remove(name);
01434 }
01435 
01436 KoFilterEffectStack * KoShape::filterEffectStack() const
01437 {
01438     Q_D(const KoShape);
01439     return d->filterEffectStack;
01440 }
01441 
01442 void KoShape::setFilterEffectStack(KoFilterEffectStack * filterEffectStack)
01443 {
01444     Q_D(KoShape);
01445     if (d->filterEffectStack)
01446         d->filterEffectStack->removeUser();
01447     d->filterEffectStack = filterEffectStack;
01448     if (d->filterEffectStack) {
01449         d->filterEffectStack->addUser();
01450     }
01451     notifyChanged();
01452 }