Files
BionxControl/nodes/services/ntxnodetree.cpp

209 lines
5.8 KiB
C++
Raw Permalink Normal View History

2026-04-02 15:15:28 +02:00
#include <QDebug>
#include <ntxnodetree.h>
#include <ntxnodefactory.h>
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<NtxInsertNodeCmd>(
std::move(parent), std::move(node), index));
}
bool NtxNodeTree::deleteNode(NtxNodePtr node)
{
return execute(std::make_unique<NtxRemoveNodeCmd>(std::move(node)));
}
bool NtxNodeTree::moveNode(NtxNodePtr node, NtxNodePtr newParent, size_t newIndex)
{
// Move = Remove + Insert als Makro
auto macro = std::make_unique<NtxMacroCommand>("Move node");
macro->add(std::make_unique<NtxRemoveNodeCmd>(node));
macro->add(std::make_unique<NtxInsertNodeCmd>(
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<NtxCommandUPtr> cmds;
cmds.reserve(nodes.size());
for (size_t i = 0; i < nodes.size(); ++i)
{
cmds.push_back(std::make_unique<NtxInsertNodeCmd>(
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<NtxCommandUPtr> 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<NtxRemoveNodeCmd>(*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<NtxMacroCommand>(
"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<NtxRemoveNodeCmd>(origNode));
}
}
}
// 2. Clones einfügen
for (size_t i = 0; i < pasted.size(); ++i)
{
macro->add(std::make_unique<NtxInsertNodeCmd>(
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