KoShape.cpp 39.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"
48
#include "KoFilterEffectStack.h"
Thomas Zander's avatar
Thomas Zander committed
49

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

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

67 68
#include <kdebug.h>

69 70
#include <limits>

71 72 73 74 75 76 77
KoShapePrivate::KoShapePrivate(KoShape *shape)
    : size(50, 50),
    parent(0),
    userData(0),
    appData(0),
    fill(0),
    border(0),
78
    q(shape),
79
    shadow(0),
80
    filterEffectStack(0),
81 82 83 84 85 86 87 88
    zIndex(0),
    visible(true),
    printable(true),
    geometryProtected(false),
    keepAspect(false),
    selectable(true),
    detectCollision(false),
    protectContent(false)
89
{
90 91 92 93
    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));
94
}
Thomas Zander's avatar
Thomas Zander committed
95

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

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

126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
void KoShapePrivate::updateBorder()
{
    if (border == 0)
        return;
    KoInsets insets;
    border->borderInsets(q, insets);
    QSizeF inner = q->size();
    // update left
    q->update(QRectF(-insets.left, -insets.top, insets.left,
                inner.height() + insets.top + insets.bottom));
    // update top
    q->update(QRectF(-insets.left, -insets.top,
                inner.width() + insets.left + insets.right, insets.top));
    // update right
    q->update(QRectF(inner.width(), -insets.top, insets.right,
                inner.height() + insets.top + insets.bottom));
    // update bottom
    q->update(QRectF(-insets.left, inner.height(),
                inner.width() + insets.left + insets.right, insets.bottom));
}
Thomas Zander's avatar
Thomas Zander committed
146

147
// ======== KoShape
Thomas Zander's avatar
Thomas Zander committed
148
KoShape::KoShape()
149
        : d_ptr(new KoShapePrivate(this))
Thomas Zander's avatar
Thomas Zander committed
150
{
151
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
152 153
}

154 155 156 157 158
KoShape::KoShape(KoShapePrivate &dd)
    : d_ptr(&dd)
{
}

Thomas Zander's avatar
Thomas Zander committed
159 160
KoShape::~KoShape()
{
161
    Q_D(KoShape);
162
    d->shapeChanged(Deleted);
163
    delete d_ptr;
Thomas Zander's avatar
Thomas Zander committed
164 165
}

166 167
void KoShape::paintDecorations(QPainter &painter, const KoViewConverter &converter, const KoCanvasBase *canvas)
{
Thomas Zander's avatar
Thomas Zander committed
168 169 170
    Q_UNUSED(painter);
    Q_UNUSED(converter);
    Q_UNUSED(canvas);
171 172
    /* 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
173
        {
174 175 176 177 178 179 180 181 182 183 184 185
            // 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
186 187
}

188
void KoShape::setScale(qreal sx, qreal sy)
Thomas Zander's avatar
Thomas Zander committed
189
{
190
    Q_D(KoShape);
191 192
    QPointF pos = position();
    QMatrix scaleMatrix;
193 194 195
    scaleMatrix.translate(pos.x(), pos.y());
    scaleMatrix.scale(sx, sy);
    scaleMatrix.translate(-pos.x(), -pos.y());
196
    d->localMatrix = d->localMatrix * scaleMatrix;
197

198
    notifyChanged();
199
    d->shapeChanged(ScaleChanged);
Thomas Zander's avatar
Thomas Zander committed
200 201
}

202
void KoShape::rotate(qreal angle)
Thomas Zander's avatar
Thomas Zander committed
203
{
204
    Q_D(KoShape);
205
    QPointF center = d->localMatrix.map(QPointF(0.5 * size().width(), 0.5 * size().height()));
206
    QMatrix rotateMatrix;
207 208 209
    rotateMatrix.translate(center.x(), center.y());
    rotateMatrix.rotate(angle);
    rotateMatrix.translate(-center.x(), -center.y());
210
    d->localMatrix = d->localMatrix * rotateMatrix;
211

212
    notifyChanged();
213
    d->shapeChanged(RotationChanged);
Thomas Zander's avatar
Thomas Zander committed
214 215
}

216
void KoShape::setShear(qreal sx, qreal sy)
Thomas Zander's avatar
Thomas Zander committed
217
{
218
    Q_D(KoShape);
219 220
    QPointF pos = position();
    QMatrix shearMatrix;
221 222 223
    shearMatrix.translate(pos.x(), pos.y());
    shearMatrix.shear(sx, sy);
    shearMatrix.translate(-pos.x(), -pos.y());
224
    d->localMatrix = d->localMatrix * shearMatrix;
225

226
    notifyChanged();
227
    d->shapeChanged(ShearChanged);
Thomas Zander's avatar
Thomas Zander committed
228 229
}

230
void KoShape::setSize(const QSizeF &newSize)
Thomas Zander's avatar
Thomas Zander committed
231
{
232
    Q_D(KoShape);
233 234
    QSizeF oldSize(size());
    if (oldSize == newSize)
Thomas Zander's avatar
Thomas Zander committed
235
        return;
236

237
    QMatrix matrix;
238 239
    oldSize.setHeight(qMax((qreal) 1E-4, oldSize.height())); // avoids devision by zero below
    oldSize.setWidth(qMax((qreal) 1E-4, oldSize.width()));
240
    matrix.scale(newSize.width()/oldSize.width(), newSize.height()/oldSize.height());
241 242

    KoGradientBackground * g = dynamic_cast<KoGradientBackground*>(d->fill);
243
    if (g) {
244
        g->setMatrix(g->matrix() * matrix);
245
    }
246
    KoLineBorder *l = dynamic_cast<KoLineBorder*>(d->border);
247 248
    if (l && l->lineBrush().gradient()) {
        QBrush brush = l->lineBrush();
249 250
        brush.setMatrix(brush.matrix() * matrix);
        l->setLineBrush(brush);
251
    }
252

Thomas Zander's avatar
Thomas Zander committed
253
    d->size = newSize;
254

255
    notifyChanged();
256
    d->shapeChanged(SizeChanged);
Thomas Zander's avatar
Thomas Zander committed
257 258
}

259
void KoShape::setPosition(const QPointF &newPosition)
Thomas Zander's avatar
Thomas Zander committed
260
{
261
    Q_D(KoShape);
262
    QPointF currentPos = position();
263
    if (newPosition == currentPos)
Thomas Zander's avatar
Thomas Zander committed
264
        return;
265
    QMatrix translateMatrix;
266
    translateMatrix.translate(newPosition.x() - currentPos.x(), newPosition.y() - currentPos.y());
267 268 269
    d->localMatrix = d->localMatrix * translateMatrix;

    notifyChanged();
270
    d->shapeChanged(PositionChanged);
Thomas Zander's avatar
Thomas Zander committed
271 272
}

273
bool KoShape::hitTest(const QPointF &position) const
Thomas Zander's avatar
Thomas Zander committed
274
{
275
    Q_D(const KoShape);
276
    if (d->parent && d->parent->childClipped(this) && !d->parent->hitTest(position))
Thomas Zander's avatar
Thomas Zander committed
277 278
        return false;

279
    QPointF point = absoluteTransformation(0).inverted().map(position);
280
    QRectF bb(QPointF(), size());
281
    if (d->border) {
282
        KoInsets insets;
283
        d->border->borderInsets(this, insets);
284
        bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
285
    }
286 287 288
    if (bb.contains(point))
        return true;

289
    // if there is no shadow we can as well just leave
290
    if (! d->shadow)
291
        return false;
Thomas Zander's avatar
Thomas Zander committed
292

293 294
    // the shadow has an offset to the shape, so we simply
    // check if the position minus the shadow offset hits the shape
295
    point = absoluteTransformation(0).inverted().map(position - d->shadow->offset());
296

297
    return bb.contains(point);
Thomas Zander's avatar
Thomas Zander committed
298 299
}

300
QRectF KoShape::boundingRect() const
Thomas Zander's avatar
Thomas Zander committed
301
{
302
    Q_D(const KoShape);
303
    QRectF bb(QPointF(0, 0), size());
304
    if (d->border) {
305 306 307 308
        KoInsets insets;
        d->border->borderInsets(this, insets);
        bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
    }
309 310
    bb = absoluteTransformation(0).mapRect(bb);
    if (d->shadow) {
311
        KoInsets insets;
312
        d->shadow->insets(this, insets);
313 314 315
        bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
    }
    return bb;
Thomas Zander's avatar
Thomas Zander committed
316 317
}

318 319
QMatrix KoShape::absoluteTransformation(const KoViewConverter *converter) const
{
320
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
321 322
    QMatrix matrix;
    // apply parents matrix to inherit any transformations done there.
323
    KoShapeContainer * container = d->parent;
324 325
    if (container) {
        if (container->childClipped(this))
326
            matrix = container->absoluteTransformation(0);
Thomas Zander's avatar
Thomas Zander committed
327
        else {
328 329 330 331
            QSizeF containerSize = container->size();
            QPointF containerPos = container->absolutePosition() - QPointF(0.5 * containerSize.width(), 0.5 * containerSize.height());
            if (converter)
                containerPos = converter->documentToView(containerPos);
332
            matrix.translate(containerPos.x(), containerPos.y());
Thomas Zander's avatar
Thomas Zander committed
333 334 335
        }
    }

336
    if (converter) {
337 338 339
        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
340
    }
341 342

    return d->localMatrix * matrix;
Thomas Zander's avatar
Thomas Zander committed
343 344
}

345
void KoShape::applyAbsoluteTransformation(const QMatrix &matrix)
346
{
347
    QMatrix globalMatrix = absoluteTransformation(0);
348 349
    // 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
350
    // to be relative to the local coordinate system
351
    QMatrix transformMatrix = globalMatrix * matrix * globalMatrix.inverted();
352
    applyTransformation(transformMatrix);
353 354
}

355
void KoShape::applyTransformation(const QMatrix &matrix)
356
{
357
    Q_D(KoShape);
358
    d->localMatrix = matrix * d->localMatrix;
359
    notifyChanged();
360
    d->shapeChanged(GenericMatrixChange);
361 362
}

363
void KoShape::setTransformation(const QMatrix &matrix)
364
{
365
    Q_D(KoShape);
366 367
    d->localMatrix = matrix;
    notifyChanged();
368
    d->shapeChanged(GenericMatrixChange);
369
}
Thomas Zander's avatar
Thomas Zander committed
370

371
QMatrix KoShape::transformation() const
372
{
373
    Q_D(const KoShape);
374 375 376
    return d->localMatrix;
}

377 378
bool KoShape::compareShapeZIndex(KoShape *s1, KoShape *s2)
{
379
    int diff = s1->zIndex() - s2->zIndex();
380
    if (diff == 0) {
381
        KoShape *s = s1->parent();
382
        while (s) {
383
            if (s == s2) // s1 is a child of s2
384 385 386 387
                return false; // children are always on top of their parents.
            s = s->parent();
        }
        s = s2->parent();
388
        while (s) {
389
            if (s == s1) // s2 is a child of s1
390 391 392 393 394
                return true;
            s = s->parent();
        }
    }
    return diff < 0;
Thomas Zander's avatar
Thomas Zander committed
395 396
}

397 398
void KoShape::setParent(KoShapeContainer *parent)
{
399
    Q_D(KoShape);
400
    if (d->parent == parent)
401
        return;
402 403 404 405
    KoShapeContainer *oldParent = d->parent;
    d->parent = 0; // avoids recursive removing
    if (oldParent)
        oldParent->removeChild(this);
Thomas Zander's avatar
Thomas Zander committed
406
    if (parent && parent != this) {
Thomas Zander's avatar
Thomas Zander committed
407
        d->parent = parent;
408
        parent->addChild(this);
409
    }
410
    notifyChanged();
411
    d->shapeChanged(ParentChanged);
Thomas Zander's avatar
Thomas Zander committed
412 413
}

414 415
int KoShape::zIndex() const
{
416
    Q_D(const KoShape);
417
    if (parent()) // we can't be under our parent...
418
        return qMax((int) d->zIndex, parent()->zIndex());
Thomas Zander's avatar
Thomas Zander committed
419
    return d->zIndex;
Thomas Zander's avatar
Thomas Zander committed
420 421
}

422 423
void KoShape::update() const
{
424
    Q_D(const KoShape);
425 426 427
    if (!d->shapeManagers.empty()) {
        QRectF rect(boundingRect());
        foreach(KoShapeManager * manager, d->shapeManagers)
Jan Hambrecht's avatar
Jan Hambrecht committed
428
            manager->update(rect, this, true);
Thomas Zander's avatar
Thomas Zander committed
429 430 431
    }
}

432 433
void KoShape::update(const QRectF &shape) const
{
434
    Q_D(const KoShape);
435
    if (!d->shapeManagers.empty() && isVisible()) {
436
        QRectF rect(absoluteTransformation(0).mapRect(shape));
437
        foreach(KoShapeManager * manager, d->shapeManagers) {
438
            manager->update(rect);
439 440
        }
    }
Thomas Zander's avatar
Thomas Zander committed
441 442
}

443 444
const QPainterPath KoShape::outline() const
{
445
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
446
    QPainterPath path;
447
    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
448 449 450
    return path;
}

451 452
QPointF KoShape::absolutePosition(KoFlake::Position anchor) const
{
453
    QPointF point;
454 455 456 457 458 459
    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;
460
    }
461
    return absoluteTransformation(0).map(point);
Thomas Zander's avatar
Thomas Zander committed
462 463
}

464 465
void KoShape::setAbsolutePosition(QPointF newPosition, KoFlake::Position anchor)
{
466
    Q_D(KoShape);
467
    QPointF currentAbsPosition = absolutePosition(anchor);
468
    QPointF translate = newPosition - currentAbsPosition;
Jan Hambrecht's avatar
Jan Hambrecht committed
469
    QMatrix translateMatrix;
470 471
    translateMatrix.translate(translate.x(), translate.y());
    applyAbsoluteTransformation(translateMatrix);
472
    notifyChanged();
473
    d->shapeChanged(PositionChanged);
Thomas Zander's avatar
Thomas Zander committed
474 475
}

476 477
void KoShape::copySettings(const KoShape *shape)
{
478
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
479 480
    d->size = shape->size();
    d->connectors.clear();
Jan Hambrecht's avatar
Jan Hambrecht committed
481 482
    foreach(const QPointF & point, shape->connectionPoints())
        addConnectionPoint(point);
Thomas Zander's avatar
Thomas Zander committed
483 484
    d->zIndex = shape->zIndex();
    d->visible = shape->isVisible();
485

486 487 488 489 490
    // Ensure printable is true by default
    if (!d->visible)
        d->printable = true;
    else
        d->printable = shape->isPrintable();
491

492
    d->geometryProtected = shape->isGeometryProtected();
Thomas Zander's avatar
Thomas Zander committed
493
    d->keepAspect = shape->keepAspectRatio();
494
    d->localMatrix = shape->d_ptr->localMatrix;
Thomas Zander's avatar
Thomas Zander committed
495 496
}

Thomas Zander's avatar
Thomas Zander committed
497
void KoShape::notifyChanged()
498
{
499
    Q_D(KoShape);
500 501
    foreach(KoShapeManager * manager, d->shapeManagers) {
        manager->notifyShapeChanged(this);
502 503 504
    }
}

505 506
void KoShape::setUserData(KoShapeUserData *userData)
{
507
    Q_D(KoShape);
508
    delete d->userData;
Thomas Zander's avatar
Thomas Zander committed
509
    d->userData = userData;
510 511
}

512 513
KoShapeUserData *KoShape::userData() const
{
514
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
515
    return d->userData;
516 517
}

518 519
void KoShape::setApplicationData(KoShapeApplicationData *appData)
{
520
    Q_D(KoShape);
521
    // appdata is deleted by the application.
Thomas Zander's avatar
Thomas Zander committed
522
    d->appData = appData;
523 524
}

525 526
KoShapeApplicationData *KoShape::applicationData() const
{
527
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
528
    return d->appData;
529 530
}

531 532
bool KoShape::hasTransparency()
{
533
    Q_D(KoShape);
534
    if (! d->fill)
Thomas Zander's avatar
Thomas Zander committed
535
        return true;
536 537
    else
        return d->fill->hasTransparency();
Thomas Zander's avatar
Thomas Zander committed
538 539
}

540 541
KoInsets KoShape::borderInsets() const
{
542
    Q_D(const KoShape);
543
    KoInsets answer;
544
    if (d->border)
545
        d->border->borderInsets(this, answer);
546 547 548
    return answer;
}

549 550
qreal KoShape::rotation() const
{
551
    Q_D(const KoShape);
552
    // try to extract the rotation angle out of the local matrix
553 554 555
    // if it is a pure rotation matrix

    // check if the matrix has shearing mixed in
556
    if (fabs(fabs(d->localMatrix.m12()) - fabs(d->localMatrix.m21())) > 1e-10)
557
        return std::numeric_limits<qreal>::quiet_NaN();
558
    // check if the matrix has scaling mixed in
559
    if (fabs(d->localMatrix.m11() - d->localMatrix.m22()) > 1e-10)
560
        return std::numeric_limits<qreal>::quiet_NaN();
561 562

    // calculate the angle from the matrix elements
563 564
    qreal angle = atan2(-d->localMatrix.m21(), d->localMatrix.m11()) * 180.0 / M_PI;
    if (angle < 0.0)
565 566 567
        angle += 360.0;

    return angle;
Thomas Zander's avatar
Thomas Zander committed
568 569
}

570
QSizeF KoShape::size() const
571
{
572
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
573 574 575
    return d->size;
}

576 577
QPointF KoShape::position() const
{
578
    Q_D(const KoShape);
579 580
    QPointF center(0.5*size().width(), 0.5*size().height());
    return d->localMatrix.map(center) - center;
581
    //return d->localMatrix.map( QPointF(0,0) );
Thomas Zander's avatar
Thomas Zander committed
582 583
}

584
void KoShape::addConnectionPoint(const QPointF &point)
585
{
586
    Q_D(KoShape);
587 588
    QSizeF s = size();
    // convert glue point from shape coordinates to factors of size
589
    d->connectors.append(QPointF(point.x() / s.width(), point.y() / s.height()));
Thomas Zander's avatar
Thomas Zander committed
590 591
}

592 593
QList<QPointF> KoShape::connectionPoints() const
{
594
    Q_D(const KoShape);
595 596 597
    QList<QPointF> points;
    QSizeF s = size();
    // convert glue points to shape coordinates
Jan Hambrecht's avatar
Jan Hambrecht committed
598 599
    foreach(const QPointF & cp, d->connectors)
        points.append(QPointF(s.width() * cp.x(), s.height() * cp.y()));
600 601

    return points;
602 603
}

604
void KoShape::addEventAction(KoEventAction * action)
605
{
606
    Q_D(KoShape);
607 608
    if (! d->eventActions.contains(action)) {
        d->eventActions.append(action);
609 610 611
    }
}

612
void KoShape::removeEventAction(KoEventAction * action)
613
{
614
    Q_D(KoShape);
615 616
    if (d->eventActions.contains(action)) {
        d->eventActions.removeAll(action);
617 618 619 620 621
    }
}

QList<KoEventAction *> KoShape::eventActions() const
{
622
    Q_D(const KoShape);
623 624 625
    return d->eventActions;
}

626
void KoShape::setBackground(KoShapeBackground * fill)
627
{
628
    Q_D(KoShape);
629
    if (d->fill)
630 631
        d->fill->removeUser();
    d->fill = fill;
632
    if (d->fill)
633
        d->fill->addUser();
634 635
    d->shapeChanged(BackgroundChanged);
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
636 637
}

638 639
KoShapeBackground * KoShape::background() const
{
640
    Q_D(const KoShape);
641
    return d->fill;
Thomas Zander's avatar
Thomas Zander committed
642 643
}

644 645
void KoShape::setZIndex(int zIndex)
{
646
    Q_D(KoShape);
647
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
648 649 650
    d->zIndex = zIndex;
}

651 652
void KoShape::setVisible(bool on)
{
653
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
654 655 656
    d->visible = on;
}

657
bool KoShape::isVisible(bool recursive) const
658
{
659
    Q_D(const KoShape);
660
    if (! recursive)
661
        return d->visible;
662
    if (recursive && ! d->visible)
Jan Hambrecht's avatar
Jan Hambrecht committed
663 664
        return false;

665
    KoShapeContainer * parentShape = parent();
666 667
    while (parentShape) {
        if (! parentShape->isVisible())
668 669 670 671
            return false;
        parentShape = parentShape->parent();
    }
    return true;
Thomas Zander's avatar
Thomas Zander committed
672 673
}

674 675
void KoShape::setPrintable(bool on)
{
676
    Q_D(KoShape);
677 678
    d->printable = on;
}
679

680 681
bool KoShape::isPrintable() const
{
682
    Q_D(const KoShape);
683 684 685 686
    if (d->visible)
        return d->printable;
    else
        return false;
687 688
}

689 690
void KoShape::setSelectable(bool selectable)
{
691
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
692 693 694
    d->selectable = selectable;
}

695 696
bool KoShape::isSelectable() const
{
697
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
698 699 700
    return d->selectable;
}

701
void KoShape::setGeometryProtected(bool on)
702
{
703
    Q_D(KoShape);
704
    d->geometryProtected = on;
Thomas Zander's avatar
Thomas Zander committed
705 706
}

707
bool KoShape::isGeometryProtected() const
708
{
709
    Q_D(const KoShape);
710
    return d->geometryProtected;
Thomas Zander's avatar
Thomas Zander committed
711 712
}

713 714
void KoShape::setContentProtected(bool protect)
{
715
    Q_D(KoShape);
716 717 718 719 720
    d->protectContent = protect;
}

bool KoShape::isContentProtected() const
{
721
    Q_D(const KoShape);
722 723 724
    return d->protectContent;
}

725 726
KoShapeContainer *KoShape::parent() const
{
727
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
728 729 730
    return d->parent;
}

731 732
void KoShape::setKeepAspectRatio(bool keepAspect)
{
733
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
734 735 736
    d->keepAspect = keepAspect;
}

737 738
bool KoShape::keepAspectRatio() const
{
739
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
740 741 742
    return d->keepAspect;
}

743 744
const QString &KoShape::shapeId() const
{
745
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
746 747 748
    return d->shapeId;
}

749 750
void KoShape::setShapeId(const QString &id)
{
751
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
752 753 754
    d->shapeId = id;
}

755 756
void KoShape::setCollisionDetection(bool detect)
{
757
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
758 759 760
    d->detectCollision = detect;
}

761 762
bool KoShape::collisionDetection()
{
763
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
764 765 766
    return d->detectCollision;
}

767
void KoShape::addShapeManager(KoShapeManager * manager)
768
{
769
    Q_D(KoShape);
770
    d->shapeManagers.insert(manager);
Thomas Zander's avatar
Thomas Zander committed
771 772
}

773
void KoShape::removeShapeManager(KoShapeManager * manager)
774
{
775
    Q_D(KoShape);
776
    d->shapeManagers.remove(manager);
Thomas Zander's avatar
Thomas Zander committed
777 778
}

779 780
KoShapeBorderModel *KoShape::border() const
{
781
    Q_D(const KoShape);
782 783 784
    return d->border;
}

785 786
void KoShape::setBorder(KoShapeBorderModel *border)
{
787
    Q_D(KoShape);
788 789
    if (border)
        border->addUser();
790
    d->updateBorder();
791
    if (d->border)
792
        d->border->removeUser();
793
    d->border = border;
794
    d->updateBorder();
795 796
    d->shapeChanged(BorderChanged);
    notifyChanged();
797 798
}

799
void KoShape::setShadow(KoShapeShadow * shadow)
800
{
801
    Q_D(KoShape);
802
    if (d->shadow)
803 804
        d->shadow->removeUser();
    d->shadow = shadow;
805
    if (d->shadow) {
806
        d->shadow->addUser();
807 808
        // TODO update changed area
    }
809 810 811 812 813 814
    d->shapeChanged(ShadowChanged);
    notifyChanged();
}

KoShapeShadow * KoShape::shadow() const
{
815
    Q_D(const KoShape);
816 817 818
    return d->shadow;
}

819 820
const QMatrix& KoShape::matrix() const
{
821
    Q_D(const KoShape);
822
    return d->localMatrix;
823 824
}

825
void KoShape::removeConnectionPoint(int index)
826
{
827
    Q_D(KoShape);
828 829
    if (index < d->connectors.count())
        d->connectors.remove(index);
830 831
}

832 833
QString KoShape::name() const
{
834
    Q_D(const KoShape);
835 836 837
    return d->name;
}

838