KoShapeManager.cpp 7.84 KB
Newer Older
Thomas Zander's avatar
Thomas Zander committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/* This file is part of the KDE project

   Copyright (C) 2006 Thorsten Zachmann <zachmann@kde.org>
   Copyright (C) 2006 Thomas Zander <zander@kde.org>

   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 "KoShapeManager.h"
#include "KoSelection.h"
#include "KoShape.h"
#include "KoCanvasBase.h"
#include "KoShapeContainer.h"
#include "KoShapeBorderModel.h"
28
#include "KoShapeGroup.h"
29
#include "KoToolProxy.h"
Thomas Zander's avatar
Thomas Zander committed
30 31 32

#include <QPainter>

Thomas Zander's avatar
Thomas Zander committed
33
KoShapeManager::KoShapeManager( KoCanvasBase *canvas, const QList<KoShape *> &shapes )
Thomas Zander's avatar
Thomas Zander committed
34
: m_selection( new KoSelection() )
Thomas Zander's avatar
Thomas Zander committed
35
, m_canvas( canvas )
36
, m_tree( 4, 2 )
Thomas Zander's avatar
Thomas Zander committed
37
{
Thomas Zander's avatar
Thomas Zander committed
38
    Q_ASSERT(m_canvas); // not optional.
Thomas Zander's avatar
Thomas Zander committed
39
    connect( m_selection, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()) );
Thomas Zander's avatar
Thomas Zander committed
40
    setShapes(shapes);
41
    m_selection->addShapeManager( this );
Thomas Zander's avatar
Thomas Zander committed
42 43 44
}

KoShapeManager::KoShapeManager(KoCanvasBase *canvas)
Thomas Zander's avatar
Thomas Zander committed
45
: m_shapes()
Thomas Zander's avatar
Thomas Zander committed
46
, m_selection( new KoSelection() )
Thomas Zander's avatar
Thomas Zander committed
47
, m_canvas( canvas )
48
, m_tree( 4, 2 )
Thomas Zander's avatar
Thomas Zander committed
49
{
Thomas Zander's avatar
Thomas Zander committed
50
    Q_ASSERT(m_canvas); // not optional.
Thomas Zander's avatar
Thomas Zander committed
51
    connect( m_selection, SIGNAL(selectionChanged()), this, SIGNAL(selectionChanged()) );
52
    m_selection->addShapeManager( this );
Thomas Zander's avatar
Thomas Zander committed
53 54 55 56 57
}


KoShapeManager::~KoShapeManager()
{
58 59
    foreach(KoShape *shape, m_shapes)
        shape->removeShapeManager( this );
Thomas Zander's avatar
Thomas Zander committed
60 61 62 63
    delete m_selection;
}


Thomas Zander's avatar
Thomas Zander committed
64
void KoShapeManager::setShapes( const QList<KoShape *> &shapes )
Thomas Zander's avatar
Thomas Zander committed
65
{
66 67 68 69 70 71
    foreach(KoShape *shape, m_shapes)
    {
        m_aggregate4update.remove( shape );
        m_tree.remove( shape );
        shape->removeShapeManager( this );
    }
Thomas Zander's avatar
Thomas Zander committed
72 73
    m_shapes = shapes;
    foreach(KoShape *shape, m_shapes)
74 75 76
    {
        add( shape );
    }
Thomas Zander's avatar
Thomas Zander committed
77 78
}

79 80 81
void KoShapeManager::add( KoShape *shape )
{
    shape->addShapeManager( this );
Thomas Zander's avatar
Thomas Zander committed
82
    m_shapes.append(shape);
83 84 85
    if( ! dynamic_cast<KoShapeGroup*>( shape ))
    {
        QRectF br( shape->boundingRect() );
86
        m_tree.insert( br, shape );
87
    }
88
    shape->repaint();
Thomas Zander's avatar
Thomas Zander committed
89 90
}

91 92 93 94 95
void KoShapeManager::remove( KoShape *shape )
{
    shape->removeShapeManager( this );
    m_aggregate4update.remove( shape );
    m_tree.remove( shape );
Thomas Zander's avatar
Thomas Zander committed
96
    m_shapes.removeAll(shape);
Thomas Zander's avatar
Thomas Zander committed
97 98
}

99
void KoShapeManager::paint( QPainter &painter, const KoViewConverter &converter, bool forPrint)
Thomas Zander's avatar
Thomas Zander committed
100
{
101
    updateTree();
Thomas Zander's avatar
Thomas Zander committed
102 103
    QPen pen(Qt::NoPen);  // painters by default have a black stroke, lets turn that off.
    painter.setPen(pen);
104
    QList<KoShape*> sorterdShapes( m_tree.intersects( converter.viewToDocument( painter.clipRegion().boundingRect() ) ) );
Thomas Zander's avatar
Thomas Zander committed
105
    qSort(sorterdShapes.begin(), sorterdShapes.end(), KoShape::compareShapeZIndex);
Thomas Zander's avatar
Thomas Zander committed
106
    const QRegion clipRegion = painter.clipRegion();
107

Thomas Zander's avatar
Thomas Zander committed
108
    foreach ( KoShape * shape, sorterdShapes ) {
109
        if(! shape->isVisible() || ( shape->parent() && ! shape->parent()->isVisible() ) )
Thomas Zander's avatar
Thomas Zander committed
110 111 112 113
            continue;
        if(shape->parent() != 0 && shape->parent()->childClipped(shape))
            continue;
        if(painter.hasClipping()) {
Thomas Zander's avatar
Thomas Zander committed
114
            QRectF shapeBox = shape->boundingRect();
115
            shapeBox = converter.documentToView(shapeBox);
Thomas Zander's avatar
Thomas Zander committed
116
            QRegion shapeRegion = QRegion(shapeBox.toRect());
Thomas Zander's avatar
Thomas Zander committed
117

Thomas Zander's avatar
Thomas Zander committed
118
            if(clipRegion.intersect(shapeRegion).isEmpty())
Thomas Zander's avatar
Thomas Zander committed
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
                continue;
        }
        painter.save();
        painter.setMatrix( shape->transformationMatrix(&converter) * painter.matrix() );

        painter.save();
        shape->paint( painter, converter );
        painter.restore();
        if(shape->border()) {
            painter.save();
            shape->border()->paintBorder(shape, painter, converter);
            painter.restore();
        }
        if(! forPrint) {
            painter.save();
            painter.setRenderHint( QPainter::Antialiasing, false );
            shape->paintDecorations( painter, converter, m_selection->isSelected(shape) );
            painter.restore();
        }
        painter.restore();  // for the matrix
    }

141 142 143 144 145 146 147 148 149 150 151
#if 0
    // paint tree
    double zx = 0;
    double zy = 0;
    converter.zoom( &zx, &zy );
    painter.save();
    painter.scale( zx, zy );
    m_tree.paint( painter );
    painter.restore();
#endif

Thomas Zander's avatar
Thomas Zander committed
152 153 154 155
    if(! forPrint)
        m_selection->paint( painter, converter );
}

Thomas Zander's avatar
Thomas Zander committed
156
KoShape * KoShapeManager::shapeAt( const QPointF &position, KoFlake::ShapeSelection selection, bool omitHiddenShapes )
Thomas Zander's avatar
Thomas Zander committed
157
{
158 159
    updateTree();
    QList<KoShape*> sorterdShapes( m_tree.contains( position ) );
Thomas Zander's avatar
Thomas Zander committed
160
    qSort(sorterdShapes.begin(), sorterdShapes.end(), KoShape::compareShapeZIndex);
Thomas Zander's avatar
Thomas Zander committed
161
    KoShape *firstUnselectedShape = 0;
Thomas Zander's avatar
Thomas Zander committed
162
    for(int count = sorterdShapes.count()-1; count >= 0; count--) {
163
        KoShape *shape = sorterdShapes.at(count);
164
        if ( omitHiddenShapes && ! shape->isVisible() )
165
            continue;
166 167 168 169
        if ( ! shape->hitTest( position ) )
            continue;

        switch ( selection )
Thomas Zander's avatar
Thomas Zander committed
170
        {
Thomas Zander's avatar
Thomas Zander committed
171
            case KoFlake::ShapeOnTop:
172
                return shape;
Thomas Zander's avatar
Thomas Zander committed
173
            case KoFlake::Selected:
174 175 176
                if ( m_selection->isSelected( shape ) )
                    return shape;
                break;
Thomas Zander's avatar
Thomas Zander committed
177
            case KoFlake::Unselected:
178 179 180
                if ( ! m_selection->isSelected( shape ) )
                    return shape;
                break;
Thomas Zander's avatar
Thomas Zander committed
181
            case KoFlake::NextUnselected:
182 183 184 185
                // we want an unselected shape
                if ( m_selection->isSelected( shape ) )
                    continue;
                // memorize the first unselected shape
Thomas Zander's avatar
Thomas Zander committed
186
                if( ! firstUnselectedShape )
187 188
                    firstUnselectedShape = shape;
                // check if the shape above is selected
189
                if( count + 1 < sorterdShapes.count() && m_selection->isSelected( sorterdShapes.at(count + 1) ) )
190 191
                    return shape;
                break;
Thomas Zander's avatar
Thomas Zander committed
192 193
        }
    }
194 195
    // if we want the next unselected below a selected but there was none selected, 
    // return the first found unselected shape
Thomas Zander's avatar
Thomas Zander committed
196
    if( selection == KoFlake::NextUnselected && firstUnselectedShape )
197 198
        return firstUnselectedShape;

Thomas Zander's avatar
Thomas Zander committed
199 200 201 202 203
    if ( m_selection->hitTest( position ) )
        return m_selection;

    return 0; // missed everything
}
Laurent Montel's avatar
Laurent Montel committed
204

205
QList<KoShape *> KoShapeManager::shapesAt( const QRectF &rect, bool omitHiddenShapes )
206 207 208 209
{
    updateTree();
    //TODO check if object is really in the rect and not 
    // only the bounding rect of the object.
210 211 212 213 214 215 216 217 218 219 220
    if( omitHiddenShapes ) {
        QList<KoShape*> intersectedShapes( m_tree.intersects( rect ) );
        for(int count = intersectedShapes.count()-1; count >= 0; count--) {
            KoShape *shape = intersectedShapes.at( count );
            if( ! shape->isVisible() )
                intersectedShapes.removeAt( count );
        }
        return intersectedShapes;
    }
    else
        return m_tree.intersects( rect );
221 222 223 224 225 226 227
}

void KoShapeManager::repaint( QRectF &rect, const KoShape *shape, bool selectionHandles )
{
    m_canvas->updateCanvas( rect );
    if ( selectionHandles && m_selection->isSelected( shape ) )
    {
228 229
        if ( m_canvas->toolProxy() )
            m_canvas->toolProxy()->repaintDecorations();
230 231 232 233 234 235 236 237 238 239 240 241 242 243
    }
}

void KoShapeManager::updateTree( KoShape * shape )
{
    m_aggregate4update.insert( shape );
}

void KoShapeManager::updateTree()
{
    foreach ( KoShape * shape, m_aggregate4update )
    {
        m_tree.remove( shape );
        QRectF br( shape->boundingRect() );
244
        m_tree.insert( br, shape );
245 246 247 248
    }
    m_aggregate4update.clear();
}

Laurent Montel's avatar
Laurent Montel committed
249
#include "KoShapeManager.moc"