File indexing completed on 2024-06-09 04:20:46

0001 /* This file is part of the KDE project
0002  * SPDX-FileCopyrightText: 2006 Thomas Zander <zander@kde.org>
0003  * SPDX-FileCopyrightText: 2006 Jan Hambrecht <jaham@gmx.net>
0004  *
0005  * SPDX-License-Identifier: LGPL-2.0-or-later
0006  */
0007 
0008 #include "KoShapeUngroupCommand.h"
0009 #include "KoShapeContainer.h"
0010 #include "KoShapeReorderCommand.h"
0011 
0012 #include <klocalizedstring.h>
0013 #include "kis_assert.h"
0014 
0015 
0016 struct KoShapeUngroupCommand::Private
0017 {
0018     Private(KoShapeContainer *_container,
0019             const QList<KoShape *> &_shapes,
0020             const QList<KoShape*> &_topLevelShapes)
0021         : container(_container),
0022           shapes(_shapes),
0023           topLevelShapes(_topLevelShapes)
0024     {
0025         std::stable_sort(shapes.begin(), shapes.end(), KoShape::compareShapeZIndex);
0026         std::sort(topLevelShapes.begin(), topLevelShapes.end(), KoShape::compareShapeZIndex);
0027     }
0028 
0029 
0030     KoShapeContainer *container;
0031     QList<KoShape*> shapes;
0032     QList<KoShape*> topLevelShapes;
0033     QScopedPointer<KUndo2Command> shapesReorderCommand;
0034 
0035 };
0036 
0037 KoShapeUngroupCommand::KoShapeUngroupCommand(KoShapeContainer *container, const QList<KoShape *> &shapes,
0038                                              const QList<KoShape*> &topLevelShapes, KUndo2Command *parent)
0039     : KUndo2Command(parent),
0040       m_d(new Private(container, shapes, topLevelShapes))
0041 {
0042     setText(kundo2_i18n("Ungroup shapes"));
0043 }
0044 
0045 KoShapeUngroupCommand::~KoShapeUngroupCommand()
0046 {
0047 }
0048 
0049 void KoShapeUngroupCommand::redo()
0050 {
0051     using IndexedShape = KoShapeReorderCommand::IndexedShape;
0052 
0053     KoShapeContainer *newParent = m_d->container->parent();
0054 
0055     QList<IndexedShape> indexedSiblings;
0056     QList<KoShape*> perspectiveSiblings;
0057 
0058     if (newParent) {
0059         perspectiveSiblings = newParent->shapes();
0060         std::sort(perspectiveSiblings.begin(), perspectiveSiblings.end(), KoShape::compareShapeZIndex);
0061     } else {
0062         perspectiveSiblings = m_d->topLevelShapes;
0063     }
0064 
0065     Q_FOREACH (KoShape *shape, perspectiveSiblings) {
0066         indexedSiblings.append(shape);
0067     }
0068 
0069     // find the place where the ungrouped shapes should be inserted
0070     // (right on the top of their current container)
0071     auto insertIt = std::upper_bound(indexedSiblings.begin(),
0072                                      indexedSiblings.end(),
0073                                      IndexedShape(m_d->container));
0074 
0075     std::copy(m_d->shapes.begin(), m_d->shapes.end(),
0076               std::inserter(indexedSiblings, insertIt));
0077 
0078     indexedSiblings = KoShapeReorderCommand::homogenizeZIndexesLazy(indexedSiblings);
0079 
0080     const QTransform ungroupTransform = m_d->container->absoluteTransformation();
0081     for (auto it = m_d->shapes.begin(); it != m_d->shapes.end(); ++it) {
0082         KoShape *shape = *it;
0083         KIS_SAFE_ASSERT_RECOVER(shape->parent() == m_d->container) { continue; }
0084 
0085         shape->setParent(newParent);
0086         shape->applyAbsoluteTransformation(ungroupTransform);
0087     }
0088 
0089     if (!indexedSiblings.isEmpty()) {
0090         m_d->shapesReorderCommand.reset(new KoShapeReorderCommand(indexedSiblings));
0091         m_d->shapesReorderCommand->redo();
0092     }
0093 }
0094 
0095 void KoShapeUngroupCommand::undo()
0096 {
0097     const QTransform groupTransform = m_d->container->absoluteTransformation().inverted();
0098     for (auto it = m_d->shapes.begin(); it != m_d->shapes.end(); ++it) {
0099         KoShape *shape = *it;
0100 
0101         shape->setParent(m_d->container);
0102         shape->applyAbsoluteTransformation(groupTransform);
0103     }
0104 
0105     if (m_d->shapesReorderCommand) {
0106         m_d->shapesReorderCommand->undo();
0107         m_d->shapesReorderCommand.reset();
0108     }
0109 }