Commit 84500c38 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Fix z-index on shape grouping/ungrouping

When grouping, the command should change z-index as little as possible.
If the new shape was above the group, it should be appended, if it was
below the group, it should be prepended.

The same should happen on ungrouping: the ungrouped shapes should be
added right above their previous parent.

This patch also rewrites TestShapeGroupCommand

BUG:381344
parent 18caf89d
......@@ -697,6 +697,25 @@ bool KoShape::inheritsTransformFromAny(const QList<KoShape *> ancestorsInQuestio
return result;
}
bool KoShape::hasCommonParent(const KoShape *shape) const
{
const KoShape *thisShape = this;
while (thisShape) {
const KoShape *otherShape = shape;
while (otherShape) {
if (thisShape == otherShape) {
return true;
}
otherShape = otherShape->parent();
}
thisShape = thisShape->parent();
}
return false;
}
qint16 KoShape::zIndex() const
{
Q_D(const KoShape);
......
......@@ -727,6 +727,11 @@ public:
*/
bool inheritsTransformFromAny(const QList<KoShape*> ancestorsInQuestion) const;
/**
* @return true if this shape has a common parent with \p shape
*/
bool hasCommonParent(const KoShape *shape) const;
/**
* Request a repaint to be queued.
* The repaint will be of the entire Shape, including its selection handles should this
......
......@@ -19,95 +19,72 @@
*/
#include "KoShapeGroupCommand.h"
#include "KoShapeGroupCommand_p.h"
#include "KoShape.h"
#include "KoShapeGroup.h"
#include "KoShapeContainer.h"
#include <commands/KoShapeReorderCommand.h>
#include <klocalizedstring.h>
// static
KoShapeGroupCommand * KoShapeGroupCommand::createCommand(KoShapeContainer *container, const QList<KoShape *> &shapes, KUndo2Command *parent)
KoShapeGroupCommand * KoShapeGroupCommand::createCommand(KoShapeContainer *container, const QList<KoShape *> &shapes, bool shouldNormalize)
{
QList<KoShape*> orderedShapes(shapes);
std::sort(orderedShapes.begin(), orderedShapes.end(), KoShape::compareShapeZIndex);
if (!orderedShapes.isEmpty()) {
KoShape * top = orderedShapes.last();
container->setParent(top->parent());
container->setZIndex(top->zIndex());
}
return new KoShapeGroupCommand(container, orderedShapes, parent);
return new KoShapeGroupCommand(container, orderedShapes, shouldNormalize, 0);
}
KoShapeGroupCommandPrivate::KoShapeGroupCommandPrivate(KoShapeContainer *c, const QList<KoShape *> &s, const QList<bool> &clip, const QList<bool> &it, bool _shouldNormalize)
: shapes(s),
clipped(clip),
inheritTransform(it),
shouldNormalize(_shouldNormalize),
container(c)
class KoShapeGroupCommandPrivate
{
}
public:
KoShapeGroupCommandPrivate(KoShapeContainer *container, const QList<KoShape *> &shapes, bool _shouldNormalize);
QRectF containerBoundingRect();
QList<KoShape*> shapes; ///<list of shapes to be grouped
bool shouldNormalize; ///< Adjust the coordinate system of the group to its origin into the topleft of the group
KoShapeContainer *container; ///< the container where the grouping should be for.
QList<KoShapeContainer*> oldParents; ///< the old parents of the shapes
KoShapeGroupCommand::KoShapeGroupCommand(KoShapeContainer *container, const QList<KoShape *> &shapes, const QList<bool> &clipped, const QList<bool> &inheritTransform, KUndo2Command *parent)
: KUndo2Command(parent),
d(new KoShapeGroupCommandPrivate(container,shapes, clipped, inheritTransform, true))
QScopedPointer<KUndo2Command> shapesReorderCommand;
};
KoShapeGroupCommandPrivate::KoShapeGroupCommandPrivate(KoShapeContainer *c, const QList<KoShape *> &s, bool _shouldNormalize)
: shapes(s),
shouldNormalize(_shouldNormalize),
container(c)
{
Q_ASSERT(d->clipped.count() == d->shapes.count());
Q_ASSERT(d->inheritTransform.count() == d->shapes.count());
d->init(this);
std::stable_sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
}
KoShapeGroupCommand::KoShapeGroupCommand(KoShapeContainer *container, const QList<KoShape *> &shapes, KUndo2Command *parent)
: KUndo2Command(parent),
d(new KoShapeGroupCommandPrivate(container,shapes, QList<bool>(), QList<bool>(), true))
: KoShapeGroupCommand(container, shapes, false, parent)
{
for (int i = 0; i < shapes.count(); ++i) {
d->clipped.append(false);
d->inheritTransform.append(false);
}
d->init(this);
}
KoShapeGroupCommand::KoShapeGroupCommand(KoShapeContainer *container, const QList<KoShape *> &shapes,
bool clipped, bool inheritTransform, bool shouldNormalize, KUndo2Command *parent)
bool shouldNormalize, KUndo2Command *parent)
: KUndo2Command(parent),
d(new KoShapeGroupCommandPrivate(container,shapes, QList<bool>(), QList<bool>(), shouldNormalize))
d(new KoShapeGroupCommandPrivate(container, shapes, shouldNormalize))
{
for (int i = 0; i < shapes.count(); ++i) {
d->clipped.append(clipped);
d->inheritTransform.append(inheritTransform);
Q_FOREACH (KoShape* shape, d->shapes) {
d->oldParents.append(shape->parent());
}
d->init(this);
}
KoShapeGroupCommand::~KoShapeGroupCommand()
{
delete d;
}
KoShapeGroupCommand::KoShapeGroupCommand(KoShapeGroupCommandPrivate &dd, KUndo2Command *parent)
: KUndo2Command(parent),
d(&dd)
{
if (d->container->shapes().isEmpty()) {
setText(kundo2_i18n("Group shapes"));
} else {
setText(kundo2_i18n("Add shapes to group"));
}
}
void KoShapeGroupCommandPrivate::init(KUndo2Command *q)
KoShapeGroupCommand::~KoShapeGroupCommand()
{
Q_FOREACH (KoShape* shape, shapes) {
oldParents.append(shape->parent());
oldClipped.append(shape->parent() && shape->parent()->isClipped(shape));
oldInheritTransform.append(shape->parent() && shape->parent()->inheritsTransform(shape));
oldZIndex.append(shape->zIndex());
}
if (container->shapes().isEmpty()) {
q->setText(kundo2_i18n("Group shapes"));
} else {
q->setText(kundo2_i18n("Add shapes to group"));
}
}
void KoShapeGroupCommand::redo()
......@@ -131,34 +108,45 @@ void KoShapeGroupCommand::redo()
QTransform groupTransform = d->container->absoluteTransformation(0).inverted();
int zIndex=0;
QList<KoShape*> shapes(d->container->shapes());
if (!shapes.isEmpty()) {
std::sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
zIndex = shapes.last()->zIndex();
QList<KoShape*> containerShapes(d->container->shapes());
std::stable_sort(containerShapes.begin(), containerShapes.end(), KoShape::compareShapeZIndex);
QList<KoShapeReorderCommand::IndexedShape> indexedShapes;
Q_FOREACH (KoShape *shape, containerShapes) {
indexedShapes.append(KoShapeReorderCommand::IndexedShape(shape));
}
uint shapeCount = d->shapes.count();
for (uint i = 0; i < shapeCount; ++i) {
KoShape * shape = d->shapes[i];
shape->setZIndex(zIndex++);
QList<KoShapeReorderCommand::IndexedShape> prependIndexedShapes;
if(d->inheritTransform[i]) {
shape->applyAbsoluteTransformation(groupTransform);
}
else {
QSizeF containerSize = d->container->size();
QPointF containerPos = d->container->absolutePosition() - QPointF(0.5 * containerSize.width(), 0.5 * containerSize.height());
Q_FOREACH (KoShape *shape, d->shapes) {
// test if they inherit the same parent
if (!shape->hasCommonParent(d->container) ||
!KoShape::compareShapeZIndex(shape, d->container)) {
QTransform matrix;
matrix.translate(containerPos.x(), containerPos.y());
shape->applyAbsoluteTransformation(matrix.inverted());
indexedShapes.append(KoShapeReorderCommand::IndexedShape(shape));
} else {
prependIndexedShapes.append(KoShapeReorderCommand::IndexedShape(shape));
}
}
indexedShapes = prependIndexedShapes + indexedShapes;
indexedShapes = KoShapeReorderCommand::homogenizeZIndexesLazy(indexedShapes);
if (!indexedShapes.isEmpty()) {
d->shapesReorderCommand.reset(new KoShapeReorderCommand(indexedShapes));
d->shapesReorderCommand->redo();
}
uint shapeCount = d->shapes.count();
for (uint i = 0; i < shapeCount; ++i) {
KoShape * shape = d->shapes[i];
shape->applyAbsoluteTransformation(groupTransform);
d->container->addShape(shape);
d->container->setClipped(shape, d->clipped[i]);
d->container->setInheritsTransform(shape, d->inheritTransform[i]);
}
}
void KoShapeGroupCommand::undo()
......@@ -168,25 +156,16 @@ void KoShapeGroupCommand::undo()
QTransform ungroupTransform = d->container->absoluteTransformation(0);
for (int i = 0; i < d->shapes.count(); i++) {
KoShape * shape = d->shapes[i];
const bool inheritedTransform = d->container->inheritsTransform(shape);
d->container->removeShape(shape);
if (d->oldParents.at(i)) {
d->oldParents.at(i)->addShape(shape);
d->oldParents.at(i)->setClipped(shape, d->oldClipped.at(i));
d->oldParents.at(i)->setInheritsTransform(shape, d->oldInheritTransform.at(i));
}
if(inheritedTransform) {
shape->applyAbsoluteTransformation(ungroupTransform);
}
else {
QSizeF containerSize = d->container->size();
QPointF containerPos = d->container->absolutePosition() - QPointF(0.5 * containerSize.width(), 0.5 * containerSize.height());
shape->applyAbsoluteTransformation(ungroupTransform);
}
QTransform matrix;
matrix.translate(containerPos.x(), containerPos.y());
shape->applyAbsoluteTransformation(matrix);
}
shape->setZIndex(d->oldZIndex[i]);
if (d->shapesReorderCommand) {
d->shapesReorderCommand->undo();
d->shapesReorderCommand.reset();
}
if (d->shouldNormalize && dynamic_cast<KoShapeGroup*>(d->container)) {
......
......@@ -24,6 +24,7 @@
#include "kritaflake_export.h"
#include <QList>
#include <QScopedPointer>
#include <kundo2command.h>
class KoShape;
......@@ -45,22 +46,9 @@ public:
* @param parent the parent command if the resulting command is a compound undo command.
* @param shapes a list of all the shapes that should be grouped.
*/
static KoShapeGroupCommand *createCommand(KoShapeContainer *container, const QList<KoShape *> &shapes, KUndo2Command *parent = 0);
static KoShapeGroupCommand *createCommand(KoShapeContainer *container, const QList<KoShape *> &shapes, bool shouldNormalize = false);
/**
* Command to group a set of shapes into a predefined container.
* @param container the container to group the shapes under.
* @param shapes a list of all the shapes that should be grouped.
* @param clipped a list of the same length as the shapes list with one bool for each shape.
* See KoShapeContainer::isClipped()
* @param inheritTransform a list of the same length as the shapes list with one bool for each shape.
* See KoShapeContainer::inheritsTransform()
* @param parent the parent command used for macro commands
*/
KoShapeGroupCommand(KoShapeContainer *container, const QList<KoShape *> &shapes,
const QList<bool> &clipped, const QList<bool> &inheritTransform, KUndo2Command *parent = 0);
/**
/**
* Command to group a set of shapes into a predefined container.
* @param container the container to group the shapes under.
* @param shapes a list of all the shapes that should be grouped.
......@@ -70,8 +58,7 @@ public:
* See KoShapeContainer::inheritsTransform()
* @param parent the parent command used for macro commands
*/
KoShapeGroupCommand(KoShapeContainer *container, const QList<KoShape *> &shapes,
bool clipped, bool inheritTransform, bool shouldNormalize, KUndo2Command *parent = 0);
KoShapeGroupCommand(KoShapeContainer *container, const QList<KoShape *> &shapes, bool shouldNormalize, KUndo2Command *parent = 0);
/**
* Command to group a set of shapes into a predefined container.
......@@ -90,8 +77,7 @@ public:
void undo() override;
protected:
KoShapeGroupCommandPrivate *d;
KoShapeGroupCommand(KoShapeGroupCommandPrivate &, KUndo2Command *parent);
const QScopedPointer<KoShapeGroupCommandPrivate> d;
};
#endif
/* This file is part of the KDE project
* Copyright (C) 2006,2009,2010 Thomas Zander <zander@kde.org>
* Copyright (C) 2006,2007 Jan Hambrecht <jaham@gmx.net>
*
* 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.
*/
#ifndef KoShapeGroupCommandPrivate_H
#define KoShapeGroupCommandPrivate_H
#include <QPair>
#include <QList>
class KoShape;
class KoShapeContainer;
class KUndo2Command;
class QRectF;
class KoShapeGroupCommandPrivate
{
public:
KoShapeGroupCommandPrivate(KoShapeContainer *container, const QList<KoShape *> &shapes, const QList<bool> &clipped, const QList<bool> &inheritTransform, bool _shouldNormalize);
void init(KUndo2Command *q);
QRectF containerBoundingRect();
QList<KoShape*> shapes; ///<list of shapes to be grouped
QList<bool> clipped; ///< list of booleans to specify the shape of the same index to be clipped
QList<bool> inheritTransform; ///< list of booleans to specify the shape of the same index to inherit transform
bool shouldNormalize; ///< Adjust the coordinate system of the group to its origin into the topleft of the group
KoShapeContainer *container; ///< the container where the grouping should be for.
QList<KoShapeContainer*> oldParents; ///< the old parents of the shapes
QList<bool> oldClipped; ///< if the shape was clipped in the old parent
QList<bool> oldInheritTransform; ///< if the shape was inheriting transform in the old parent
QList<int> oldZIndex; ///< the old z-index of the shapes
QList<QPair<KoShape*, int> > oldAncestorsZIndex; // only used by the ungroup command
};
#endif
......@@ -36,6 +36,10 @@ KoShapeReorderCommand::IndexedShape::IndexedShape(KoShape *_shape)
{
}
bool KoShapeReorderCommand::IndexedShape::operator<(const KoShapeReorderCommand::IndexedShape &rhs) const
{
return zIndex < rhs.zIndex;
}
class KoShapeReorderCommandPrivate
{
......@@ -249,10 +253,8 @@ KoShapeReorderCommand *KoShapeReorderCommand::mergeInShape(QList<KoShape *> shap
return !reindexedShapes.isEmpty() ? new KoShapeReorderCommand(reindexedShapes, reindexedIndexes, parent) : 0;
}
namespace {
QList<KoShapeReorderCommand::IndexedShape>
homogenizeZIndexes(QList<KoShapeReorderCommand::IndexedShape> shapes)
KoShapeReorderCommand::homogenizeZIndexes(QList<KoShapeReorderCommand::IndexedShape> shapes)
{
if (shapes.isEmpty()) return shapes;
......@@ -291,6 +293,20 @@ homogenizeZIndexes(QList<KoShapeReorderCommand::IndexedShape> shapes)
return shapes;
}
QList<KoShapeReorderCommand::IndexedShape>
KoShapeReorderCommand::homogenizeZIndexesLazy(QList<KoShapeReorderCommand::IndexedShape> shapes)
{
shapes = homogenizeZIndexes(shapes);
// remove shapes that didn't change
for (auto it = shapes.begin(); it != shapes.end();) {
if (it->zIndex == it->shape->zIndex()) {
it = shapes.erase(it);
} else {
++it;
}
}
return shapes;
}
QList<KoShapeReorderCommand::IndexedShape>
......@@ -308,16 +324,11 @@ KoShapeReorderCommand::mergeDownShapes(QList<KoShape *> shapesBelow, QList<KoSha
shapes.append(IndexedShape(shape));
}
shapes = homogenizeZIndexes(shapes);
// remove shapes that didn't change
for (auto it = shapes.begin(); it != shapes.end();) {
if (it->zIndex == it->shape->zIndex()) {
it = shapes.erase(it);
} else {
++it;
}
}
return homogenizeZIndexesLazy(shapes);
}
return shapes;
QDebug operator<<(QDebug dbg, const KoShapeReorderCommand::IndexedShape &indexedShape)
{
dbg.nospace() << "IndexedShape (" << indexedShape.shape << ", " << indexedShape.zIndex << ")";
return dbg.space();
}
......@@ -22,6 +22,7 @@
#include "kritaflake_export.h"
#include <boost/operators.hpp>
#include <kundo2command.h>
#include <QList>
......@@ -33,10 +34,12 @@ class KoShapeReorderCommandPrivate;
class KRITAFLAKE_EXPORT KoShapeReorderCommand : public KUndo2Command
{
public:
struct IndexedShape {
struct IndexedShape : boost::less_than_comparable<IndexedShape> {
IndexedShape();
IndexedShape(KoShape *_shape);
bool operator<(const IndexedShape &rhs) const;
int zIndex = 0;
KoShape *shape = 0;
};
......@@ -88,6 +91,25 @@ public:
static KoShapeReorderCommand *mergeInShape(QList<KoShape*> shapes, KoShape *newShape,
KUndo2Command *parent = 0);
/**
* Recalculates the attached z-indexes of \p shapes so that all indexes go
* strictly in ascending order and no shapes have repetitive indexes. The
* physical order of the shapes in the array is not changed, on the indexes
* in IndexedShape are corrected.
*/
static
QList<KoShapeReorderCommand::IndexedShape>
homogenizeZIndexes(QList<IndexedShape> shapes);
/**
* Convenience version of homogenizeZIndexes() that removes all the IndexedShape
* objects, which z-index didn't change during homogenization. In a result
* you get a list that can be passed to KoShapeReorderCommand directly.
*/
static
QList<KoShapeReorderCommand::IndexedShape>
homogenizeZIndexesLazy(QList<IndexedShape> shapes);
/**
* Put all the shapes in \p shapesAbove above the shapes in \p shapesBelow, adjusting their
* z-index values.
......@@ -103,4 +125,6 @@ private:
KoShapeReorderCommandPrivate * const d;
};
KRITAFLAKE_EXPORT QDebug operator<<(QDebug dbg, const KoShapeReorderCommand::IndexedShape &indexedShape);
#endif
......@@ -19,66 +19,104 @@
*/
#include "KoShapeUngroupCommand.h"
#include "KoShapeGroupCommand_p.h"
#include "KoShapeContainer.h"
#include "KoShapeReorderCommand.h"
#include <klocalizedstring.h>
#include "kis_assert.h"
KoShapeUngroupCommand::KoShapeUngroupCommand(KoShapeContainer *container, const QList<KoShape *> &shapes,
const QList<KoShape*> &topLevelShapes, KUndo2Command *parent)
: KoShapeGroupCommand(*(new KoShapeGroupCommandPrivate(container,
shapes,
QList<bool>(),
QList<bool>(),
false)), parent)
struct KoShapeUngroupCommand::Private
{
QList<KoShape*> orderdShapes(shapes);
std::sort(orderdShapes.begin(), orderdShapes.end(), KoShape::compareShapeZIndex);
d->shapes = orderdShapes;
QList<KoShape*> ancestors = d->container->parent()? d->container->parent()->shapes(): topLevelShapes;
if (ancestors.count()) {
std::sort(ancestors.begin(), ancestors.end(), KoShape::compareShapeZIndex);
QList<KoShape*>::const_iterator it(std::find(ancestors.constBegin(), ancestors.constEnd(), d->container));
Q_ASSERT(it != ancestors.constEnd());
for (; it != ancestors.constEnd(); ++it) {
d->oldAncestorsZIndex.append(QPair<KoShape*, int>(*it, (*it)->zIndex()));
}
Private(KoShapeContainer *_container,
const QList<KoShape *> &_shapes,
const QList<KoShape*> &_topLevelShapes)
: container(_container),
shapes(_shapes),
topLevelShapes(_topLevelShapes)
{
std::stable_sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
std::sort(topLevelShapes.begin(), topLevelShapes.end(), KoShape::compareShapeZIndex);
}
int zIndex = d->container->zIndex();
Q_FOREACH (KoShape *shape, d->shapes) {
d->clipped.append(d->container->isClipped(shape));
d->oldParents.append(d->container->parent());
d->oldClipped.append(d->container->isClipped(shape));
d->oldInheritTransform.append(shape->parent() && shape->parent()->inheritsTransform(shape));
d->inheritTransform.append(d->container->inheritsTransform(shape));
// TODO this might also need to change the children of the parent but that is very problematic if the parent is 0
d->oldZIndex.append(zIndex++);
}
d->shouldNormalize = false;
KoShapeContainer *container;
QList<KoShape*> shapes;
QList<KoShape*> topLevelShapes;
QScopedPointer<KUndo2Command> shapesReorderCommand;
};
KoShapeUngroupCommand::KoShapeUngroupCommand(KoShapeContainer *container, const QList<KoShape *> &shapes,
const QList<KoShape*> &topLevelShapes, KUndo2Command *parent)
: KUndo2Command(parent),
m_d(new Private(container, shapes, topLevelShapes))
{
setText(kundo2_i18n("Ungroup shapes"));
}
KoShapeUngroupCommand::~KoShapeUngroupCommand()
{
}
void KoShapeUngroupCommand::redo()
{
KoShapeGroupCommand::undo();
if (d->oldAncestorsZIndex.count()) {
int zIndex = d->container->zIndex() + d->oldZIndex.count() - 1;
for (QList<QPair<KoShape*, int> >::const_iterator it(d->oldAncestorsZIndex.constBegin()); it != d->oldAncestorsZIndex.constEnd(); ++it) {
it->first->setZIndex(zIndex++);
}
using IndexedShape = KoShapeReorderCommand::IndexedShape;
KoShapeContainer *newParent = m_d->container->parent();
QList<IndexedShape> indexedSiblings;
QList<KoShape*> perspectiveSiblings;
if (newParent) {
perspectiveSiblings = newParent->shapes();
std::sort(perspectiveSiblings.begin(), perspectiveSiblings.end(), KoShape::compareShapeZIndex);
} else {
perspectiveSiblings = m_d->topLevelShapes;
}
Q_FOREACH (KoShape *shape, perspectiveSiblings) {
indexedSiblings.append(shape);
}
// find the place where the ungrouped shapes should be inserted
// (right on the top of their current container)
auto insertIt = std::upper_bound(indexedSiblings.begin(),
indexedSiblings.end(),
IndexedShape(m_d->container));
std::copy(m_d->shapes.begin(), m_d->shapes.end(),
std::inserter(indexedSiblings, insertIt));
indexedSiblings = KoShapeReorderCommand::homogenizeZIndexesLazy(indexedSiblings);
const QTransform ungroupTransform = m_d->container->absoluteTransformation(0);
for (auto it = m_d->shapes.begin(); it != m_d->shapes.end(); ++it) {
KoShape *shape = *it;
KIS_SAFE_ASSERT_RECOVER(shape->parent() == m_d->container) { continue; }
shape->setParent(newParent);
shape->applyAbsoluteTransformation(ungroupTransform);
}
if (!indexedSiblings.isEmpty()) {
m_d->shapesReorderCommand.reset(new KoShapeReorderCommand(indexedSiblings));
m_d->shapesReorderCommand->redo();
}
}
void KoShapeUngroupCommand::undo()
{
KoShapeGroupCommand::redo();
if (d->oldAncestorsZIndex.count()) {
for (QList<QPair<KoShape*, int> >::const_iterator it(d->oldAncestorsZIndex.constBegin()); it != d->oldAncestorsZIndex.constEnd(); ++it) {
it->first->setZIndex(it->second);
}
const QTransform groupTransform = m_d->container->absoluteTransformation(0).inverted();
for (auto it = m_d->shapes.begin(); it != m_d->shapes.end(); ++it) {
KoShape *shape = *it;
shape->setParent(m_d->container);
shape->applyAbsoluteTransformation(groupTransform);
}
if (m_d->shapesReorderCommand) {
m_d->shapesReorderCommand->undo();
m_d->shapesReorderCommand.reset();
}
}
......@@ -21,14 +21,16 @@
#ifndef KOSHAPEUNGROUPCOMMAND_H
#define KOSHAPEUNGROUPCOMMAND_H
#include "KoShapeGroupCommand.h"
#include "kritaflake_export.h"
#include <kundo2command.h>
#include <QScopedPointer>
class KoShape;
class KoShapeGroup;
class KoShapeContainer;
/// The undo / redo command for ungrouping shapes
class KRITAFLAKE_EXPORT KoShapeUngroupCommand : public KoShapeGroupCommand
class KRITAFLAKE_EXPORT KoShapeUngroupCommand : public KUndo2Command
{
public:
/**
......@@ -39,10 +41,17 @@ public:
*/
KoShapeUngroupCommand(KoShapeContainer *container, const QList<KoShape *> &shapes,
const QList<KoShape *> &topLevelShapes = QList<KoShape*>(), KUndo2Command *parent = 0);
~KoShapeUngroupCommand();
/// redo the command
void redo() override;
/// revert the actions done in redo
void undo() override;
private:
struct Private;
const QScopedPointer<Private> m_d;
};
#endif
......@@ -1245,8 +1245,8 @@ void SvgParser::addToGroup(QList<KoShape*> shapes, KoShapeContainer *group)
if (!group || shapes.isEmpty())
return;
// not clipped, but inherit transform
KoShapeGroupCommand cmd(group, shapes, false, true, false);
// not normalized
KoShapeGroupCommand cmd(group, shapes, false);
cmd.redo();
}
......