~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to libs/flake/KoShapeManager.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2010-09-21 15:36:35 UTC
  • mfrom: (1.4.1 upstream) (60.2.11 maverick)
  • Revision ID: james.westby@ubuntu.com-20100921153635-6tejqkiro2u21ydi
Tags: 1:2.2.2-0ubuntu3
Add kubuntu_03_fix-crash-on-closing-sqlite-connection-2.2.2.diff and
kubuntu_04_support-large-memo-values-for-msaccess-2.2.2.diff as
recommended by upstream http://kexi-
project.org/wiki/wikiview/index.php@Kexi2.2_Patches.html#sqlite_stab
ility

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* This file is part of the KDE project
2
2
 
3
3
   Copyright (C) 2006-2008 Thorsten Zachmann <zachmann@kde.org>
4
 
   Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
5
 
   Copyright (C) 2009 Jan Hambrecht <jaham@gmx.net>
 
4
   Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
 
5
   Copyright (C) 2009-2010 Jan Hambrecht <jaham@gmx.net>
6
6
 
7
7
   This library is free software; you can redistribute it and/or
8
8
   modify it under the terms of the GNU Library General Public
25
25
#include "KoToolManager.h"
26
26
#include "KoPointerEvent.h"
27
27
#include "KoShape.h"
 
28
#include "KoShape_p.h"
28
29
#include "KoCanvasBase.h"
29
30
#include "KoShapeContainer.h"
30
31
#include "KoShapeBorderModel.h"
36
37
#include "KoFilterEffect.h"
37
38
#include "KoFilterEffectStack.h"
38
39
#include "KoFilterEffectRenderContext.h"
39
 
 
 
40
#include "KoShapeBackground.h"
40
41
#include <KoRTree.h>
41
42
 
42
43
#include <QPainter>
65
66
     */
66
67
    void updateTree();
67
68
 
 
69
    /**
 
70
     * Recursively paints the given group shape to the specified painter
 
71
     * This is needed for filter effects on group shapes where the filter effect
 
72
     * applies to all the children of the group shape at once
 
73
     */
 
74
    void paintGroup(KoShapeGroup *group, QPainter &painter, const KoViewConverter &converter, bool forPrint);
 
75
 
68
76
    class DetectCollision
69
77
    {
70
78
    public:
90
98
 
91
99
        void fireSignals() {
92
100
            foreach(KoShape *shape, shapesWithCollisionDetection)
93
 
                shape->shapeChanged(KoShape::CollisionDetected);
 
101
                shape->priv()->shapeChanged(KoShape::CollisionDetected);
94
102
        }
95
103
 
96
104
    private:
119
127
        selectionModified = selectionModified || selection->isSelected(shape);
120
128
    }
121
129
 
122
 
    foreach(KoShape * shape, aggregate4update) {
 
130
    foreach (KoShape *shape, aggregate4update) {
123
131
        tree.remove(shape);
124
132
        QRectF br(shape->boundingRect());
125
133
        strategy->adapt(shape, br);
127
135
    }
128
136
 
129
137
    // do it again to see which shapes we intersect with _after_ moving.
130
 
    foreach(KoShape *shape, aggregate4update)
 
138
    foreach (KoShape *shape, aggregate4update)
131
139
        detector.detect(tree, shape, shapeIndexesBeforeUpdate[shape]);
132
140
    aggregate4update.clear();
133
141
    shapeIndexesBeforeUpdate.clear();
139
147
    }
140
148
}
141
149
 
 
150
void KoShapeManager::Private::paintGroup(KoShapeGroup *group, QPainter &painter, const KoViewConverter &converter, bool forPrint)
 
151
{
 
152
    QList<KoShape*> childShapes = group->childShapes();
 
153
    qSort(childShapes.begin(), childShapes.end(), KoShape::compareShapeZIndex);
 
154
    foreach(KoShape *child, childShapes) {
 
155
        // we paint recursively here, so we do not have to check recursively for visibility
 
156
        if (!child->isVisible())
 
157
            continue;
 
158
        KoShapeGroup *childGroup = dynamic_cast<KoShapeGroup*>(child);
 
159
        if (childGroup) {
 
160
            paintGroup(childGroup, painter, converter, forPrint);
 
161
        } else {
 
162
            painter.save();
 
163
            strategy->paint(child, painter, converter, forPrint);
 
164
            painter.restore();
 
165
        }
 
166
    }
 
167
}
 
168
 
142
169
KoShapeManager::KoShapeManager(KoCanvasBase *canvas, const QList<KoShape *> &shapes)
143
170
        : d(new Private(this, canvas))
144
171
{
157
184
KoShapeManager::~KoShapeManager()
158
185
{
159
186
    foreach(KoShape *shape, d->shapes) {
160
 
        shape->removeShapeManager(this);
 
187
        shape->priv()->removeShapeManager(this);
161
188
    }
162
189
    foreach(KoShape *shape, d->additionalShapes) {
163
 
        shape->removeShapeManager(this);
 
190
        shape->priv()->removeShapeManager(this);
164
191
    }
165
192
    delete d;
166
193
}
171
198
    //clear selection
172
199
    d->selection->deselectAll();
173
200
    foreach(KoShape *shape, d->shapes) {
174
 
        shape->removeShapeManager(this);
 
201
        shape->priv()->removeShapeManager(this);
175
202
    }
176
203
    d->aggregate4update.clear();
177
204
    d->tree.clear();
185
212
{
186
213
    if (d->shapes.contains(shape))
187
214
        return;
188
 
    shape->addShapeManager(this);
 
215
    shape->priv()->addShapeManager(this);
189
216
    d->shapes.append(shape);
190
217
    if (! dynamic_cast<KoShapeGroup*>(shape) && ! dynamic_cast<KoShapeLayer*>(shape)) {
191
218
        QRectF br(shape->boundingRect());
196
223
    }
197
224
 
198
225
    // add the children of a KoShapeContainer
199
 
    KoShapeContainer* container = dynamic_cast<KoShapeContainer*>(shape);
 
226
    KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
200
227
 
201
228
    if (container) {
202
 
        foreach(KoShape* containerShape, container->childShapes()) {
 
229
        foreach (KoShape *containerShape, container->childShapes()) {
203
230
            add(containerShape, repaint);
204
231
        }
205
232
    }
206
233
 
207
234
    Private::DetectCollision detector;
208
 
    detector.detect( d->tree, shape, shape->zIndex() );
 
235
    detector.detect(d->tree, shape, shape->zIndex());
209
236
    detector.fireSignals();
210
237
}
211
238
 
212
239
void KoShapeManager::addAdditional(KoShape *shape)
213
240
{
214
 
    if ( shape ) {
 
241
    if (shape) {
215
242
        if (d->additionalShapes.contains(shape)) {
216
243
            return;
217
244
        }
218
 
        shape->addShapeManager(this);
 
245
        shape->priv()->addShapeManager(this);
219
246
        d->additionalShapes.append(shape);
220
247
    }
221
248
}
227
254
    detector.fireSignals();
228
255
 
229
256
    shape->update();
230
 
    shape->removeShapeManager(this);
 
257
    shape->priv()->removeShapeManager(this);
231
258
    d->selection->deselect(shape);
232
259
    d->aggregate4update.remove(shape);
233
260
    d->tree.remove(shape);
234
261
    d->shapes.removeAll(shape);
235
262
 
236
263
    // remove the children of a KoShapeContainer
237
 
    KoShapeContainer* container = dynamic_cast<KoShapeContainer*>(shape);
238
 
 
 
264
    KoShapeContainer *container = dynamic_cast<KoShapeContainer*>(shape);
239
265
    if (container) {
240
 
        foreach(KoShape* containerShape, container->childShapes()) {
 
266
        foreach (KoShape *containerShape, container->childShapes()) {
241
267
            remove(containerShape);
242
268
        }
243
269
    }
245
271
 
246
272
void KoShapeManager::removeAdditional(KoShape *shape)
247
273
{
248
 
    if ( shape ) {
249
 
        shape->removeShapeManager(this);
 
274
    if (shape) {
 
275
        shape->priv()->removeShapeManager(this);
250
276
        d->additionalShapes.removeAll(shape);
251
277
    }
252
278
}
267
293
    }
268
294
 
269
295
    // filter all hidden shapes from the list
 
296
    // also filter shapes with a parent which has filter effects applied
270
297
    QList<KoShape*> sortedShapes;
271
 
    foreach(KoShape * shape, unsortedShapes) {
272
 
        if (shape->isVisible(true))
 
298
    foreach (KoShape *shape, unsortedShapes) {
 
299
        if (!shape->isVisible(true))
 
300
            continue;
 
301
        bool addShapeToList = true;
 
302
        // check if one of the shapes ancestors have filter effects
 
303
        KoShapeContainer *parent = shape->parent();
 
304
        while (parent) {
 
305
            // parent must be part of the shape manager to be taken into account
 
306
            if (!d->shapes.contains(parent))
 
307
                break;
 
308
            if (parent->filterEffectStack() && !parent->filterEffectStack()->isEmpty()) {
 
309
                    addShapeToList = false;
 
310
                    break;
 
311
            }
 
312
            parent = parent->parent();
 
313
        }
 
314
        if (addShapeToList) {
273
315
            sortedShapes.append(shape);
 
316
        } else if (parent) {
 
317
            sortedShapes.append(parent);
 
318
        }
274
319
    }
275
320
 
276
321
    qSort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex);
277
322
 
278
 
    foreach(KoShape * shape, sortedShapes) {
 
323
    foreach (KoShape *shape, sortedShapes) {
279
324
        if (shape->parent() != 0 && shape->parent()->childClipped(shape))
280
325
            continue;
281
326
 
 
327
        painter.save();
282
328
        d->strategy->paint(shape, painter, converter, forPrint);
 
329
        painter.restore();
283
330
    }
284
331
 
285
332
#ifdef KOFFICE_RTREE_DEBUG
297
344
        d->selection->paint(painter, converter);
298
345
}
299
346
 
300
 
void KoShapeManager::paintShape(KoShape * shape, QPainter &painter, const KoViewConverter &converter, bool forPrint)
 
347
void KoShapeManager::paintShape(KoShape *shape, QPainter &painter, const KoViewConverter &converter, bool forPrint)
301
348
{
 
349
    painter.save();
 
350
    qreal transparency = shape->transparency(true);
 
351
    if (transparency > 0.0) {
 
352
        painter.setOpacity(1.0-transparency);
 
353
    }
 
354
 
302
355
    if (shape->shadow()) {
303
356
        painter.save();
304
357
        shape->shadow()->paint(shape, painter, converter);
305
358
        painter.restore();
306
359
    }
307
 
    if(!shape->filterEffectStack() || shape->filterEffectStack()->filterEffects().isEmpty()) {
 
360
    if (!shape->filterEffectStack() || shape->filterEffectStack()->isEmpty()) {
308
361
        painter.save();
309
362
        shape->paint(painter, converter);
310
363
        painter.restore();
311
364
        if (shape->border()) {
312
365
            painter.save();
313
 
            shape->border()->paintBorder(shape, painter, converter);
 
366
            shape->border()->paint(shape, painter, converter);
314
367
            painter.restore();
315
368
        }
316
369
    } else {
317
 
        // There are filter effets, then we need to prerender the shape on an image, to filter it
 
370
        // There are filter effects, then we need to prerender the shape on an image, to filter it
318
371
        QRectF shapeBound(QPointF(), shape->size());
319
372
        // First step, compute the rectangle used for the image
320
373
        QRectF clipRegion = shape->filterEffectStack()->clipRectForBoundingRect(shapeBound);
323
376
        // determine the offset of the clipping rect from the shapes origin
324
377
        QPointF clippingOffset = zoomedClipRegion.topLeft();
325
378
 
326
 
        // Init the buffer image
 
379
        // Initialize the buffer image
327
380
        QImage sourceGraphic(zoomedClipRegion.size().toSize(), QImage::Format_ARGB32_Premultiplied);
328
381
        sourceGraphic.fill(qRgba(0,0,0,0));
329
382
 
330
 
        // Init the buffer painter
331
 
        QPainter imagePainter(&sourceGraphic);
332
 
        imagePainter.translate(-1.0f*clippingOffset);
333
 
        imagePainter.setPen(Qt::NoPen);
334
 
        imagePainter.setBrush(Qt::NoBrush);
335
 
        imagePainter.setRenderHint(QPainter::Antialiasing, painter.testRenderHint(QPainter::Antialiasing));
336
 
 
337
 
        // Paint the shape on the image
338
 
        imagePainter.save();
339
 
        shape->paint(imagePainter, converter);
340
 
        imagePainter.restore();
341
 
        if (shape->border()) {
342
 
            imagePainter.save();
343
 
            shape->border()->paintBorder(shape, imagePainter, converter);
344
 
            imagePainter.restore();
345
 
        }
346
 
        imagePainter.end();
347
 
 
348
 
        QImage sourceAlpha = sourceGraphic;
349
 
        sourceAlpha.fill(qRgba(0,0,0,255));
350
 
        sourceAlpha.setAlphaChannel(sourceGraphic.alphaChannel());
351
 
 
352
383
        QHash<QString, QImage> imageBuffers;
 
384
 
 
385
        QSet<QString> requiredStdInputs = shape->filterEffectStack()->requiredStandarsInputs();
 
386
 
 
387
        if (requiredStdInputs.contains("SourceGraphic") || requiredStdInputs.contains("SourceAlpha")) {
 
388
            // Init the buffer painter
 
389
            QPainter imagePainter(&sourceGraphic);
 
390
            imagePainter.translate(-1.0f*clippingOffset);
 
391
            imagePainter.setPen(Qt::NoPen);
 
392
            imagePainter.setBrush(Qt::NoBrush);
 
393
            imagePainter.setRenderHint(QPainter::Antialiasing, painter.testRenderHint(QPainter::Antialiasing));
 
394
 
 
395
            // Paint the shape on the image
 
396
            KoShapeGroup *group = dynamic_cast<KoShapeGroup*>(shape);
 
397
            if (group) {
 
398
                // the childrens matrix contains the groups matrix as well
 
399
                // so we have to compensate for that before painting the children
 
400
                imagePainter.setMatrix(group->absoluteTransformation(&converter).inverted(), true);
 
401
                d->paintGroup(group, imagePainter, converter, forPrint);
 
402
            } else {
 
403
                imagePainter.save();
 
404
                shape->paint(imagePainter, converter);
 
405
                imagePainter.restore();
 
406
                if (shape->border()) {
 
407
                    imagePainter.save();
 
408
                    shape->border()->paint(shape, imagePainter, converter);
 
409
                    imagePainter.restore();
 
410
                }
 
411
                imagePainter.end();
 
412
            }
 
413
        }
 
414
        if (requiredStdInputs.contains("SourceAlpha")) {
 
415
            QImage sourceAlpha = sourceGraphic;
 
416
            sourceAlpha.fill(qRgba(0,0,0,255));
 
417
            sourceAlpha.setAlphaChannel(sourceGraphic.alphaChannel());
 
418
            imageBuffers.insert("SourceAlpha", sourceAlpha);
 
419
        }
 
420
        if (requiredStdInputs.contains("FillPaint")) {
 
421
            QImage fillPaint = sourceGraphic;
 
422
            if (shape->background()) {
 
423
                QPainter fillPainter(&fillPaint);
 
424
                QPainterPath fillPath;
 
425
                fillPath.addRect(fillPaint.rect().adjusted(-1,-1,1,1));
 
426
                shape->background()->paint(fillPainter, fillPath);
 
427
            } else {
 
428
                fillPaint.fill(qRgba(0,0,0,0));
 
429
            }
 
430
            imageBuffers.insert("FillPaint", fillPaint);
 
431
        }
 
432
 
353
433
        imageBuffers.insert("SourceGraphic", sourceGraphic);
354
434
        imageBuffers.insert(QString(), sourceGraphic);
355
 
        imageBuffers.insert("SourceAlpha", sourceAlpha);
356
435
 
357
 
        QMatrix coordTransform = QMatrix().scale(shapeBound.width(), shapeBound.height());
358
436
        KoFilterEffectRenderContext renderContext(converter);
359
 
        renderContext.setCoordinateTransformation(coordTransform);
360
 
        
 
437
        renderContext.setShapeBoundingBox(shapeBound);
 
438
 
 
439
        QImage result;
361
440
        QList<KoFilterEffect*> filterEffects = shape->filterEffectStack()->filterEffects();
362
441
        // Filter
363
 
        foreach(KoFilterEffect* filterEffect, filterEffects) {
364
 
            QRectF filterRegion = filterEffect->filterRectForBoundingRect(clipRegion);
 
442
        foreach (KoFilterEffect *filterEffect, filterEffects) {
 
443
            QRectF filterRegion = filterEffect->filterRectForBoundingRect(shapeBound);
365
444
            filterRegion = converter.documentToView(filterRegion);
366
 
            QPointF filterOffset = filterRegion.topLeft()-2*clippingOffset;
367
 
            QRect subRegion = filterRegion.translated(filterOffset).toRect();
368
 
 
 
445
            QRect subRegion = filterRegion.translated(-clippingOffset).toRect();
369
446
            // set current filter region
370
 
            renderContext.setFilterRegion(subRegion);
371
 
            
372
 
            if (filterEffect->maximalInputCount() == 1) {
 
447
            renderContext.setFilterRegion(subRegion & sourceGraphic.rect());
 
448
 
 
449
            if (filterEffect->maximalInputCount() <= 1) {
373
450
                QList<QString> inputs = filterEffect->inputs();
374
451
                QString input = inputs.count() ? inputs.first() : QString();
375
 
                // get input image from image buffers
376
 
                QImage inputImage = imageBuffers.value(input);
377
 
                // apply the filter effect
378
 
                QImage result = filterEffect->processImage(inputImage, renderContext);
379
 
                // store result of effect
380
 
                imageBuffers.insert(filterEffect->output(), result);
 
452
                // get input image from image buffers and apply the filter effect
 
453
                QImage image = imageBuffers.value(input);
 
454
                if (!image.isNull()) {
 
455
                    result = filterEffect->processImage(imageBuffers.value(input), renderContext);
 
456
                }
381
457
            } else {
382
458
                QList<QImage> inputImages;
383
459
                foreach(const QString &input, filterEffect->inputs()) {
384
 
                    inputImages.append(imageBuffers.value(input));
 
460
                    QImage image = imageBuffers.value(input);
 
461
                    if (!image.isNull())
 
462
                        inputImages.append(imageBuffers.value(input));
385
463
                }
386
464
                // apply the filter effect
387
 
                QImage result = filterEffect->processImages(inputImages, renderContext);
388
 
                // store result of effect
389
 
                imageBuffers.insert(filterEffect->output(), result);
 
465
                if (filterEffect->inputs().count() == inputImages.count())
 
466
                    result = filterEffect->processImages(inputImages, renderContext);
390
467
            }
 
468
            // store result of effect
 
469
            imageBuffers.insert(filterEffect->output(), result);
391
470
        }
392
471
 
393
 
        KoFilterEffect * lastEffect = filterEffects.last();
 
472
        KoFilterEffect *lastEffect = filterEffects.last();
394
473
 
395
474
        // Paint the result
396
475
        painter.save();
403
482
        shape->paintDecorations(painter, converter, d->canvas);
404
483
        painter.restore();
405
484
    }
 
485
    painter.restore();
406
486
}
407
487
 
408
 
 
409
 
KoShape * KoShapeManager::shapeAt(const QPointF &position, KoFlake::ShapeSelection selection, bool omitHiddenShapes)
 
488
KoShape *KoShapeManager::shapeAt(const QPointF &position, KoFlake::ShapeSelection selection, bool omitHiddenShapes)
410
489
{
411
490
    d->updateTree();
412
491
    QList<KoShape*> sortedShapes(d->tree.contains(position));
464
543
        KoShape *shape = intersectedShapes.at(count);
465
544
        if ( omitHiddenShapes && ! shape->isVisible(true)) {
466
545
            intersectedShapes.removeAt(count);
467
 
        }
468
 
        else {
 
546
        } else {
469
547
            const QPainterPath outline = shape->absoluteTransformation(0).map(shape->outline());
470
 
            if( ! outline.intersects( rect ) && ! outline.contains( rect ) ) {
 
548
            if (! outline.intersects(rect) && ! outline.contains(rect)) {
471
549
                intersectedShapes.removeAt(count);
472
550
            }
473
551
        }
484
562
    }
485
563
}
486
564
 
487
 
void KoShapeManager::notifyShapeChanged(KoShape * shape)
 
565
void KoShapeManager::notifyShapeChanged(KoShape *shape)
488
566
{
489
567
    Q_ASSERT(shape);
490
568
    if (d->aggregate4update.contains(shape) || d->additionalShapes.contains(shape)) {
517
595
    return shapes;
518
596
}
519
597
 
520
 
KoSelection * KoShapeManager::selection() const
 
598
KoSelection *KoShapeManager::selection() const
521
599
{
522
600
    return d->selection;
523
601
}
538
616
        KoToolManager::instance()->preferredToolForSelection(shapes));
539
617
}
540
618
 
541
 
void KoShapeManager::setPaintingStrategy(KoShapeManagerPaintingStrategy * strategy)
 
619
void KoShapeManager::setPaintingStrategy(KoShapeManagerPaintingStrategy *strategy)
542
620
{
543
621
    delete d->strategy;
544
622
    d->strategy = strategy;
545
623
}
546
624
 
547
 
#include "KoShapeManager.moc"
 
625
#include <KoShapeManager.moc>