| 1261 | } |
| 1262 | |
| 1263 | void RcxController::batchRemoveNodes(const QVector<int>& nodeIndices) { |
| 1264 | QSet<uint64_t> idSet; |
| 1265 | for (int idx : nodeIndices) { |
| 1266 | if (idx >= 0 && idx < m_doc->tree.nodes.size()) |
| 1267 | idSet.insert(m_doc->tree.nodes[idx].id); |
| 1268 | } |
| 1269 | idSet = m_doc->tree.normalizePreferAncestors(idSet); |
| 1270 | if (idSet.isEmpty()) return; |
| 1271 | |
| 1272 | // Clear selection before delete (prevents stale highlight on shifted lines) |
| 1273 | m_selIds.clear(); |
| 1274 | m_anchorLine = -1; |
| 1275 | |
| 1276 | m_suppressRefresh = true; |
| 1277 | m_doc->undoStack.beginMacro(QString("Delete %1 nodes").arg(idSet.size())); |
| 1278 | for (uint64_t id : idSet) { |
| 1279 | int idx = m_doc->tree.indexOfId(id); |
| 1280 | if (idx >= 0) removeNode(idx); |
| 1281 | } |
| 1282 | m_doc->undoStack.endMacro(); |
| 1283 | m_suppressRefresh = false; |
| 1284 | refresh(); |
| 1285 | } |
| 1286 | |
| 1287 | void RcxController::batchChangeKind(const QVector<int>& nodeIndices, NodeKind newKind) { |
| 1288 | QSet<uint64_t> idSet; |