KoShape.cpp 49.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-2010 Thomas Zander <zander@kde.org>
4
   Copyright (C) 2006-2010 Thorsten Zachmann <zachmann@kde.org>
5
   Copyright (C) 2007-2009 Jan Hambrecht <jaham@gmx.net>
6
   CopyRight (C) 2010 Boudewijn Rempt <boud@kogmbh.com>
Thomas Zander's avatar
Thomas Zander committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20

   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,
21
   Boston, MA 02110-1301, USA.
Thomas Zander's avatar
Thomas Zander committed
22 23 24
*/

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

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

Thomas Zander's avatar
Thomas Zander committed
62
#include <QPainter>
63
#include <QVariant>
Thomas Zander's avatar
Thomas Zander committed
64
#include <QPainterPath>
65
#include <QList>
66
#include <QMap>
67
#include <QByteArray>
68 69
#include <kdebug.h>

70 71
#include <limits>

72 73
// KoShapeCache

74
/// Empty all cached images from the image cache
75 76 77 78 79 80 81 82
void KoShapeCache::purge()
{
    qDeleteAll(deviceData);
    deviceData.clear();
}

// KoShapePrivate

83 84
KoShapePrivate::KoShapePrivate(KoShape *shape)
    : size(50, 50),
85 86 87 88 89 90 91 92 93 94
      parent(0),
      userData(0),
      appData(0),
      fill(0),
      border(0),
      q_ptr(shape),
      shadow(0),
      filterEffectStack(0),
      transparency(0.0),
      zIndex(0),
95
      runThrough(0),
96 97 98 99 100 101 102
      visible(true),
      printable(true),
      geometryProtected(false),
      keepAspect(false),
      selectable(true),
      detectCollision(false),
      protectContent(false),
103
      cacheMode(KoShape::NoCache),
104 105 106
      cache(0),
      textRunAroundSide(KoShape::BiggestRunAroundSide),
      textRunAroundDistance(1.0)
107
{
108 109 110 111
    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));
112
}
Thomas Zander's avatar
Thomas Zander committed
113

114 115
KoShapePrivate::~KoShapePrivate()
{
116
    Q_Q(KoShape);
117
    if (parent)
118
        parent->removeShape(q);
119
    foreach(KoShapeManager *manager, shapeManagers) {
120 121
        manager->remove(q);
        manager->removeAdditional(q);
Thomas Zander's avatar
Thomas Zander committed
122
    }
123 124
    delete userData;
    delete appData;
125
    if (border && !border->deref())
126
        delete border;
127
    if (shadow && !shadow->deref())
128
        delete shadow;
129
    if (fill && !fill->deref())
130
        delete fill;
131
    if (filterEffectStack && !filterEffectStack->deref())
132
        delete filterEffectStack;
133 134
    qDeleteAll(eventActions);
}
Thomas Zander's avatar
Thomas Zander committed
135

136 137
void KoShapePrivate::shapeChanged(KoShape::ChangeType type)
{
138
    Q_Q(KoShape);
139
    if (parent)
140 141
        parent->model()->childChanged(q, type);
    q->shapeChanged(type);
142
    foreach(KoShape * shape, dependees)
143
        shape->shapeChanged(type, q);
144
}
145

146 147
void KoShapePrivate::updateBorder()
{
148
    Q_Q(KoShape);
149 150 151 152 153 154 155
    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,
156
                     inner.height() + insets.top + insets.bottom));
157 158
    // update top
    q->update(QRectF(-insets.left, -insets.top,
159
                     inner.width() + insets.left + insets.right, insets.top));
160 161
    // update right
    q->update(QRectF(inner.width(), -insets.top, insets.right,
162
                     inner.height() + insets.top + insets.bottom));
163 164
    // update bottom
    q->update(QRectF(-insets.left, inner.height(),
165
                     inner.width() + insets.left + insets.right, insets.bottom));
166
}
Thomas Zander's avatar
Thomas Zander committed
167

168 169 170 171 172 173 174 175
void KoShapePrivate::addShapeManager(KoShapeManager *manager)
{
    shapeManagers.insert(manager);
}

void KoShapePrivate::removeShapeManager(KoShapeManager *manager)
{
    shapeManagers.remove(manager);
176 177 178 179 180 181 182 183 184 185 186
    if (cacheMode == KoShape::ScaledCache) {
        if (KoShapeCache *cache = maybeShapeCache()) {
            KoShapeCache::DeviceData *deviceData = cache->deviceData.take(manager);
            delete deviceData;
        }
    }
}

KoShapeCache *KoShapePrivate::maybeShapeCache() const
{
    return cache;
187
}
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206

KoShapeCache *KoShapePrivate::shapeCache() const
{
    if (!cache) {
        const_cast<KoShapePrivate *>(this)->cache = new KoShapeCache;
    }
    return cache;
}

void KoShapePrivate::removeShapeCache()
{
    if (cache) {
        cache->purge();
        delete cache;
        cache = 0;
    }
}


207
// static
208
QString KoShapePrivate::getStyleProperty(const char *property, KoShapeLoadingContext &context)
209 210 211 212 213 214 215 216 217 218 219
{
    KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
    QString value;

    if (styleStack.hasProperty(KoXmlNS::draw, property)) {
        value = styleStack.property(KoXmlNS::draw, property);
    }

    return value;
}

220 221


222
// ======== KoShape
Thomas Zander's avatar
Thomas Zander committed
223
KoShape::KoShape()
224
    : d_ptr(new KoShapePrivate(this))
Thomas Zander's avatar
Thomas Zander committed
225
{
226
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
227 228
}

229 230 231 232 233
KoShape::KoShape(KoShapePrivate &dd)
    : d_ptr(&dd)
{
}

Thomas Zander's avatar
Thomas Zander committed
234 235
KoShape::~KoShape()
{
236
    Q_D(KoShape);
237
    d->shapeChanged(Deleted);
238
    d->removeShapeCache();
239
    delete d_ptr;
Thomas Zander's avatar
Thomas Zander committed
240 241
}

242 243
void KoShape::paintDecorations(QPainter &painter, const KoViewConverter &converter, const KoCanvasBase *canvas)
{
Thomas Zander's avatar
Thomas Zander committed
244 245 246
    Q_UNUSED(painter);
    Q_UNUSED(converter);
    Q_UNUSED(canvas);
247
    /* Since this code is not actually used (kivio is going to be the main user) lets disable instead of fix.
248
        if (selected)
Thomas Zander's avatar
Thomas Zander committed
249
        {
250
            // draw connectors
251 252 253 254 255
            QPen pen(Qt::blue);
            pen.setWidth(0);
            painter.setPen(pen);
            painter.setBrush(Qt::NoBrush);
            for (int i = 0; i < d->connectors.size(); ++i)
256
          {
257
                QPointF p = converter.documentToView(d->connectors[ i ]);
258 259
                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));
260 261
            }
        }*/
Thomas Zander's avatar
Thomas Zander committed
262 263
}

Thomas Zander's avatar
Thomas Zander committed
264
void KoShape::scale(qreal sx, qreal sy)
Thomas Zander's avatar
Thomas Zander committed
265
{
266
    Q_D(KoShape);
267
    QPointF pos = position();
268
    QTransform scaleMatrix;
269 270 271
    scaleMatrix.translate(pos.x(), pos.y());
    scaleMatrix.scale(sx, sy);
    scaleMatrix.translate(-pos.x(), -pos.y());
272
    d->localMatrix = d->localMatrix * scaleMatrix;
273

274
    notifyChanged();
275
    d->shapeChanged(ScaleChanged);
Thomas Zander's avatar
Thomas Zander committed
276 277
}

278
void KoShape::rotate(qreal angle)
Thomas Zander's avatar
Thomas Zander committed
279
{
280
    Q_D(KoShape);
281
    QPointF center = d->localMatrix.map(QPointF(0.5 * size().width(), 0.5 * size().height()));
282
    QTransform rotateMatrix;
283 284 285
    rotateMatrix.translate(center.x(), center.y());
    rotateMatrix.rotate(angle);
    rotateMatrix.translate(-center.x(), -center.y());
286
    d->localMatrix = d->localMatrix * rotateMatrix;
287

288
    notifyChanged();
289
    d->shapeChanged(RotationChanged);
Thomas Zander's avatar
Thomas Zander committed
290 291
}

Thomas Zander's avatar
Thomas Zander committed
292
void KoShape::shear(qreal sx, qreal sy)
Thomas Zander's avatar
Thomas Zander committed
293
{
294
    Q_D(KoShape);
295
    QPointF pos = position();
296
    QTransform shearMatrix;
297 298 299
    shearMatrix.translate(pos.x(), pos.y());
    shearMatrix.shear(sx, sy);
    shearMatrix.translate(-pos.x(), -pos.y());
300
    d->localMatrix = d->localMatrix * shearMatrix;
301

302
    notifyChanged();
303
    d->shapeChanged(ShearChanged);
Thomas Zander's avatar
Thomas Zander committed
304 305
}

306
void KoShape::setSize(const QSizeF &newSize)
Thomas Zander's avatar
Thomas Zander committed
307
{
308
    Q_D(KoShape);
309 310
    QSizeF oldSize(size());
    if (oldSize == newSize)
Thomas Zander's avatar
Thomas Zander committed
311
        return;
312

Thomas Zander's avatar
Thomas Zander committed
313
    d->size = newSize;
314

315
    notifyChanged();
316
    d->shapeChanged(SizeChanged);
Thomas Zander's avatar
Thomas Zander committed
317 318
}

319
void KoShape::setPosition(const QPointF &newPosition)
Thomas Zander's avatar
Thomas Zander committed
320
{
321
    Q_D(KoShape);
322
    QPointF currentPos = position();
323
    if (newPosition == currentPos)
Thomas Zander's avatar
Thomas Zander committed
324
        return;
325
    QTransform translateMatrix;
326
    translateMatrix.translate(newPosition.x() - currentPos.x(), newPosition.y() - currentPos.y());
327 328 329
    d->localMatrix = d->localMatrix * translateMatrix;

    notifyChanged();
330
    d->shapeChanged(PositionChanged);
Thomas Zander's avatar
Thomas Zander committed
331 332
}

333
bool KoShape::hitTest(const QPointF &position) const
Thomas Zander's avatar
Thomas Zander committed
334
{
335
    Q_D(const KoShape);
336
    if (d->parent && d->parent->isClipped(this) && !d->parent->hitTest(position))
Thomas Zander's avatar
Thomas Zander committed
337 338
        return false;

339
    QPointF point = absoluteTransformation(0).inverted().map(position);
340
    QRectF bb(QPointF(), size());
341
    if (d->border) {
342
        KoInsets insets;
343
        d->border->borderInsets(this, insets);
344
        bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
345
    }
346 347 348
    if (bb.contains(point))
        return true;

349
    // if there is no shadow we can as well just leave
350
    if (! d->shadow)
351
        return false;
Thomas Zander's avatar
Thomas Zander committed
352

353 354
    // the shadow has an offset to the shape, so we simply
    // check if the position minus the shadow offset hits the shape
355
    point = absoluteTransformation(0).inverted().map(position - d->shadow->offset());
356

357
    return bb.contains(point);
Thomas Zander's avatar
Thomas Zander committed
358 359
}

360
QRectF KoShape::boundingRect() const
Thomas Zander's avatar
Thomas Zander committed
361
{
362
    Q_D(const KoShape);
363
    QSizeF mySize = size();
364
    QTransform transform = absoluteTransformation(0);
365
    QRectF bb = outlineRect();
366
    if (d->border) {
367 368 369 370
        KoInsets insets;
        d->border->borderInsets(this, insets);
        bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
    }
371
    bb = transform.mapRect(bb);
372
    if (d->shadow) {
373
        KoInsets insets;
Thomas Zander's avatar
Thomas Zander committed
374
        d->shadow->insets(insets);
375 376
        bb.adjust(-insets.left, -insets.top, insets.right, insets.bottom);
    }
377
    if (d->filterEffectStack) {
378
        QRectF clipRect = d->filterEffectStack->clipRectForBoundingRect(outlineRect());
379 380
        bb |= transform.mapRect(clipRect);
    }
Thomas Zander's avatar
Thomas Zander committed
381

382
    return bb;
Thomas Zander's avatar
Thomas Zander committed
383 384
}

385
QTransform KoShape::absoluteTransformation(const KoViewConverter *converter) const
386
{
387
    Q_D(const KoShape);
388
    QTransform matrix;
Thomas Zander's avatar
Thomas Zander committed
389
    // apply parents matrix to inherit any transformations done there.
390
    KoShapeContainer * container = d->parent;
391
    if (container) {
392
        if (container->inheritsTransform(this)) {
393 394 395 396
            // We do need to pass the converter here, otherwise the parent's
            // translation is not inherited.
            matrix = container->absoluteTransformation(converter);
        } else {
397 398 399 400
            QSizeF containerSize = container->size();
            QPointF containerPos = container->absolutePosition() - QPointF(0.5 * containerSize.width(), 0.5 * containerSize.height());
            if (converter)
                containerPos = converter->documentToView(containerPos);
401
            matrix.translate(containerPos.x(), containerPos.y());
Thomas Zander's avatar
Thomas Zander committed
402 403 404
        }
    }

405
    if (converter) {
406 407 408
        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
409
    }
410 411

    return d->localMatrix * matrix;
Thomas Zander's avatar
Thomas Zander committed
412 413
}

414
void KoShape::applyAbsoluteTransformation(const QTransform &matrix)
415
{
416
    QTransform globalMatrix = absoluteTransformation(0);
417 418
    // 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
419
    // to be relative to the local coordinate system
420
    QTransform transformMatrix = globalMatrix * matrix * globalMatrix.inverted();
421
    applyTransformation(transformMatrix);
422 423
}

424
void KoShape::applyTransformation(const QTransform &matrix)
425
{
426
    Q_D(KoShape);
427
    d->localMatrix = matrix * d->localMatrix;
428
    notifyChanged();
429
    d->shapeChanged(GenericMatrixChange);
430 431
}

432
void KoShape::setTransformation(const QTransform &matrix)
433
{
434
    Q_D(KoShape);
435 436
    d->localMatrix = matrix;
    notifyChanged();
437
    d->shapeChanged(GenericMatrixChange);
438
}
Thomas Zander's avatar
Thomas Zander committed
439

440
QTransform KoShape::transformation() const
441
{
442
    Q_D(const KoShape);
443 444 445
    return d->localMatrix;
}

446 447
bool KoShape::compareShapeZIndex(KoShape *s1, KoShape *s2)
{
448 449 450 451 452 453 454
    if(s1->runThrough() > s2->runThrough()) {
        return false;
    }
    if(s1->runThrough() < s2->runThrough()) {
        return true;
    }

455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
    bool foundCommonParent = false;
    KoShape *parentShapeS1 = s1;
    KoShape *parentShapeS2 = s2;
    int index1 = parentShapeS1->zIndex();
    int index2 = parentShapeS2->zIndex();
    while (parentShapeS1 && !foundCommonParent) {
        parentShapeS2 = s2;
        index2 = parentShapeS2->zIndex();
        while (parentShapeS2) {
            if (parentShapeS2 == parentShapeS1) {
                foundCommonParent = true;
                break;
            }
            index2 = parentShapeS2->zIndex();
            parentShapeS2 = parentShapeS2->parent();
470
        }
471 472 473 474

        if (!foundCommonParent) {
            index1 = parentShapeS1->zIndex();
            parentShapeS1 = parentShapeS1->parent();
475 476
        }
    }
477 478 479 480 481 482 483
    if (s1 == parentShapeS2) {
        return true;
    }
    else if (s2 == parentShapeS1) {
        return false;
    }
    return index1 < index2;
Thomas Zander's avatar
Thomas Zander committed
484 485
}

486 487
void KoShape::setParent(KoShapeContainer *parent)
{
488
    Q_D(KoShape);
489
    if (d->parent == parent)
490
        return;
491 492 493
    KoShapeContainer *oldParent = d->parent;
    d->parent = 0; // avoids recursive removing
    if (oldParent)
494
        oldParent->removeShape(this);
Thomas Zander's avatar
Thomas Zander committed
495
    if (parent && parent != this) {
Thomas Zander's avatar
Thomas Zander committed
496
        d->parent = parent;
497
        parent->addShape(this);
498
    }
499
    notifyChanged();
500
    d->shapeChanged(ParentChanged);
Thomas Zander's avatar
Thomas Zander committed
501 502
}

503 504
int KoShape::zIndex() const
{
505
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
506
    return d->zIndex;
Thomas Zander's avatar
Thomas Zander committed
507 508
}

509 510
void KoShape::update() const
{
511
    Q_D(const KoShape);
512 513 514 515 516 517 518 519 520 521

    if (d->cacheMode != NoCache) {
        KoShapeCache *cache = d->shapeCache();
        foreach(KoShapeCache::DeviceData *data, cache->deviceData.values()) {
            data->allExposed = true;
            data->exposed.clear();
        }

    }

522 523
    if (!d->shapeManagers.empty()) {
        QRectF rect(boundingRect());
524
        foreach(KoShapeManager * manager, d->shapeManagers) {
Jan Hambrecht's avatar
Jan Hambrecht committed
525
            manager->update(rect, this, true);
526
        }
Thomas Zander's avatar
Thomas Zander committed
527 528 529
    }
}

530
void KoShape::update(const QRectF &rect) const
531
{
532 533 534 535 536

    if (rect.isEmpty() && !rect.isNull()) {
        return;
    }

537
    Q_D(const KoShape);
538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553

    if (d->cacheMode != NoCache) {
        KoShapeCache *cache = d->shapeCache();
        foreach(KoShapeCache::DeviceData *data, cache->deviceData.values()) {
            if (!data->allExposed) {
                if (rect.isNull()) {
                    data->allExposed = true;
                    data->exposed.clear();
                }
                else {
                    data->exposed.append(rect);
                }
            }
        }
    }

554
    if (!d->shapeManagers.empty() && isVisible()) {
555
        QRectF rc(absoluteTransformation(0).mapRect(rect));
556
        foreach(KoShapeManager * manager, d->shapeManagers) {
557
            manager->update(rc);
558 559
        }
    }
Thomas Zander's avatar
Thomas Zander committed
560 561
}

562
QPainterPath KoShape::outline() const
563
{
Thomas Zander's avatar
Thomas Zander committed
564
    QPainterPath path;
565
    path.addRect(outlineRect());
Thomas Zander's avatar
Thomas Zander committed
566 567 568
    return path;
}

569 570 571 572 573 574
QRectF KoShape::outlineRect() const
{
    Q_D(const KoShape);
    return QRectF(QPointF(0, 0), QSizeF(qMax(d->size.width(), qreal(0.0001)), qMax(d->size.height(), qreal(0.0001))));
}

575 576
QPointF KoShape::absolutePosition(KoFlake::Position anchor) const
{
577
    QPointF point;
578 579 580 581 582 583
    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;
584
    }
585
    return absoluteTransformation(0).map(point);
Thomas Zander's avatar
Thomas Zander committed
586 587
}

588 589
void KoShape::setAbsolutePosition(QPointF newPosition, KoFlake::Position anchor)
{
590
    Q_D(KoShape);
591
    QPointF currentAbsPosition = absolutePosition(anchor);
592
    QPointF translate = newPosition - currentAbsPosition;
593
    QTransform translateMatrix;
594 595
    translateMatrix.translate(translate.x(), translate.y());
    applyAbsoluteTransformation(translateMatrix);
596
    notifyChanged();
597
    d->shapeChanged(PositionChanged);
Thomas Zander's avatar
Thomas Zander committed
598 599
}

600 601
void KoShape::copySettings(const KoShape *shape)
{
602
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
603 604
    d->size = shape->size();
    d->connectors.clear();
605
    foreach(const QPointF &point, shape->connectionPoints())
Jan Hambrecht's avatar
Jan Hambrecht committed
606
        addConnectionPoint(point);
Thomas Zander's avatar
Thomas Zander committed
607 608
    d->zIndex = shape->zIndex();
    d->visible = shape->isVisible();
609

610 611 612 613 614
    // Ensure printable is true by default
    if (!d->visible)
        d->printable = true;
    else
        d->printable = shape->isPrintable();
615

616
    d->geometryProtected = shape->isGeometryProtected();
Thomas Zander's avatar
Thomas Zander committed
617 618
    d->protectContent = shape->isContentProtected();
    d->selectable = shape->isSelectable();
Thomas Zander's avatar
Thomas Zander committed
619
    d->keepAspect = shape->keepAspectRatio();
620
    d->localMatrix = shape->d_ptr->localMatrix;
Thomas Zander's avatar
Thomas Zander committed
621 622
}

Thomas Zander's avatar
Thomas Zander committed
623
void KoShape::notifyChanged()
624
{
625
    Q_D(KoShape);
626 627
    foreach(KoShapeManager * manager, d->shapeManagers) {
        manager->notifyShapeChanged(this);
628
    }
629 630 631 632
    KoShapeCache *cache = d->maybeShapeCache();
    if (cache) {
        cache->purge();
    }
633 634
}

635 636
void KoShape::setUserData(KoShapeUserData *userData)
{
637
    Q_D(KoShape);
638
    delete d->userData;
Thomas Zander's avatar
Thomas Zander committed
639
    d->userData = userData;
640 641
}

642 643
KoShapeUserData *KoShape::userData() const
{
644
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
645
    return d->userData;
646 647
}

648 649
void KoShape::setApplicationData(KoShapeApplicationData *appData)
{
650
    Q_D(KoShape);
651
    // appdata is deleted by the application.
Thomas Zander's avatar
Thomas Zander committed
652
    d->appData = appData;
653 654
}

655 656
KoShapeApplicationData *KoShape::applicationData() const
{
657
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
658
    return d->appData;
659 660
}

Thomas Zander's avatar
Thomas Zander committed
661
bool KoShape::hasTransparency() const
662
{
Thomas Zander's avatar
Thomas Zander committed
663
    Q_D(const KoShape);
664
    if (! d->fill)
Thomas Zander's avatar
Thomas Zander committed
665
        return true;
666
    else
667 668 669 670 671 672
        return d->fill->hasTransparency() || d->transparency > 0.0;
}

void KoShape::setTransparency(qreal transparency)
{
    Q_D(KoShape);
673
    d->transparency = qBound<qreal>(0.0, transparency, 1.0);
674 675 676 677 678 679 680 681 682 683 684 685
}

qreal KoShape::transparency(bool recursive) const
{
    Q_D(const KoShape);
    if (!recursive || !parent()) {
        return d->transparency;
    } else {
        const qreal parentOpacity = 1.0-parent()->transparency(recursive);
        const qreal childOpacity = 1.0-d->transparency;
        return 1.0-(parentOpacity*childOpacity);
    }
Thomas Zander's avatar
Thomas Zander committed
686 687
}

688 689
KoInsets KoShape::borderInsets() const
{
690
    Q_D(const KoShape);
691
    KoInsets answer;
692
    if (d->border)
693
        d->border->borderInsets(this, answer);
694 695 696
    return answer;
}

697 698
qreal KoShape::rotation() const
{
699
    Q_D(const KoShape);
700
    // try to extract the rotation angle out of the local matrix
701 702 703
    // if it is a pure rotation matrix

    // check if the matrix has shearing mixed in
704
    if (fabs(fabs(d->localMatrix.m12()) - fabs(d->localMatrix.m21())) > 1e-10)
705
        return std::numeric_limits<qreal>::quiet_NaN();
706
    // check if the matrix has scaling mixed in
707
    if (fabs(d->localMatrix.m11() - d->localMatrix.m22()) > 1e-10)
708
        return std::numeric_limits<qreal>::quiet_NaN();
709 710

    // calculate the angle from the matrix elements
711 712
    qreal angle = atan2(-d->localMatrix.m21(), d->localMatrix.m11()) * 180.0 / M_PI;
    if (angle < 0.0)
713 714 715
        angle += 360.0;

    return angle;
Thomas Zander's avatar
Thomas Zander committed
716 717
}

718
QSizeF KoShape::size() const
719
{
720
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
721 722 723
    return d->size;
}

724 725
QPointF KoShape::position() const
{
726
    Q_D(const KoShape);
727 728
    QPointF center(0.5*size().width(), 0.5*size().height());
    return d->localMatrix.map(center) - center;
Thomas Zander's avatar
Thomas Zander committed
729 730
}

731
void KoShape::addConnectionPoint(const QPointF &point)
732
{
733
    Q_D(KoShape);
734 735
    QSizeF s = size();
    // convert glue point from shape coordinates to factors of size
736
    d->connectors.append(QPointF(point.x() / s.width(), point.y() / s.height()));
Thomas Zander's avatar
Thomas Zander committed
737 738
}

739 740
QList<QPointF> KoShape::connectionPoints() const
{
741
    Q_D(const KoShape);
742 743 744
    QList<QPointF> points;
    QSizeF s = size();
    // convert glue points to shape coordinates
745
    foreach(const QPointF &cp, d->connectors)
Jan Hambrecht's avatar
Jan Hambrecht committed
746
        points.append(QPointF(s.width() * cp.x(), s.height() * cp.y()));
747 748

    return points;
749 750
}

751
void KoShape::addEventAction(KoEventAction *action)
752
{
753
    Q_D(KoShape);
754
    d->eventActions.insert(action);
755 756
}

757
void KoShape::removeEventAction(KoEventAction *action)
758
{
759
    Q_D(KoShape);
760
    d->eventActions.remove(action);
761 762
}

763
QSet<KoEventAction *> KoShape::eventActions() const
764
{
765
    Q_D(const KoShape);
766 767 768
    return d->eventActions;
}

769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
KoShape::TextRunAroundSide KoShape::textRunAroundSide() const
{
    Q_D(const KoShape);
    return d->textRunAroundSide;
}

void KoShape::setTextRunAroundSide(TextRunAroundSide side, Through runThrought)
{
    Q_D(KoShape);
    d->textRunAroundSide = side;

    if (side == RunThrough) {
        if (runThrought == Background) {
            setRunThrough(-1);
        } else {
            setRunThrough(1);
        }
    } else {
        setRunThrough(0);
    }
}

qreal KoShape::textRunAroundDistance() const
{
    Q_D(const KoShape);
    return d->textRunAroundDistance;
}

void KoShape::setTextRunAroundDistance(qreal distance)
{
    Q_D(KoShape);
    d->textRunAroundDistance = distance;
}

803
void KoShape::setBackground(KoShapeBackground *fill)
804
{
805
    Q_D(KoShape);
806
    if (d->fill)
807
        d->fill->deref();
808
    d->fill = fill;
809
    if (d->fill)
810
        d->fill->ref();
811
    d->shapeChanged(BackgroundChanged);
Thomas Zander's avatar
Thomas Zander committed
812 813
}

814 815
KoShapeBackground * KoShape::background() const
{
816
    Q_D(const KoShape);
817
    return d->fill;
Thomas Zander's avatar
Thomas Zander committed
818 819
}

820 821
void KoShape::setZIndex(int zIndex)
{
822
    Q_D(KoShape);
823
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
824 825 826
    d->zIndex = zIndex;
}

827 828 829 830 831 832 833 834 835 836 837 838
int KoShape::runThrough()
{
    Q_D(const KoShape);
    return d->runThrough;
}

void KoShape::setRunThrough(short int runThrough)
{
    Q_D(KoShape);
    d->runThrough = runThrough;
}

839 840
void KoShape::setVisible(bool on)
{
841
    Q_D(KoShape);
842
    if (d->visible == on) return;
Thomas Zander's avatar
Thomas Zander committed
843
    d->visible = on;
844 845 846 847 848 849
    if (d->visible) {
        KoShapeCache *cache = d->maybeShapeCache();
        if (cache) {
            cache->purge();
        }
    }
Thomas Zander's avatar
Thomas Zander committed
850 851
}

852
bool KoShape::isVisible(bool recursive) const
853
{
854
    Q_D(const KoShape);
855
    if (! recursive)
856
        return d->visible;
857
    if (recursive && ! d->visible)
Jan Hambrecht's avatar
Jan Hambrecht committed
858 859
        return false;

860
    KoShapeContainer * parentShape = parent();
861 862
    while (parentShape) {
        if (! parentShape->isVisible())
863 864 865 866
            return false;
        parentShape = parentShape->parent();
    }
    return true;
Thomas Zander's avatar
Thomas Zander committed
867 868
}

869 870
void KoShape::setPrintable(bool on)
{
871
    Q_D(KoShape);
872 873
    d->printable = on;
}
874

875 876
bool KoShape::isPrintable() const
{
877
    Q_D(const KoShape);
878 879 880 881
    if (d->visible)
        return d->printable;
    else
        return false;
882 883
}

884 885
void KoShape::setSelectable(bool selectable)
{
886
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
887 888 889
    d->selectable = selectable;
}

890 891
bool KoShape::isSelectable() const
{
892
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
893 894 895
    return d->selectable;
}

896
void KoShape::setGeometryProtected(bool on)
897
{
898
    Q_D(KoShape);
899
    d->geometryProtected = on;
Thomas Zander's avatar
Thomas Zander committed
900 901
}

902
bool KoShape::isGeometryProtected() const
903
{
904
    Q_D(const KoShape);