#include #include #include namespace ntx { NtxNodeTree::NtxNodeTree(NtxClassTypeId id) { //m_ctypeId = id; } NtxNodePtr NtxNodeTree::clone() const { /* auto cloned = NtxNodeFactory::makeNode(getClassTypeLabel()); qDebug() << "Cloning NtxNodeTree with CTypeLabel: NOT DONE: " << getClassTypeLabel().c_str(); forEachProperty([&](const NtxString& key, const NtxVariant& value) { cloned->setProperty(key, value); }); for (size_t i = 0; i < getChildCount(); ++i) cloned->addChild(getChild(i)->clone()); return cloned; */ return nullptr; } // ========================================================================= // Command-Ausführung (delegiert an NtxUndoStack) // ========================================================================= bool NtxNodeTree::execute(NtxCommandUPtr cmd) { if (!cmd || !cmd->canExecute()) return false; m_undoStack.push(std::move(cmd)); return true; } bool NtxNodeTree::undo() { if (!canUndo()) return false; m_undoStack.undo(); return true; } bool NtxNodeTree::redo() { if (!canRedo()) return false; m_undoStack.redo(); return true; } bool NtxNodeTree::canUndo() const { return m_undoStack.canUndo(); } bool NtxNodeTree::canRedo() const { return m_undoStack.canRedo(); } NtxString NtxNodeTree::undoText() const { return m_undoStack.undoText(); } NtxString NtxNodeTree::redoText() const { return m_undoStack.redoText(); } void NtxNodeTree::setClean() { m_undoStack.setClean(); } bool NtxNodeTree::isDirty() const { return !m_undoStack.isClean(); } // ========================================================================= // Einzel-Operationen // ========================================================================= bool NtxNodeTree::addNode(NtxNodePtr parent, NtxNodePtr node, size_t index) { return execute(std::make_unique( std::move(parent), std::move(node), index)); } bool NtxNodeTree::deleteNode(NtxNodePtr node) { return execute(std::make_unique(std::move(node))); } bool NtxNodeTree::moveNode(NtxNodePtr node, NtxNodePtr newParent, size_t newIndex) { // Move = Remove + Insert als Makro auto macro = std::make_unique("Move node"); macro->add(std::make_unique(node)); macro->add(std::make_unique( std::move(newParent), std::move(node), newIndex)); return execute(std::move(macro)); } // ========================================================================= // Listen-Operationen (Makro-Commands) // ========================================================================= bool NtxNodeTree::addNodes(NtxNodePtr parent, const NtxNodeList& nodes, size_t index) { std::vector cmds; cmds.reserve(nodes.size()); for (size_t i = 0; i < nodes.size(); ++i) { cmds.push_back(std::make_unique( parent, nodes[i], index + i)); } return execute(NtxMacroCommand::create( "Insert " + std::to_string(nodes.size()) + " nodes", std::move(cmds))); } bool NtxNodeTree::deleteNodes(const NtxNodeList& nodes) { std::vector cmds; cmds.reserve(nodes.size()); // Rückwärts löschen → Indizes bleiben stabil for (auto it = nodes.rbegin(); it != nodes.rend(); ++it) cmds.push_back(std::make_unique(*it)); return execute(NtxMacroCommand::create( "Delete " + std::to_string(nodes.size()) + " nodes", std::move(cmds))); } // ========================================================================= // Clipboard // ========================================================================= void NtxNodeTree::copyNodes(const NtxNodeList& nodes) { m_clipboard.copyNodes(nodes); m_isCutOperation = false; } void NtxNodeTree::cutNodes(const NtxNodeList& nodes) { m_clipboard.copyNodes(nodes); m_isCutOperation = true; } NtxNodeList NtxNodeTree::pasteNodes(NtxNodePtr parent, size_t index) { NtxNodeList pasted = m_clipboard.pasteNodes(); if (pasted.empty()) return {}; if (m_isCutOperation) { // Cut+Paste = Remove originals + Insert clones (als Makro) auto macro = std::make_unique( "Paste " + std::to_string(pasted.size()) + " nodes (cut)"); // 1. Originale entfernen (rückwärts für stabile Indizes) const auto& entries = m_clipboard.getEntries(); for (auto it = entries.rbegin(); it != entries.rend(); ++it) { if (auto origParent = it->originalParent.lock()) { if (it->originalPosition < origParent->getChildCount()) { auto origNode = origParent->getChild(it->originalPosition); if (origNode) macro->add(std::make_unique(origNode)); } } } // 2. Clones einfügen for (size_t i = 0; i < pasted.size(); ++i) { macro->add(std::make_unique( parent, pasted[i], index + i)); } if (!execute(std::move(macro))) return {}; m_isCutOperation = false; m_clipboard.clear(); } else { // Copy+Paste = nur Insert if (!addNodes(parent, pasted, index)) return {}; } return pasted; } bool NtxNodeTree::hasClipboard() const { return !m_clipboard.isEmpty(); } void NtxNodeTree::clearClipboard() { m_clipboard.clear(); m_isCutOperation = false; } } // namespace ntx