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