KoShape.cpp 38.9 KB
Newer Older
Thomas Zander's avatar
Thomas Zander committed
1
/* This file is part of the KDE project
Thomas Zander's avatar
Thomas Zander committed
2
   Copyright (C) 2006 Casper Boemann Rasmussen <cbr@boemann.dk>
3
   Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
4
   Copyright (C) 2006-2008 Thorsten Zachmann <zachmann@kde.org>
5
   Copyright (C) 2007-2009 Jan Hambrecht <jaham@gmx.net>
Thomas Zander's avatar
Thomas Zander committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA 02110-1301, USA.
*/

#include "KoShape.h"
24
#include "KoShape_p.h"
Thomas Zander's avatar
Thomas Zander committed
25
#include "KoShapeContainer.h"
26
#include "KoShapeLayer.h"
27
#include "KoShapeContainerModel.h"
Thomas Zander's avatar
Thomas Zander committed
28
#include "KoSelection.h"
29
#include "KoPointerEvent.h"
Thomas Zander's avatar
Thomas Zander committed
30 31
#include "KoInsets.h"
#include "KoShapeBorderModel.h"
32 33 34 35
#include "KoShapeBackground.h"
#include "KoColorBackground.h"
#include "KoGradientBackground.h"
#include "KoPatternBackground.h"
36
#include "KoShapeManager.h"
37
#include "KoShapeUserData.h"
38
#include "KoShapeApplicationData.h"
39
#include "KoShapeSavingContext.h"
40
#include "KoShapeLoadingContext.h"
41
#include "KoViewConverter.h"
42
#include "KoLineBorder.h"
43
#include "ShapeDeleter_p.h"
44
#include "KoShapeShadow.h"
Thorsten Zachmann's avatar
Thorsten Zachmann committed
45 46
#include "KoEventAction.h"
#include "KoEventActionRegistry.h"
47
#include "KoOdfWorkaround.h"
Thomas Zander's avatar
Thomas Zander committed
48

49
#include <KoXmlReader.h>
50
#include <KoXmlWriter.h>
51
#include <KoXmlNS.h>
52
#include <KoGenStyle.h>
53
#include <KoGenStyles.h>
54
#include <KoUnit.h>
55
#include <KoOdfStylesReader.h>
56
#include <KoOdfGraphicStyles.h>
57
#include <KoOdfLoadingContext.h>
58

Thomas Zander's avatar
Thomas Zander committed
59
#include <QPainter>
60
#include <QVariant>
Thomas Zander's avatar
Thomas Zander committed
61
#include <QPainterPath>
62
#include <QList>
63
#include <QMap>
64
#include <QByteArray>
Thomas Zander's avatar
Thomas Zander committed
65

66 67
#include <kdebug.h>

68 69
#include <limits>

70 71 72 73 74 75 76
KoShapePrivate::KoShapePrivate(KoShape *shape)
    : size(50, 50),
    parent(0),
    userData(0),
    appData(0),
    fill(0),
    border(0),
77
    q(shape),
78 79 80 81 82 83 84 85 86
    shadow(0),
    zIndex(0),
    visible(true),
    printable(true),
    geometryProtected(false),
    keepAspect(false),
    selectable(true),
    detectCollision(false),
    protectContent(false)
87
{
88 89 90 91
    connectors.append(QPointF(0.5, 0.0));
    connectors.append(QPointF(1.0, 0.5));
    connectors.append(QPointF(0.5, 1.0));
    connectors.append(QPointF(0.0, 0.5));
92
}
Thomas Zander's avatar
Thomas Zander committed
93

94 95 96
KoShapePrivate::~KoShapePrivate()
{
    if (parent)
97
        parent->removeChild(q);
98
    foreach(KoShapeManager *manager, shapeManagers) {
99 100
        manager->remove(q);
        manager->removeAdditional(q);
Thomas Zander's avatar
Thomas Zander committed
101
    }
102 103 104 105 106 107 108 109 110
    delete userData;
    delete appData;
    if (border && ! border->removeUser())
        delete border;
    if (shadow && ! shadow->removeUser())
        delete shadow;
    if (fill && ! fill->removeUser())
        delete fill;
    qDeleteAll(eventActions);
111
    qDeleteAll(filterEffects);
112
}
Thomas Zander's avatar
Thomas Zander committed
113

114 115 116
void KoShapePrivate::shapeChanged(KoShape::ChangeType type)
{
    if (parent)
117 118
        parent->model()->childChanged(q, type);
    q->shapeChanged(type);
119
    foreach(KoShape * shape, dependees)
120
        shape->shapeChanged(type, q);
121
}
122

Thomas Zander's avatar
Thomas Zander committed
123

124
// ======== KoShape
Thomas Zander's avatar
Thomas Zander committed
125
KoShape::KoShape()
126
        : d_ptr(new KoShapePrivate(this))
Thomas Zander's avatar
Thomas Zander committed
127
{
128
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
129 130
}

131 132 133 134 135
KoShape::KoShape(KoShapePrivate &dd)
    : d_ptr(&dd)
{
}

Thomas Zander's avatar
Thomas Zander committed
136 137
KoShape::~KoShape()
{
138
    Q_D(KoShape);
139
    d->shapeChanged(Deleted);
140
    delete d_ptr;
Thomas Zander's avatar
Thomas Zander committed
141 142
}

143 144
void KoShape::paintDecorations(QPainter &painter, const KoViewConverter &converter, const KoCanvasBase *canvas)
{
Thomas Zander's avatar
Thomas Zander committed
145 146 147
    Q_UNUSED(painter);
    Q_UNUSED(converter);
    Q_UNUSED(canvas);
148 149
    /* Since this code is not actually used (kivio is going to be the main user) lets disable instead of fix.
        if ( selected )
Thomas Zander's avatar
Thomas Zander committed
150
        {
151 152 153 154 155 156 157 158 159 160 161 162
            // draw connectors
            QPen pen( Qt::blue );
            pen.setWidth( 0 );
            painter.setPen( pen );
            painter.setBrush( Qt::NoBrush );
            for ( int i = 0; i < d->connectors.size(); ++i )
            {
                QPointF p = converter.documentToView(d->connectors[ i ]);
                painter.drawLine( QPointF( p.x() - 2, p.y() + 2 ), QPointF( p.x() + 2, p.y() - 2 ) );
                painter.drawLine( QPointF( p.x() + 2, p.y() + 2 ), QPointF( p.x() - 2, p.y() - 2 ) );
            }
        }*/
Thomas Zander's avatar
Thomas Zander committed
163 164
}

165
void KoShape::setScale(qreal sx, qreal sy)
Thomas Zander's avatar
Thomas Zander committed
166
{
167
    Q_D(KoShape);
168 169
    QPointF pos = position();
    QMatrix scaleMatrix;
170 171 172
    scaleMatrix.translate(pos.x(), pos.y());
    scaleMatrix.scale(sx, sy);
    scaleMatrix.translate(-pos.x(), -pos.y());
173
    d->localMatrix = d->localMatrix * scaleMatrix;
174

175
    notifyChanged();
176
    d->shapeChanged(ScaleChanged);
Thomas Zander's avatar
Thomas Zander committed
177 178
}

179
void KoShape::rotate(qreal angle)
Thomas Zander's avatar
Thomas Zander committed
180
{
181
    Q_D(KoShape);
182
    QPointF center = d->localMatrix.map(QPointF(0.5 * size().width(), 0.5 * size().height()));
183
    QMatrix rotateMatrix;
184 185 186
    rotateMatrix.translate(center.x(), center.y());
    rotateMatrix.rotate(angle);
    rotateMatrix.translate(-center.x(), -center.y());
187
    d->localMatrix = d->localMatrix * rotateMatrix;
188

189
    notifyChanged();
190
    d->shapeChanged(RotationChanged);
Thomas Zander's avatar
Thomas Zander committed
191 192
}

193
void KoShape::setShear(qreal sx, qreal sy)
Thomas Zander's avatar
Thomas Zander committed
194
{
195
    Q_D(KoShape);
196 197
    QPointF pos = position();
    QMatrix shearMatrix;
198 199 200
    shearMatrix.translate(pos.x(), pos.y());
    shearMatrix.shear(sx, sy);
    shearMatrix.translate(-pos.x(), -pos.y());
201
    d->localMatrix = d->localMatrix * shearMatrix;
202

203
    notifyChanged();
204
    d->shapeChanged(ShearChanged);
Thomas Zander's avatar
Thomas Zander committed
205 206
}

207
void KoShape::setSize(const QSizeF &newSize)
Thomas Zander's avatar
Thomas Zander committed
208
{
209
    Q_D(KoShape);
210 211
    QSizeF oldSize(size());
    if (oldSize == newSize)
Thomas Zander's avatar
Thomas Zander committed
212
        return;
213

214
    QMatrix matrix;
215 216
    oldSize.setHeight(qMax((qreal) 1E-4, oldSize.height())); // avoids devision by zero below
    oldSize.setWidth(qMax((qreal) 1E-4, oldSize.width()));
217
    matrix.scale(newSize.width()/oldSize.width(), newSize.height()/oldSize.height());
218 219

    KoGradientBackground * g = dynamic_cast<KoGradientBackground*>(d->fill);
220
    if (g) {
221
        g->setMatrix(g->matrix() * matrix);
222
    }
223
    KoLineBorder *l = dynamic_cast<KoLineBorder*>(d->border);
224 225
    if (l && l->lineBrush().gradient()) {
        QBrush brush = l->lineBrush();
226 227
        brush.setMatrix(brush.matrix() * matrix);
        l->setLineBrush(brush);
228
    }
229

Thomas Zander's avatar
Thomas Zander committed
230
    d->size = newSize;
231

232
    notifyChanged();
233
    d->shapeChanged(SizeChanged);
Thomas Zander's avatar
Thomas Zander committed
234 235
}

236
void KoShape::setPosition(const QPointF &newPosition)
Thomas Zander's avatar
Thomas Zander committed
237
{
238
    Q_D(KoShape);
239
    QPointF currentPos = position();
240
    if (newPosition == currentPos)
Thomas Zander's avatar
Thomas Zander committed
241
        return;
242
    QMatrix translateMatrix;
243
    translateMatrix.translate(newPosition.x() - currentPos.x(), newPosition.y() - currentPos.y());
244 245 246
    d->localMatrix = d->localMatrix * translateMatrix;

    notifyChanged();
247
    d->shapeChanged(PositionChanged);
Thomas Zander's avatar
Thomas Zander committed
248 249
}

250
bool KoShape::hitTest(const QPointF &position) const
Thomas Zander's avatar
Thomas Zander committed
251
{
252
    Q_D(const KoShape);
253
    if (d->parent && d->parent->childClipped(this) && !d->parent->hitTest(position))
Thomas Zander's avatar
Thomas Zander committed
254 255
        return false;

256
    QPointF point = absoluteTransformation(0).inverted().map(position);
257
    QRectF bb(QPointF(), size());
258
    if (d->border) {
259
        KoInsets insets;
260
        d->border->borderInsets(this, insets);
261
        bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
262
    }
263 264 265
    if (bb.contains(point))
        return true;

266
    // if there is no shadow we can as well just leave
267
    if (! d->shadow)
268
        return false;
Thomas Zander's avatar
Thomas Zander committed
269

270 271
    // the shadow has an offset to the shape, so we simply
    // check if the position minus the shadow offset hits the shape
272
    point = absoluteTransformation(0).inverted().map(position - d->shadow->offset());
273

274
    return bb.contains(point);
Thomas Zander's avatar
Thomas Zander committed
275 276
}

277
QRectF KoShape::boundingRect() const
Thomas Zander's avatar
Thomas Zander committed
278
{
279
    Q_D(const KoShape);
280
    QRectF bb(QPointF(0, 0), size());
281
    if (d->border) {
282 283 284 285
        KoInsets insets;
        d->border->borderInsets(this, insets);
        bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
    }
286 287
    bb = absoluteTransformation(0).mapRect(bb);
    if (d->shadow) {
288
        KoInsets insets;
289
        d->shadow->insets(this, insets);
290 291 292
        bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
    }
    return bb;
Thomas Zander's avatar
Thomas Zander committed
293 294
}

295 296
QMatrix KoShape::absoluteTransformation(const KoViewConverter *converter) const
{
297
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
298 299
    QMatrix matrix;
    // apply parents matrix to inherit any transformations done there.
300
    KoShapeContainer * container = d->parent;
301 302
    if (container) {
        if (container->childClipped(this))
303
            matrix = container->absoluteTransformation(0);
Thomas Zander's avatar
Thomas Zander committed
304
        else {
305 306 307 308
            QSizeF containerSize = container->size();
            QPointF containerPos = container->absolutePosition() - QPointF(0.5 * containerSize.width(), 0.5 * containerSize.height());
            if (converter)
                containerPos = converter->documentToView(containerPos);
309
            matrix.translate(containerPos.x(), containerPos.y());
Thomas Zander's avatar
Thomas Zander committed
310 311 312
        }
    }

313
    if (converter) {
314 315 316
        QPointF pos = d->localMatrix.map(QPointF());
        QPointF trans = converter->documentToView(pos) - pos;
        matrix.translate(trans.x(), trans.y());
Thomas Zander's avatar
Thomas Zander committed
317
    }
318 319

    return d->localMatrix * matrix;
Thomas Zander's avatar
Thomas Zander committed
320 321
}

322
void KoShape::applyAbsoluteTransformation(const QMatrix &matrix)
323
{
324
    QMatrix globalMatrix = absoluteTransformation(0);
325 326
    // the transformation is relative to the global coordinate system
    // but we want to change the local matrix, so convert the matrix
Thomas Zander's avatar
Thomas Zander committed
327
    // to be relative to the local coordinate system
328
    QMatrix transformMatrix = globalMatrix * matrix * globalMatrix.inverted();
329
    applyTransformation(transformMatrix);
330 331
}

332
void KoShape::applyTransformation(const QMatrix &matrix)
333
{
334
    Q_D(KoShape);
335
    d->localMatrix = matrix * d->localMatrix;
336
    notifyChanged();
337
    d->shapeChanged(GenericMatrixChange);
338 339
}

340
void KoShape::setTransformation(const QMatrix &matrix)
341
{
342
    Q_D(KoShape);
343 344
    d->localMatrix = matrix;
    notifyChanged();
345
    d->shapeChanged(GenericMatrixChange);
346
}
Thomas Zander's avatar
Thomas Zander committed
347

348
QMatrix KoShape::transformation() const
349
{
350
    Q_D(const KoShape);
351 352 353
    return d->localMatrix;
}

354 355
bool KoShape::compareShapeZIndex(KoShape *s1, KoShape *s2)
{
356
    int diff = s1->zIndex() - s2->zIndex();
357
    if (diff == 0) {
358
        KoShape *s = s1->parent();
359
        while (s) {
360
            if (s == s2) // s1 is a child of s2
361 362 363 364
                return false; // children are always on top of their parents.
            s = s->parent();
        }
        s = s2->parent();
365
        while (s) {
366
            if (s == s1) // s2 is a child of s1
367 368 369 370 371
                return true;
            s = s->parent();
        }
    }
    return diff < 0;
Thomas Zander's avatar
Thomas Zander committed
372 373
}

374 375
void KoShape::setParent(KoShapeContainer *parent)
{
376
    Q_D(KoShape);
377
    if (d->parent == parent)
378
        return;
379 380 381 382
    KoShapeContainer *oldParent = d->parent;
    d->parent = 0; // avoids recursive removing
    if (oldParent)
        oldParent->removeChild(this);
Thomas Zander's avatar
Thomas Zander committed
383
    if (parent && parent != this) {
Thomas Zander's avatar
Thomas Zander committed
384
        d->parent = parent;
385
        parent->addChild(this);
386
    }
387
    notifyChanged();
388
    d->shapeChanged(ParentChanged);
Thomas Zander's avatar
Thomas Zander committed
389 390
}

391 392
int KoShape::zIndex() const
{
393
    Q_D(const KoShape);
394
    if (parent()) // we can't be under our parent...
395
        return qMax((int) d->zIndex, parent()->zIndex());
Thomas Zander's avatar
Thomas Zander committed
396
    return d->zIndex;
Thomas Zander's avatar
Thomas Zander committed
397 398
}

399 400
void KoShape::update() const
{
401
    Q_D(const KoShape);
402 403 404
    if (!d->shapeManagers.empty()) {
        QRectF rect(boundingRect());
        foreach(KoShapeManager * manager, d->shapeManagers)
Jan Hambrecht's avatar
Jan Hambrecht committed
405
            manager->update(rect, this, true);
Thomas Zander's avatar
Thomas Zander committed
406 407 408
    }
}

409 410
void KoShape::update(const QRectF &shape) const
{
411
    Q_D(const KoShape);
412
    if (!d->shapeManagers.empty() && isVisible()) {
413
        QRectF rect(absoluteTransformation(0).mapRect(shape));
414
        foreach(KoShapeManager * manager, d->shapeManagers) {
415
            manager->update(rect);
416 417
        }
    }
Thomas Zander's avatar
Thomas Zander committed
418 419
}

420 421
const QPainterPath KoShape::outline() const
{
422
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
423
    QPainterPath path;
424
    path.addRect(QRectF(QPointF(0, 0), QSizeF(qMax(d->size.width(), qreal(0.0001)), qMax(d->size.height(), qreal(0.0001)))));
Thomas Zander's avatar
Thomas Zander committed
425 426 427
    return path;
}

428 429
QPointF KoShape::absolutePosition(KoFlake::Position anchor) const
{
430
    QPointF point;
431 432 433 434 435 436
    switch (anchor) {
    case KoFlake::TopLeftCorner: break;
    case KoFlake::TopRightCorner: point = QPointF(size().width(), 0.0); break;
    case KoFlake::BottomLeftCorner: point = QPointF(0.0, size().height()); break;
    case KoFlake::BottomRightCorner: point = QPointF(size().width(), size().height()); break;
    case KoFlake::CenteredPosition: point = QPointF(size().width() / 2.0, size().height() / 2.0); break;
437
    }
438
    return absoluteTransformation(0).map(point);
Thomas Zander's avatar
Thomas Zander committed
439 440
}

441 442
void KoShape::setAbsolutePosition(QPointF newPosition, KoFlake::Position anchor)
{
443
    Q_D(KoShape);
444
    QPointF currentAbsPosition = absolutePosition(anchor);
445
    QPointF translate = newPosition - currentAbsPosition;
Jan Hambrecht's avatar
Jan Hambrecht committed
446
    QMatrix translateMatrix;
447 448
    translateMatrix.translate(translate.x(), translate.y());
    applyAbsoluteTransformation(translateMatrix);
449
    notifyChanged();
450
    d->shapeChanged(PositionChanged);
Thomas Zander's avatar
Thomas Zander committed
451 452
}

453 454
void KoShape::copySettings(const KoShape *shape)
{
455
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
456 457
    d->size = shape->size();
    d->connectors.clear();
Jan Hambrecht's avatar
Jan Hambrecht committed
458 459
    foreach(const QPointF & point, shape->connectionPoints())
        addConnectionPoint(point);
Thomas Zander's avatar
Thomas Zander committed
460 461
    d->zIndex = shape->zIndex();
    d->visible = shape->isVisible();
462

463 464 465 466 467
    // Ensure printable is true by default
    if (!d->visible)
        d->printable = true;
    else
        d->printable = shape->isPrintable();
468

469
    d->geometryProtected = shape->isGeometryProtected();
Thomas Zander's avatar
Thomas Zander committed
470
    d->keepAspect = shape->keepAspectRatio();
471
    d->localMatrix = shape->d_ptr->localMatrix;
Thomas Zander's avatar
Thomas Zander committed
472 473
}

Thomas Zander's avatar
Thomas Zander committed
474
void KoShape::notifyChanged()
475
{
476
    Q_D(KoShape);
477 478
    foreach(KoShapeManager * manager, d->shapeManagers) {
        manager->notifyShapeChanged(this);
479 480 481
    }
}

482 483
void KoShape::setUserData(KoShapeUserData *userData)
{
484
    Q_D(KoShape);
485
    delete d->userData;
Thomas Zander's avatar
Thomas Zander committed
486
    d->userData = userData;
487 488
}

489 490
KoShapeUserData *KoShape::userData() const
{
491
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
492
    return d->userData;
493 494
}

495 496
void KoShape::setApplicationData(KoShapeApplicationData *appData)
{
497
    Q_D(KoShape);
498
    // appdata is deleted by the application.
Thomas Zander's avatar
Thomas Zander committed
499
    d->appData = appData;
500 501
}

502 503
KoShapeApplicationData *KoShape::applicationData() const
{
504
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
505
    return d->appData;
506 507
}

508 509
bool KoShape::hasTransparency()
{
510
    Q_D(KoShape);
511
    if (! d->fill)
Thomas Zander's avatar
Thomas Zander committed
512
        return true;
513 514
    else
        return d->fill->hasTransparency();
Thomas Zander's avatar
Thomas Zander committed
515 516
}

517 518
KoInsets KoShape::borderInsets() const
{
519
    Q_D(const KoShape);
520
    KoInsets answer;
521
    if (d->border)
522
        d->border->borderInsets(this, answer);
523 524 525
    return answer;
}

526 527
qreal KoShape::rotation() const
{
528
    Q_D(const KoShape);
529
    // try to extract the rotation angle out of the local matrix
530 531 532
    // if it is a pure rotation matrix

    // check if the matrix has shearing mixed in
533
    if (fabs(fabs(d->localMatrix.m12()) - fabs(d->localMatrix.m21())) > 1e-10)
534
        return std::numeric_limits<qreal>::quiet_NaN();
535
    // check if the matrix has scaling mixed in
536
    if (fabs(d->localMatrix.m11() - d->localMatrix.m22()) > 1e-10)
537
        return std::numeric_limits<qreal>::quiet_NaN();
538 539

    // calculate the angle from the matrix elements
540 541
    qreal angle = atan2(-d->localMatrix.m21(), d->localMatrix.m11()) * 180.0 / M_PI;
    if (angle < 0.0)
542 543 544
        angle += 360.0;

    return angle;
Thomas Zander's avatar
Thomas Zander committed
545 546
}

547
QSizeF KoShape::size() const
548
{
549
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
550 551 552
    return d->size;
}

553 554
QPointF KoShape::position() const
{
555
    Q_D(const KoShape);
556 557
    QPointF center(0.5*size().width(), 0.5*size().height());
    return d->localMatrix.map(center) - center;
558
    //return d->localMatrix.map( QPointF(0,0) );
Thomas Zander's avatar
Thomas Zander committed
559 560
}

561
void KoShape::addConnectionPoint(const QPointF &point)
562
{
563
    Q_D(KoShape);
564 565
    QSizeF s = size();
    // convert glue point from shape coordinates to factors of size
566
    d->connectors.append(QPointF(point.x() / s.width(), point.y() / s.height()));
Thomas Zander's avatar
Thomas Zander committed
567 568
}

569 570
QList<QPointF> KoShape::connectionPoints() const
{
571
    Q_D(const KoShape);
572 573 574
    QList<QPointF> points;
    QSizeF s = size();
    // convert glue points to shape coordinates
Jan Hambrecht's avatar
Jan Hambrecht committed
575 576
    foreach(const QPointF & cp, d->connectors)
        points.append(QPointF(s.width() * cp.x(), s.height() * cp.y()));
577 578

    return points;
579 580
}

581
void KoShape::addEventAction(KoEventAction * action)
582
{
583
    Q_D(KoShape);
584 585
    if (! d->eventActions.contains(action)) {
        d->eventActions.append(action);
586 587 588
    }
}

589
void KoShape::removeEventAction(KoEventAction * action)
590
{
591
    Q_D(KoShape);
592 593
    if (d->eventActions.contains(action)) {
        d->eventActions.removeAll(action);
594 595 596 597 598
    }
}

QList<KoEventAction *> KoShape::eventActions() const
{
599
    Q_D(const KoShape);
600 601 602
    return d->eventActions;
}

603
void KoShape::setBackground(KoShapeBackground * fill)
604
{
605
    Q_D(KoShape);
606
    if (d->fill)
607 608
        d->fill->removeUser();
    d->fill = fill;
609
    if (d->fill)
610
        d->fill->addUser();
611 612
    d->shapeChanged(BackgroundChanged);
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
613 614
}

615 616
KoShapeBackground * KoShape::background() const
{
617
    Q_D(const KoShape);
618
    return d->fill;
Thomas Zander's avatar
Thomas Zander committed
619 620
}

621 622
void KoShape::setZIndex(int zIndex)
{
623
    Q_D(KoShape);
624
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
625 626 627
    d->zIndex = zIndex;
}

628 629
void KoShape::setVisible(bool on)
{
630
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
631 632 633
    d->visible = on;
}

634
bool KoShape::isVisible(bool recursive) const
635
{
636
    Q_D(const KoShape);
637
    if (! recursive)
638
        return d->visible;
639
    if (recursive && ! d->visible)
Jan Hambrecht's avatar
Jan Hambrecht committed
640 641
        return false;

642
    KoShapeContainer * parentShape = parent();
643 644
    while (parentShape) {
        if (! parentShape->isVisible())
645 646 647 648
            return false;
        parentShape = parentShape->parent();
    }
    return true;
Thomas Zander's avatar
Thomas Zander committed
649 650
}

651 652
void KoShape::setPrintable(bool on)
{
653
    Q_D(KoShape);
654 655
    d->printable = on;
}
656

657 658
bool KoShape::isPrintable() const
{
659
    Q_D(const KoShape);
660 661 662 663
    if (d->visible)
        return d->printable;
    else
        return false;
664 665
}

666 667
void KoShape::setSelectable(bool selectable)
{
668
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
669 670 671
    d->selectable = selectable;
}

672 673
bool KoShape::isSelectable() const
{
674
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
675 676 677
    return d->selectable;
}

678
void KoShape::setGeometryProtected(bool on)
679
{
680
    Q_D(KoShape);
681
    d->geometryProtected = on;
Thomas Zander's avatar
Thomas Zander committed
682 683
}

684
bool KoShape::isGeometryProtected() const
685
{
686
    Q_D(const KoShape);
687
    return d->geometryProtected;
Thomas Zander's avatar
Thomas Zander committed
688 689
}

690 691
void KoShape::setContentProtected(bool protect)
{
692
    Q_D(KoShape);
693 694 695 696 697
    d->protectContent = protect;
}

bool KoShape::isContentProtected() const
{
698
    Q_D(const KoShape);
699 700 701
    return d->protectContent;
}

702 703
KoShapeContainer *KoShape::parent() const
{
704
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
705 706 707
    return d->parent;
}

708 709
void KoShape::setKeepAspectRatio(bool keepAspect)
{
710
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
711 712 713
    d->keepAspect = keepAspect;
}

714 715
bool KoShape::keepAspectRatio() const
{
716
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
717 718 719
    return d->keepAspect;
}

720 721
const QString &KoShape::shapeId() const
{
722
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
723 724 725
    return d->shapeId;
}

726 727
void KoShape::setShapeId(const QString &id)
{
728
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
729 730 731
    d->shapeId = id;
}

732 733
void KoShape::setCollisionDetection(bool detect)
{
734
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
735 736 737
    d->detectCollision = detect;
}

738 739
bool KoShape::collisionDetection()
{
740
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
741 742 743
    return d->detectCollision;
}

744
void KoShape::addShapeManager(KoShapeManager * manager)
745
{
746
    Q_D(KoShape);
747
    d->shapeManagers.insert(manager);
Thomas Zander's avatar
Thomas Zander committed
748 749
}

750
void KoShape::removeShapeManager(KoShapeManager * manager)
751
{
752
    Q_D(KoShape);
753
    d->shapeManagers.remove(manager);
Thomas Zander's avatar
Thomas Zander committed
754 755
}

756 757
KoShapeBorderModel *KoShape::border() const
{
758
    Q_D(const KoShape);
759 760 761
    return d->border;
}

762 763
void KoShape::setBorder(KoShapeBorderModel *border)
{
764
    Q_D(KoShape);
765
    if (d->border)
766
        d->border->removeUser();
767
    d->border = border;
768
    if (d->border)
769
        d->border->addUser();
770 771
    d->shapeChanged(BorderChanged);
    notifyChanged();
772 773
}

774
void KoShape::setShadow(KoShapeShadow * shadow)
775
{
776
    Q_D(KoShape);
777
    if (d->shadow)
778 779
        d->shadow->removeUser();
    d->shadow = shadow;
780
    if (d->shadow)
781 782 783 784 785 786 787
        d->shadow->addUser();
    d->shapeChanged(ShadowChanged);
    notifyChanged();
}

KoShapeShadow * KoShape::shadow() const
{
788
    Q_D(const KoShape);
789 790 791
    return d->shadow;
}

792 793
const QMatrix& KoShape::matrix() const
{
794
    Q_D(const KoShape);
795
    return d->localMatrix;
796 797
}

798
void KoShape::removeConnectionPoint(int index)
799
{
800
    Q_D(KoShape);
801 802
    if (index < d->connectors.count())
        d->connectors.remove(index);
803 804
}

805 806
QString KoShape::name() const
{
807
    Q_D(const KoShape);
808 809 810
    return d->name;
}

811
void KoShape::setName(const QString & name)
812
{
813
    Q_D(KoShape);
814 815
    d->name = name;
}
816

817 818
void KoShape::deleteLater()
{
819
    Q_D(KoShape);
820
    foreach(KoShapeManager *manager, d->shapeManagers)
Jan Hambrecht's avatar
Jan Hambrecht committed
821
        manager->remove(this);
822 823 824 825
    d->shapeManagers.clear();
    new ShapeDeleter(this);
}

826 827
bool KoShape::isEditable() const
{