File indexing completed on 2024-05-19 03:48:33
0001 /* 0002 File : aspectcommands.h 0003 Project : LabPlot 0004 Description : Undo commands used by AbstractAspect. 0005 Only meant to be used within AbstractAspect.cpp 0006 -------------------------------------------------------------------- 0007 SPDX-FileCopyrightText: 2007-2010 Knut Franke <knut.franke@gmx.de> 0008 SPDX-FileCopyrightText: 2007-2009 Tilman Benkert <thzs@gmx.net> 0009 SPDX-FileCopyrightText: 2013-2021 Alexander Semke <alexander.semke@web.de> 0010 SPDX-License-Identifier: GPL-2.0-or-later 0011 */ 0012 0013 #ifndef ASPECTCOMMANDS_H 0014 #define ASPECTCOMMANDS_H 0015 0016 #include "AspectPrivate.h" 0017 #include <KLocalizedString> 0018 #include <QUndoCommand> 0019 0020 class AspectCommonCmd : public QUndoCommand { 0021 public: 0022 AspectCommonCmd(QUndoCommand* parent = nullptr) 0023 : QUndoCommand(parent) { 0024 } 0025 int removeChild(AbstractAspectPrivate* parent, AbstractAspect* child) { 0026 int index = parent->indexOfChild(child); 0027 Q_ASSERT(index != -1); 0028 parent->m_children.removeAll(child); 0029 QObject::disconnect(child, nullptr, nullptr, nullptr); 0030 child->setParentAspect(nullptr); 0031 // QDEBUG(Q_FUNC_INFO << " DONE. CHILD = " << child) 0032 return index; 0033 } 0034 }; 0035 0036 class AspectChildRemoveCmd : public AspectCommonCmd { 0037 public: 0038 AspectChildRemoveCmd(AbstractAspectPrivate* target, AbstractAspect* child, QUndoCommand* parent = nullptr) 0039 : AspectCommonCmd(parent) 0040 , m_target(target) 0041 , m_child(child) 0042 , m_moved(child->isMoved()) { 0043 setText(i18n("%1: remove %2", m_target->m_name, m_child->name())); 0044 } 0045 0046 ~AspectChildRemoveCmd() override { 0047 // TODO: this makes labplot crashing on project close/save. 0048 // if (m_removed) 0049 // delete m_child; 0050 } 0051 0052 // calling redo transfers ownership of m_child to the undo command 0053 void redo() override { 0054 // QDEBUG(Q_FUNC_INFO << ", TARGET = " << m_target->q << " CHILD = " << m_child << ", PARENT = " << m_child->parentAspect()) 0055 AbstractAspect* nextSibling; 0056 if (m_child == m_target->m_children.last()) 0057 nextSibling = nullptr; 0058 else 0059 nextSibling = m_target->m_children.at(m_target->indexOfChild(m_child) + 1); 0060 0061 // emit the "about to be removed" signal also for all children columns so the curves can react. 0062 // no need to notify when the parent is just being moved (move up, moved down in the project explorer), 0063 //(move = delete at the current position + insert at the new position) 0064 if (!m_moved) { 0065 const auto& columns = m_child->children<Column>(AbstractAspect::ChildIndexFlag::Recursive); 0066 for (auto* col : columns) 0067 Q_EMIT col->parentAspect()->childAspectAboutToBeRemoved(col); 0068 } 0069 0070 // no need to emit signals if the aspect is hidden, the only exceptions is it's a datapicker point 0071 // and we need to react on its removal in order to update the data spreadsheet. 0072 // TODO: the check for hidden was added originally to avoid crashes in the debug build of Qt because 0073 // of asserts for negative values in the model. It also helps wrt. the performance since we don't need 0074 // to react on such events in the model for hidden aspects. Adding here the exception for the datapicker 0075 // will most probably trigger again crashes in the debug build of Qt if the datapicker is involved but we 0076 // rather accept this "edge case" than having no undo/redo for position changes for datapicker points until 0077 // we have a better solution. 0078 if (!m_child->hidden() || m_child->type() == AspectType::DatapickerPoint) 0079 Q_EMIT m_target->q->childAspectAboutToBeRemoved(m_child); 0080 Q_EMIT m_child->aspectAboutToBeRemoved(m_child); 0081 0082 m_index = removeChild(m_target, m_child); 0083 0084 if (!m_child->hidden() || m_child->type() == AspectType::DatapickerPoint) 0085 Q_EMIT m_target->q->childAspectRemoved(m_target->q, nextSibling, m_child); 0086 0087 // QDEBUG(Q_FUNC_INFO << ", DONE. CHILD = " << m_child) 0088 // m_removed = true; 0089 } 0090 0091 // calling undo transfers ownership of m_child back to its parent aspect 0092 void undo() override { 0093 Q_ASSERT(m_index != -1); // m_child must be a child of m_target->q 0094 0095 if (m_moved) 0096 m_child->setMoved(true); 0097 0098 Q_EMIT m_target->q->childAspectAboutToBeAdded(m_target->q, nullptr, m_child); 0099 Q_EMIT m_target->q->childAspectAboutToBeAdded(m_target->q, m_index, m_child); 0100 m_target->insertChild(m_index, m_child); 0101 m_child->finalizeAdd(); 0102 Q_EMIT m_target->q->childAspectAdded(m_child); 0103 0104 if (m_moved) 0105 m_child->setMoved(false); 0106 // m_removed = false; 0107 } 0108 0109 protected: 0110 AbstractAspectPrivate* m_target{nullptr}; 0111 AbstractAspect* m_child{nullptr}; 0112 int m_index{-1}; 0113 bool m_moved{false}; 0114 // bool m_removed{false}; 0115 }; 0116 0117 class AspectChildAddCmd : public AspectChildRemoveCmd { 0118 public: 0119 AspectChildAddCmd(AbstractAspectPrivate* target, AbstractAspect* child, int index, QUndoCommand* parent) 0120 : AspectChildRemoveCmd(target, child, parent) { 0121 setText(i18n("%1: add %2", m_target->m_name, m_child->name())); 0122 m_index = index; 0123 // m_removed = true; 0124 } 0125 0126 void redo() override { 0127 AspectChildRemoveCmd::undo(); 0128 } 0129 0130 void undo() override { 0131 AspectChildRemoveCmd::redo(); 0132 } 0133 }; 0134 0135 class AspectChildReparentCmd : public AspectCommonCmd { 0136 public: 0137 AspectChildReparentCmd(AbstractAspectPrivate* target, 0138 AbstractAspectPrivate* new_parent, 0139 AbstractAspect* child, 0140 int new_index, 0141 QUndoCommand* parent = nullptr) 0142 : AspectCommonCmd(parent) 0143 , m_target(target) 0144 , m_new_parent(new_parent) 0145 , m_child(child) 0146 , m_new_index(new_index) { 0147 setText(i18n("%1: move %2 to %3.", m_target->m_name, m_child->name(), m_new_parent->m_name)); 0148 } 0149 0150 // calling redo transfers ownership of m_child to the new parent aspect 0151 void redo() override { 0152 Q_EMIT m_child->childAspectAboutToBeRemoved(m_child); 0153 m_index = removeChild(m_target, m_child); 0154 m_new_parent->insertChild(m_new_index, m_child); 0155 Q_EMIT m_child->childAspectAdded(m_child); 0156 } 0157 0158 // calling undo transfers ownership of m_child back to its previous parent aspect 0159 void undo() override { 0160 Q_ASSERT(m_index != -1); 0161 Q_EMIT m_child->childAspectAboutToBeRemoved(m_child); 0162 removeChild(m_new_parent, m_child); 0163 m_target->insertChild(m_index, m_child); 0164 Q_EMIT m_child->childAspectAdded(m_child); 0165 } 0166 0167 protected: 0168 AbstractAspectPrivate* m_target; 0169 AbstractAspectPrivate* m_new_parent; 0170 AbstractAspect* m_child; 0171 int m_index{-1}; 0172 int m_new_index; 0173 }; 0174 0175 class AspectNameChangeCmd : public AspectCommonCmd { 0176 public: 0177 AspectNameChangeCmd(AbstractAspectPrivate* aspect, const QString& newName, QUndoCommand* parent = nullptr) 0178 : AspectCommonCmd(parent) 0179 , m_aspect(aspect) 0180 , m_name(newName) { 0181 setText(i18n("%1: rename to %2", m_aspect->m_name, newName)); 0182 } 0183 0184 void redo() override { 0185 Q_EMIT m_aspect->q->aspectDescriptionAboutToChange(m_aspect->q); 0186 const QString name = m_aspect->m_name; 0187 m_aspect->m_name = m_name; 0188 m_name = name; 0189 Q_EMIT m_aspect->q->aspectDescriptionChanged(m_aspect->q); 0190 } 0191 0192 void undo() override { 0193 redo(); 0194 } 0195 0196 protected: 0197 AbstractAspectPrivate* m_aspect; 0198 QString m_name; 0199 }; 0200 0201 #endif