From 74501db7fcf0bdaaa5c1659a88470de92a8128de Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Thu, 7 Aug 2025 13:36:46 +0500 Subject: [PATCH 1/2] Manager: Add machine deletion --- src/qt/qt_vmmanager_main.cpp | 26 ++++++++++++++++++++++++++ src/qt/qt_vmmanager_main.hpp | 1 + src/qt/qt_vmmanager_model.cpp | 14 +++++++++++++- src/qt/qt_vmmanager_model.hpp | 1 + 4 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_vmmanager_main.cpp b/src/qt/qt_vmmanager_main.cpp index bf22e367e..484696954 100644 --- a/src/qt/qt_vmmanager_main.cpp +++ b/src/qt/qt_vmmanager_main.cpp @@ -107,6 +107,13 @@ VMManagerMain::VMManagerMain(QWidget *parent) : }); killIcon.setEnabled(selected_sysconfig->process->state() == QProcess::Running); + QAction deleteAction(tr("&Delete")); + contextMenu.addAction(&deleteAction); + connect(&deleteAction, &QAction::triggered, [this, parent] { + deleteSystem(selected_sysconfig); + }); + deleteAction.setEnabled(selected_sysconfig->process->state() == QProcess::NotRunning); + contextMenu.addSeparator(); QAction showRawConfigFile(tr("Show &config file")); @@ -433,6 +440,25 @@ VMManagerMain::addNewSystem(const QString &name, const QString &dir, const QStri }); } + +void +VMManagerMain::deleteSystem(VMManagerSystem *sysconfig) +{ + QMessageBox msgbox(QMessageBox::Icon::Warning, tr("Warning"), tr("Do you really want to delete the virtual machine \"%1\" and all its files? This action cannot be undone!").arg(sysconfig->displayName), QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No, qobject_cast(this->parent())); + msgbox.exec(); + if (msgbox.result() == QMessageBox::Yes) { + auto qrmdir = new QDir(sysconfig->config_dir); + if (const bool rmdirResult = qrmdir->removeRecursively(); !rmdirResult) { + QMessageBox::critical(this, tr("Remove directory failed"), tr("Some files in the machine's directory were unable to be deleted. Please delete them manually.")); + return; + } + auto config = new VMManagerConfig(VMManagerConfig::ConfigType::General); + config->remove(sysconfig->uuid); + vm_model->removeConfigFromModel(sysconfig); + delete sysconfig; + } +} + QStringList VMManagerMain::getSearchCompletionList() const { diff --git a/src/qt/qt_vmmanager_main.hpp b/src/qt/qt_vmmanager_main.hpp index d41d57938..9b9401d0f 100644 --- a/src/qt/qt_vmmanager_main.hpp +++ b/src/qt/qt_vmmanager_main.hpp @@ -70,6 +70,7 @@ public slots: void shutdownForceButtonPressed() const; void searchSystems(const QString &text) const; void newMachineWizard(); + void deleteSystem(VMManagerSystem *sysconfig); void addNewSystem(const QString &name, const QString &dir, const QString &displayName = QString(), const QString &configFile = {}); #if __GNUC__ >= 11 [[nodiscard]] QStringList getSearchCompletionList() const; diff --git a/src/qt/qt_vmmanager_model.cpp b/src/qt/qt_vmmanager_model.cpp index 76fcbffd6..3f6bdc4f9 100644 --- a/src/qt/qt_vmmanager_model.cpp +++ b/src/qt/qt_vmmanager_model.cpp @@ -140,6 +140,18 @@ VMManagerModel::addConfigToModel(VMManagerSystem *system_config) connect(system_config, &VMManagerSystem::itemDataChanged, this, &VMManagerModel::modelDataChanged); endInsertRows(); } + +void +VMManagerModel::removeConfigFromModel(VMManagerSystem *system_config) +{ + const QModelIndex index = getIndexForConfigFile(system_config->config_file); + disconnect(system_config, &VMManagerSystem::itemDataChanged, this, &VMManagerModel::modelDataChanged); + beginRemoveRows(QModelIndex(), index.row(), index.row()); + machines.remove(index.row()); + endRemoveRows(); + emit systemDataChanged(); +} + void VMManagerModel::modelDataChanged() { @@ -177,4 +189,4 @@ VMManagerModel::getActiveMachineCount() running++; } return running; -} \ No newline at end of file +} diff --git a/src/qt/qt_vmmanager_model.hpp b/src/qt/qt_vmmanager_model.hpp index 9fed1ca8c..4205e8098 100644 --- a/src/qt/qt_vmmanager_model.hpp +++ b/src/qt/qt_vmmanager_model.hpp @@ -51,6 +51,7 @@ public: [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role) const override; void addConfigToModel(VMManagerSystem *system_config); + void removeConfigFromModel(VMManagerSystem *system_config); [[nodiscard]] VMManagerSystem * getConfigObjectForIndex(const QModelIndex &index) const; QModelIndex getIndexForConfigFile(const QFileInfo& config_file); From 6ee2e66b56ed6463dc8142f8729bef0f9a07a18f Mon Sep 17 00:00:00 2001 From: Alexander Babikov Date: Fri, 8 Aug 2025 01:36:24 +0500 Subject: [PATCH 2/2] Fix the details screen after deleting every machine --- src/qt/qt_vmmanager_main.cpp | 20 ++++++++++++++++++-- src/qt/qt_vmmanager_system.hpp | 1 + 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/src/qt/qt_vmmanager_main.cpp b/src/qt/qt_vmmanager_main.cpp index 484696954..b55e2be2a 100644 --- a/src/qt/qt_vmmanager_main.cpp +++ b/src/qt/qt_vmmanager_main.cpp @@ -188,11 +188,19 @@ VMManagerMain::currentSelectionChanged(const QModelIndex ¤t, return; } - disconnect(selected_sysconfig, &VMManagerSystem::configurationChanged, this, &VMManagerMain::onConfigUpdated); + /* hack to prevent strange segfaults when adding a machine after + removing all machines previously */ + if (selected_sysconfig->config_signal_connected == true) { + disconnect(selected_sysconfig, &VMManagerSystem::configurationChanged, this, &VMManagerMain::onConfigUpdated); + selected_sysconfig->config_signal_connected = false; + } const auto mapped_index = proxy_model->mapToSource(current); selected_sysconfig = vm_model->getConfigObjectForIndex(mapped_index); vm_details->updateData(selected_sysconfig); - connect(selected_sysconfig, &VMManagerSystem::configurationChanged, this, &VMManagerMain::onConfigUpdated); + if (selected_sysconfig->config_signal_connected == false) { + connect(selected_sysconfig, &VMManagerSystem::configurationChanged, this, &VMManagerMain::onConfigUpdated); + selected_sysconfig->config_signal_connected = true; + } // Emit that the selection changed, include with the process state emit selectionChanged(current, selected_sysconfig->process->state()); @@ -456,6 +464,14 @@ VMManagerMain::deleteSystem(VMManagerSystem *sysconfig) config->remove(sysconfig->uuid); vm_model->removeConfigFromModel(sysconfig); delete sysconfig; + + if (vm_model->rowCount(QModelIndex()) <= 0) { + /* no machines left - get rid of the last machine's leftovers */ + ui->detailsArea->layout()->removeWidget(vm_details); + delete vm_details; + vm_details = new VMManagerDetails(); + ui->detailsArea->layout()->addWidget(vm_details); + } } } diff --git a/src/qt/qt_vmmanager_system.hpp b/src/qt/qt_vmmanager_system.hpp index 27b9fda57..5914e46cb 100644 --- a/src/qt/qt_vmmanager_system.hpp +++ b/src/qt/qt_vmmanager_system.hpp @@ -136,6 +136,7 @@ public: QProcess *process = new QProcess(); bool window_obscured; + bool config_signal_connected = false; QString getDisplayValue(VMManager::Display::Name key); QFileInfoList getScreenshots();