FreeCAD
137 строк · 6.1 Кб
1# SPDX-License-Identifier: LGPL-2.1-or-later
2# ***************************************************************************
3# * *
4# * Copyright (c) 2022 FreeCAD Project Association *
5# * *
6# * This file is part of FreeCAD. *
7# * *
8# * FreeCAD is free software: you can redistribute it and/or modify it *
9# * under the terms of the GNU Lesser General Public License as *
10# * published by the Free Software Foundation, either version 2.1 of the *
11# * License, or (at your option) any later version. *
12# * *
13# * FreeCAD is distributed in the hope that it will be useful, but *
14# * WITHOUT ANY WARRANTY; without even the implied warranty of *
15# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
16# * Lesser General Public License for more details. *
17# * *
18# * You should have received a copy of the GNU Lesser General Public *
19# * License along with FreeCAD. If not, see *
20# * <https://www.gnu.org/licenses/>. *
21# * *
22# ***************************************************************************
23
24"""GUI functions for uninstalling an Addon or Macro."""
25
26import FreeCAD
27import FreeCADGui
28
29from PySide import QtCore, QtWidgets
30
31from addonmanager_uninstaller import AddonUninstaller, MacroUninstaller
32import addonmanager_utilities as utils
33
34translate = FreeCAD.Qt.translate
35
36
37class AddonUninstallerGUI(QtCore.QObject):
38"""User interface for uninstalling an Addon: asks for confirmation, displays a progress dialog,
39displays completion and/or error dialogs, and emits the finished() signal when all work is
40complete."""
41
42finished = QtCore.Signal()
43
44def __init__(self, addon_to_remove):
45super().__init__()
46self.addon_to_remove = addon_to_remove
47if hasattr(self.addon_to_remove, "macro") and self.addon_to_remove.macro is not None:
48self.uninstaller = MacroUninstaller(self.addon_to_remove)
49else:
50self.uninstaller = AddonUninstaller(self.addon_to_remove)
51self.uninstaller.success.connect(self._succeeded)
52self.uninstaller.failure.connect(self._failed)
53self.worker_thread = QtCore.QThread()
54self.uninstaller.moveToThread(self.worker_thread)
55self.uninstaller.finished.connect(self.worker_thread.quit)
56self.worker_thread.started.connect(self.uninstaller.run)
57self.progress_dialog = None
58self.dialog_timer = QtCore.QTimer()
59self.dialog_timer.timeout.connect(self._show_progress_dialog)
60self.dialog_timer.setSingleShot(True)
61self.dialog_timer.setInterval(1000) # Can override from external (e.g. testing) code
62
63def run(self):
64"""Begin the user interaction: asynchronous, only blocks while showing the initial modal
65confirmation dialog."""
66ok_to_proceed = self._confirm_uninstallation()
67if not ok_to_proceed:
68self._finalize()
69return
70
71self.dialog_timer.start()
72self._run_uninstaller()
73
74def _confirm_uninstallation(self) -> bool:
75"""Present a modal dialog asking the user if they really want to uninstall. Returns True to
76continue with the uninstallation, or False to stop the process."""
77confirm = QtWidgets.QMessageBox.question(
78utils.get_main_am_window(),
79translate("AddonsInstaller", "Confirm remove"),
80translate("AddonsInstaller", "Are you sure you want to uninstall {}?").format(
81self.addon_to_remove.display_name
82),
83QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.Cancel,
84)
85return confirm == QtWidgets.QMessageBox.Yes
86
87def _show_progress_dialog(self):
88self.progress_dialog = QtWidgets.QMessageBox(
89QtWidgets.QMessageBox.NoIcon,
90translate("AddonsInstaller", "Removing Addon"),
91translate("AddonsInstaller", "Removing {}").format(self.addon_to_remove.display_name)
92+ "...",
93QtWidgets.QMessageBox.Cancel,
94parent=utils.get_main_am_window(),
95)
96self.progress_dialog.rejected.connect(self._cancel_removal)
97self.progress_dialog.show()
98
99def _run_uninstaller(self):
100self.worker_thread.start()
101
102def _cancel_removal(self):
103"""Ask the QThread to interrupt. Probably has no effect, most of the work is in a single OS
104call."""
105self.worker_thread.requestInterruption()
106
107def _succeeded(self, addon):
108"""Callback for successful removal"""
109self.dialog_timer.stop()
110if self.progress_dialog:
111self.progress_dialog.hide()
112QtWidgets.QMessageBox.information(
113utils.get_main_am_window(),
114translate("AddonsInstaller", "Uninstall complete"),
115translate("AddonInstaller", "Finished removing {}").format(addon.display_name),
116)
117self._finalize()
118
119def _failed(self, addon, message):
120"""Callback for failed or partially failed removal"""
121self.dialog_timer.stop()
122if self.progress_dialog:
123self.progress_dialog.hide()
124QtWidgets.QMessageBox.critical(
125utils.get_main_am_window(),
126translate("AddonsInstaller", "Uninstall failed"),
127translate("AddonInstaller", "Failed to remove some files") + ":\n" + message,
128)
129self._finalize()
130
131def _finalize(self):
132"""Clean up and emit finished signal"""
133if self.worker_thread.isRunning():
134self.worker_thread.requestInterruption()
135self.worker_thread.quit()
136self.worker_thread.wait(500)
137self.finished.emit()
138