KoShape.cpp 35.5 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 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 24

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

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

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

64 65
#include <kdebug.h>

66 67
#include <limits>

68 69
class KoShape::Private
{
Thomas Zander's avatar
Thomas Zander committed
70
public:
71
    Private(KoShape *shape)
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
            : size(50, 50),
            zIndex(0),
            parent(0),
            visible(true),
            printable(true),
            locked(false),
            keepAspect(false),
            selectable(true),
            detectCollision(false),
            userData(0),
            appData(0),
            fill(0),
            border(0),
            me(shape),
            shadow(0) {
Thomas Zander's avatar
Thomas Zander committed
87 88
    }

89
    ~Private() {
90 91
        if (parent)
            parent->removeChild(me);
Jan Hambrecht's avatar
Jan Hambrecht committed
92
        foreach(KoShapeManager *manager, shapeManagers) {
Jan Hambrecht's avatar
Jan Hambrecht committed
93
            manager->remove(me);
Jan Hambrecht's avatar
Jan Hambrecht committed
94 95
            manager->removeAdditional(me);
        }
Thomas Zander's avatar
Thomas Zander committed
96 97
        delete userData;
        delete appData;
98
        if (border && ! border->removeUser())
99
            delete border;
100
        if (shadow && ! shadow->removeUser())
101
            delete shadow;
102
        if (fill && ! fill->removeUser())
103
            delete fill;
104
        qDeleteAll(eventActions);
Thomas Zander's avatar
Thomas Zander committed
105 106
    }

107
    void shapeChanged(ChangeType type) {
108
        if (parent)
109 110
            parent->model()->childChanged(me, type);
        me->shapeChanged(type);
111
        foreach(KoShape * shape, dependees)
Jan Hambrecht's avatar
Jan Hambrecht committed
112
            shape->notifyShapeChanged(me, type);
113 114
    }

Thomas Zander's avatar
Thomas Zander committed
115 116
    QSizeF size; // size in pt
    QString shapeId;
117
    QString name; ///< the shapes names
Thomas Zander's avatar
Thomas Zander committed
118

119
    QMatrix localMatrix; ///< the shapes local transformation matrix
Thomas Zander's avatar
Thomas Zander committed
120 121 122 123 124 125 126

    QVector<QPointF> connectors; // in pt

    int zIndex;
    KoShapeContainer *parent;

    bool visible;
127
    bool printable;
Thomas Zander's avatar
Thomas Zander committed
128 129 130 131 132 133 134 135
    bool locked;
    bool keepAspect;
    bool selectable;
    bool detectCollision;

    QSet<KoShapeManager *> shapeManagers;
    KoShapeUserData *userData;
    KoShapeApplicationData *appData;
136
    KoShapeBackground * fill; ///< Stands for the background color / fill etc.
137
    KoShapeBorderModel *border; ///< points to a border, or 0 if there is no border
138
    KoShape *me;
139
    QList<KoShape*> dependees; ///< list of shape dependent on this shape
140
    KoShapeShadow * shadow; ///< the current shape shadow
141
    QMap<QByteArray, QString> additionalAttributes;
142
    QMap<QByteArray, QString> additionalStyleAttributes;
Thorsten Zachmann's avatar
Thorsten Zachmann committed
143
    QList<KoEventAction *> eventActions; ///< list of event actions the shape has
Thomas Zander's avatar
Thomas Zander committed
144 145
};

Thomas Zander's avatar
Thomas Zander committed
146
KoShape::KoShape()
147
        : d(new Private(this))
Thomas Zander's avatar
Thomas Zander committed
148
{
149 150 151 152
    d->connectors.append(QPointF(0.5, 0.0));
    d->connectors.append(QPointF(1.0, 0.5));
    d->connectors.append(QPointF(0.5, 1.0));
    d->connectors.append(QPointF(0.0, 0.5));
153

154
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
155 156 157 158
}

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

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

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

194
    notifyChanged();
195
    d->shapeChanged(ScaleChanged);
Thomas Zander's avatar
Thomas Zander committed
196 197
}

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

207
    notifyChanged();
208
    d->shapeChanged(RotationChanged);
Thomas Zander's avatar
Thomas Zander committed
209 210
}

211
void KoShape::setShear(qreal sx, qreal sy)
Thomas Zander's avatar
Thomas Zander committed
212
{
213 214
    QPointF pos = position();
    QMatrix shearMatrix;
215 216 217
    shearMatrix.translate(pos.x(), pos.y());
    shearMatrix.shear(sx, sy);
    shearMatrix.translate(-pos.x(), -pos.y());
218
    d->localMatrix = d->localMatrix * shearMatrix;
219

220
    notifyChanged();
221
    d->shapeChanged(ShearChanged);
Thomas Zander's avatar
Thomas Zander committed
222 223
}

224
void KoShape::setSize(const QSizeF &newSize)
Thomas Zander's avatar
Thomas Zander committed
225
{
226 227
    QSizeF oldSize(size());
    if (oldSize == newSize)
Thomas Zander's avatar
Thomas Zander committed
228
        return;
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
    QPointF currentPos = position();
239
    if (newPosition == currentPos)
Thomas Zander's avatar
Thomas Zander committed
240
        return;
241
    QMatrix translateMatrix;
242
    translateMatrix.translate(newPosition.x() - currentPos.x(), newPosition.y() - currentPos.y());
243 244 245
    d->localMatrix = d->localMatrix * translateMatrix;

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

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

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

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

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

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

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

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

309
    if (converter) {
310 311 312
        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
313
    }
314 315

    return d->localMatrix * matrix;
Thomas Zander's avatar
Thomas Zander committed
316 317
}

318
void KoShape::applyAbsoluteTransformation(const QMatrix &matrix)
319
{
320
    QMatrix globalMatrix = absoluteTransformation(0);
321 322
    // 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
323
    // to be relative to the local coordinate system
324
    QMatrix transformMatrix = globalMatrix * matrix * globalMatrix.inverted();
325
    applyTransformation(transformMatrix);
326 327
}

328
void KoShape::applyTransformation(const QMatrix &matrix)
329 330
{
    d->localMatrix = matrix * d->localMatrix;
331
    notifyChanged();
332
    d->shapeChanged(GenericMatrixChange);
333 334
}

335
void KoShape::setTransformation(const QMatrix &matrix)
336 337 338
{
    d->localMatrix = matrix;
    notifyChanged();
339
    d->shapeChanged(GenericMatrixChange);
340
}
Thomas Zander's avatar
Thomas Zander committed
341

342
QMatrix KoShape::transformation() const
343 344 345 346
{
    return d->localMatrix;
}

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

367 368 369
void KoShape::setParent(KoShapeContainer *parent)
{
    if (d->parent == parent)
370
        return;
371
    if (parent && dynamic_cast<KoShape*>(parent) != this) {
372 373
        if (d->parent)
            d->parent->removeChild(this);
Thomas Zander's avatar
Thomas Zander committed
374
        d->parent = parent;
375
        parent->addChild(this);
376
    } else
Thomas Zander's avatar
Thomas Zander committed
377
        d->parent = 0;
378
    notifyChanged();
379
    d->shapeChanged(ParentChanged);
Thomas Zander's avatar
Thomas Zander committed
380 381
}

382 383 384
int KoShape::zIndex() const
{
    if (parent()) // we can't be under our parent...
Thomas Zander's avatar
Thomas Zander committed
385 386
        return qMax(d->zIndex, parent()->zIndex());
    return d->zIndex;
Thomas Zander's avatar
Thomas Zander committed
387 388
}

389 390
void KoShape::update() const
{
391 392 393
    if (!d->shapeManagers.empty()) {
        QRectF rect(boundingRect());
        foreach(KoShapeManager * manager, d->shapeManagers)
Jan Hambrecht's avatar
Jan Hambrecht committed
394
            manager->update(rect, this, true);
Thomas Zander's avatar
Thomas Zander committed
395 396 397
    }
}

398 399
void KoShape::update(const QRectF &shape) const
{
400
    if (!d->shapeManagers.empty() && isVisible()) {
401
        QRectF rect(absoluteTransformation(0).mapRect(shape));
402
        foreach(KoShapeManager * manager, d->shapeManagers) {
403
            manager->update(rect);
404 405
        }
    }
Thomas Zander's avatar
Thomas Zander committed
406 407
}

408 409
const QPainterPath KoShape::outline() const
{
Thomas Zander's avatar
Thomas Zander committed
410
    QPainterPath path;
411
    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
412 413 414
    return path;
}

415 416
QPointF KoShape::absolutePosition(KoFlake::Position anchor) const
{
417
    QPointF point;
418 419 420 421 422 423
    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;
424
    }
425
    return absoluteTransformation(0).map(point);
Thomas Zander's avatar
Thomas Zander committed
426 427
}

428 429
void KoShape::setAbsolutePosition(QPointF newPosition, KoFlake::Position anchor)
{
430
    QPointF currentAbsPosition = absolutePosition(anchor);
431
    QPointF translate = newPosition - currentAbsPosition;
Jan Hambrecht's avatar
Jan Hambrecht committed
432
    QMatrix translateMatrix;
433 434
    translateMatrix.translate(translate.x(), translate.y());
    applyAbsoluteTransformation(translateMatrix);
435
    notifyChanged();
436
    d->shapeChanged(PositionChanged);
Thomas Zander's avatar
Thomas Zander committed
437 438
}

439 440
void KoShape::copySettings(const KoShape *shape)
{
Thomas Zander's avatar
Thomas Zander committed
441 442
    d->size = shape->size();
    d->connectors.clear();
Jan Hambrecht's avatar
Jan Hambrecht committed
443 444
    foreach(const QPointF & point, shape->connectionPoints())
        addConnectionPoint(point);
Thomas Zander's avatar
Thomas Zander committed
445 446
    d->zIndex = shape->zIndex();
    d->visible = shape->isVisible();
447

448 449 450 451 452
    // Ensure printable is true by default
    if (!d->visible)
        d->printable = true;
    else
        d->printable = shape->isPrintable();
453

Thomas Zander's avatar
Thomas Zander committed
454 455
    d->locked = shape->isLocked();
    d->keepAspect = shape->keepAspectRatio();
456
    d->localMatrix = shape->d->localMatrix;
Thomas Zander's avatar
Thomas Zander committed
457 458
}

Thomas Zander's avatar
Thomas Zander committed
459
void KoShape::notifyChanged()
460
{
461 462
    foreach(KoShapeManager * manager, d->shapeManagers) {
        manager->notifyShapeChanged(this);
463 464 465
    }
}

466 467
void KoShape::setUserData(KoShapeUserData *userData)
{
Thomas Zander's avatar
Thomas Zander committed
468
    delete d->userData;
Thomas Zander's avatar
Thomas Zander committed
469
    d->userData = userData;
470 471
}

472 473
KoShapeUserData *KoShape::userData() const
{
Thomas Zander's avatar
Thomas Zander committed
474
    return d->userData;
475 476
}

477 478
void KoShape::setApplicationData(KoShapeApplicationData *appData)
{
Thomas Zander's avatar
Thomas Zander committed
479
    // appdata is deleted by the application.
Thomas Zander's avatar
Thomas Zander committed
480
    d->appData = appData;
481 482
}

483 484
KoShapeApplicationData *KoShape::applicationData() const
{
Thomas Zander's avatar
Thomas Zander committed
485
    return d->appData;
486 487
}

488 489
bool KoShape::hasTransparency()
{
490
    if (! d->fill)
Thomas Zander's avatar
Thomas Zander committed
491
        return true;
492 493
    else
        return d->fill->hasTransparency();
Thomas Zander's avatar
Thomas Zander committed
494 495
}

496 497
KoInsets KoShape::borderInsets() const
{
498
    KoInsets answer;
499
    if (d->border)
500
        d->border->borderInsets(this, answer);
501 502 503
    return answer;
}

504 505
qreal KoShape::rotation() const
{
506
    // try to extract the rotation angle out of the local matrix
507 508 509
    // if it is a pure rotation matrix

    // check if the matrix has shearing mixed in
510
    if (fabs(fabs(d->localMatrix.m12()) - fabs(d->localMatrix.m21())) > 1e-10)
511
        return std::numeric_limits<qreal>::quiet_NaN();
512
    // check if the matrix has scaling mixed in
513
    if (fabs(d->localMatrix.m11() - d->localMatrix.m22()) > 1e-10)
514
        return std::numeric_limits<qreal>::quiet_NaN();
515 516

    // calculate the angle from the matrix elements
517 518
    qreal angle = atan2(-d->localMatrix.m21(), d->localMatrix.m11()) * 180.0 / M_PI;
    if (angle < 0.0)
519 520 521
        angle += 360.0;

    return angle;
Thomas Zander's avatar
Thomas Zander committed
522 523
}

524
QSizeF KoShape::size() const
525
{
Thomas Zander's avatar
Thomas Zander committed
526 527 528
    return d->size;
}

529 530
QPointF KoShape::position() const
{
531 532
    QPointF center(0.5*size().width(), 0.5*size().height());
    return d->localMatrix.map(center) - center;
533
    //return d->localMatrix.map( QPointF(0,0) );
Thomas Zander's avatar
Thomas Zander committed
534 535
}

536
void KoShape::addConnectionPoint(const QPointF &point)
537
{
538 539
    QSizeF s = size();
    // convert glue point from shape coordinates to factors of size
540
    d->connectors.append(QPointF(point.x() / s.width(), point.y() / s.height()));
Thomas Zander's avatar
Thomas Zander committed
541 542
}

543 544
QList<QPointF> KoShape::connectionPoints() const
{
545 546 547
    QList<QPointF> points;
    QSizeF s = size();
    // convert glue points to shape coordinates
Jan Hambrecht's avatar
Jan Hambrecht committed
548 549
    foreach(const QPointF & cp, d->connectors)
        points.append(QPointF(s.width() * cp.x(), s.height() * cp.y()));
550 551

    return points;
552 553
}

554
void KoShape::addEventAction(KoEventAction * action)
555
{
556 557
    if (! d->eventActions.contains(action)) {
        d->eventActions.append(action);
558 559 560
    }
}

561
void KoShape::removeEventAction(KoEventAction * action)
562
{
563 564
    if (d->eventActions.contains(action)) {
        d->eventActions.removeAll(action);
565 566 567 568 569 570 571 572
    }
}

QList<KoEventAction *> KoShape::eventActions() const
{
    return d->eventActions;
}

573
void KoShape::setBackground(KoShapeBackground * fill)
574 575
{
    if (d->fill)
576 577
        d->fill->removeUser();
    d->fill = fill;
578
    if (d->fill)
579
        d->fill->addUser();
580 581
    d->shapeChanged(BackgroundChanged);
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
582 583
}

584 585
KoShapeBackground * KoShape::background() const
{
586
    return d->fill;
Thomas Zander's avatar
Thomas Zander committed
587 588
}

589 590
void KoShape::setZIndex(int zIndex)
{
591
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
592 593 594
    d->zIndex = zIndex;
}

595 596
void KoShape::setVisible(bool on)
{
Thomas Zander's avatar
Thomas Zander committed
597 598 599
    d->visible = on;
}

600
bool KoShape::isVisible(bool recursive) const
601
{
602
    if (! recursive)
603
        return d->visible;
604
    if (recursive && ! d->visible)
Jan Hambrecht's avatar
Jan Hambrecht committed
605 606
        return false;

607
    KoShapeContainer * parentShape = parent();
608 609
    while (parentShape) {
        if (! parentShape->isVisible())
610 611 612 613
            return false;
        parentShape = parentShape->parent();
    }
    return true;
Thomas Zander's avatar
Thomas Zander committed
614 615
}

616 617 618 619
void KoShape::setPrintable(bool on)
{
    d->printable = on;
}
620

621 622
bool KoShape::isPrintable() const
{
623 624 625 626
    if (d->visible)
        return d->printable;
    else
        return false;
627 628
}

629 630
void KoShape::setSelectable(bool selectable)
{
Thomas Zander's avatar
Thomas Zander committed
631 632 633
    d->selectable = selectable;
}

634 635
bool KoShape::isSelectable() const
{
Thomas Zander's avatar
Thomas Zander committed
636 637 638
    return d->selectable;
}

639 640
void KoShape::setLocked(bool locked)
{
Thomas Zander's avatar
Thomas Zander committed
641 642 643
    d->locked = locked;
}

644 645
bool KoShape::isLocked() const
{
Thomas Zander's avatar
Thomas Zander committed
646 647 648
    return d->locked;
}

649 650
KoShapeContainer *KoShape::parent() const
{
Thomas Zander's avatar
Thomas Zander committed
651 652 653
    return d->parent;
}

654 655
void KoShape::setKeepAspectRatio(bool keepAspect)
{
Thomas Zander's avatar
Thomas Zander committed
656 657 658
    d->keepAspect = keepAspect;
}

659 660
bool KoShape::keepAspectRatio() const
{
Thomas Zander's avatar
Thomas Zander committed
661 662 663
    return d->keepAspect;
}

664 665
const QString &KoShape::shapeId() const
{
Thomas Zander's avatar
Thomas Zander committed
666 667 668
    return d->shapeId;
}

669 670
void KoShape::setShapeId(const QString &id)
{
Thomas Zander's avatar
Thomas Zander committed
671 672 673
    d->shapeId = id;
}

674 675
void KoShape::setCollisionDetection(bool detect)
{
Thomas Zander's avatar
Thomas Zander committed
676 677 678
    d->detectCollision = detect;
}

679 680
bool KoShape::collisionDetection()
{
Thomas Zander's avatar
Thomas Zander committed
681 682 683
    return d->detectCollision;
}

684
void KoShape::addShapeManager(KoShapeManager * manager)
685
{
686
    d->shapeManagers.insert(manager);
Thomas Zander's avatar
Thomas Zander committed
687 688
}

689
void KoShape::removeShapeManager(KoShapeManager * manager)
690
{
691
    d->shapeManagers.remove(manager);
Thomas Zander's avatar
Thomas Zander committed
692 693
}

694 695
KoShapeBorderModel *KoShape::border() const
{
696 697 698
    return d->border;
}

699 700 701
void KoShape::setBorder(KoShapeBorderModel *border)
{
    if (d->border)
702
        d->border->removeUser();
703
    d->border = border;
704
    if (d->border)
705
        d->border->addUser();
706 707
    d->shapeChanged(BorderChanged);
    notifyChanged();
708 709
}

710
void KoShape::setShadow(KoShapeShadow * shadow)
711
{
712
    if (d->shadow)
713 714
        d->shadow->removeUser();
    d->shadow = shadow;
715
    if (d->shadow)
716 717 718 719 720 721 722 723 724 725
        d->shadow->addUser();
    d->shapeChanged(ShadowChanged);
    notifyChanged();
}

KoShapeShadow * KoShape::shadow() const
{
    return d->shadow;
}

726 727
const QMatrix& KoShape::matrix() const
{
728
    return d->localMatrix;
729 730
}

731
void KoShape::removeConnectionPoint(int index)
732
{
733 734
    if (index < d->connectors.count())
        d->connectors.remove(index);
735 736
}

737 738
QString KoShape::name() const
{
739 740 741
    return d->name;
}

742
void KoShape::setName(const QString & name)
743
{
744 745
    d->name = name;
}
746

747 748
void KoShape::deleteLater()
{
749
    foreach(KoShapeManager *manager, d->shapeManagers)
Jan Hambrecht's avatar
Jan Hambrecht committed
750
        manager->remove(this);
751 752 753 754
    d->shapeManagers.clear();
    new ShapeDeleter(this);
}

755 756
bool KoShape::isEditable() const
{
757
    if (!d->visible || d->locked)
758 759
        return false;

Thomas Zander's avatar
Thomas Zander committed
760
    if (d->parent && d->parent->isChildLocked(this))
761 762 763 764
        return false;

    return true;
}
765

766
// loading & saving methods
767
QString KoShape::saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const
768 769 770
{
    // and fill the style
    KoShapeBorderModel * b = border();
771 772
    if (b) {
        b->fillStyle(style, context);
773
    }
774 775 776
    else {
        style.addProperty( "draw:stroke", "none" );
    }
777
    KoShapeShadow * s = shadow();
778 779
    if (s)
        s->fillStyle(style, context);
780

781
    KoShapeBackground * bg = background();
782
    if (bg) {
783
        bg->fillStyle(style, context);
784 785 786 787
    }
    else {
        style.addProperty( "draw:fill", "none" );
    }
788

789 790
    if (context.isSet(KoShapeSavingContext::AutoStyleInStyleXml)) {
        style.setAutoStyleInStylesDotXml(true);
791
    }
792

793 794 795 796 797
    QMap<QByteArray, QString>::const_iterator it(d->additionalStyleAttributes.constBegin());
    for (; it != d->additionalStyleAttributes.constEnd(); ++it) {
        style.addProperty(it.key(), it.value());
    }

798
    return context.mainStyles().lookup(style, context.isSet(KoShapeSavingContext::PresentationShape) ? "pr" : "gr");
799 800
}