KoShape.cpp 35 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-2007 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);
92
        foreach(KoShapeManager *manager, shapeManagers)
93
        manager->remove(me);
Thomas Zander's avatar
Thomas Zander committed
94 95
        delete userData;
        delete appData;
96
        if (border && ! border->removeUser())
97
            delete border;
98
        if (shadow && ! shadow->removeUser())
99
            delete shadow;
100
        if (fill && ! fill->removeUser())
101
            delete fill;
102
        qDeleteAll(eventActions);
Thomas Zander's avatar
Thomas Zander committed
103 104
    }

105
    void shapeChanged(ChangeType type) {
106
        if (parent)
107 108
            parent->model()->childChanged(me, type);
        me->shapeChanged(type);
109 110
        foreach(KoShape * shape, dependees)
        shape->notifyShapeChanged(me, type);
111 112
    }

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

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

    QVector<QPointF> connectors; // in pt

    int zIndex;
    KoShapeContainer *parent;

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

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

Thomas Zander's avatar
Thomas Zander committed
143
KoShape::KoShape()
144
        : d(new Private(this))
Thomas Zander's avatar
Thomas Zander committed
145
{
146 147 148 149
    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));
150

151
    notifyChanged();
Thomas Zander's avatar
Thomas Zander committed
152 153 154 155
}

KoShape::~KoShape()
{
156
    d->shapeChanged(Deleted);
Thomas Zander's avatar
Thomas Zander committed
157
    delete d;
Thomas Zander's avatar
Thomas Zander committed
158 159
}

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

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

191
    notifyChanged();
192
    d->shapeChanged(ScaleChanged);
Thomas Zander's avatar
Thomas Zander committed
193 194
}

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

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

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

217
    notifyChanged();
218
    d->shapeChanged(ShearChanged);
Thomas Zander's avatar
Thomas Zander committed
219 220
}

221
void KoShape::setSize(const QSizeF &newSize)
Thomas Zander's avatar
Thomas Zander committed
222
{
223 224
    QSizeF oldSize(size());
    if (oldSize == newSize)
Thomas Zander's avatar
Thomas Zander committed
225
        return;
226

Thomas Zander's avatar
Thomas Zander committed
227
    d->size = newSize;
228

229
    notifyChanged();
230
    d->shapeChanged(SizeChanged);
Thomas Zander's avatar
Thomas Zander committed
231 232
}

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

    notifyChanged();
243
    d->shapeChanged(PositionChanged);
Thomas Zander's avatar
Thomas Zander committed
244 245
}

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

251
    QPointF point = absoluteTransformation(0).inverted().map(position);
252
    const QPainterPath outlinePath = outline();
253
    if (d->border) {
254
        KoInsets insets;
255
        d->border->borderInsets(this, insets);
256 257 258 259 260 261 262
        QRectF roi( QPointF(-insets.left, -insets.top), QPointF(insets.right, insets.bottom) );
        roi.moveCenter( point );
        if( outlinePath.intersects( roi ) || outlinePath.contains( roi ) )
            return true;
    } else {
        if( outlinePath.contains( point ) )
            return true;
263
    }
264
    
265
    // if there is no shadow we can as well just leave
266
    if (! d->shadow)
267
        return false;
Thomas Zander's avatar
Thomas Zander committed
268

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return points;
553 554
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

748 749
void KoShape::deleteLater()
{
750
    foreach(KoShapeManager *manager, d->shapeManagers)
751
    manager->remove(this);
752 753 754 755
    d->shapeManagers.clear();
    new ShapeDeleter(this);
}

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

    KoShapeContainer * p = parent();
762
    if (p && p->isChildLocked(this))
763
        return false;
764 765
    while (p) {
        if (! p->isVisible())
766 767 768 769 770 771
            return false;
        p = p->parent();
    }

    return true;
}
772

773
// loading & saving methods
774
QString KoShape::saveStyle(KoGenStyle &style, KoShapeSavingContext &context) const
775 776 777
{
    // and fill the style
    KoShapeBorderModel * b = border();
778 779
    if (b) {
        b->fillStyle(style, context);
780
    }
781
    KoShapeShadow * s = shadow();
782 783
    if (s)
        s->fillStyle(style, context);
784

785
    KoShapeBackground * bg = background();
786 787
    if (bg)
        bg->fillStyle(style, context);
788

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

793
    return context.mainStyles().lookup(style, context.isSet(KoShapeSavingContext::PresentationShape) ? "pr" : "gr");
794 795
}

796
void KoShape::loadStyle(const KoXmlElement & element, KoShapeLoadingContext &context)
797
{
798
    KoStyleStack &styleStack = context.odfLoadingContext().styleStack();
799 800 801
    styleStack.save();

    // fill the style stack with the shapes style
802 803 804 805 806 807
    if (element.hasAttributeNS(KoXmlNS::draw, "style-name")) {
        context.odfLoadingContext().fillStyleStack(element, KoXmlNS::draw, "style-name", "graphic");
        styleStack.setTypeProperties("graphic");
    } else if (element.hasAttributeNS(KoXmlNS::presentation, "style-name")) {
        context.odfLoadingContext().fillStyleStack(element, KoXmlNS::presentation, "style-name", "presentation");
        styleStack.setTypeProperties("graphic");
808 809
    }

810 811 812
    setBackground(loadOdfFill(element, context));
    setBorder(loadOdfStroke(element, context));
    setShadow(loadOdfShadow(element, context));
813 814

    styleStack.restore();
815 816
}

817
bool KoShape::loadOdfAttributes(const KoXmlElement & element, KoShapeLoadingContext &context, int attributes)
818
{
819 820 821 822 823 824 825
    if (attributes & OdfPosition) {
        QPointF pos(position());
        if (element.hasAttributeNS(KoXmlNS::svg, "x"))
            pos.setX(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "x", QString())));
        if (element.hasAttributeNS(KoXmlNS::svg, "y"))
            pos.setY(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "y", QString())));
        setPosition(pos);
826
    }
827

828 829 830 831 832 833 834
    if (attributes & OdfSize) {
        QSizeF s(size());
        if (element.hasAttributeNS(KoXmlNS::svg, "width"))
            s.setWidth(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "width", QString())));
        if (element.hasAttributeNS(KoXmlNS::svg, "height"))
            s.setHeight(KoUnit::parseValue(element.attributeNS(KoXmlNS::svg, "height", QString())));
        setSize(s);
835 836
    }

837 838 839 840 841
    if (attributes & OdfLayer) {
        if (element.hasAttributeNS(KoXmlNS::draw, "layer")) {
            KoShapeLayer * layer = context.layer(element.attributeNS(KoXmlNS::draw, "layer"));
            if (layer) {
                setParent(layer);
842 843
            }
        }
844 845
    }

846 847 848 849 850
    if (attributes & OdfId) {
        if (element.hasAttributeNS(KoXmlNS::draw, "id")) {
            QString id = element.attributeNS(KoXmlNS::draw, "id");
            if (!id.isNull()) {
                context.addShapeId(this, id);
851 852
            }
        }
853 854
    }

855 856 857
    if (attributes & OdfZIndex) {
        if (element.hasAttributeNS(KoXmlNS::draw, "z-index")) {
            context.addShapeZIndex(this, element.attributeNS(KoXmlNS::draw, "z-index").toInt());
858
        }
859
        setZIndex(context.zIndex());
860 861
    }

862
    if (attributes & OdfName) {
863

864 865
        if (element.hasAttributeNS(KoXmlNS::draw, "name")) {
            setName(element.attributeNS(KoXmlNS::draw, "name"));
866
        }
867
    }
Jan Hambrecht's avatar
Jan Hambrecht committed
868

869 870
    if (attributes & OdfStyle) {
        loadStyle(element, context);
871
    }
872

873 874 875 876
    if (attributes & OdfTransformation) {
        QString transform = element.attributeNS(KoXmlNS::draw, "transform", QString());
        if (! transform.isEmpty())
            applyAbsoluteTransformation(parseOdfTransform(transform));
Jan Hambrecht's avatar
 
Jan Hambrecht committed
877 878
    }

879
    if (attributes & OdfAdditionalAttributes) {
880
        QSet<KoShapeLoadingContext::AdditionalAttributeData> additionalAttributeData = KoShapeLoadingContext::additionalAttributeData();
881 882 883
        foreach(KoShapeLoadingContext::AdditionalAttributeData attributeData, additionalAttributeData) {
            if (element.hasAttributeNS(attributeData.ns, attributeData.tag)) {
                QString value = element.attributeNS(attributeData.ns, attributeData.tag);
884
                //kDebug(30006) << "load additional attribute" << attributeData.tag << value;
885
                setAdditionalAttribute(attributeData.name, value);
886 887
            }
        }
888 889
    }

890 891 892 893
    if (attributes & OdfCommonChildElements) {
        const KoXmlElement eventActionsElement(KoXml::namedItemNS(element, KoXmlNS::office, "event-listeners"));
        if (!eventActionsElement.isNull()) {
            d->eventActions = KoEventActionRegistry::instance()->createEventActionsFromOdf(eventActionsElement, context);
Thorsten Zachmann's avatar