diff --git a/Source/GUI/MemWatcher/MemWatchModel.cpp b/Source/GUI/MemWatcher/MemWatchModel.cpp index ae54bf7..c669e4a 100644 --- a/Source/GUI/MemWatcher/MemWatchModel.cpp +++ b/Source/GUI/MemWatcher/MemWatchModel.cpp @@ -207,6 +207,52 @@ void MemWatchModel::deleteNode(const QModelIndex& index) } } +void MemWatchModel::groupSelection(const QModelIndexList& indexes) +{ + if (indexes.isEmpty()) + return; + + // Collect nodes from indexes; indexes will be invalidated shortly as nodes are removed from their + // parents. + std::vector nodes; + for (const QModelIndex& index : indexes) + { + nodes.push_back(static_cast(index.internalPointer())); + } + + MemWatchTreeNode* newParent{}; + int newRow{std::numeric_limits::max()}; + + // Extract nodes from their current parent. + for (MemWatchTreeNode* const node : nodes) + { + MemWatchTreeNode* const parent{node->getParent()}; + const int row{static_cast(parent->getChildren().indexOf(node))}; + + if (!newParent || newParent == parent) + { + newParent = parent; + newRow = std::min(newRow, row); + } + + beginRemoveRows(getIndexFromTreeNode(parent), row, row); + parent->removeChild(node); + endRemoveRows(); + } + + beginInsertRows(getIndexFromTreeNode(newParent), newRow, newRow); + + // Create new group with all the extracted nodes, and insert in the new parent. + MemWatchTreeNode* const group{new MemWatchTreeNode(nullptr, nullptr, true, "New Group")}; + for (MemWatchTreeNode* const node : nodes) + { + group->appendChild(node); + } + newParent->insertChild(newRow, group); + + endInsertRows(); +} + int MemWatchModel::columnCount(const QModelIndex& parent) const { (void)parent; @@ -630,3 +676,15 @@ MemWatchTreeNode* MemWatchModel::getTreeNodeFromIndex(const QModelIndex& index) { return static_cast(index.internalPointer()); } + +QModelIndex MemWatchModel::getIndexFromTreeNode(const MemWatchTreeNode* const node) +{ + if (node == m_rootNode) + { + return createIndex(0, 0, m_rootNode); + } + + const MemWatchTreeNode* const parent{node->getParent()}; + return index(static_cast(parent->getChildren().indexOf(node)), 0, + getIndexFromTreeNode(parent)); +} diff --git a/Source/GUI/MemWatcher/MemWatchModel.h b/Source/GUI/MemWatcher/MemWatchModel.h index e4e2bbc..e0389b8 100644 --- a/Source/GUI/MemWatcher/MemWatchModel.h +++ b/Source/GUI/MemWatcher/MemWatchModel.h @@ -62,6 +62,7 @@ class MemWatchModel : public QAbstractItemModel void editEntry(MemWatchEntry* entry, const QModelIndex& index); void clearRoot(); void deleteNode(const QModelIndex& index); + void groupSelection(const QModelIndexList& indexes); void onUpdateTimer(); void onFreezeTimer(); void loadRootFromJsonRecursive(const QJsonObject& json); @@ -71,6 +72,7 @@ class MemWatchModel : public QAbstractItemModel bool hasAnyNodes() const; MemWatchTreeNode* getRootNode() const; static MemWatchTreeNode* getTreeNodeFromIndex(const QModelIndex& index); + QModelIndex getIndexFromTreeNode(const MemWatchTreeNode* node); bool editData(const QModelIndex& index, const QVariant& value, int role, bool emitEdit = false); signals: diff --git a/Source/GUI/MemWatcher/MemWatchWidget.cpp b/Source/GUI/MemWatcher/MemWatchWidget.cpp index 93cbf33..54b2da9 100644 --- a/Source/GUI/MemWatcher/MemWatchWidget.cpp +++ b/Source/GUI/MemWatcher/MemWatchWidget.cpp @@ -247,6 +247,15 @@ void MemWatchWidget::onMemWatchContextMenuRequested(const QPoint& pos) node = m_watchModel->getRootNode(); } + const QModelIndexList simplifiedSelection{simplifySelection()}; + if (!simplifiedSelection.empty()) + { + QAction* const groupAction{new QAction(tr("&Group"), this)}; + connect(groupAction, &QAction::triggered, this, &MemWatchWidget::groupCurrentSelection); + contextMenu->addAction(groupAction); + contextMenu->addSeparator(); + } + QAction* cut = new QAction(tr("Cu&t"), this); connect(cut, &QAction::triggered, this, [this] { cutSelectedWatchesToClipBoard(); }); contextMenu->addAction(cut); @@ -293,6 +302,11 @@ void MemWatchWidget::setSelectedWatchesBase(MemWatchEntry* entry, Common::MemBas m_hasUnsavedChanges = true; } +void MemWatchWidget::groupCurrentSelection() +{ + m_watchModel->groupSelection(simplifySelection()); +} + void MemWatchWidget::cutSelectedWatchesToClipBoard() { copySelectedWatchesToClipBoard(); diff --git a/Source/GUI/MemWatcher/MemWatchWidget.h b/Source/GUI/MemWatcher/MemWatchWidget.h index 45e36c8..cb8098d 100644 --- a/Source/GUI/MemWatcher/MemWatchWidget.h +++ b/Source/GUI/MemWatcher/MemWatchWidget.h @@ -33,6 +33,7 @@ class MemWatchWidget : public QWidget void onRowsInserted(const QModelIndex& parent, int first, int last); void openWatchFile(); void setSelectedWatchesBase(MemWatchEntry* entry, Common::MemBase base); + void groupCurrentSelection(); void copySelectedWatchesToClipBoard(); void cutSelectedWatchesToClipBoard(); void pasteWatchFromClipBoard(const QModelIndex& referenceIndex); diff --git a/Source/MemoryWatch/MemWatchTreeNode.cpp b/Source/MemoryWatch/MemWatchTreeNode.cpp index c98b6b9..89a2a71 100644 --- a/Source/MemoryWatch/MemWatchTreeNode.cpp +++ b/Source/MemoryWatch/MemWatchTreeNode.cpp @@ -109,9 +109,19 @@ void MemWatchTreeNode::insertChild(const int row, MemWatchTreeNode* node) void MemWatchTreeNode::removeChild(const int row) { + m_children[row]->m_parent = nullptr; m_children.remove(row); } +void MemWatchTreeNode::removeChild(MemWatchTreeNode* const child) +{ + m_children.removeAll(child); + if (child->m_parent == this) + { + child->m_parent = nullptr; + } +} + void MemWatchTreeNode::removeChildren() { m_children.clear(); diff --git a/Source/MemoryWatch/MemWatchTreeNode.h b/Source/MemoryWatch/MemWatchTreeNode.h index b52e99c..1dc6a1f 100644 --- a/Source/MemoryWatch/MemWatchTreeNode.h +++ b/Source/MemoryWatch/MemWatchTreeNode.h @@ -36,6 +36,7 @@ class MemWatchTreeNode void appendChild(MemWatchTreeNode* node); void insertChild(int row, MemWatchTreeNode* node); void removeChild(int row); + void removeChild(MemWatchTreeNode* child); void removeChildren(); void deleteChildren();