KoShape.cpp 46.4 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
      cache(0)
105
{
106 107 108 109
    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));
110
}
Thomas Zander's avatar
Thomas Zander committed
111

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

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

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

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

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

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

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;
    }
}


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

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

    return value;
}

218 219


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

227 228 229 230 231
KoShape::KoShape(KoShapePrivate &dd)
    : d_ptr(&dd)
{
}

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

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

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

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

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

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

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

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

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

Thomas Zander's avatar
Thomas Zander committed
311
    d->size = newSize;
312

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

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

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

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

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

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

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

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

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

380
    return bb;
Thomas Zander's avatar
Thomas Zander committed
381 382
}

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

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

    return d->localMatrix * matrix;
Thomas Zander's avatar
Thomas Zander committed
410 411
}

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

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

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

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

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

453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
    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();
468
        }
469 470 471 472

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

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

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

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

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

    }

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

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

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

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

    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);
                }
            }
        }
    }

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

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

567 568 569 570 571 572
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))));
}

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

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

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

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

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

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

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

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

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

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

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

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

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
684 685
}

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

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

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

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

    return angle;
Thomas Zander's avatar
Thomas Zander committed
714 715
}

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

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

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

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

    return points;
747 748
}

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

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

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

767
void KoShape::setBackground(KoShapeBackground *fill)
768
{
769
    Q_D(KoShape);
770
    if (d->fill)
771
        d->fill->deref();
772
    d->fill = fill;
773
    if (d->fill)
774
        d->fill->ref();
775
    d->shapeChanged(BackgroundChanged);
Thomas Zander's avatar
Thomas Zander committed
776 777
}

778 779
KoShapeBackground * KoShape::background() const
{
780
    Q_D(const KoShape);
781
    return d->fill;
Thomas Zander's avatar
Thomas Zander committed
782 783
}

784 785
void KoShape::setZIndex(int zIndex)
{
786
    Q_D(KoShape);
787
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
788 789 790
    d->zIndex = zIndex;
}

791 792 793 794 795 796 797 798 799 800 801 802
int KoShape::runThrough()
{
    Q_D(const KoShape);
    return d->runThrough;
}

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

803 804
void KoShape::setVisible(bool on)
{
805
    Q_D(KoShape);
806
    if (d->visible == on) return;
Thomas Zander's avatar
Thomas Zander committed
807
    d->visible = on;
808 809 810 811 812 813
    if (d->visible) {
        KoShapeCache *cache = d->maybeShapeCache();
        if (cache) {
            cache->purge();
        }
    }
Thomas Zander's avatar
Thomas Zander committed
814 815
}

816
bool KoShape::isVisible(bool recursive) const
817
{
818
    Q_D(const KoShape);
819
    if (! recursive)
820
        return d->visible;
821
    if (recursive && ! d->visible)
Jan Hambrecht's avatar
Jan Hambrecht committed
822 823
        return false;

824
    KoShapeContainer * parentShape = parent();
825 826
    while (parentShape) {
        if (! parentShape->isVisible())
827 828 829 830
            return false;
        parentShape = parentShape->parent();
    }
    return true;
Thomas Zander's avatar
Thomas Zander committed
831 832
}

833 834
void KoShape::setPrintable(bool on)
{
835
    Q_D(KoShape);
836 837
    d->printable = on;
}
838

839 840
bool KoShape::isPrintable() const
{
841
    Q_D(const KoShape);
842 843 844 845
    if (d->visible)
        return d->printable;
    else
        return false;
846 847
}

848 849
void KoShape::setSelectable(bool selectable)
{
850
    Q_D(KoShape);
Thomas Zander's avatar
Thomas Zander committed
851 852 853
    d->selectable = selectable;
}

854 855
bool KoShape::isSelectable() const
{
856
    Q_D(const KoShape);
Thomas Zander's avatar
Thomas Zander committed
857 858 859
    return d->selectable;
}

860
void KoShape::setGeometryProtected(bool on)
861
{
862
    Q_D(KoShape);
863
    d->geometryProtected = on;
Thomas Zander's avatar
Thomas Zander committed
864 865
}

866
bool KoShape::isGeometryProtected() const
867
{
868
    Q_D(const KoShape);
869
    return d->geometryProtected;
Thomas Zander's avatar
Thomas Zander committed
870 871
}

872 873
void KoShape::setContentProtected(bool protect)
{
874
    Q_D(KoShape);
875
    d->protectContent = protect;
876 877 878 879
}

bool KoShape::isContentProtected() const
{
880
    Q_D(const KoShape);