KoShapeContainer.cpp 6.88 KB
Newer Older
Thomas Zander's avatar
Thomas Zander committed
1
/* This file is part of the KDE project
2
 * Copyright (C) 2006-2007 Thomas Zander <zander@kde.org>
Thomas Zander's avatar
Thomas Zander committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * 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.
 */
19
#include <kdebug.h>
Thomas Zander's avatar
Thomas Zander committed
20 21 22 23 24 25

#include "KoShapeContainer.h"

#include <QPointF>
#include <QPainter>

Thomas Zander's avatar
Thomas Zander committed
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
class ChildrenData : public KoShapeContainerModel {
public:
    ChildrenData() {}
    ~ChildrenData() {
        qDeleteAll(m_relations);
    }

    void add(KoShape *child) {
        Relation *r = new Relation(child);
        m_relations.append(r);
    }

    void setClipping(const KoShape *child, bool clipping) {
        Relation *relation = findRelation(child);
        if(relation == 0) // throw exception?
            return;
        if(relation->m_inside == clipping)
            return;
        relation->m_inside = clipping;
        relation->child()->repaint();
        relation->child()->recalcMatrix();
        relation->child()->repaint();
    }

    bool childClipped(const KoShape *child) const {
        Relation *relation = findRelation(child);
        if(relation == 0) // throw exception?
            return false;
        return relation->m_inside;
    }

    void remove(KoShape *child) {
        Relation *relation = findRelation(child);
        if(relation == 0)
            return;
        m_relations.removeAll(relation);
    }

    int count() const {
        return m_relations.count();
    }

    QList<KoShape*> iterator() const {
        QList<KoShape*> answer;
        foreach (Relation *relation, m_relations)
            answer.append(relation->child());
        return answer;
    }

    void containerChanged(KoShapeContainer *) { }

private:
    /**
     * This class is a simple data-storage class for Relation objects.
     */
    class Relation {
        public:
            explicit Relation(KoShape *child) :m_inside(false) , m_child(child) { }
            KoShape* child() { return m_child; }
            bool m_inside; ///< if true, the child will be clipped by the parent.
        private:
            KoShape *m_child;
    };

    Relation* findRelation(const KoShape *child) const {
        foreach(Relation *relation, m_relations) {
            if(relation->child() == child)
                return relation;
        }
        return 0;
    }

private: // members
    QList <Relation *> m_relations;
};

102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
class KoShapeContainer::Private {
public:
    Private() : children(0) {}
    ~Private() {
        if(children)
        {
            foreach (KoShape *shape, children->iterator())
                shape->setParent(0);
            delete children;
        }
    }
    KoShapeContainerModel *children;
};

KoShapeContainer::KoShapeContainer() : KoShape(), d(new Private()) {
Thomas Zander's avatar
Thomas Zander committed
117 118
}

119
KoShapeContainer::KoShapeContainer(KoShapeContainerModel *model)
120 121 122 123
: KoShape(),
 d(new Private())
{
    d->children = model;
Thomas Zander's avatar
Thomas Zander committed
124 125 126
}

KoShapeContainer::~KoShapeContainer() {
127
    delete d;
Thomas Zander's avatar
Thomas Zander committed
128 129
}

130 131
void KoShapeContainer::addChild(KoShape *shape) {
    Q_ASSERT(shape);
132 133
    if(d->children == 0)
        d->children = new ChildrenData();
134 135
    if( shape->parent() )
        shape->parent()->removeChild( shape );
136
    d->children->add(shape);
137 138
    shape->setParent(this);
    childCountChanged();
Thomas Zander's avatar
Thomas Zander committed
139 140
}

141 142
void KoShapeContainer::removeChild(KoShape *shape) {
    Q_ASSERT(shape);
143
    if(d->children == 0)
Thomas Zander's avatar
Thomas Zander committed
144
        return;
145
    d->children->remove(shape);
146 147
    shape->setParent(0);
    childCountChanged();
Thomas Zander's avatar
Thomas Zander committed
148 149 150
}

int  KoShapeContainer::childCount() const {
151
    if(d->children == 0)
Thomas Zander's avatar
Thomas Zander committed
152
        return 0;
153
    return d->children->count();
Thomas Zander's avatar
Thomas Zander committed
154 155 156
}

void KoShapeContainer::setClipping(const KoShape *child, bool clipping) {
157
    if(d->children == 0)
Thomas Zander's avatar
Thomas Zander committed
158
        return;
159
    d->children->setClipping(child, clipping);
Thomas Zander's avatar
Thomas Zander committed
160 161
}

162
void KoShapeContainer::paint(QPainter &painter, const KoViewConverter &converter) {
Thomas Zander's avatar
Thomas Zander committed
163 164 165 166
    painter.save();
    applyConversion(painter, converter);
    paintComponent(painter, converter);
    painter.restore();
167
    if(d->children == 0 || d->children->count() == 0)
Thomas Zander's avatar
Thomas Zander committed
168 169
        return;

170
    QList<KoShape*> sortedObjects = d->children->iterator();
171
    qSort(sortedObjects.begin(), sortedObjects.end(), KoShape::compareShapeZIndex);
172
    painter.setMatrix( matrix().inverted() * painter.matrix() );
Thomas Zander's avatar
Thomas Zander committed
173
    QMatrix myMatrix = transformationMatrix(&converter);
174
    foreach (KoShape *shape, sortedObjects) {
Thomas Zander's avatar
Thomas Zander committed
175
        kDebug(30006) << "painting shape: " << shape->shapeId() << ", " << shape->boundingRect() << endl;
Thomas Zander's avatar
Thomas Zander committed
176 177 178 179 180 181 182
        if(! shape->isVisible())
            continue;
        // TODO this is not perfect yet..
//           QRectF clipRect(QPoint(0,0), size()); // old
//           QPolygon clip = (myMatrix * shapeMatrix.inverted()).mapToPolygon(clipRect.toRect());
//           painter.setClipRegion(QRegion(clip));

183 184
/*        if(! childClipped(shape) )
            continue;*/
185
        painter.save();
Jan Hambrecht's avatar
Jan Hambrecht committed
186

187 188 189 190 191 192 193 194 195
        if( childClipped(shape) ) {
            QRectF clipRect(QPointF(0, 0), size());
            clipRect = converter.documentToView(clipRect);

            QPolygon clip = myMatrix.mapToPolygon(clipRect.toRect());
            clip.translate( (position() - converter.documentToView(position())).toPoint() );
            painter.setClipRegion(QRegion(clip));
        }

Thomas Zander's avatar
Thomas Zander committed
196 197
//kDebug(30006) << "rect: " << position() << endl;
//kDebug(30006) << "polygon: " << clip.boundingRect() << endl;
Thomas Zander's avatar
Thomas Zander committed
198 199 200 201 202 203 204
        //painter.drawPolygon(clip);
        painter.setMatrix( shape->transformationMatrix(&converter) * painter.matrix() );
        shape->paint(painter, converter);
        painter.restore();
    }
}

205
void KoShapeContainer::shapeChanged(ChangeType type) {
206
    if(d->children == 0)
Thomas Zander's avatar
Thomas Zander committed
207
        return;
208 209
    if(! (type == RotationChanged || type == ScaleChanged || type == ShearChanged
                || type == SizeChanged || type == PositionChanged))
Thomas Zander's avatar
Thomas Zander committed
210
        return;
211 212
    d->children->containerChanged(this);
    foreach (KoShape *shape, d->children->iterator())
Thomas Zander's avatar
Thomas Zander committed
213 214 215 216
        shape->recalcMatrix();
}

bool KoShapeContainer::childClipped(const KoShape *child) const {
217
    if(d->children == 0) // throw exception??
Thomas Zander's avatar
Thomas Zander committed
218
        return false;
219
    return d->children->childClipped(child);
Thomas Zander's avatar
Thomas Zander committed
220 221 222 223
}

void KoShapeContainer::repaint() const {
    KoShape::repaint();
224 225
    if(d->children)
        foreach ( KoShape *shape, d->children->iterator())
226
            shape->repaint();
Thomas Zander's avatar
Thomas Zander committed
227 228 229
}

QList<KoShape*> KoShapeContainer::iterator() const {
230
    if(d->children == 0)
231 232
        return QList<KoShape*>();

233
    return d->children->iterator();
Thomas Zander's avatar
Thomas Zander committed
234 235
}

Thomas Zander's avatar
Thomas Zander committed
236