1 /*
2  *  This file is part of Calligra tests
3  *
4  *  Copyright (C) 2006-2010 Thomas Zander <zander@kde.org>
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  */
20 
21 #include "TestShapePainting.h"
22 
23 #include <QtGui>
24 #include "KoShapeContainer.h"
25 #include "KoShapeManager.h"
26 #include "KoShapePaintingContext.h"
27 #include <sdk/tests/kistest.h>
28 #include <MockShapes.h>
29 
30 #include <QTest>
31 
testPaintShape()32 void TestShapePainting::testPaintShape()
33 {
34     MockShape *shape1 = new MockShape();
35     MockShape *shape2 = new MockShape();
36     QScopedPointer<MockContainer> container(new MockContainer());
37 
38     container->addShape(shape1);
39     container->addShape(shape2);
40     QCOMPARE(shape1->parent(), container.data());
41     QCOMPARE(shape2->parent(), container.data());
42     container->setClipped(shape1, false);
43     container->setClipped(shape2, false);
44     QCOMPARE(container->isClipped(shape1), false);
45     QCOMPARE(container->isClipped(shape2), false);
46 
47     MockCanvas canvas;
48     KoShapeManager manager(&canvas);
49     manager.addShape(container.data());
50     QCOMPARE(manager.shapes().count(), 3);
51 
52     QImage image(100, 100,  QImage::Format_Mono);
53     QPainter painter(&image);
54     manager.paint(painter, false);
55 
56     // with the shape not being clipped, the shapeManager will paint it for us.
57     QCOMPARE(shape1->paintedCount, 1);
58     QCOMPARE(shape2->paintedCount, 1);
59     QCOMPARE(container->paintedCount, 1);
60 
61     // the container should thus not paint the shape
62     shape1->paintedCount = 0;
63     shape2->paintedCount = 0;
64     container->paintedCount = 0;
65     KoShapePaintingContext paintContext;
66     container->paint(painter, paintContext);
67     QCOMPARE(shape1->paintedCount, 0);
68     QCOMPARE(shape2->paintedCount, 0);
69     QCOMPARE(container->paintedCount, 1);
70 
71 
72     container->setClipped(shape1, false);
73     container->setClipped(shape2, true);
74     QCOMPARE(container->isClipped(shape1), false);
75     QCOMPARE(container->isClipped(shape2), true);
76 
77     shape1->paintedCount = 0;
78     shape2->paintedCount = 0;
79     container->paintedCount = 0;
80     manager.paint(painter, false);
81 
82 
83     // with this shape not being clipped, the shapeManager will paint the container and this shape
84     QCOMPARE(shape1->paintedCount, 1);
85     // with this shape being clipped, the container will paint it for us.
86     QCOMPARE(shape2->paintedCount, 1);
87     QCOMPARE(container->paintedCount, 1);
88 }
89 
testPaintHiddenShape()90 void TestShapePainting::testPaintHiddenShape()
91 {
92     QScopedPointer<MockContainer> top(new MockContainer());
93 
94     MockShape *shape = new MockShape();
95     MockContainer *fourth = new MockContainer();
96     MockContainer *thirth = new MockContainer();
97     MockContainer *second = new MockContainer();
98 
99 
100     top->addShape(second);
101     second->addShape(thirth);
102     thirth->addShape(fourth);
103     fourth->addShape(shape);
104 
105     second->setVisible(false);
106 
107     MockCanvas canvas;
108     KoShapeManager manager(&canvas);
109     manager.addShape(top.data());
110     QCOMPARE(manager.shapes().count(), 5);
111 
112     QImage image(100, 100,  QImage::Format_Mono);
113     QPainter painter(&image);
114     manager.paint(painter, false);
115 
116     QCOMPARE(top->paintedCount, 1);
117     QCOMPARE(second->paintedCount, 0);
118     QCOMPARE(thirth->paintedCount, 0);
119     QCOMPARE(fourth->paintedCount, 0);
120     QCOMPARE(shape->paintedCount, 0);
121 }
122 
testPaintOrder()123 void TestShapePainting::testPaintOrder()
124 {
125     // the stacking order determines the painting order so things on top
126     // get their paint called last.
127     // Each shape has a zIndex and within the children a container has
128     // it determines the stacking order. Its important to realize that
129     // the zIndex is thus local to a container, if you have layer1 and layer2
130     // with both various child shapes the stacking order of the layer shapes
131     // is most important, then within this the child shape index is used.
132 
133     class OrderedMockShape : public MockShape {
134     public:
135         OrderedMockShape(QList<const MockShape*> *list) : order(list) {}
136         void paint(QPainter &painter, KoShapePaintingContext &paintcontext) const override {
137             order->append(this);
138             MockShape::paint(painter, paintcontext);
139         }
140         mutable QList<const MockShape*> *order;
141     };
142 
143     QList<const MockShape*> order;
144 
145     {
146         QScopedPointer<MockContainer> top(new MockContainer());
147         top->setZIndex(2);
148         OrderedMockShape *shape1 = new OrderedMockShape(&order);
149         shape1->setZIndex(5);
150         OrderedMockShape *shape2 = new OrderedMockShape(&order);
151         shape2->setZIndex(0);
152         top->addShape(shape1);
153         top->addShape(shape2);
154 
155         QScopedPointer<MockContainer> bottom(new MockContainer());
156         bottom->setZIndex(1);
157         OrderedMockShape *shape3 = new OrderedMockShape(&order);
158         shape3->setZIndex(-1);
159         OrderedMockShape *shape4 = new OrderedMockShape(&order);
160         shape4->setZIndex(9);
161         bottom->addShape(shape3);
162         bottom->addShape(shape4);
163 
164         MockCanvas canvas;
165         KoShapeManager manager(&canvas);
166         manager.addShape(top.data());
167         manager.addShape(bottom.data());
168         QCOMPARE(manager.shapes().count(), 6);
169 
170         QImage image(100, 100,  QImage::Format_Mono);
171         QPainter painter(&image);
172         manager.paint(painter, false);
173         QCOMPARE(top->paintedCount, 1);
174         QCOMPARE(bottom->paintedCount, 1);
175         QCOMPARE(shape1->paintedCount, 1);
176         QCOMPARE(shape2->paintedCount, 1);
177         QCOMPARE(shape3->paintedCount, 1);
178         QCOMPARE(shape4->paintedCount, 1);
179 
180         QCOMPARE(order.count(), 4);
181         QVERIFY(order[0] == shape3); // lowest first
182         QVERIFY(order[1] == shape4);
183         QVERIFY(order[2] == shape2);
184         QVERIFY(order[3] == shape1);
185 
186         // again, with clipping.
187         order.clear();
188         painter.setClipRect(0, 0, 100, 100);
189         manager.paint(painter, false);
190         QCOMPARE(top->paintedCount, 2);
191         QCOMPARE(bottom->paintedCount, 2);
192         QCOMPARE(shape1->paintedCount, 2);
193         QCOMPARE(shape2->paintedCount, 2);
194         QCOMPARE(shape3->paintedCount, 2);
195         QCOMPARE(shape4->paintedCount, 2);
196 
197         QCOMPARE(order.count(), 4);
198         QVERIFY(order[0] == shape3); // lowest first
199         QVERIFY(order[1] == shape4);
200         QVERIFY(order[2] == shape2);
201         QVERIFY(order[3] == shape1);
202 
203     }
204 
205     order.clear();
206 
207     {
208         QScopedPointer<MockContainer> root(new MockContainer());
209         root->setZIndex(0);
210 
211         MockContainer *branch1 = new MockContainer();
212         branch1->setZIndex(1);
213         OrderedMockShape *child1_1 = new OrderedMockShape(&order);
214         child1_1->setZIndex(1);
215         OrderedMockShape *child1_2 = new OrderedMockShape(&order);
216         child1_2->setZIndex(2);
217         branch1->addShape(child1_1);
218         branch1->addShape(child1_2);
219 
220         MockContainer *branch2 = new MockContainer();
221         branch2->setZIndex(2);
222         OrderedMockShape *child2_1 = new OrderedMockShape(&order);
223         child2_1->setZIndex(1);
224         OrderedMockShape *child2_2 = new OrderedMockShape(&order);
225         child2_2->setZIndex(2);
226         branch2->addShape(child2_1);
227         branch2->addShape(child2_2);
228 
229         root->addShape(branch1);
230         root->addShape(branch2);
231 
232         QList<KoShape*> sortedShapes;
233         sortedShapes.append(root.data());
234         sortedShapes.append(branch1);
235         sortedShapes.append(branch2);
236         sortedShapes.append(branch1->shapes());
237         sortedShapes.append(branch2->shapes());
238 
239         std::sort(sortedShapes.begin(), sortedShapes.end(), KoShape::compareShapeZIndex);
240         QCOMPARE(sortedShapes.count(), 7);
241         QVERIFY(sortedShapes[0] == root.data());
242         QVERIFY(sortedShapes[1] == branch1);
243         QVERIFY(sortedShapes[2] == child1_1);
244         QVERIFY(sortedShapes[3] == child1_2);
245         QVERIFY(sortedShapes[4] == branch2);
246         QVERIFY(sortedShapes[5] == child2_1);
247         QVERIFY(sortedShapes[6] == child2_2);
248     }
249 }
250 #include <kundo2command.h>
251 #include <KoShapeController.h>
252 #include <KoShapeGroupCommand.h>
253 #include <KoShapeUngroupCommand.h>
254 #include "kis_debug.h"
testGroupUngroup()255 void TestShapePainting::testGroupUngroup()
256 {
257     MockShapeController controller;
258     MockCanvas canvas(&controller);
259 
260     KoShapeManager *manager = canvas.shapeManager();
261 
262     QScopedPointer<MockContainer> shapesFakeLayer(new MockContainer());
263     shapesFakeLayer->setAssociatedRootShapeManager(manager);
264 
265     MockShape *shape1(new MockShape());
266     MockShape *shape2(new MockShape());
267     shape1->setName("shape1");
268     shape2->setName("shape2");
269     shape1->setParent(shapesFakeLayer.data());
270     shape2->setParent(shapesFakeLayer.data());
271 
272     QList<KoShape*> groupedShapes = {shape1, shape2};
273 
274     QImage image(100, 100,  QImage::Format_Mono);
275     QPainter painter(&image);
276     painter.setClipRect(image.rect());
277 
278     for (int i = 0; i < 3; i++) {
279         KoShapeGroup *group = new KoShapeGroup();
280 
281         {
282             group->setName("group");
283 
284             KUndo2Command groupingCommand;
285             canvas.shapeController()->addShapeDirect(group, shapesFakeLayer.data(), &groupingCommand);
286             new KoShapeGroupCommand(group, groupedShapes, true, &groupingCommand);
287 
288             groupingCommand.redo();
289 
290             manager->paint(painter, false);
291 
292             QCOMPARE(shape1->paintedCount, 2 * i + 1);
293             QCOMPARE(shape2->paintedCount, 2 * i + 1);
294             QCOMPARE(manager->shapes().size(), 3);
295         }
296 
297         {
298             KUndo2Command ungroupingCommand;
299 
300             new KoShapeUngroupCommand(group, group->shapes(), QList<KoShape*>(), &ungroupingCommand);
301             canvas.shapeController()->removeShape(group, &ungroupingCommand);
302             // NOTE: group will be deleted in ungroupingCommand's d-tor
303 
304             ungroupingCommand.redo();
305 
306             manager->paint(painter, false);
307 
308             QCOMPARE(shape1->paintedCount, 2 * i + 2);
309             QCOMPARE(shape2->paintedCount, 2 * i + 2);
310             QCOMPARE(manager->shapes().size(), 2);
311         }
312     }
313 }
314 
315 KISTEST_MAIN(TestShapePainting)
316