From 54253e2108af73d6b994f14899afeacf9ecb0162 Mon Sep 17 00:00:00 2001 From: Glutanimate Date: Sat, 4 Jan 2020 04:30:33 +0100 Subject: [PATCH 1/5] Make sure to pass pending imports on to installAddon also: refactor add-on check --- qt/aqt/main.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/qt/aqt/main.py b/qt/aqt/main.py index 2cc6cf7ad..b6b69982f 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -334,7 +334,10 @@ close the profile or restart Anki.""" # import pending? if self.pendingImport: - self.handleImport(self.pendingImport) + if self._isAddon(self.pendingImport): + self.installAddon(self.pendingImport) + else: + self.handleImport(self.pendingImport) self.pendingImport = None runHook("profileLoaded") if onsuccess: @@ -1482,7 +1485,7 @@ will be lost. Continue?""" self.app.appMsg.connect(self.onAppMsg) def onAppMsg(self, buf: str) -> Optional[QTimer]: - is_addon = buf.endswith(".ankiaddon") + is_addon = self._isAddon(buf) if self.state == "startup": # try again in a second @@ -1531,6 +1534,9 @@ Please ensure a profile is open and Anki is not busy, then try again.""" return None + def _isAddon(self, buf: str) -> bool: + return buf.endswith(self.addonManager.ext) + # GC ########################################################################## # ensure gc runs in main thread From d9e56e22f9854042bf72b75820acdaa53ed11ccb Mon Sep 17 00:00:00 2001 From: Glutanimate Date: Sat, 4 Jan 2020 04:31:33 +0100 Subject: [PATCH 2/5] Fix type hints and remove obsolete argument --- qt/aqt/addons.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qt/aqt/addons.py b/qt/aqt/addons.py index 1bac9266b..54bf35a50 100644 --- a/qt/aqt/addons.py +++ b/qt/aqt/addons.py @@ -345,7 +345,7 @@ and have been disabled: %(found)s" ###################################################################### def _installationErrorReport( - self, result: AddonInstallationResult, base: str, mode="download" + self, result: AddonInstallationResult, base: str, mode: str = "download" ) -> List[str]: messages = { @@ -370,7 +370,7 @@ and have been disabled: %(found)s" return [template % dict(base=name, id=name, error=msg)] def _installationSuccessReport( - self, result: AddonInstallationResult, base: str, mode="download" + self, result: AddonInstallationResult, base: str, mode: str = "download" ) -> List[str]: if mode == "download": # preserve old format strings for i18n @@ -666,7 +666,7 @@ class AddonsDialog(QDialog): def onGetAddons(self): GetAddons(self) - def onInstallFiles(self, paths: Optional[List[str]] = None, external: bool = False): + def onInstallFiles(self, paths: Optional[List[str]] = None): if not paths: key = _("Packaged Anki Add-on") + " (*{})".format(self.mgr.ext) paths = getFile( From 6a7f11b1724b276ee9053d413306b097b3e4e7b9 Mon Sep 17 00:00:00 2001 From: Glutanimate Date: Sat, 4 Jan 2020 04:34:16 +0100 Subject: [PATCH 3/5] When possible, install add-on before add-ons are loaded Removes the need to restart Anki if it is not running when user launches .ankiaddon file --- qt/aqt/addons.py | 15 ++++++--------- qt/aqt/main.py | 18 +++++++++++++----- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/qt/aqt/addons.py b/qt/aqt/addons.py index 54bf35a50..06dacf442 100644 --- a/qt/aqt/addons.py +++ b/qt/aqt/addons.py @@ -859,18 +859,19 @@ class ConfigEditor(QDialog): def installAddonPackages( addonsManager: AddonManager, paths: List[str], - parent: QWidget = None, - external: bool = False, + parent: Optional[QWidget] = None, + warn: bool = False, + strictly_modal: bool = False ) -> bool: - if external: + if warn: names = ",
".join(f"{os.path.basename(p)}" for p in paths) q = _( "Important: As add-ons are programs downloaded from the internet, " "they are potentially malicious." "You should only install add-ons you trust.

" "Are you sure you want to proceed with the installation of the " - "following add-on(s)?

%(names)s" + "following Anki add-on(s)?

%(names)s" ) % dict(names=names) if ( not showInfo( @@ -888,11 +889,7 @@ def installAddonPackages( if log: log_html = "
".join(log) - if external: - log_html += "

" + _( - "Please restart Anki to complete the installation." - ) - if len(log) == 1: + if len(log) == 1 and not strictly_modal: tooltip(log_html, parent=parent) else: showInfo( diff --git a/qt/aqt/main.py b/qt/aqt/main.py index b6b69982f..81198238f 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -72,7 +72,7 @@ class AnkiQt(QMainWindow): self.safeMode = self.app.queryKeyboardModifiers() & Qt.ShiftModifier try: self.setupUI() - self.setupAddons() + self.setupAddons(args) except: showInfo(_("Error during startup:\n%s") % traceback.format_exc()) sys.exit(1) @@ -85,7 +85,7 @@ class AnkiQt(QMainWindow): ) ) # were we given a file to import? - if args and args[0]: + if args and args[0] and not self._isAddon(args[0]): self.onAppMsg(args[0]) # Load profile in a timer so we can let the window finish init and not # close on profile load error. @@ -750,10 +750,14 @@ title="%s" %s>%s""" % ( self.errorHandler = aqt.errors.ErrorHandler(self) - def setupAddons(self) -> None: + def setupAddons(self, args: Optional[List]) -> None: import aqt.addons self.addonManager = aqt.addons.AddonManager(self) + + if args and args[0] and self._isAddon(args[0]): + self.installAddon(args[0], startup=True) + if not self.safeMode: self.addonManager.loadAddons() @@ -1028,10 +1032,14 @@ QTreeWidget { # Installing add-ons from CLI / mimetype handler ########################################################################## - def installAddon(self, path): + def installAddon(self, path: str, startup: bool = False): from aqt.addons import installAddonPackages - installAddonPackages(self.addonManager, [path], external=True, parent=self) + parent = None if startup else self + + installAddonPackages( + self.addonManager, [path], warn=True, strictly_modal=startup, parent=parent + ) # Cramming ########################################################################## From 7348e9c69e0093c17a1b7b5b3a934f27d09bfda6 Mon Sep 17 00:00:00 2001 From: Glutanimate Date: Sat, 4 Jan 2020 04:45:43 +0100 Subject: [PATCH 4/5] Further tweak messaging depending on Anki's state at installation time --- qt/aqt/addons.py | 7 ++++++- qt/aqt/main.py | 9 ++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/qt/aqt/addons.py b/qt/aqt/addons.py index 06dacf442..e0eb7cd5f 100644 --- a/qt/aqt/addons.py +++ b/qt/aqt/addons.py @@ -861,7 +861,8 @@ def installAddonPackages( paths: List[str], parent: Optional[QWidget] = None, warn: bool = False, - strictly_modal: bool = False + strictly_modal: bool = False, + advise_restart: bool = False, ) -> bool: if warn: @@ -889,6 +890,10 @@ def installAddonPackages( if log: log_html = "
".join(log) + if advise_restart: + log_html += "

" + _( + "Please restart Anki to complete the installation." + ) if len(log) == 1 and not strictly_modal: tooltip(log_html, parent=parent) else: diff --git a/qt/aqt/main.py b/qt/aqt/main.py index 81198238f..c041042f0 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -1035,10 +1035,13 @@ QTreeWidget { def installAddon(self, path: str, startup: bool = False): from aqt.addons import installAddonPackages - parent = None if startup else self - installAddonPackages( - self.addonManager, [path], warn=True, strictly_modal=startup, parent=parent + self.addonManager, + [path], + warn=True, + advise_restart=not startup, + strictly_modal=startup, + parent=None if startup else self, ) # Cramming From a2124e2ee8e726a97a13fcfc081e4051dabf1e63 Mon Sep 17 00:00:00 2001 From: Glutanimate Date: Sat, 4 Jan 2020 04:49:36 +0100 Subject: [PATCH 5/5] Use add-on name rather than package name when reporting on conflicts Brings _installationSuccessReport more in line with messaging in AddonManager.toggleEnabled --- qt/aqt/addons.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qt/aqt/addons.py b/qt/aqt/addons.py index e0eb7cd5f..b6d4b46db 100644 --- a/qt/aqt/addons.py +++ b/qt/aqt/addons.py @@ -385,7 +385,7 @@ and have been disabled: %(found)s" strings.append( _("The following conflicting add-ons were disabled:") + " " - + " ".join(result.conflicts) + + ", ".join(self.addonName(f) for f in result.conflicts) ) return strings