mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
feat: safe workspace tree deletion with reference cleanup and confirmation
- Add deleteRootStruct() that clears orphaned refId references before removal - Show confirmation dialog listing all fields that reference the deleted type - Auto-switch view to next root struct when the viewed one is deleted - Entire operation is a single undo macro (Ctrl+Z restores everything)
This commit is contained in:
@@ -776,6 +776,48 @@ void RcxController::removeNode(int nodeIdx) {
|
||||
cmd::Remove{nodeId, subtree, adjs}));
|
||||
}
|
||||
|
||||
void RcxController::deleteRootStruct(uint64_t structId) {
|
||||
int ni = m_doc->tree.indexOfId(structId);
|
||||
if (ni < 0) return;
|
||||
const Node& node = m_doc->tree.nodes[ni];
|
||||
if (node.parentId != 0 || node.kind != NodeKind::Struct) return;
|
||||
|
||||
bool wasSuppressed = m_suppressRefresh;
|
||||
m_suppressRefresh = true;
|
||||
m_doc->undoStack.beginMacro(QStringLiteral("Delete root struct"));
|
||||
|
||||
// Clear all refId references pointing to this struct
|
||||
for (int i = 0; i < m_doc->tree.nodes.size(); i++) {
|
||||
auto& n = m_doc->tree.nodes[i];
|
||||
if (n.refId == structId) {
|
||||
m_doc->undoStack.push(new RcxCommand(this,
|
||||
cmd::ChangePointerRef{n.id, n.refId, (uint64_t)0}));
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the struct + subtree (re-lookup since commands may shift indices)
|
||||
ni = m_doc->tree.indexOfId(structId);
|
||||
if (ni >= 0)
|
||||
removeNode(ni);
|
||||
|
||||
m_doc->undoStack.endMacro();
|
||||
m_suppressRefresh = wasSuppressed;
|
||||
|
||||
// Switch view if we just deleted the viewed root
|
||||
if (m_viewRootId == structId) {
|
||||
uint64_t nextRoot = 0;
|
||||
for (const auto& n : m_doc->tree.nodes) {
|
||||
if (n.parentId == 0 && n.kind == NodeKind::Struct) {
|
||||
nextRoot = n.id;
|
||||
break;
|
||||
}
|
||||
}
|
||||
setViewRootId(nextRoot);
|
||||
}
|
||||
|
||||
if (!m_suppressRefresh) refresh();
|
||||
}
|
||||
|
||||
void RcxController::toggleCollapse(int nodeIdx) {
|
||||
if (nodeIdx < 0 || nodeIdx >= m_doc->tree.nodes.size()) return;
|
||||
auto& node = m_doc->tree.nodes[nodeIdx];
|
||||
|
||||
@@ -99,6 +99,7 @@ public:
|
||||
void showContextMenu(RcxEditor* editor, int line, int nodeIdx, int subLine, const QPoint& globalPos);
|
||||
void batchRemoveNodes(const QVector<int>& nodeIndices);
|
||||
void batchChangeKind(const QVector<int>& nodeIndices, NodeKind newKind);
|
||||
void deleteRootStruct(uint64_t structId);
|
||||
|
||||
void applyCommand(const Command& cmd, bool isUndo);
|
||||
void refresh();
|
||||
|
||||
48
src/main.cpp
48
src/main.cpp
@@ -1698,7 +1698,53 @@ void MainWindow::createWorkspaceDock() {
|
||||
|
||||
QAction* chosen = menu.exec(m_workspaceTree->viewport()->mapToGlobal(pos));
|
||||
if (chosen == actDelete) {
|
||||
tab.ctrl->removeNode(ni);
|
||||
QString typeName = tab.doc->tree.nodes[ni].structTypeName.isEmpty()
|
||||
? tab.doc->tree.nodes[ni].name
|
||||
: tab.doc->tree.nodes[ni].structTypeName;
|
||||
if (typeName.isEmpty()) typeName = QStringLiteral("(unnamed)");
|
||||
|
||||
// Collect detailed reference info
|
||||
QStringList refDetails;
|
||||
for (const auto& n : tab.doc->tree.nodes) {
|
||||
if (n.refId == structId) {
|
||||
QString ownerName;
|
||||
uint64_t pid = n.parentId;
|
||||
while (pid != 0) {
|
||||
int pi = tab.doc->tree.indexOfId(pid);
|
||||
if (pi < 0) break;
|
||||
if (tab.doc->tree.nodes[pi].parentId == 0) {
|
||||
ownerName = tab.doc->tree.nodes[pi].structTypeName.isEmpty()
|
||||
? tab.doc->tree.nodes[pi].name
|
||||
: tab.doc->tree.nodes[pi].structTypeName;
|
||||
break;
|
||||
}
|
||||
pid = tab.doc->tree.nodes[pi].parentId;
|
||||
}
|
||||
QString fieldDesc = ownerName.isEmpty()
|
||||
? n.name
|
||||
: QStringLiteral("%1::%2").arg(ownerName, n.name);
|
||||
refDetails << QStringLiteral(" \u2022 %1 (%2)")
|
||||
.arg(fieldDesc, kindToString(n.kind));
|
||||
}
|
||||
}
|
||||
|
||||
QString msg;
|
||||
if (refDetails.isEmpty()) {
|
||||
msg = QString("Delete '%1'?").arg(typeName);
|
||||
} else {
|
||||
msg = QString("Delete '%1'?\n\n"
|
||||
"The following %2 field(s) reference this type "
|
||||
"and will become untyped (void):\n\n%3")
|
||||
.arg(typeName)
|
||||
.arg(refDetails.size())
|
||||
.arg(refDetails.join('\n'));
|
||||
}
|
||||
|
||||
auto answer = QMessageBox::question(this, "Delete Type", msg,
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||
if (answer != QMessageBox::Yes) return;
|
||||
|
||||
tab.ctrl->deleteRootStruct(structId);
|
||||
rebuildWorkspaceModel();
|
||||
} else if (chosen && chosen == actConvert) {
|
||||
QString newKw = kw == QStringLiteral("class")
|
||||
|
||||
Reference in New Issue
Block a user