209 lines
5.8 KiB
C++
209 lines
5.8 KiB
C++
#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
|