Krita Source Code Documentation
Loading...
Searching...
No Matches
KoShapeGroupCommand.cpp
Go to the documentation of this file.
1/* This file is part of the KDE project
2 * SPDX-FileCopyrightText: 2006, 2010 Thomas Zander <zander@kde.org>
3 * SPDX-FileCopyrightText: 2006, 2007 Jan Hambrecht <jaham@gmx.net>
4 *
5 * SPDX-License-Identifier: LGPL-2.0-or-later
6 */
7
9#include "KoShape.h"
10#include "KoShapeGroup.h"
11#include "KoShapeContainer.h"
12
14
15#include <klocalizedstring.h>
16
17// static
19{
20 QList<KoShape*> orderedShapes(shapes);
21 if (!orderedShapes.isEmpty()) {
22 KoShape * top = orderedShapes.last();
23 container->setParent(top->parent());
24 container->setZIndex(top->zIndex());
25 }
26
27 return new KoShapeGroupCommand(container, orderedShapes, shouldNormalize, 0);
28}
29
43
45 : shapes(s),
46 shouldNormalize(_shouldNormalize),
47 container(c)
48{
49 std::stable_sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
50}
51
53 : KoShapeGroupCommand(container, shapes, false, parent)
54{
55}
56
58 bool shouldNormalize, KUndo2Command *parent)
59 : KUndo2Command(parent),
60 d(new KoShapeGroupCommandPrivate(container, shapes, shouldNormalize))
61{
62 Q_FOREACH (KoShape* shape, d->shapes) {
63 d->oldParents.append(shape->parent());
64 }
65
66 if (d->container->shapes().isEmpty()) {
67 setText(kundo2_i18n("Group shapes"));
68 } else {
69 setText(kundo2_i18n("Add shapes to group"));
70 }
71}
72
76
78{
80
81 if (d->shouldNormalize && dynamic_cast<KoShapeGroup*>(d->container)) {
82 QRectF bound = d->containerBoundingRect();
83 QPointF oldGroupPosition = d->container->absolutePosition(KoFlake::TopLeft);
84 d->container->setAbsolutePosition(bound.topLeft(), KoFlake::TopLeft);
85 d->container->setSize(bound.size());
86
87 if (d->container->shapeCount() > 0) {
88 // the group has changed position and so have the group child shapes
89 // -> we need compensate the group position change
90 QPointF positionOffset = oldGroupPosition - bound.topLeft();
91 Q_FOREACH (KoShape * child, d->container->shapes())
92 child->setAbsolutePosition(child->absolutePosition() + positionOffset);
93 }
94 }
95
96 QTransform groupTransform = d->container->absoluteTransformation().inverted();
97
98 QList<KoShape*> containerShapes(d->container->shapes());
99 std::stable_sort(containerShapes.begin(), containerShapes.end(), KoShape::compareShapeZIndex);
100
102 Q_FOREACH (KoShape *shape, containerShapes) {
103 indexedShapes.append(KoShapeReorderCommand::IndexedShape(shape));
104 }
105
107
108 Q_FOREACH (KoShape *shape, d->shapes) {
109 // test if they inherit the same parent
110
111 if (!shape->hasCommonParent(d->container) ||
112 !KoShape::compareShapeZIndex(shape, d->container)) {
113
114 indexedShapes.append(KoShapeReorderCommand::IndexedShape(shape));
115 } else {
116 prependIndexedShapes.append(KoShapeReorderCommand::IndexedShape(shape));
117 }
118 }
119
120 indexedShapes = prependIndexedShapes + indexedShapes;
121 indexedShapes = KoShapeReorderCommand::homogenizeZIndexesLazy(indexedShapes);
122
123 if (!indexedShapes.isEmpty()) {
124 d->shapesReorderCommand.reset(new KoShapeReorderCommand(indexedShapes));
125 d->shapesReorderCommand->redo();
126 }
127
128 uint shapeCount = d->shapes.count();
129 for (uint i = 0; i < shapeCount; ++i) {
130 KoShape * shape = d->shapes[i];
131
132 shape->applyAbsoluteTransformation(groupTransform);
133 d->container->addShape(shape);
134 }
135
136
137}
138
140{
142
143 QTransform ungroupTransform = d->container->absoluteTransformation();
144 for (int i = 0; i < d->shapes.count(); i++) {
145 KoShape * shape = d->shapes[i];
146 d->container->removeShape(shape);
147 if (d->oldParents.at(i)) {
148 d->oldParents.at(i)->addShape(shape);
149 }
150 shape->applyAbsoluteTransformation(ungroupTransform);
151 }
152
153 if (d->shapesReorderCommand) {
154 d->shapesReorderCommand->undo();
155 d->shapesReorderCommand.reset();
156 }
157
158 if (d->shouldNormalize && dynamic_cast<KoShapeGroup*>(d->container)) {
159 QPointF oldGroupPosition = d->container->absolutePosition(KoFlake::TopLeft);
160 if (d->container->shapeCount() > 0) {
161 bool boundingRectInitialized = false;
162 QRectF bound;
163 Q_FOREACH (KoShape * shape, d->container->shapes()) {
164 if (! boundingRectInitialized) {
165 bound = shape->boundingRect();
166 boundingRectInitialized = true;
167 } else
168 bound = bound.united(shape->boundingRect());
169 }
170 // the group has changed position and so have the group child shapes
171 // -> we need compensate the group position change
172 QPointF positionOffset = oldGroupPosition - bound.topLeft();
173 Q_FOREACH (KoShape * child, d->container->shapes())
174 child->setAbsolutePosition(child->absolutePosition() + positionOffset);
175
176 d->container->setAbsolutePosition(bound.topLeft(), KoFlake::TopLeft);
177 d->container->setSize(bound.size());
178 }
179 }
180}
181
183{
184 QRectF bound;
185 if (container->shapeCount() > 0) {
187 }
188
189 Q_FOREACH (KoShape *shape, shapes) {
190 bound |= shape->absoluteTransformation().mapRect(shape->outlineRect());
191 }
192
193 return bound;
194}
unsigned int uint
virtual void undo()
void setText(const KUndo2MagicString &text)
const KUndo2Command * child(int index) const
virtual void redo()
KoShapeContainer * container
the container where the grouping should be for.
bool shouldNormalize
Adjust the coordinate system of the group to its origin into the topleft of the group.
QList< KoShapeContainer * > oldParents
the old parents of the shapes
QScopedPointer< KUndo2Command > shapesReorderCommand
QList< KoShape * > shapes
list of shapes to be grouped
KoShapeGroupCommandPrivate(KoShapeContainer *container, const QList< KoShape * > &shapes, bool _shouldNormalize)
The undo / redo command for grouping shapes.
const QScopedPointer< KoShapeGroupCommandPrivate > d
KoShapeGroupCommand(KoShapeContainer *container, const QList< KoShape * > &shapes, bool shouldNormalize, KUndo2Command *parent=0)
void redo() override
redo the command
void undo() override
revert the actions done in redo
static KoShapeGroupCommand * createCommand(KoShapeContainer *container, const QList< KoShape * > &shapes, bool shouldNormalize=false)
This command allows you to change the zIndex of a number of shapes.
static QList< KoShapeReorderCommand::IndexedShape > homogenizeZIndexesLazy(QList< IndexedShape > shapes)
virtual QRectF outlineRect() const
Definition KoShape.cpp:637
bool hasCommonParent(const KoShape *shape) const
Definition KoShape.cpp:581
void setZIndex(qint16 zIndex)
Definition KoShape.cpp:954
void applyAbsoluteTransformation(const QTransform &matrix)
Definition KoShape.cpp:400
static bool compareShapeZIndex(KoShape *s1, KoShape *s2)
Definition KoShape.cpp:434
virtual QRectF boundingRect() const
Get the bounding box of the shape.
Definition KoShape.cpp:335
KoShapeContainer * parent() const
Definition KoShape.cpp:1039
QTransform absoluteTransformation() const
Definition KoShape.cpp:382
void setParent(KoShapeContainer *parent)
Definition KoShape.cpp:535
qint16 zIndex() const
Definition KoShape.cpp:600
KUndo2MagicString kundo2_i18n(const char *text)
@ TopLeft
Definition KoFlake.h:86