From a7812dedc096627692ab3d7e64b90be632f52134 Mon Sep 17 00:00:00 2001 From: Damien Elmes Date: Tue, 5 Oct 2021 13:53:01 +1000 Subject: [PATCH] switch to new-style PyQt scoped enums and Qt6 The enum changes should work on PyQt 5.x, and are required in PyQt 6.x. They are not supported by the PyQt5 typings however, so we need to run our tests with PyQt6. --- qt/.pylintrc | 2 +- qt/BUILD.bazel | 6 +- qt/aqt/BUILD.bazel | 2 +- qt/aqt/__init__.py | 51 ++++++++------ qt/aqt/about.py | 4 +- qt/aqt/addcards.py | 13 ++-- qt/aqt/addons.py | 54 +++++++++------ qt/aqt/browser/browser.py | 10 +-- qt/aqt/browser/card_info.py | 4 +- qt/aqt/browser/find_and_replace.py | 8 ++- qt/aqt/browser/find_duplicates.py | 4 +- qt/aqt/browser/previewer.py | 12 ++-- qt/aqt/browser/sidebar/model.py | 39 +++++++---- qt/aqt/browser/sidebar/searchbar.py | 4 +- qt/aqt/browser/sidebar/toolbar.py | 2 +- qt/aqt/browser/sidebar/tree.py | 38 ++++++---- qt/aqt/browser/table/model.py | 25 ++++--- qt/aqt/browser/table/table.py | 69 ++++++++++--------- qt/aqt/changenotetype.py | 2 +- qt/aqt/clayout.py | 16 +++-- qt/aqt/customstudy.py | 4 +- qt/aqt/deckconf.py | 6 +- qt/aqt/deckdescription.py | 6 +- qt/aqt/deckoptions.py | 4 +- qt/aqt/editcurrent.py | 4 +- qt/aqt/editor.py | 19 ++--- qt/aqt/emptycards.py | 2 +- qt/aqt/exporting.py | 4 +- qt/aqt/fields.py | 28 +++++--- qt/aqt/filtered_deck.py | 6 +- qt/aqt/forms/findreplace.ui | 10 +-- qt/aqt/importing.py | 9 +-- qt/aqt/main.py | 21 +++--- qt/aqt/mediacheck.py | 12 ++-- qt/aqt/mediasync.py | 6 +- qt/aqt/models.py | 6 +- qt/aqt/operations/scheduling.py | 2 +- qt/aqt/preferences.py | 10 ++- qt/aqt/profiles.py | 4 +- qt/aqt/progress.py | 8 +-- qt/aqt/qt.py | 42 ++++++++---- qt/aqt/qt5.py | 2 + qt/aqt/reviewer.py | 8 +-- qt/aqt/sound.py | 9 ++- qt/aqt/stats.py | 12 ++-- qt/aqt/studydeck.py | 24 +++---- qt/aqt/switch.py | 16 +++-- qt/aqt/sync.py | 8 +-- qt/aqt/tagedit.py | 29 ++++---- qt/aqt/taglimit.py | 18 +++-- qt/aqt/theme.py | 46 ++++++++----- qt/aqt/update.py | 10 +-- qt/aqt/utils.py | 103 +++++++++++++++------------- qt/aqt/webview.py | 45 ++++++------ qt/dmypy.py | 2 +- qt/mypy.ini | 1 + 56 files changed, 526 insertions(+), 385 deletions(-) diff --git a/qt/.pylintrc b/qt/.pylintrc index 510c08da4..6107eeed3 100644 --- a/qt/.pylintrc +++ b/qt/.pylintrc @@ -1,6 +1,6 @@ [MASTER] persistent = no -extension-pkg-whitelist=PyQt5,PyQt6 +extension-pkg-whitelist=PyQt6 ignore = forms,hooks_gen.py [TYPECHECK] diff --git a/qt/BUILD.bazel b/qt/BUILD.bazel index a2e4bfd65..93d5473b3 100644 --- a/qt/BUILD.bazel +++ b/qt/BUILD.bazel @@ -45,21 +45,21 @@ py_test( args = [ "aqt", "$(location mypy.ini)", - "$(location @pyqt5//:__init__.py)", + "$(location @pyqt6//:__init__.py)", "$(location //pip/stubs:extendsitepkgs)", ], data = [ "mypy.ini", "//pip/stubs", "//pip/stubs:extendsitepkgs", - "@pyqt5//:__init__.py", + "@pyqt6//:__init__.py", ], env = {"EXTRA_SITE_PACKAGES": "$(location //pip/stubs)"}, main = "tests/run_mypy.py", deps = [ "//pylib/anki", "//qt/aqt:aqt_without_data", - "@pyqt5//:pkg", + "@pyqt6//:pkg", requirement("mypy"), ], ) diff --git a/qt/aqt/BUILD.bazel b/qt/aqt/BUILD.bazel index e4bac550a..ad816a68b 100644 --- a/qt/aqt/BUILD.bazel +++ b/qt/aqt/BUILD.bazel @@ -50,7 +50,7 @@ aqt_deps = [ requirement("waitress"), requirement("send2trash"), requirement("jsonschema"), - "@pyqt5//:pkg", + "@pyqt6//:pkg", ] + select({ "@bazel_tools//src/conditions:host_windows": [ requirement("psutil"), diff --git a/qt/aqt/__init__.py b/qt/aqt/__init__.py index f910bbc1f..ea2742d7d 100644 --- a/qt/aqt/__init__.py +++ b/qt/aqt/__init__.py @@ -99,8 +99,10 @@ class DialogManager: def open(self, name: str, *args: Any, **kwargs: Any) -> Any: (creator, instance) = self._dialogs[name] if instance: - if instance.windowState() & Qt.WindowMinimized: - instance.setWindowState(instance.windowState() & ~Qt.WindowMinimized) + if instance.windowState() & Qt.WindowState.WindowMinimized: + instance.setWindowState( + instance.windowState() & ~Qt.WindowState.WindowMinimized + ) instance.activateWindow() instance.raise_() if hasattr(instance, "reopen"): @@ -224,9 +226,9 @@ def setupLangAndBackend( # switch direction for RTL languages if anki.lang.is_rtl(lang): - app.setLayoutDirection(Qt.RightToLeft) + app.setLayoutDirection(Qt.LayoutDirection.RightToLeft) else: - app.setLayoutDirection(Qt.LeftToRight) + app.setLayoutDirection(Qt.LayoutDirection.LeftToRight) # load qt translations _qtrans = QTranslator() @@ -238,7 +240,10 @@ def setupLangAndBackend( os.path.join(aqt_data_folder(), "..", "qt_translations") ) else: - qt_dir = QLibraryInfo.location(QLibraryInfo.TranslationsPath) + if qtmajor == 5: + qt_dir = QLibraryInfo.location(QLibraryInfo.TranslationsPath) # type: ignore + else: + qt_dir = QLibraryInfo.path(QLibraryInfo.LibraryPath.TranslationsPath) qt_lang = lang.replace("-", "_") if _qtrans.load(f"qtbase_{qt_lang}", qt_dir): app.installTranslator(_qtrans) @@ -285,7 +290,7 @@ class AnkiApp(QApplication): def sendMsg(self, txt: str) -> bool: sock = QLocalSocket(self) - sock.connectToServer(self.KEY, QIODevice.WriteOnly) + sock.connectToServer(self.KEY, QIODevice.OpenModeFlag.WriteOnly) if not sock.waitForConnected(self.TMOUT): # first instance or previous instance dead return False @@ -315,7 +320,7 @@ class AnkiApp(QApplication): ################################################## def event(self, evt: QEvent) -> bool: - if evt.type() == QEvent.FileOpen: + if evt.type() == QEvent.Type.FileOpen: self.appMsg.emit(evt.file() or "raise") # type: ignore return True return QApplication.event(self, evt) @@ -360,17 +365,17 @@ def setupGL(pm: aqt.profiles.ProfileManager) -> None: # catch opengl errors def msgHandler(category: Any, ctx: Any, msg: Any) -> None: - if category == QtDebugMsg: + if category == QtMsgType.QtDebugMsg: category = "debug" - elif category == QtInfoMsg: + elif category == QtMsgType.QtInfoMsg: category = "info" - elif category == QtWarningMsg: + elif category == QtMsgType.QtWarningMsg: category = "warning" - elif category == QtCriticalMsg: + elif category == QtMsgType.QtCriticalMsg: category = "critical" - elif category == QtDebugMsg: + elif category == QtMsgType.QtDebugMsg: category = "debug" - elif category == QtFatalMsg: + elif category == QtMsgType.QtFatalMsg: category = "fatal" else: category = "unknown" @@ -405,7 +410,7 @@ def setupGL(pm: aqt.profiles.ProfileManager) -> None: if isWin: os.environ["QT_OPENGL"] = driver.value elif isMac: - QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL) + QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_UseSoftwareOpenGL) elif isLin: os.environ["QT_XCB_FORCE_SOFTWARE_OPENGL"] = "1" @@ -499,15 +504,15 @@ def _run(argv: Optional[list[str]] = None, exec: bool = True) -> Optional[AnkiAp os.environ["QT_SCALE_FACTOR"] = str(pm.uiScale()) # opt in to full hidpi support? - if not os.environ.get("ANKI_NOHIGHDPI"): - QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling) - QCoreApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) + if not os.environ.get("ANKI_NOHIGHDPI") and qtmajor == 5: + QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_EnableHighDpiScaling) # type: ignore + QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_UseHighDpiPixmaps) # type: ignore os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "1" os.environ["QT_SCALE_FACTOR_ROUNDING_POLICY"] = "PassThrough" # Opt into software rendering. Useful for buggy systems. if os.environ.get("ANKI_SOFTWAREOPENGL"): - QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL) + QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_UseSoftwareOpenGL) if ( isWin @@ -535,11 +540,13 @@ def _run(argv: Optional[list[str]] = None, exec: bool = True) -> Optional[AnkiAp # disable icons on mac; this must be done before window created if isMac: - app.setAttribute(Qt.AA_DontShowIconsInMenus) + app.setAttribute(Qt.ApplicationAttribute.AA_DontShowIconsInMenus) # disable help button in title bar on qt versions that support it - if isWin and qtminor >= 10: - QApplication.setAttribute(Qt.AA_DisableWindowContextHelpButton) + if isWin and qtmajor == 5 and qtminor >= 10: + QApplication.setAttribute( + QApplication.Attribute.AA_DisableWindowContextHelpButton # type: ignore + ) # proxy configured? from urllib.request import getproxies, proxy_bypass @@ -559,7 +566,7 @@ def _run(argv: Optional[list[str]] = None, exec: bool = True) -> Optional[AnkiAp if disable_proxies: print("webview proxy use disabled") proxy = QNetworkProxy() - proxy.setType(QNetworkProxy.NoProxy) + proxy.setType(QNetworkProxy.ProxyType.NoProxy) QNetworkProxy.setApplicationProxy(proxy) # we must have a usable temp dir diff --git a/qt/aqt/about.py b/qt/aqt/about.py index 357d346ec..3f5d47164 100644 --- a/qt/aqt/about.py +++ b/qt/aqt/about.py @@ -88,8 +88,8 @@ def show(mw: aqt.AnkiQt) -> QDialog: btn = QPushButton(tr.about_copy_debug_info()) qconnect(btn.clicked, onCopy) - abt.buttonBox.addButton(btn, QDialogButtonBox.ActionRole) - abt.buttonBox.button(QDialogButtonBox.Ok).setFocus() + abt.buttonBox.addButton(btn, QDialogButtonBox.ButtonRole.ActionRole) + abt.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setFocus() # WebView contents ###################################################################### diff --git a/qt/aqt/addcards.py b/qt/aqt/addcards.py index f5280c233..7d42ba133 100644 --- a/qt/aqt/addcards.py +++ b/qt/aqt/addcards.py @@ -35,7 +35,7 @@ from aqt.utils import ( class AddCards(QDialog): def __init__(self, mw: AnkiQt) -> None: - QDialog.__init__(self, None, Qt.Window) + QDialog.__init__(self, None, Qt.WindowType.Window) mw.garbage_collect_on_dialog_finish(self) self.mw = mw self.col = mw.col @@ -85,7 +85,7 @@ class AddCards(QDialog): def setupButtons(self) -> None: bb = self.form.buttonBox - ar = QDialogButtonBox.ActionRole + ar = QDialogButtonBox.ButtonRole.ActionRole # add self.addButton = bb.addButton(tr.actions_add(), ar) qconnect(self.addButton.clicked, self.add_current_note) @@ -97,11 +97,11 @@ class AddCards(QDialog): # close self.closeButton = QPushButton(tr.actions_close()) self.closeButton.setAutoDefault(False) - bb.addButton(self.closeButton, QDialogButtonBox.RejectRole) + bb.addButton(self.closeButton, QDialogButtonBox.ButtonRole.RejectRole) # help self.helpButton = QPushButton(tr.actions_help(), clicked=self.helpRequested) # type: ignore self.helpButton.setAutoDefault(False) - bb.addButton(self.helpButton, QDialogButtonBox.HelpRole) + bb.addButton(self.helpButton, QDialogButtonBox.ButtonRole.HelpRole) # history b = bb.addButton(f"{tr.adding_history()} {downArrow()}", ar) if isMac: @@ -266,7 +266,10 @@ class AddCards(QDialog): def keyPressEvent(self, evt: QKeyEvent) -> None: "Show answer on RET or register answer." - if evt.key() in (Qt.Key_Enter, Qt.Key_Return) and self.editor.tags.hasFocus(): + if ( + evt.key() in (Qt.Key.Key_Enter, Qt.Key.Key_Return) + and self.editor.tags.hasFocus() + ): evt.accept() return return QDialog.keyPressEvent(self, evt) diff --git a/qt/aqt/addons.py b/qt/aqt/addons.py index 5a94e048a..c8c69b6de 100644 --- a/qt/aqt/addons.py +++ b/qt/aqt/addons.py @@ -804,7 +804,7 @@ class AddonsDialog(QDialog): name = self.name_for_addon_list(addon) item = QListWidgetItem(name, addonList) if self.should_grey(addon): - item.setForeground(Qt.gray) + item.setForeground(Qt.GlobalColor.gray) if addon.dir_name in selected: item.setSelected(True) @@ -947,7 +947,7 @@ class GetAddons(QDialog): self.form = aqt.forms.getaddons.Ui_Dialog() self.form.setupUi(self) b = self.form.buttonBox.addButton( - tr.addons_browse_addons(), QDialogButtonBox.ActionRole + tr.addons_browse_addons(), QDialogButtonBox.ButtonRole.ActionRole ) qconnect(b.clicked, self.onBrowse) disable_help_button(self) @@ -1183,7 +1183,7 @@ class ChooseAddonsToUpdateList(QListWidget): ) self.ignore_check_evt = False self.setup() - self.setContextMenuPolicy(Qt.CustomContextMenu) + self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) qconnect(self.itemClicked, self.on_click) qconnect(self.itemChanged, self.on_check) qconnect(self.itemDoubleClicked, self.on_double_click) @@ -1191,7 +1191,9 @@ class ChooseAddonsToUpdateList(QListWidget): def setup(self) -> None: header_item = QListWidgetItem(tr.addons_choose_update_update_all(), self) - header_item.setFlags(Qt.ItemFlag(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)) + header_item.setFlags( + Qt.ItemFlag(Qt.ItemFlag.ItemIsUserCheckable | Qt.ItemFlag.ItemIsEnabled) + ) self.header_item = header_item for update_info in self.updated_addons: addon_id = update_info.id @@ -1204,22 +1206,22 @@ class ChooseAddonsToUpdateList(QListWidget): addon_label = f"{update_time:%Y-%m-%d} {addon_name}" item = QListWidgetItem(addon_label, self) # Not user checkable because it overlaps with itemClicked signal - item.setFlags(Qt.ItemFlag(Qt.ItemIsEnabled)) + item.setFlags(Qt.ItemFlag(Qt.ItemFlag.ItemIsEnabled)) if update_enabled: - item.setCheckState(Qt.Checked) + item.setCheckState(Qt.CheckState.Checked) else: - item.setCheckState(Qt.Unchecked) + item.setCheckState(Qt.CheckState.Unchecked) item.setData(self.ADDON_ID_ROLE, addon_id) self.refresh_header_check_state() def bool_to_check(self, check_bool: bool) -> Qt.CheckState: if check_bool: - return Qt.Checked + return Qt.CheckState.Checked else: - return Qt.Unchecked + return Qt.CheckState.Unchecked def checked(self, item: QListWidgetItem) -> bool: - return item.checkState() == Qt.Checked + return item.checkState() == Qt.CheckState.Checked def on_click(self, item: QListWidgetItem) -> None: if item == self.header_item: @@ -1262,9 +1264,9 @@ class ChooseAddonsToUpdateList(QListWidget): for i in range(1, self.count()): item = self.item(i) if not self.checked(item): - self.check_item(self.header_item, Qt.Unchecked) + self.check_item(self.header_item, Qt.CheckState.Unchecked) return - self.check_item(self.header_item, Qt.Checked) + self.check_item(self.header_item, Qt.CheckState.Checked) def get_selected_addon_ids(self) -> list[int]: addon_ids = [] @@ -1290,7 +1292,7 @@ class ChooseAddonsToUpdateDialog(QDialog): ) -> None: QDialog.__init__(self, parent) self.setWindowTitle(tr.addons_choose_update_window_title()) - self.setWindowModality(Qt.WindowModal) + self.setWindowModality(Qt.WindowModality.WindowModal) self.mgr = mgr self.updated_addons = updated_addons self.setup() @@ -1306,9 +1308,14 @@ class ChooseAddonsToUpdateDialog(QDialog): layout.addWidget(addons_list_widget) self.addons_list_widget = addons_list_widget - button_box = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) # type: ignore - qconnect(button_box.button(QDialogButtonBox.Ok).clicked, self.accept) - qconnect(button_box.button(QDialogButtonBox.Cancel).clicked, self.reject) + button_box = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) # type: ignore + qconnect( + button_box.button(QDialogButtonBox.StandardButton.Ok).clicked, self.accept + ) + qconnect( + button_box.button(QDialogButtonBox.StandardButton.Cancel).clicked, + self.reject, + ) layout.addWidget(button_box) self.setLayout(layout) @@ -1317,7 +1324,7 @@ class ChooseAddonsToUpdateDialog(QDialog): ret = self.exec() saveGeom(self, "addonsChooseUpdate") self.addons_list_widget.save_check_state() - if ret == QDialog.Accepted: + if ret == QDialog.DialogCode.Accepted: return self.addons_list_widget.get_selected_addon_ids() else: return [] @@ -1475,7 +1482,9 @@ class ConfigEditor(QDialog): self.mgr = dlg.mgr self.form = aqt.forms.addonconf.Ui_Dialog() self.form.setupUi(self) - restore = self.form.buttonBox.button(QDialogButtonBox.RestoreDefaults) + restore = self.form.buttonBox.button( + QDialogButtonBox.StandardButton.RestoreDefaults + ) qconnect(restore.clicked, self.onRestoreDefaults) self.setupFonts() self.updateHelp() @@ -1498,7 +1507,7 @@ class ConfigEditor(QDialog): tooltip(tr.addons_restored_defaults(), parent=self) def setupFonts(self) -> None: - font_mono = QFontDatabase.systemFont(QFontDatabase.FixedFont) + font_mono = QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont) font_mono.setPointSize(font_mono.pointSize() + 1) self.form.editor.setFont(font_mono) @@ -1600,9 +1609,12 @@ def installAddonPackages( parent=parent, title=tr.addons_install_anki_addon(), type="warning", - customBtns=[QMessageBox.No, QMessageBox.Yes], + customBtns=[ + QMessageBox.StandardButton.No, + QMessageBox.StandardButton.Yes, + ], ) - == QMessageBox.Yes + == QMessageBox.StandardButton.Yes ): return False diff --git a/qt/aqt/browser/browser.py b/qt/aqt/browser/browser.py index 34a6133fe..1c90beeaf 100644 --- a/qt/aqt/browser/browser.py +++ b/qt/aqt/browser/browser.py @@ -104,7 +104,7 @@ class Browser(QMainWindow): search -- set and perform search; caller must ensure validity """ - QMainWindow.__init__(self, None, Qt.Window) + QMainWindow.__init__(self, None, Qt.WindowType.Window) self.mw = mw self.col = self.mw.col self.lastFilter = "" @@ -255,7 +255,7 @@ class Browser(QMainWindow): onsuccess() def keyPressEvent(self, evt: QKeyEvent) -> None: - if evt.key() == Qt.Key_Escape: + if evt.key() == Qt.Key.Key_Escape: self.close() else: super().keyPressEvent(evt) @@ -490,9 +490,9 @@ class Browser(QMainWindow): def setupSidebar(self) -> None: dw = self.sidebarDockWidget = QDockWidget(tr.browsing_sidebar(), self) - dw.setFeatures(QDockWidget.NoDockWidgetFeatures) + dw.setFeatures(QDockWidget.DockWidgetFeature.NoDockWidgetFeatures) dw.setObjectName("Sidebar") - dw.setAllowedAreas(Qt.LeftDockWidgetArea) + dw.setAllowedAreas(Qt.DockWidgetArea.LeftDockWidgetArea) self.sidebar = SidebarTreeView(self) self.sidebarTree = self.sidebar # legacy alias @@ -513,7 +513,7 @@ class Browser(QMainWindow): self.sidebarDockWidget.setFloating(False) self.sidebarDockWidget.setTitleBarWidget(QWidget()) - self.addDockWidget(Qt.LeftDockWidgetArea, dw) + self.addDockWidget(Qt.DockWidgetArea.LeftDockWidgetArea, dw) # schedule sidebar to refresh after browser window has loaded, so the # UI is more responsive diff --git a/qt/aqt/browser/card_info.py b/qt/aqt/browser/card_info.py index 046870362..b059bfaa5 100644 --- a/qt/aqt/browser/card_info.py +++ b/qt/aqt/browser/card_info.py @@ -28,7 +28,7 @@ class CardInfoDialog(QDialog): self.show() def _setup_ui(self, card_id: CardId) -> None: - self.setWindowModality(Qt.ApplicationModal) + self.setWindowModality(Qt.WindowModality.ApplicationModal) self.mw.garbage_collect_on_dialog_finish(self) disable_help_button(self) restoreGeom(self, self.GEOMETRY_KEY) @@ -40,7 +40,7 @@ class CardInfoDialog(QDialog): layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.addWidget(self.web) - buttons = QDialogButtonBox(QDialogButtonBox.Close) + buttons = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) buttons.setContentsMargins(10, 0, 10, 10) layout.addWidget(buttons) qconnect(buttons.rejected, self.reject) diff --git a/qt/aqt/browser/find_and_replace.py b/qt/aqt/browser/find_and_replace.py index 60b2f3d77..39add80e6 100644 --- a/qt/aqt/browser/find_and_replace.py +++ b/qt/aqt/browser/find_and_replace.py @@ -73,16 +73,18 @@ class FindAndReplaceDialog(QDialog): disable_help_button(self) self.form = aqt.forms.findreplace.Ui_Dialog() self.form.setupUi(self) - self.setWindowModality(Qt.WindowModal) + self.setWindowModality(Qt.WindowModality.WindowModal) self._find_history = restore_combo_history( self.form.find, self.COMBO_NAME + "Find" ) - self.form.find.completer().setCaseSensitivity(Qt.CaseSensitive) + self.form.find.completer().setCaseSensitivity(Qt.CaseSensitivity.CaseSensitive) self._replace_history = restore_combo_history( self.form.replace, self.COMBO_NAME + "Replace" ) - self.form.replace.completer().setCaseSensitivity(Qt.CaseSensitive) + self.form.replace.completer().setCaseSensitivity( + Qt.CaseSensitivity.CaseSensitive + ) if not self.note_ids: # no selected notes to affect diff --git a/qt/aqt/browser/find_duplicates.py b/qt/aqt/browser/find_duplicates.py index bd5c3237d..4af17cfe2 100644 --- a/qt/aqt/browser/find_duplicates.py +++ b/qt/aqt/browser/find_duplicates.py @@ -71,7 +71,7 @@ class FindDuplicatesDialog(QDialog): ).run_in_background() search = form.buttonBox.addButton( - tr.actions_search(), QDialogButtonBox.ActionRole + tr.actions_search(), QDialogButtonBox.ButtonRole.ActionRole ) qconnect(search.clicked, on_click) self.show() @@ -80,7 +80,7 @@ class FindDuplicatesDialog(QDialog): self._dupes = dupes if not self._dupesButton: self._dupesButton = b = self.form.buttonBox.addButton( - tr.browsing_tag_duplicates(), QDialogButtonBox.ActionRole + tr.browsing_tag_duplicates(), QDialogButtonBox.ButtonRole.ActionRole ) qconnect(b.clicked, self._tag_duplicates) text = "" diff --git a/qt/aqt/browser/previewer.py b/qt/aqt/browser/previewer.py index 774354070..190d65ecb 100644 --- a/qt/aqt/browser/previewer.py +++ b/qt/aqt/browser/previewer.py @@ -46,14 +46,14 @@ class Previewer(QDialog): def __init__( self, parent: QWidget, mw: AnkiQt, on_close: Callable[[], None] ) -> None: - super().__init__(None, Qt.Window) + super().__init__(None, Qt.WindowType.Window) mw.garbage_collect_on_dialog_finish(self) self._open = True self._parent = parent self._close_callback = on_close self.mw = mw icon = QIcon() - icon.addPixmap(QPixmap("icons:anki.png"), QIcon.Normal, QIcon.Off) + icon.addPixmap(QPixmap("icons:anki.png"), QIcon.Mode.Normal, QIcon.State.Off) disable_help_button(self) self.setWindowIcon(icon) @@ -86,7 +86,7 @@ class Previewer(QDialog): self.bbox = QDialogButtonBox() self._replay = self.bbox.addButton( - tr.actions_replay_audio(), QDialogButtonBox.ActionRole + tr.actions_replay_audio(), QDialogButtonBox.ButtonRole.ActionRole ) self._replay.setAutoDefault(False) self._replay.setShortcut(QKeySequence("R")) @@ -96,7 +96,7 @@ class Previewer(QDialog): both_sides_button = QCheckBox(tr.qt_misc_back_side_only()) both_sides_button.setShortcut(QKeySequence("B")) both_sides_button.setToolTip(tr.actions_shortcut_key(val="B")) - self.bbox.addButton(both_sides_button, QDialogButtonBox.ActionRole) + self.bbox.addButton(both_sides_button, QDialogButtonBox.ButtonRole.ActionRole) self._show_both_sides = self.mw.col.get_config_bool( Config.Bool.PREVIEW_BOTH_SIDES ) @@ -266,12 +266,12 @@ class MultiCardPreviewer(Previewer): def _create_gui(self) -> None: super()._create_gui() - self._prev = self.bbox.addButton("<", QDialogButtonBox.ActionRole) + self._prev = self.bbox.addButton("<", QDialogButtonBox.ButtonRole.ActionRole) self._prev.setAutoDefault(False) self._prev.setShortcut(QKeySequence("Left")) self._prev.setToolTip(tr.qt_misc_shortcut_key_left_arrow()) - self._next = self.bbox.addButton(">", QDialogButtonBox.ActionRole) + self._next = self.bbox.addButton(">", QDialogButtonBox.ButtonRole.ActionRole) self._next.setAutoDefault(True) self._next.setShortcut(QKeySequence("Right")) self._next.setToolTip(tr.qt_misc_shortcut_key_right_arrow_or_enter()) diff --git a/qt/aqt/browser/sidebar/model.py b/qt/aqt/browser/sidebar/model.py index 6376f176f..e9b3062d3 100644 --- a/qt/aqt/browser/sidebar/model.py +++ b/qt/aqt/browser/sidebar/model.py @@ -76,35 +76,48 @@ class SidebarModel(QAbstractItemModel): return self.createIndex(row, 0, parentItem) - def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> QVariant: + def data( + self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole + ) -> QVariant: if not index.isValid(): return QVariant() - if role not in (Qt.DisplayRole, Qt.DecorationRole, Qt.ToolTipRole, Qt.EditRole): + if role not in ( + Qt.ItemDataRole.DisplayRole, + Qt.ItemDataRole.DecorationRole, + Qt.ItemDataRole.ToolTipRole, + Qt.ItemDataRole.EditRole, + ): return QVariant() item: SidebarItem = index.internalPointer() - if role in (Qt.DisplayRole, Qt.EditRole): + if role in (Qt.ItemDataRole.DisplayRole, Qt.ItemDataRole.EditRole): return QVariant(item.name) - if role == Qt.ToolTipRole: + if role == Qt.ItemDataRole.ToolTipRole: return QVariant(item.tooltip) return QVariant(theme_manager.icon_from_resources(item.icon)) - def setData(self, index: QModelIndex, text: str, _role: int = Qt.EditRole) -> bool: + def setData( + self, index: QModelIndex, text: str, _role: int = Qt.ItemDataRole.EditRole + ) -> bool: return self.sidebar._on_rename(index.internalPointer(), text) - def supportedDropActions(self) -> Qt.DropActions: - return cast(Qt.DropActions, Qt.MoveAction) + def supportedDropActions(self) -> Qt.DropAction: + return cast(Qt.DropAction, Qt.DropAction.MoveAction) - def flags(self, index: QModelIndex) -> Qt.ItemFlags: + def flags(self, index: QModelIndex) -> Qt.ItemFlag: if not index.isValid(): - return cast(Qt.ItemFlags, Qt.ItemIsEnabled) - flags = Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsDragEnabled + return cast(Qt.ItemFlag, Qt.ItemFlag.ItemIsEnabled) + flags = ( + Qt.ItemFlag.ItemIsEnabled + | Qt.ItemFlag.ItemIsSelectable + | Qt.ItemFlag.ItemIsDragEnabled + ) item: SidebarItem = index.internalPointer() if item.item_type in self.sidebar.valid_drop_types: - flags |= Qt.ItemIsDropEnabled + flags |= Qt.ItemFlag.ItemIsDropEnabled if item.item_type.is_editable(): - flags |= Qt.ItemIsEditable + flags |= Qt.ItemFlag.ItemIsEditable - return cast(Qt.ItemFlags, flags) + return flags diff --git a/qt/aqt/browser/sidebar/searchbar.py b/qt/aqt/browser/sidebar/searchbar.py index b06ad7fcb..ae08f22fb 100644 --- a/qt/aqt/browser/sidebar/searchbar.py +++ b/qt/aqt/browser/sidebar/searchbar.py @@ -43,9 +43,9 @@ class SidebarSearchBar(QLineEdit): self.sidebar.search_for(self.text()) def keyPressEvent(self, evt: QKeyEvent) -> None: - if evt.key() in (Qt.Key_Up, Qt.Key_Down): + if evt.key() in (Qt.Key.Key_Up, Qt.Key.Key_Down): self.sidebar.setFocus() - elif evt.key() in (Qt.Key_Enter, Qt.Key_Return): + elif evt.key() in (Qt.Key.Key_Enter, Qt.Key.Key_Return): self.onSearch() else: QLineEdit.keyPressEvent(self, evt) diff --git a/qt/aqt/browser/sidebar/toolbar.py b/qt/aqt/browser/sidebar/toolbar.py index 61a0b0b5e..3f544682d 100644 --- a/qt/aqt/browser/sidebar/toolbar.py +++ b/qt/aqt/browser/sidebar/toolbar.py @@ -29,7 +29,7 @@ class SidebarToolbar(QToolBar): qconnect(self._action_group.triggered, self._on_action_group_triggered) self._setup_tools() self.setIconSize(QSize(16, 16)) - self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) self.setStyle(QStyleFactory.create("fusion")) def _setup_tools(self) -> None: diff --git a/qt/aqt/browser/sidebar/tree.py b/qt/aqt/browser/sidebar/tree.py index c48e45491..02be98c58 100644 --- a/qt/aqt/browser/sidebar/tree.py +++ b/qt/aqt/browser/sidebar/tree.py @@ -79,14 +79,14 @@ class SidebarTreeView(QTreeView): self.valid_drop_types: tuple[SidebarItemType, ...] = () self._refresh_needed = False - self.setContextMenuPolicy(Qt.CustomContextMenu) + self.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self.customContextMenuRequested.connect(self.onContextMenu) # type: ignore self.setUniformRowHeights(True) self.setHeaderHidden(True) self.setIndentation(15) self.setAutoExpandDelay(600) self.setDragDropOverwriteMode(False) - self.setEditTriggers(QAbstractItemView.EditKeyPressed) + self.setEditTriggers(QAbstractItemView.EditTrigger.EditKeyPressed) qconnect(self.expanded, self._on_expansion) qconnect(self.collapsed, self._on_collapse) @@ -122,12 +122,12 @@ class SidebarTreeView(QTreeView): def tool(self, tool: SidebarTool) -> None: self._tool = tool if tool == SidebarTool.SEARCH: - selection_mode = QAbstractItemView.SingleSelection - drag_drop_mode = QAbstractItemView.NoDragDrop + selection_mode = QAbstractItemView.SelectionMode.SingleSelection + drag_drop_mode = QAbstractItemView.DragDropMode.NoDragDrop double_click_expands = False else: - selection_mode = QAbstractItemView.ExtendedSelection - drag_drop_mode = QAbstractItemView.InternalMove + selection_mode = QAbstractItemView.SelectionMode.ExtendedSelection + drag_drop_mode = QAbstractItemView.DragDropMode.InternalMove double_click_expands = True self.setSelectionMode(selection_mode) self.setDragDropMode(drag_drop_mode) @@ -191,9 +191,9 @@ class SidebarTreeView(QTreeView): if current := self.find_item(current.has_same_id): index = self.model().index_for_item(current) self.selectionModel().setCurrentIndex( - index, QItemSelectionModel.SelectCurrent + index, QItemSelectionModel.SelectionFlag.SelectCurrent ) - self.scrollTo(index, QAbstractItemView.PositionAtCenter) + self.scrollTo(index, QAbstractItemView.ScrollHint.PositionAtCenter) def find_item( self, @@ -247,9 +247,12 @@ class SidebarTreeView(QTreeView): self.setExpanded(idx, True) if item.is_highlighted() and scroll_to_first_match: self.selectionModel().setCurrentIndex( - idx, QItemSelectionModel.SelectCurrent + idx, + QItemSelectionModel.SelectionFlag.SelectCurrent, + ) + self.scrollTo( + idx, QAbstractItemView.ScrollHint.PositionAtCenter ) - self.scrollTo(idx, QAbstractItemView.PositionAtCenter) scroll_to_first_match = False expand_node(parent or QModelIndex()) @@ -301,22 +304,29 @@ class SidebarTreeView(QTreeView): def dropEvent(self, event: QDropEvent) -> None: model = self.model() - target_item = model.item_for_index(self.indexAt(event.pos())) + if qtmajor == 5: + pos = event.pos() # type: ignore + else: + pos = event.position().toPoint() + target_item = model.item_for_index(self.indexAt(pos)) if self.handle_drag_drop(self._selected_items(), target_item): event.acceptProposedAction() def mouseReleaseEvent(self, event: QMouseEvent) -> None: super().mouseReleaseEvent(event) - if self.tool == SidebarTool.SEARCH and event.button() == Qt.LeftButton: + if ( + self.tool == SidebarTool.SEARCH + and event.button() == Qt.MouseButton.LeftButton + ): if (index := self.currentIndex()) == self.indexAt(event.pos()): self._on_search(index) def keyPressEvent(self, event: QKeyEvent) -> None: index = self.currentIndex() - if event.key() in (Qt.Key_Return, Qt.Key_Enter): + if event.key() in (Qt.Key.Key_Return, Qt.Key.Key_Enter): if not self.isPersistentEditorOpen(index): self._on_search(index) - elif event.key() == Qt.Key_Delete: + elif event.key() == Qt.Key.Key_Delete: self._on_delete_key(index) else: super().keyPressEvent(event) diff --git a/qt/aqt/browser/table/model.py b/qt/aqt/browser/table/model.py index f2ab6270b..e997bf230 100644 --- a/qt/aqt/browser/table/model.py +++ b/qt/aqt/browser/table/model.py @@ -3,7 +3,7 @@ from __future__ import annotations import time -from typing import Any, Callable, Sequence, cast +from typing import Any, Callable, Sequence import aqt from anki.cards import Card, CardId @@ -307,7 +307,7 @@ class DataModel(QAbstractTableModel): def data(self, index: QModelIndex = QModelIndex(), role: int = 0) -> Any: if not index.isValid(): return QVariant() - if role == Qt.FontRole: + if role == Qt.ItemDataRole.FontRole: if not self.column_at(index).uses_cell_font: return QVariant() qfont = QFont() @@ -315,30 +315,33 @@ class DataModel(QAbstractTableModel): qfont.setFamily(row.font_name) qfont.setPixelSize(row.font_size) return qfont - elif role == Qt.TextAlignmentRole: - align: Qt.AlignmentFlag | int = Qt.AlignVCenter + elif role == Qt.ItemDataRole.TextAlignmentRole: + align: Qt.AlignmentFlag | int = Qt.AlignmentFlag.AlignVCenter if self.column_at(index).alignment == Columns.ALIGNMENT_CENTER: - align |= Qt.AlignHCenter + align |= Qt.AlignmentFlag.AlignHCenter return align - elif role == Qt.DisplayRole: + elif role == Qt.ItemDataRole.DisplayRole: return self.get_cell(index).text - elif role == Qt.ToolTipRole and self._want_tooltips: + elif role == Qt.ItemDataRole.ToolTipRole and self._want_tooltips: return self.get_cell(index).text return QVariant() def headerData( self, section: int, orientation: Qt.Orientation, role: int = 0 ) -> str | None: - if orientation == Qt.Horizontal and role == Qt.DisplayRole: + if ( + orientation == Qt.Orientation.Horizontal + and role == Qt.ItemDataRole.DisplayRole + ): return self._state.column_label(self.column_at_section(section)) return None - def flags(self, index: QModelIndex) -> Qt.ItemFlags: + def flags(self, index: QModelIndex) -> Qt.ItemFlag: # shortcut for large selections (Ctrl+A) to avoid fetching large numbers of rows at once if row := self.get_cached_row(index): if row.is_deleted: - return Qt.ItemFlags(Qt.NoItemFlags) - return cast(Qt.ItemFlags, Qt.ItemIsEnabled | Qt.ItemIsSelectable) + return Qt.ItemFlag(Qt.ItemFlag.NoItemFlags) + return Qt.ItemFlag.ItemIsEnabled | Qt.ItemFlag.ItemIsSelectable def addon_column_fillin(key: str) -> Column: diff --git a/qt/aqt/browser/table/table.py b/qt/aqt/browser/table/table.py index f1eef337a..d08858b46 100644 --- a/qt/aqt/browser/table/table.py +++ b/qt/aqt/browser/table/table.py @@ -2,7 +2,7 @@ # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html from __future__ import annotations -from typing import Any, Callable, Sequence, cast +from typing import Any, Callable, Sequence import aqt import aqt.forms @@ -127,10 +127,8 @@ class Table: self.select_all() self._view.selectionModel().select( selection, - cast( - QItemSelectionModel.SelectionFlags, - QItemSelectionModel.Deselect | QItemSelectionModel.Rows, - ), + QItemSelectionModel.SelectionFlag.Deselect + | QItemSelectionModel.SelectionFlag.Rows, ) def select_single_card(self, card_id: CardId) -> None: @@ -202,10 +200,10 @@ class Table: # Move cursor def to_previous_row(self) -> None: - self._move_current(QAbstractItemView.MoveUp) + self._move_current(QAbstractItemView.CursorAction.MoveUp) def to_next_row(self) -> None: - self._move_current(QAbstractItemView.MoveDown) + self._move_current(QAbstractItemView.CursorAction.MoveDown) def to_first_row(self) -> None: self._move_current_to_row(0) @@ -248,7 +246,8 @@ class Table: def clear_current(self) -> None: self._view.selectionModel().setCurrentIndex( - QModelIndex(), QItemSelectionModel.NoUpdate + QModelIndex(), + QItemSelectionModel.SelectionFlag.NoUpdate, ) # Private methods @@ -268,7 +267,10 @@ class Table: index = self._model.index( row, self._view.horizontalHeader().logicalIndex(column) ) - self._view.selectionModel().setCurrentIndex(index, QItemSelectionModel.NoUpdate) + self._view.selectionModel().setCurrentIndex( + index, + QItemSelectionModel.SelectionFlag.NoUpdate, + ) def _reset_selection(self) -> None: """Remove selection and focus without emitting signals. @@ -286,7 +288,9 @@ class Table: self._model.index(row, 0), self._model.index(row, self._model.len_columns() - 1), ) - self._view.selectionModel().select(selection, QItemSelectionModel.SelectCurrent) + self._view.selectionModel().select( + selection, QItemSelectionModel.SelectionFlag.SelectCurrent + ) def _set_sort_indicator(self) -> None: hh = self._view.horizontalHeader() @@ -295,9 +299,9 @@ class Table: hh.setSortIndicatorShown(False) return if self._state.sort_backwards: - order = Qt.DescendingOrder + order = Qt.SortOrder.DescendingOrder else: - order = Qt.AscendingOrder + order = Qt.SortOrder.AscendingOrder hh.blockSignals(True) hh.setSortIndicator(index, order) hh.blockSignals(False) @@ -305,9 +309,10 @@ class Table: def _set_column_sizes(self) -> None: hh = self._view.horizontalHeader() - hh.setSectionResizeMode(QHeaderView.Interactive) + hh.setSectionResizeMode(QHeaderView.ResizeMode.Interactive) hh.setSectionResizeMode( - hh.logicalIndex(self._model.len_columns() - 1), QHeaderView.Stretch + hh.logicalIndex(self._model.len_columns() - 1), + QHeaderView.ResizeMode.Stretch, ) # this must be set post-resize or it doesn't work hh.setCascadingSectionResizes(False) @@ -334,7 +339,7 @@ class Table: ) qconnect(self._view.selectionModel().currentChanged, self._on_current_changed) self._view.setWordWrap(False) - self._view.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel) + self._view.setHorizontalScrollMode(QAbstractItemView.ScrollMode.ScrollPerPixel) self._view.horizontalScrollBar().setSingleStep(10) self._update_font() if not theme_manager.night_mode: @@ -346,7 +351,7 @@ class Table: self._view.setStyleSheet( f"QTableView {{ gridline-color: {colors.FRAME_BG} }}" ) - self._view.setContextMenuPolicy(Qt.CustomContextMenu) + self._view.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) qconnect(self._view.customContextMenuRequested, self._on_context_menu) def _update_font(self) -> None: @@ -369,7 +374,7 @@ class Table: hh.setHighlightSections(False) hh.setMinimumSectionSize(50) hh.setSectionsMovable(True) - hh.setContextMenuPolicy(Qt.CustomContextMenu) + hh.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu) self._restore_header() qconnect(hh.customContextMenuRequested, self._on_header_context) qconnect(hh.sortIndicatorChanged, self._on_sort_column_changed) @@ -573,7 +578,9 @@ class Table: visible = top_border >= 0 and bottom_border < self._view.viewport().height() if not visible or scroll_even_if_visible: horizontal = self._view.horizontalScrollBar().value() - self._view.scrollTo(self._model.index(row, 0), self._view.PositionAtTop) + self._view.scrollTo( + self._model.index(row, 0), QAbstractItemView.ScrollHint.PositionAtTop + ) self._view.horizontalScrollBar().setValue(horizontal) def _scroll_to_column(self, column: int) -> None: @@ -583,26 +590,26 @@ class Table: if not visible: vertical = self._view.verticalScrollBar().value() self._view.scrollTo( - self._model.index(0, column), self._view.PositionAtCenter + self._model.index(0, column), + QAbstractItemView.ScrollHint.PositionAtCenter, ) self._view.verticalScrollBar().setValue(vertical) - def _move_current(self, direction: int, index: QModelIndex = None) -> None: + def _move_current( + self, direction: QAbstractItemView.CursorAction, index: QModelIndex = None + ) -> None: if not self.has_current(): return if index is None: index = self._view.moveCursor( - cast(QAbstractItemView.CursorAction, direction), + direction, self.browser.mw.app.keyboardModifiers(), ) self._view.selectionModel().setCurrentIndex( index, - cast( - QItemSelectionModel.SelectionFlag, - QItemSelectionModel.Clear - | QItemSelectionModel.Select - | QItemSelectionModel.Rows, - ), + QItemSelectionModel.SelectionFlag.Clear + | QItemSelectionModel.SelectionFlag.Select + | QItemSelectionModel.SelectionFlag.Rows, ) def _move_current_to_row(self, row: int) -> None: @@ -614,10 +621,8 @@ class Table: selection = QItemSelection(new, old) self._view.selectionModel().select( selection, - cast( - QItemSelectionModel.SelectionFlag, - QItemSelectionModel.SelectCurrent | QItemSelectionModel.Rows, - ), + QItemSelectionModel.SelectionFlag.SelectCurrent + | QItemSelectionModel.SelectionFlag.Rows, ) @@ -630,7 +635,7 @@ class StatusDelegate(QItemDelegate): self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex ) -> None: if self._model.get_cell(index).is_rtl: - option.direction = Qt.RightToLeft + option.direction = Qt.LayoutDirection.RightToLeft if row_color := self._model.get_row(index).color: brush = QBrush(theme_manager.qcolor(row_color)) painter.save() diff --git a/qt/aqt/changenotetype.py b/qt/aqt/changenotetype.py index 89be796fb..d66209931 100644 --- a/qt/aqt/changenotetype.py +++ b/qt/aqt/changenotetype.py @@ -43,7 +43,7 @@ class ChangeNotetypeDialog(QDialog): self.show() def _setup_ui(self, notetype_id: NotetypeId) -> None: - self.setWindowModality(Qt.ApplicationModal) + self.setWindowModality(Qt.WindowModality.ApplicationModal) self.mw.garbage_collect_on_dialog_finish(self) self.setMinimumWidth(400) disable_help_button(self) diff --git a/qt/aqt/clayout.py b/qt/aqt/clayout.py index a499c5f42..ca081af87 100644 --- a/qt/aqt/clayout.py +++ b/qt/aqt/clayout.py @@ -45,7 +45,7 @@ class CardLayout(QDialog): parent: Optional[QWidget] = None, fill_empty: bool = False, ) -> None: - QDialog.__init__(self, parent or mw, Qt.Window) + QDialog.__init__(self, parent or mw, Qt.WindowType.Window) mw.garbage_collect_on_dialog_finish(self) self.mw = aqt.mw self.note = note @@ -80,7 +80,7 @@ class CardLayout(QDialog): self.redraw_everything() restoreGeom(self, "CardLayout") restoreSplitter(self.mainArea, "CardLayoutMainArea") - self.setWindowModality(Qt.ApplicationModal) + self.setWindowModality(Qt.WindowModality.ApplicationModal) self.show() # take the focus away from the first input area when starting up, # as users tend to accidentally type into the template @@ -108,7 +108,9 @@ class CardLayout(QDialog): def setupTopArea(self) -> None: self.topArea = QWidget() - self.topArea.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum) + self.topArea.setSizePolicy( + QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum + ) self.topAreaForm = aqt.forms.clayout_top.Ui_Form() self.topAreaForm.setupUi(self.topArea) self.topAreaForm.templateOptions.setText( @@ -215,8 +217,8 @@ class CardLayout(QDialog): def setupMainArea(self) -> None: split = self.mainArea = QSplitter() - split.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding) - split.setOrientation(Qt.Horizontal) + split.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + split.setOrientation(Qt.Orientation.Horizontal) left = QWidget() tform = self.tform = aqt.forms.template.Ui_Form() tform.setupUi(left) @@ -305,7 +307,7 @@ class CardLayout(QDialog): if not editor.find(text): # try again from top cursor = editor.textCursor() - cursor.movePosition(QTextCursor.Start) + cursor.movePosition(QTextCursor.MoveOperation.Start) editor.setTextCursor(cursor) if not editor.find(text): tooltip("No matches found.") @@ -752,7 +754,7 @@ class CardLayout(QDialog): if t["did"]: te.setText(self.col.decks.get(t["did"])["name"]) te.selectAll() - bb = QDialogButtonBox(QDialogButtonBox.Close) + bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) qconnect(bb.rejected, d.close) l.addWidget(bb) d.setLayout(l) diff --git a/qt/aqt/customstudy.py b/qt/aqt/customstudy.py index 8b056342b..878149e48 100644 --- a/qt/aqt/customstudy.py +++ b/qt/aqt/customstudy.py @@ -30,7 +30,7 @@ class CustomStudy(QDialog): self.created_custom_study = False f.setupUi(self) disable_help_button(self) - self.setWindowModality(Qt.WindowModal) + self.setWindowModality(Qt.WindowModality.WindowModal) self.setupSignals() f.radioNew.click() self.exec() @@ -116,7 +116,7 @@ class CustomStudy(QDialog): f.spin.setValue(sval) f.preSpin.setText(pre) f.postSpin.setText(post) - f.buttonBox.button(QDialogButtonBox.Ok).setText(ok) + f.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText(ok) self.radioIdx = idx def accept(self) -> None: diff --git a/qt/aqt/deckconf.py b/qt/aqt/deckconf.py index c7d5ac753..40432613f 100644 --- a/qt/aqt/deckconf.py +++ b/qt/aqt/deckconf.py @@ -40,13 +40,15 @@ class DeckConf(QDialog): self.mw.checkpoint(tr.actions_options()) self.setupCombos() self.setupConfs() - self.setWindowModality(Qt.WindowModal) + self.setWindowModality(Qt.WindowModality.WindowModal) qconnect( self.form.buttonBox.helpRequested, lambda: openHelp(HelpPage.DECK_OPTIONS) ) qconnect(self.form.confOpts.clicked, self.confOpts) qconnect( - self.form.buttonBox.button(QDialogButtonBox.RestoreDefaults).clicked, + self.form.buttonBox.button( + QDialogButtonBox.StandardButton.RestoreDefaults + ).clicked, self.onRestore, ) self.setWindowTitle( diff --git a/qt/aqt/deckdescription.py b/qt/aqt/deckdescription.py index 064883613..ccd534601 100644 --- a/qt/aqt/deckdescription.py +++ b/qt/aqt/deckdescription.py @@ -17,7 +17,7 @@ class DeckDescriptionDialog(QDialog): silentlyClose = True def __init__(self, mw: aqt.main.AnkiQt) -> None: - QDialog.__init__(self, mw, Qt.Window) + QDialog.__init__(self, mw, Qt.WindowType.Window) self.mw = mw # set on success @@ -39,7 +39,7 @@ class DeckDescriptionDialog(QDialog): def _setup_ui(self) -> None: self.setWindowTitle(tr.scheduling_description()) - self.setWindowModality(Qt.ApplicationModal) + self.setWindowModality(Qt.WindowModality.ApplicationModal) self.mw.garbage_collect_on_dialog_finish(self) self.setMinimumWidth(400) disable_help_button(self) @@ -58,7 +58,7 @@ class DeckDescriptionDialog(QDialog): box.addWidget(self.description) button_box = QDialogButtonBox() - ok = button_box.addButton(QDialogButtonBox.Ok) + ok = button_box.addButton(QDialogButtonBox.StandardButton.Ok) qconnect(ok.clicked, self.save_and_accept) box.addWidget(button_box) diff --git a/qt/aqt/deckoptions.py b/qt/aqt/deckoptions.py index 3a89969d0..76bf44dcb 100644 --- a/qt/aqt/deckoptions.py +++ b/qt/aqt/deckoptions.py @@ -28,14 +28,14 @@ class DeckOptionsDialog(QDialog): silentlyClose = True def __init__(self, mw: aqt.main.AnkiQt, deck: DeckDict) -> None: - QDialog.__init__(self, mw, Qt.Window) + QDialog.__init__(self, mw, Qt.WindowType.Window) self.mw = mw self._deck = deck self._setup_ui() self.show() def _setup_ui(self) -> None: - self.setWindowModality(Qt.ApplicationModal) + self.setWindowModality(Qt.WindowModality.ApplicationModal) self.mw.garbage_collect_on_dialog_finish(self) self.setMinimumWidth(400) disable_help_button(self) diff --git a/qt/aqt/editcurrent.py b/qt/aqt/editcurrent.py index fa934f305..4d841b5bc 100644 --- a/qt/aqt/editcurrent.py +++ b/qt/aqt/editcurrent.py @@ -12,7 +12,7 @@ from aqt.utils import disable_help_button, restoreGeom, saveGeom, tr class EditCurrent(QDialog): def __init__(self, mw: aqt.AnkiQt) -> None: - QDialog.__init__(self, None, Qt.Window) + QDialog.__init__(self, None, Qt.WindowType.Window) mw.garbage_collect_on_dialog_finish(self) self.mw = mw self.form = aqt.forms.editcurrent.Ui_Dialog() @@ -21,7 +21,7 @@ class EditCurrent(QDialog): disable_help_button(self) self.setMinimumHeight(400) self.setMinimumWidth(250) - self.form.buttonBox.button(QDialogButtonBox.Close).setShortcut( + self.form.buttonBox.button(QDialogButtonBox.StandardButton.Close).setShortcut( QKeySequence("Ctrl+Return") ) self.editor = aqt.editor.Editor(self.mw, self.form.fieldsArea, self) diff --git a/qt/aqt/editor.py b/qt/aqt/editor.py index 5fce6df39..620802ed4 100644 --- a/qt/aqt/editor.py +++ b/qt/aqt/editor.py @@ -902,7 +902,7 @@ $editorToolbar.then(({{ toolbar }}) => toolbar.appendGroup({{ @deprecated(info=_js_legacy) def _onHtmlEdit(self, field: int) -> None: - d = QDialog(self.widget, Qt.Window) + d = QDialog(self.widget, Qt.WindowType.Window) form = aqt.forms.edithtml.Ui_Dialog() form.setupUi(d) restoreGeom(d, "htmlEditor") @@ -911,11 +911,11 @@ $editorToolbar.then(({{ toolbar }}) => toolbar.appendGroup({{ form.buttonBox.helpRequested, lambda: openHelp(HelpPage.EDITING_FEATURES) ) font = QFont("Courier") - font.setStyleHint(QFont.TypeWriter) + font.setStyleHint(QFont.StyleHint.TypeWriter) form.textEdit.setFont(font) form.textEdit.setPlainText(self.note.fields[field]) d.show() - form.textEdit.moveCursor(QTextCursor.End) + form.textEdit.moveCursor(QTextCursor.MoveOperation.End) d.exec() html = form.textEdit.toPlainText() if html.find(">") > -1: @@ -997,7 +997,10 @@ $editorToolbar.then(({{ toolbar }}) => toolbar.appendGroup({{ def onChangeCol(self) -> None: if isLin: new = QColorDialog.getColor( - QColor(self.fcolour), None, None, QColorDialog.DontUseNativeDialog + QColor(self.fcolour), + None, + None, + QColorDialog.ColorDialogOption.DontUseNativeDialog, ) else: new = QColorDialog.getColor(QColor(self.fcolour), None) @@ -1118,10 +1121,10 @@ class EditorWebView(AnkiWebView): self._flagAnkiText() def onCut(self) -> None: - self.triggerPageAction(QWebEnginePage.Cut) + self.triggerPageAction(QWebEnginePage.WebAction.Cut) def onCopy(self) -> None: - self.triggerPageAction(QWebEnginePage.Copy) + self.triggerPageAction(QWebEnginePage.WebAction.Copy) def _wantsExtendedPaste(self) -> bool: strip_html = self.editor.mw.col.get_config_bool( @@ -1140,10 +1143,10 @@ class EditorWebView(AnkiWebView): self.editor.doPaste(html, internal, extended) def onPaste(self) -> None: - self._onPaste(QClipboard.Clipboard) + self._onPaste(QClipboard.Mode.Clipboard) def onMiddleClickPaste(self) -> None: - self._onPaste(QClipboard.Selection) + self._onPaste(QClipboard.Mode.Selection) def dragEnterEvent(self, evt: QDragEnterEvent) -> None: evt.accept() diff --git a/qt/aqt/emptycards.py b/qt/aqt/emptycards.py index a84bc309f..1048caddd 100644 --- a/qt/aqt/emptycards.py +++ b/qt/aqt/emptycards.py @@ -63,7 +63,7 @@ class EmptyCardsDialog(QDialog): qconnect(self.finished, on_finished) self._delete_button = self.form.buttonBox.addButton( - tr.empty_cards_delete_button(), QDialogButtonBox.ActionRole + tr.empty_cards_delete_button(), QDialogButtonBox.ButtonRole.ActionRole ) self._delete_button.setAutoDefault(False) qconnect(self._delete_button.clicked, self._on_delete) diff --git a/qt/aqt/exporting.py b/qt/aqt/exporting.py index dbcdf6260..7fbfbe001 100644 --- a/qt/aqt/exporting.py +++ b/qt/aqt/exporting.py @@ -31,7 +31,7 @@ class ExportDialog(QDialog): did: DeckId | None = None, cids: list[CardId] | None = None, ): - QDialog.__init__(self, mw, Qt.Window) + QDialog.__init__(self, mw, Qt.WindowType.Window) self.mw = mw self.col = mw.col.weakref() self.frm = aqt.forms.exporting.Ui_ExportDialog() @@ -64,7 +64,7 @@ class ExportDialog(QDialog): self.frm.deck.addItems(self.decks) # save button b = QPushButton(tr.exporting_export()) - self.frm.buttonBox.addButton(b, QDialogButtonBox.AcceptRole) + self.frm.buttonBox.addButton(b, QDialogButtonBox.ButtonRole.AcceptRole) # set default option if accessed through deck button if did: name = self.mw.col.decks.get(did)["name"] diff --git a/qt/aqt/fields.py b/qt/aqt/fields.py index 9048e935e..00155a79b 100644 --- a/qt/aqt/fields.py +++ b/qt/aqt/fields.py @@ -45,13 +45,19 @@ class FieldDialog(QDialog): without_unicode_isolation(tr.fields_fields_for(val=self.model["name"])) ) disable_help_button(self) - self.form.buttonBox.button(QDialogButtonBox.Help).setAutoDefault(False) - self.form.buttonBox.button(QDialogButtonBox.Cancel).setAutoDefault(False) - self.form.buttonBox.button(QDialogButtonBox.Save).setAutoDefault(False) + self.form.buttonBox.button(QDialogButtonBox.StandardButton.Help).setAutoDefault( + False + ) + self.form.buttonBox.button( + QDialogButtonBox.StandardButton.Cancel + ).setAutoDefault(False) + self.form.buttonBox.button(QDialogButtonBox.StandardButton.Save).setAutoDefault( + False + ) self.currentIdx: Optional[int] = None self.fillFields() self.setupSignals() - self.form.fieldList.setDragDropMode(QAbstractItemView.InternalMove) + self.form.fieldList.setDragDropMode(QAbstractItemView.DragDropMode.InternalMove) self.form.fieldList.dropEvent = self.onDrop # type: ignore[assignment] self.form.fieldList.setCurrentRow(open_at) self.exec() @@ -77,15 +83,21 @@ class FieldDialog(QDialog): def onDrop(self, ev: QDropEvent) -> None: fieldList = self.form.fieldList indicatorPos = fieldList.dropIndicatorPosition() - dropPos = fieldList.indexAt(ev.pos()).row() + if qtmajor == 5: + pos = ev.pos() # type: ignore + else: + pos = ev.position().toPoint() + dropPos = fieldList.indexAt(pos).row() idx = self.currentIdx if dropPos == idx: return - if indicatorPos == QAbstractItemView.OnViewport: # to bottom. + if ( + indicatorPos == QAbstractItemView.DropIndicatorPosition.OnViewport + ): # to bottom. movePos = fieldList.count() - 1 - elif indicatorPos == QAbstractItemView.AboveItem: + elif indicatorPos == QAbstractItemView.DropIndicatorPosition.AboveItem: movePos = dropPos - elif indicatorPos == QAbstractItemView.BelowItem: + elif indicatorPos == QAbstractItemView.DropIndicatorPosition.BelowItem: movePos = dropPos + 1 # the item in idx is removed thus subtract 1. if idx < dropPos: diff --git a/qt/aqt/filtered_deck.py b/qt/aqt/filtered_deck.py index 1876521ba..e225cb0e7 100644 --- a/qt/aqt/filtered_deck.py +++ b/qt/aqt/filtered_deck.py @@ -90,7 +90,7 @@ class FilteredDeckConfigDialog(QDialog): QPushButton[label="hint"] {{ color: {grey} }}""" ) disable_help_button(self) - self.setWindowModality(Qt.WindowModal) + self.setWindowModality(Qt.WindowModality.WindowModal) qconnect( self.form.buttonBox.helpRequested, lambda: openHelp(HelpPage.FILTERED_DECK) ) @@ -117,7 +117,9 @@ class FilteredDeckConfigDialog(QDialog): build_label = tr.actions_rebuild() else: build_label = tr.decks_build() - self.form.buttonBox.button(QDialogButtonBox.Ok).setText(build_label) + self.form.buttonBox.button(QDialogButtonBox.StandardButton.Ok).setText( + build_label + ) form.resched.setChecked(config.reschedule) self._onReschedToggled(0) diff --git a/qt/aqt/forms/findreplace.ui b/qt/aqt/forms/findreplace.ui index 8d08770ab..ec11bbc24 100644 --- a/qt/aqt/forms/findreplace.ui +++ b/qt/aqt/forms/findreplace.ui @@ -6,8 +6,8 @@ 0 0 - 377 - 224 + 479 + 247 @@ -31,7 +31,7 @@ QComboBox::NoInsert - QComboBox::AdjustToMinimumContentsLength + QComboBox::AdjustToMinimumContentsLengthWithIcon @@ -59,7 +59,7 @@ - QComboBox::AdjustToMinimumContentsLength + QComboBox::AdjustToMinimumContentsLengthWithIcon @@ -95,7 +95,7 @@ QComboBox::NoInsert - QComboBox::AdjustToMinimumContentsLength + QComboBox::AdjustToMinimumContentsLengthWithIcon diff --git a/qt/aqt/importing.py b/qt/aqt/importing.py index 46f852e3d..7260ac16f 100644 --- a/qt/aqt/importing.py +++ b/qt/aqt/importing.py @@ -35,7 +35,7 @@ from aqt.utils import ( class ChangeMap(QDialog): def __init__(self, mw: AnkiQt, model: dict, current: str) -> None: - QDialog.__init__(self, mw, Qt.Window) + QDialog.__init__(self, mw, Qt.WindowType.Window) self.mw = mw self.model = model self.frm = aqt.forms.changemap.Ui_ChangeMap() @@ -85,13 +85,14 @@ class ImportDialog(QDialog): _DEFAULT_FILE_DELIMITER = "\t" def __init__(self, mw: AnkiQt, importer: Any) -> None: - QDialog.__init__(self, mw, Qt.Window) + QDialog.__init__(self, mw, Qt.WindowType.Window) self.mw = mw self.importer = importer self.frm = aqt.forms.importing.Ui_ImportDialog() self.frm.setupUi(self) qconnect( - self.frm.buttonBox.button(QDialogButtonBox.Help).clicked, self.helpRequested + self.frm.buttonBox.button(QDialogButtonBox.StandardButton.Help).clicked, + self.helpRequested, ) disable_help_button(self) self.setupMappingFrame() @@ -108,7 +109,7 @@ class ImportDialog(QDialog): self.frm.tagModified.setCol(self.mw.col) # import button b = QPushButton(tr.actions_import()) - self.frm.buttonBox.addButton(b, QDialogButtonBox.AcceptRole) + self.frm.buttonBox.addButton(b, QDialogButtonBox.ButtonRole.AcceptRole) self.exec() def setupOptions(self) -> None: diff --git a/qt/aqt/main.py b/qt/aqt/main.py index 967819ff8..1249e764f 100644 --- a/qt/aqt/main.py +++ b/qt/aqt/main.py @@ -107,10 +107,7 @@ class AnkiQt(QMainWindow): self.pm = profileManager # init rest of app self.safeMode = ( - bool( - cast(Qt.KeyboardModifier, self.app.queryKeyboardModifiers()) - & Qt.ShiftModifier - ) + bool(self.app.queryKeyboardModifiers() & Qt.KeyboardModifier.ShiftModifier) or self.opts.safemode ) try: @@ -817,15 +814,15 @@ title="{}" {}>{}""".format( self.form.setupUi(self) # toolbar tweb = self.toolbarWeb = aqt.webview.AnkiWebView(title="top toolbar") - tweb.setFocusPolicy(Qt.WheelFocus) + tweb.setFocusPolicy(Qt.FocusPolicy.WheelFocus) self.toolbar = aqt.toolbar.Toolbar(self, tweb) # main area self.web = aqt.webview.AnkiWebView(title="main webview") - self.web.setFocusPolicy(Qt.WheelFocus) + self.web.setFocusPolicy(Qt.FocusPolicy.WheelFocus) self.web.setMinimumWidth(400) # bottom area sweb = self.bottomWeb = aqt.webview.AnkiWebView(title="bottom toolbar") - sweb.setFocusPolicy(Qt.WheelFocus) + sweb.setFocusPolicy(Qt.FocusPolicy.WheelFocus) # add in a layout self.mainLayout = QVBoxLayout() self.mainLayout.setContentsMargins(0, 0, 0, 0) @@ -991,7 +988,7 @@ title="{}" {}>{}""".format( def raiseMain(self) -> bool: if not self.app.activeWindow(): # make sure window is shown - self.setWindowState(self.windowState() & ~Qt.WindowMinimized) # type: ignore + self.setWindowState(self.windowState() & ~Qt.WindowState.WindowMinimized) # type: ignore return True def setupStyle(self) -> None: @@ -1393,7 +1390,7 @@ title="{}" {}>{}""".format( frm.setupUi(d) restoreGeom(d, "DebugConsoleWindow") restoreSplitter(frm.splitter, "DebugConsoleWindow") - font = QFontDatabase.systemFont(QFontDatabase.FixedFont) + font = QFontDatabase.systemFont(QFontDatabase.SystemFont.FixedFont) font.setPointSize(frm.text.font().pointSize() + 1) frm.text.setFont(font) frm.log.setFont(font) @@ -1485,7 +1482,7 @@ title="{}" {}>{}""".format( def onDebugPrint(self, frm: aqt.forms.debug.Ui_Dialog) -> None: cursor = frm.text.textCursor() position = cursor.position() - cursor.select(QTextCursor.LineUnderCursor) + cursor.select(QTextCursor.SelectionType.LineUnderCursor) line = cursor.selectedText() pfx, sfx = "pp(", ")" if not line.startswith(pfx): @@ -1566,7 +1563,7 @@ title="{}" {}>{}""".format( cast(QAction, action).setStatusTip("") def onMacMinimize(self) -> None: - self.setWindowState(self.windowState() | Qt.WindowMinimized) # type: ignore + self.setWindowState(self.windowState() | Qt.WindowState.WindowMinimized) # type: ignore # Single instance support ########################################################################## @@ -1606,7 +1603,7 @@ title="{}" {}>{}""".format( if isWin: # on windows we can raise the window by minimizing and restoring self.showMinimized() - self.setWindowState(Qt.WindowActive) + self.setWindowState(Qt.WindowState.WindowActive) self.showNormal() else: # on osx we can raise the window. on unity the icon in the tray will just flash. diff --git a/qt/aqt/mediacheck.py b/qt/aqt/mediacheck.py index 299031444..fd58d4274 100644 --- a/qt/aqt/mediacheck.py +++ b/qt/aqt/mediacheck.py @@ -105,33 +105,33 @@ class MediaChecker: text = QPlainTextEdit() text.setReadOnly(True) text.setPlainText(report) - text.setWordWrapMode(QTextOption.NoWrap) + text.setWordWrapMode(QTextOption.WrapMode.NoWrap) layout.addWidget(text) - box = QDialogButtonBox(QDialogButtonBox.Close) + box = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) layout.addWidget(box) if output.unused: b = QPushButton(tr.media_check_delete_unused()) b.setAutoDefault(False) - box.addButton(b, QDialogButtonBox.RejectRole) + box.addButton(b, QDialogButtonBox.ButtonRole.RejectRole) qconnect(b.clicked, lambda c: self._on_trash_files(output.unused)) if output.missing: if any(map(lambda x: x.startswith("latex-"), output.missing)): b = QPushButton(tr.media_check_render_latex()) b.setAutoDefault(False) - box.addButton(b, QDialogButtonBox.RejectRole) + box.addButton(b, QDialogButtonBox.ButtonRole.RejectRole) qconnect(b.clicked, self._on_render_latex) if output.have_trash: b = QPushButton(tr.media_check_empty_trash()) b.setAutoDefault(False) - box.addButton(b, QDialogButtonBox.RejectRole) + box.addButton(b, QDialogButtonBox.ButtonRole.RejectRole) qconnect(b.clicked, lambda c: self._on_empty_trash()) b = QPushButton(tr.media_check_restore_trash()) b.setAutoDefault(False) - box.addButton(b, QDialogButtonBox.RejectRole) + box.addButton(b, QDialogButtonBox.ButtonRole.RejectRole) qconnect(b.clicked, lambda c: self._on_restore_trash()) qconnect(box.rejected, diag.reject) diff --git a/qt/aqt/mediasync.py b/qt/aqt/mediasync.py index 8b8e4a92d..1c5a366ff 100644 --- a/qt/aqt/mediasync.py +++ b/qt/aqt/mediasync.py @@ -162,7 +162,9 @@ class MediaSyncDialog(QDialog): self.abort_button = QPushButton(tr.sync_abort_button()) qconnect(self.abort_button.clicked, self._on_abort) self.abort_button.setAutoDefault(False) - self.form.buttonBox.addButton(self.abort_button, QDialogButtonBox.ActionRole) + self.form.buttonBox.addButton( + self.abort_button, QDialogButtonBox.ButtonRole.ActionRole + ) self.abort_button.setHidden(not self._syncer.is_syncing()) gui_hooks.media_sync_did_progress.append(self._on_log_entry) @@ -171,7 +173,7 @@ class MediaSyncDialog(QDialog): self.form.plainTextEdit.setPlainText( "\n".join(self._entry_to_text(x) for x in syncer.entries()) ) - self.form.plainTextEdit.moveCursor(QTextCursor.End) + self.form.plainTextEdit.moveCursor(QTextCursor.MoveOperation.End) self.show() def reject(self) -> None: diff --git a/qt/aqt/models.py b/qt/aqt/models.py index e395b3d3d..5904acbda 100644 --- a/qt/aqt/models.py +++ b/qt/aqt/models.py @@ -48,7 +48,7 @@ class Models(QDialog): parent = parent or mw self.fromMain = fromMain self.selected_notetype_id = selected_notetype_id - QDialog.__init__(self, parent, Qt.Window) + QDialog.__init__(self, parent, Qt.WindowType.Window) self.col = mw.col.weakref() assert self.col self.mm = self.col.models @@ -97,7 +97,7 @@ class Models(QDialog): default_buttons.append((tr.notetypes_options(), self.onAdvanced)) for label, func in gui_hooks.models_did_init_buttons(default_buttons, self): - button = box.addButton(label, QDialogButtonBox.ActionRole) + button = box.addButton(label, QDialogButtonBox.ButtonRole.ActionRole) qconnect(button.clicked, func) qconnect(f.modelsList.itemDoubleClicked, self.onRename) @@ -235,7 +235,7 @@ class AddModel(QDialog): self.parent_ = parent or mw self.mw = mw self.col = mw.col - QDialog.__init__(self, self.parent_, Qt.Window) + QDialog.__init__(self, self.parent_, Qt.WindowType.Window) self.model = None self.dialog = aqt.forms.addmodel.Ui_Dialog() self.dialog.setupUi(self) diff --git a/qt/aqt/operations/scheduling.py b/qt/aqt/operations/scheduling.py index 52bc95f01..7cfeea6f8 100644 --- a/qt/aqt/operations/scheduling.py +++ b/qt/aqt/operations/scheduling.py @@ -93,7 +93,7 @@ def reposition_new_cards_dialog( d = QDialog(parent) disable_help_button(d) - d.setWindowModality(Qt.WindowModal) + d.setWindowModality(Qt.WindowModality.WindowModal) frm = aqt.forms.reposition.Ui_Dialog() frm.setupUi(d) diff --git a/qt/aqt/preferences.py b/qt/aqt/preferences.py index 6a163df97..1ebb87e4a 100644 --- a/qt/aqt/preferences.py +++ b/qt/aqt/preferences.py @@ -16,14 +16,18 @@ from aqt.utils import HelpPage, disable_help_button, openHelp, showInfo, showWar class Preferences(QDialog): def __init__(self, mw: AnkiQt) -> None: - QDialog.__init__(self, mw, Qt.Window) + QDialog.__init__(self, mw, Qt.WindowType.Window) self.mw = mw self.prof = self.mw.pm.profile self.form = aqt.forms.preferences.Ui_Preferences() self.form.setupUi(self) disable_help_button(self) - self.form.buttonBox.button(QDialogButtonBox.Help).setAutoDefault(False) - self.form.buttonBox.button(QDialogButtonBox.Close).setAutoDefault(False) + self.form.buttonBox.button(QDialogButtonBox.StandardButton.Help).setAutoDefault( + False + ) + self.form.buttonBox.button( + QDialogButtonBox.StandardButton.Close + ).setAutoDefault(False) qconnect( self.form.buttonBox.helpRequested, lambda: openHelp(HelpPage.PREFERENCES) ) diff --git a/qt/aqt/profiles.py b/qt/aqt/profiles.py index 3832dca5f..ce1fabef6 100644 --- a/qt/aqt/profiles.py +++ b/qt/aqt/profiles.py @@ -461,9 +461,9 @@ create table if not exists profiles code = obj[1] name = obj[0] r = QMessageBox.question( - None, "Anki", tr.profiles_confirm_lang_choice(lang=name), QMessageBox.Yes | QMessageBox.No, QMessageBox.No # type: ignore + None, "Anki", tr.profiles_confirm_lang_choice(lang=name), QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No, QMessageBox.StandardButton.No # type: ignore ) - if r != QMessageBox.Yes: + if r != QMessageBox.StandardButton.Yes: return self.setDefaultLang(f.lang.currentRow()) self.setLang(code) diff --git a/qt/aqt/progress.py b/qt/aqt/progress.py index 2d8b8e290..0e89195e3 100644 --- a/qt/aqt/progress.py +++ b/qt/aqt/progress.py @@ -92,7 +92,7 @@ class ProgressManager: self._win.form.progressBar.setTextVisible(False) self._win.form.label.setText(label) self._win.setWindowTitle("Anki") - self._win.setWindowModality(Qt.ApplicationModal) + self._win.setWindowModality(Qt.WindowModality.ApplicationModal) self._win.setMinimumWidth(300) self._busy_cursor_timer = QTimer(self.mw) self._busy_cursor_timer.setSingleShot(True) @@ -177,7 +177,7 @@ class ProgressManager: elap = time.time() - self._shown if elap >= 0.5: break - self.app.processEvents(QEventLoop.ExcludeUserInputEvents) # type: ignore #possibly related to https://github.com/python/mypy/issues/6910 + self.app.processEvents(QEventLoop.ProcessEventsFlag.ExcludeUserInputEvents) # type: ignore #possibly related to https://github.com/python/mypy/issues/6910 # if the parent window has been deleted, the progress dialog may have # already been dropped; delete it if it hasn't been if not sip.isdeleted(self._win): @@ -186,7 +186,7 @@ class ProgressManager: self._shown = 0 def _set_busy_cursor(self) -> None: - self.mw.app.setOverrideCursor(QCursor(Qt.WaitCursor)) + self.mw.app.setOverrideCursor(QCursor(Qt.CursorShape.WaitCursor)) def _restore_cursor(self) -> None: self.app.restoreOverrideCursor() @@ -235,6 +235,6 @@ class ProgressDialog(QDialog): evt.ignore() def keyPressEvent(self, evt: QKeyEvent) -> None: - if evt.key() == Qt.Key_Escape: + if evt.key() == Qt.Key.Key_Escape: evt.ignore() self.wantCancel = True diff --git a/qt/aqt/qt.py b/qt/aqt/qt.py index 1d53b9fcf..541a3fb8c 100644 --- a/qt/aqt/qt.py +++ b/qt/aqt/qt.py @@ -9,14 +9,34 @@ import sys import traceback from typing import Callable, Union -from PyQt5.Qt import * # type: ignore -from PyQt5.QtCore import * -from PyQt5.QtCore import pyqtRemoveInputHook # pylint: disable=no-name-in-module -from PyQt5.QtGui import * # type: ignore -from PyQt5.QtNetwork import QLocalServer, QLocalSocket, QNetworkProxy -from PyQt5.QtWebChannel import QWebChannel -from PyQt5.QtWebEngineWidgets import * -from PyQt5.QtWidgets import * +try: + from PyQt6 import sip + from PyQt6.QtCore import * + + # conflicting Qt and qFuzzyCompare definitions require an ignore + from PyQt6.QtGui import * # type: ignore[misc] + from PyQt6.QtNetwork import QLocalServer, QLocalSocket, QNetworkProxy + from PyQt6.QtWebChannel import QWebChannel + from PyQt6.QtWebEngineCore import * + from PyQt6.QtWebEngineWidgets import * + from PyQt6.QtWidgets import * +except: + from PyQt5.QtCore import * # type: ignore + from PyQt5.QtGui import * # type: ignore + from PyQt5.QtNetwork import ( # type: ignore + QLocalServer, + QLocalSocket, + QNetworkProxy, + ) + from PyQt5.QtWebChannel import QWebChannel # type: ignore + from PyQt5.QtWebEngineCore import * # type: ignore + from PyQt5.QtWebEngineWidgets import * # type: ignore + from PyQt5.QtWidgets import * # type: ignore + + try: + from PyQt5 import sip # type: ignore + except ImportError: + import sip # type: ignore from anki.utils import isMac, isWin @@ -24,12 +44,6 @@ from anki.utils import isMac, isWin os.environ["LIBOVERLAY_SCROLLBAR"] = "0" -try: - from PyQt5 import sip -except ImportError: - import sip # type: ignore - - def debug() -> None: from pdb import set_trace diff --git a/qt/aqt/qt5.py b/qt/aqt/qt5.py index 401c1fc1a..927eccbf1 100644 --- a/qt/aqt/qt5.py +++ b/qt/aqt/qt5.py @@ -1,6 +1,8 @@ # Copyright: Ankitects Pty Ltd and contributors # License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html +# pylint: skip-file + """ PyQt5-only code """ diff --git a/qt/aqt/reviewer.py b/qt/aqt/reviewer.py index 31ba40529..afc309655 100644 --- a/qt/aqt/reviewer.py +++ b/qt/aqt/reviewer.py @@ -433,11 +433,11 @@ class Reviewer: return [ ("e", self.mw.onEditCurrent), (" ", self.onEnterKey), - (Qt.Key_Return, self.onEnterKey), - (Qt.Key_Enter, self.onEnterKey), + (Qt.Key.Key_Return, self.onEnterKey), + (Qt.Key.Key_Enter, self.onEnterKey), ("m", self.showContextMenu), ("r", self.replayAudio), - (Qt.Key_F5, self.replayAudio), + (Qt.Key.Key_F5, self.replayAudio), *( (f"Ctrl+{flag.index}", self.set_flag_func(flag.index)) for flag in self.mw.flags.all() @@ -875,7 +875,7 @@ time = %(time)d; part2 = tr.studying_minute(count=mins) fin = tr.studying_finish() diag = askUserDialog(f"{part1} {part2}", [tr.studying_continue(), fin]) - diag.setIcon(QMessageBox.Information) + diag.setIcon(QMessageBox.Icon.Information) if diag.run() == fin: self.mw.moveToState("deckBrowser") return True diff --git a/qt/aqt/sound.py b/qt/aqt/sound.py index 3670413b1..b7d3a5c99 100644 --- a/qt/aqt/sound.py +++ b/qt/aqt/sound.py @@ -666,15 +666,18 @@ class RecordDialog(QDialog): hbox.addWidget(self.label) v = QVBoxLayout() v.addLayout(hbox) - buts = QDialogButtonBox.Save | QDialogButtonBox.Cancel + buts = ( + QDialogButtonBox.StandardButton.Save + | QDialogButtonBox.StandardButton.Cancel + ) b = QDialogButtonBox(buts) # type: ignore v.addWidget(b) self.setLayout(v) - save_button = b.button(QDialogButtonBox.Save) + save_button = b.button(QDialogButtonBox.StandardButton.Save) save_button.setDefault(True) save_button.setAutoDefault(True) qconnect(save_button.clicked, self.accept) - cancel_button = b.button(QDialogButtonBox.Cancel) + cancel_button = b.button(QDialogButtonBox.StandardButton.Cancel) cancel_button.setDefault(False) cancel_button.setAutoDefault(False) qconnect(cancel_button.clicked, self.reject) diff --git a/qt/aqt/stats.py b/qt/aqt/stats.py index 755a3d355..cd2b32d5d 100644 --- a/qt/aqt/stats.py +++ b/qt/aqt/stats.py @@ -25,7 +25,7 @@ class NewDeckStats(QDialog): """New deck stats.""" def __init__(self, mw: aqt.main.AnkiQt) -> None: - QDialog.__init__(self, mw, Qt.Window) + QDialog.__init__(self, mw, Qt.WindowType.Window) mw.garbage_collect_on_dialog_finish(self) self.mw = mw self.name = "deckStats" @@ -40,7 +40,9 @@ class NewDeckStats(QDialog): f.groupBox.setVisible(False) f.groupBox_2.setVisible(False) restoreGeom(self, self.name) - b = f.buttonBox.addButton(tr.statistics_save_pdf(), QDialogButtonBox.ActionRole) + b = f.buttonBox.addButton( + tr.statistics_save_pdf(), QDialogButtonBox.ButtonRole.ActionRole + ) qconnect(b.clicked, self.saveImage) b.setAutoDefault(False) maybeHideClose(self.form.buttonBox) @@ -104,7 +106,7 @@ class DeckStats(QDialog): """Legacy deck stats, used by some add-ons.""" def __init__(self, mw: aqt.main.AnkiQt) -> None: - QDialog.__init__(self, mw, Qt.Window) + QDialog.__init__(self, mw, Qt.WindowType.Window) mw.garbage_collect_on_dialog_finish(self) self.mw = mw self.name = "deckStats" @@ -123,7 +125,9 @@ class DeckStats(QDialog): self.setStyleSheet("QGroupBox { border: 0; }") f.setupUi(self) restoreGeom(self, self.name) - b = f.buttonBox.addButton(tr.statistics_save_pdf(), QDialogButtonBox.ActionRole) + b = f.buttonBox.addButton( + tr.statistics_save_pdf(), QDialogButtonBox.ButtonRole.ActionRole + ) qconnect(b.clicked, self.saveImage) b.setAutoDefault(False) qconnect(f.groups.clicked, lambda: self.changeScope("deck")) diff --git a/qt/aqt/studydeck.py b/qt/aqt/studydeck.py index 7403e6437..adc432ca1 100644 --- a/qt/aqt/studydeck.py +++ b/qt/aqt/studydeck.py @@ -49,18 +49,18 @@ class StudyDeck(QDialog): disable_help_button(self) if not cancel: self.form.buttonBox.removeButton( - self.form.buttonBox.button(QDialogButtonBox.Cancel) + self.form.buttonBox.button(QDialogButtonBox.StandardButton.Cancel) ) if buttons is not None: for button_or_label in buttons: self.form.buttonBox.addButton( - button_or_label, QDialogButtonBox.ActionRole + button_or_label, QDialogButtonBox.ButtonRole.ActionRole ) else: b = QPushButton(tr.actions_add()) b.setShortcut(QKeySequence("Ctrl+N")) b.setToolTip(shortcut(tr.decks_add_new_deck_ctrlandn())) - self.form.buttonBox.addButton(b, QDialogButtonBox.ActionRole) + self.form.buttonBox.addButton(b, QDialogButtonBox.ButtonRole.ActionRole) qconnect(b.clicked, self.onAddDeck) if title: self.setWindowTitle(title) @@ -78,9 +78,9 @@ class StudyDeck(QDialog): self.origNames = names() self.name: Optional[str] = None self.ok = self.form.buttonBox.addButton( - accept or tr.decks_study(), QDialogButtonBox.AcceptRole + accept or tr.decks_study(), QDialogButtonBox.ButtonRole.AcceptRole ) - self.setWindowModality(Qt.WindowModal) + self.setWindowModality(Qt.WindowModality.WindowModal) qconnect(self.form.buttonBox.helpRequested, lambda: openHelp(help)) qconnect(self.form.filter.textEdited, self.redraw) qconnect(self.form.list.itemDoubleClicked, self.accept) @@ -90,20 +90,20 @@ class StudyDeck(QDialog): self.exec() def eventFilter(self, obj: QObject, evt: QEvent) -> bool: - if isinstance(evt, QKeyEvent) and evt.type() == QEvent.KeyPress: + if isinstance(evt, QKeyEvent) and evt.type() == QEvent.Type.KeyPress: new_row = current_row = self.form.list.currentRow() rows_count = self.form.list.count() key = evt.key() - if key == Qt.Key_Up: + if key == Qt.Key.Key_Up: new_row = current_row - 1 - elif key == Qt.Key_Down: + elif key == Qt.Key.Key_Down: new_row = current_row + 1 elif ( - int(evt.modifiers()) & Qt.ControlModifier - and Qt.Key_1 <= key <= Qt.Key_9 + evt.modifiers() & Qt.KeyboardModifier.ControlModifier + and Qt.Key.Key_1 <= key <= Qt.Key.Key_9 ): - row_index = key - Qt.Key_1 + row_index = key - Qt.Key.Key_1 if row_index < rows_count: new_row = row_index @@ -126,7 +126,7 @@ class StudyDeck(QDialog): else: idx = 0 l.setCurrentRow(idx) - l.scrollToItem(l.item(idx), QAbstractItemView.PositionAtCenter) + l.scrollToItem(l.item(idx), QAbstractItemView.ScrollHint.PositionAtCenter) def _matches(self, name: str, filt: str) -> bool: name = name.lower() diff --git a/qt/aqt/switch.py b/qt/aqt/switch.py index f9ad05343..2d8a610e1 100644 --- a/qt/aqt/switch.py +++ b/qt/aqt/switch.py @@ -28,7 +28,7 @@ class Switch(QAbstractButton): super().__init__(parent=parent) self.setCheckable(True) super().setChecked(False) - self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) + self.setSizePolicy(QSizePolicy.Policy.Fixed, QSizePolicy.Policy.Fixed) self._left_label = left_label self._right_label = right_label self._left_color = left_color @@ -76,8 +76,8 @@ class Switch(QAbstractButton): def paintEvent(self, _event: QPaintEvent) -> None: painter = QPainter(self) - painter.setRenderHint(QPainter.Antialiasing, True) - painter.setPen(Qt.NoPen) + painter.setRenderHint(QPainter.RenderHint.Antialiasing, True) + painter.setPen(Qt.PenStyle.NoPen) self._paint_path(painter) self._paint_knob(painter) self._paint_label(painter) @@ -113,15 +113,17 @@ class Switch(QAbstractButton): font = painter.font() font.setPixelSize(int(1.2 * self._knob_radius)) painter.setFont(font) - painter.drawText(self._current_knob_rectangle(), Qt.AlignCenter, self.label) + painter.drawText( + self._current_knob_rectangle(), Qt.AlignmentFlag.AlignCenter, self.label + ) def mouseReleaseEvent(self, event: QMouseEvent) -> None: super().mouseReleaseEvent(event) - if event.button() == Qt.LeftButton: + if event.button() == Qt.MouseButton.LeftButton: self._animate_toggle() - def enterEvent(self, event: QEvent) -> None: - self.setCursor(Qt.PointingHandCursor) + def enterEvent(self, event: QEnterEvent) -> None: + self.setCursor(Qt.CursorShape.PointingHandCursor) super().enterEvent(event) def toggle(self) -> None: diff --git a/qt/aqt/sync.py b/qt/aqt/sync.py index f84df9ce8..2da20d933 100644 --- a/qt/aqt/sync.py +++ b/qt/aqt/sync.py @@ -292,7 +292,7 @@ def get_id_and_pass_from_user( diag = QDialog(mw) diag.setWindowTitle("Anki") disable_help_button(diag) - diag.setWindowModality(Qt.WindowModal) + diag.setWindowModality(Qt.WindowModality.WindowModal) vbox = QVBoxLayout() info_label = QLabel( without_unicode_isolation( @@ -313,11 +313,11 @@ def get_id_and_pass_from_user( g.addWidget(l2, 1, 0) passwd = QLineEdit() passwd.setText(password) - passwd.setEchoMode(QLineEdit.Password) + passwd.setEchoMode(QLineEdit.EchoMode.Password) g.addWidget(passwd, 1, 1) vbox.addLayout(g) - bb = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) # type: ignore - bb.button(QDialogButtonBox.Ok).setAutoDefault(True) + bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel) # type: ignore + bb.button(QDialogButtonBox.StandardButton.Ok).setAutoDefault(True) qconnect(bb.accepted, diag.accept) qconnect(bb.rejected, diag.reject) vbox.addWidget(bb) diff --git a/qt/aqt/tagedit.py b/qt/aqt/tagedit.py index 69c31d320..90cbf56ed 100644 --- a/qt/aqt/tagedit.py +++ b/qt/aqt/tagedit.py @@ -26,9 +26,9 @@ class TagEdit(QLineEdit): self._completer = TagCompleter(self.model, parent, self) else: self._completer = QCompleter(self.model, parent) - self._completer.setCompletionMode(QCompleter.PopupCompletion) - self._completer.setCaseSensitivity(Qt.CaseInsensitive) - self._completer.setFilterMode(Qt.MatchContains) + self._completer.setCompletionMode(QCompleter.CompletionMode.PopupCompletion) + self._completer.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive) + self._completer.setFilterMode(Qt.MatchFlag.MatchContains) self.setCompleter(self._completer) def setCol(self, col: Collection) -> None: @@ -45,12 +45,15 @@ class TagEdit(QLineEdit): QLineEdit.focusInEvent(self, evt) def keyPressEvent(self, evt: QKeyEvent) -> None: - if evt.key() in (Qt.Key_Up, Qt.Key_Down): + if evt.key() in (Qt.Key.Key_Up, Qt.Key.Key_Down): # show completer on arrow key up/down if not self._completer.popup().isVisible(): self.showCompleter() return - if evt.key() == Qt.Key_Tab and int(evt.modifiers()) & Qt.ControlModifier: + if ( + evt.key() == Qt.Key.Key_Tab + and evt.modifiers() & Qt.KeyboardModifier.ControlModifier + ): # select next completion if not self._completer.popup().isVisible(): self.showCompleter() @@ -61,7 +64,7 @@ class TagEdit(QLineEdit): self._completer.setCurrentRow(0) return if ( - evt.key() in (Qt.Key_Enter, Qt.Key_Return) + evt.key() in (Qt.Key.Key_Enter, Qt.Key.Key_Return) and self._completer.popup().isVisible() ): # apply first completion if no suggestion selected @@ -78,13 +81,13 @@ class TagEdit(QLineEdit): # if it's a modifier, don't show return if evt.key() not in ( - Qt.Key_Enter, - Qt.Key_Return, - Qt.Key_Escape, - Qt.Key_Space, - Qt.Key_Tab, - Qt.Key_Backspace, - Qt.Key_Delete, + Qt.Key.Key_Enter, + Qt.Key.Key_Return, + Qt.Key.Key_Escape, + Qt.Key.Key_Space, + Qt.Key.Key_Tab, + Qt.Key.Key_Backspace, + Qt.Key.Key_Delete, ): self.showCompleter() gui_hooks.tag_editor_did_process_key(self, evt) diff --git a/qt/aqt/taglimit.py b/qt/aqt/taglimit.py index 1affd4550..0a04ef3ad 100644 --- a/qt/aqt/taglimit.py +++ b/qt/aqt/taglimit.py @@ -13,7 +13,7 @@ from aqt.utils import disable_help_button, restoreGeom, saveGeom, showWarning, t class TagLimit(QDialog): def __init__(self, mw: AnkiQt, parent: CustomStudy) -> None: - QDialog.__init__(self, parent, Qt.Window) + QDialog.__init__(self, parent, Qt.WindowType.Window) self.tags: str = "" self.tags_list: list[str] = [] self.mw = mw @@ -23,11 +23,15 @@ class TagLimit(QDialog): self.dialog.setupUi(self) disable_help_button(self) s = QShortcut( - QKeySequence("ctrl+d"), self.dialog.activeList, context=Qt.WidgetShortcut + QKeySequence("ctrl+d"), + self.dialog.activeList, + context=Qt.ShortcutContext.WidgetShortcut, ) qconnect(s.activated, self.dialog.activeList.clearSelection) s = QShortcut( - QKeySequence("ctrl+d"), self.dialog.inactiveList, context=Qt.WidgetShortcut + QKeySequence("ctrl+d"), + self.dialog.inactiveList, + context=Qt.ShortcutContext.WidgetShortcut, ) qconnect(s.activated, self.dialog.inactiveList.clearSelection) self.rebuildTagList() @@ -54,19 +58,19 @@ class TagLimit(QDialog): item = QListWidgetItem(t.replace("_", " ")) self.dialog.activeList.addItem(item) if t in yesHash: - mode = QItemSelectionModel.Select + mode = QItemSelectionModel.SelectionFlag.Select self.dialog.activeCheck.setChecked(True) else: - mode = QItemSelectionModel.Deselect + mode = QItemSelectionModel.SelectionFlag.Deselect idx = self.dialog.activeList.indexFromItem(item) self.dialog.activeList.selectionModel().select(idx, mode) # inactive item = QListWidgetItem(t.replace("_", " ")) self.dialog.inactiveList.addItem(item) if t in noHash: - mode = QItemSelectionModel.Select + mode = QItemSelectionModel.SelectionFlag.Select else: - mode = QItemSelectionModel.Deselect + mode = QItemSelectionModel.SelectionFlag.Deselect idx = self.dialog.inactiveList.indexFromItem(item) self.dialog.inactiveList.selectionModel().select(idx, mode) diff --git a/qt/aqt/theme.py b/qt/aqt/theme.py index 5148b8228..f95799d50 100644 --- a/qt/aqt/theme.py +++ b/qt/aqt/theme.py @@ -92,7 +92,9 @@ class ThemeManager: icon = QIcon(path.path) pixmap = icon.pixmap(16) painter = QPainter(pixmap) - painter.setCompositionMode(QPainter.CompositionMode_SourceIn) + painter.setCompositionMode( + QPainter.CompositionMode.CompositionMode_SourceIn + ) painter.fillRect(pixmap.rect(), QColor(path.current_color(self.night_mode))) painter.end() icon = QIcon(pixmap) @@ -207,34 +209,44 @@ QTabWidget {{ background-color: {}; }} palette = QPalette() text_fg = self.qcolor(colors.TEXT_FG) - palette.setColor(QPalette.WindowText, text_fg) - palette.setColor(QPalette.ToolTipText, text_fg) - palette.setColor(QPalette.Text, text_fg) - palette.setColor(QPalette.ButtonText, text_fg) + palette.setColor(QPalette.ColorRole.WindowText, text_fg) + palette.setColor(QPalette.ColorRole.ToolTipText, text_fg) + palette.setColor(QPalette.ColorRole.Text, text_fg) + palette.setColor(QPalette.ColorRole.ButtonText, text_fg) hlbg = self.qcolor(colors.HIGHLIGHT_BG) hlbg.setAlpha(64) - palette.setColor(QPalette.HighlightedText, self.qcolor(colors.HIGHLIGHT_FG)) - palette.setColor(QPalette.Highlight, hlbg) + palette.setColor( + QPalette.ColorRole.HighlightedText, self.qcolor(colors.HIGHLIGHT_FG) + ) + palette.setColor(QPalette.ColorRole.Highlight, hlbg) window_bg = self.qcolor(colors.WINDOW_BG) - palette.setColor(QPalette.Window, window_bg) - palette.setColor(QPalette.AlternateBase, window_bg) + palette.setColor(QPalette.ColorRole.Window, window_bg) + palette.setColor(QPalette.ColorRole.AlternateBase, window_bg) - palette.setColor(QPalette.Button, QColor("#454545")) + palette.setColor(QPalette.ColorRole.Button, QColor("#454545")) frame_bg = self.qcolor(colors.FRAME_BG) - palette.setColor(QPalette.Base, frame_bg) - palette.setColor(QPalette.ToolTipBase, frame_bg) + palette.setColor(QPalette.ColorRole.Base, frame_bg) + palette.setColor(QPalette.ColorRole.ToolTipBase, frame_bg) disabled_color = self.qcolor(colors.DISABLED) - palette.setColor(QPalette.Disabled, QPalette.Text, disabled_color) - palette.setColor(QPalette.Disabled, QPalette.ButtonText, disabled_color) - palette.setColor(QPalette.Disabled, QPalette.HighlightedText, disabled_color) + palette.setColor( + QPalette.ColorGroup.Disabled, QPalette.ColorRole.Text, disabled_color + ) + palette.setColor( + QPalette.ColorGroup.Disabled, QPalette.ColorRole.ButtonText, disabled_color + ) + palette.setColor( + QPalette.ColorGroup.Disabled, + QPalette.ColorRole.HighlightedText, + disabled_color, + ) - palette.setColor(QPalette.Link, self.qcolor(colors.LINK)) + palette.setColor(QPalette.ColorRole.Link, self.qcolor(colors.LINK)) - palette.setColor(QPalette.BrightText, Qt.red) + palette.setColor(QPalette.ColorRole.BrightText, Qt.GlobalColor.red) app.setPalette(palette) diff --git a/qt/aqt/update.py b/qt/aqt/update.py index 912c0beae..4b5a00fbd 100644 --- a/qt/aqt/update.py +++ b/qt/aqt/update.py @@ -59,17 +59,17 @@ class LatestVersionFinder(QThread): def askAndUpdate(mw: aqt.AnkiQt, ver: str) -> None: baseStr = tr.qt_misc_anki_updatedanki_has_been_released(val=ver) msg = QMessageBox(mw) - msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No) # type: ignore - msg.setIcon(QMessageBox.Information) + msg.setStandardButtons(QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No) # type: ignore + msg.setIcon(QMessageBox.Icon.Information) msg.setText(baseStr + tr.qt_misc_would_you_like_to_download_it()) button = QPushButton(tr.qt_misc_ignore_this_update()) - msg.addButton(button, QMessageBox.RejectRole) - msg.setDefaultButton(QMessageBox.Yes) + msg.addButton(button, QMessageBox.ButtonRole.RejectRole) + msg.setDefaultButton(QMessageBox.StandardButton.Yes) ret = msg.exec() if msg.clickedButton() == button: # ignore this update mw.pm.meta["suppressUpdate"] = ver - elif ret == QMessageBox.Yes: + elif ret == QMessageBox.StandardButton.Yes: openLink(aqt.appWebsite) diff --git a/qt/aqt/utils.py b/qt/aqt/utils.py index 1aa282820..3d8dd4120 100644 --- a/qt/aqt/utils.py +++ b/qt/aqt/utils.py @@ -7,7 +7,7 @@ import re import subprocess import sys from functools import wraps -from typing import TYPE_CHECKING, Any, Literal, Sequence, cast +from typing import TYPE_CHECKING, Any, Literal, Sequence import aqt from anki.collection import Collection, HelpPage @@ -96,16 +96,16 @@ def showInfo( else: parent_widget = parent if type == "warning": - icon = QMessageBox.Warning + icon = QMessageBox.Icon.Warning elif type == "critical": - icon = QMessageBox.Critical + icon = QMessageBox.Icon.Critical else: - icon = QMessageBox.Information + icon = QMessageBox.Icon.Information mb = QMessageBox(parent_widget) # if textFormat == "plain": - mb.setTextFormat(Qt.PlainText) + mb.setTextFormat(Qt.TextFormat.PlainText) elif textFormat == "rich": - mb.setTextFormat(Qt.RichText) + mb.setTextFormat(Qt.TextFormat.RichText) elif textFormat is not None: raise Exception("unexpected textFormat type") mb.setText(text) @@ -119,10 +119,10 @@ def showInfo( default = b mb.setDefaultButton(default) else: - b = mb.addButton(QMessageBox.Ok) + b = mb.addButton(QMessageBox.StandardButton.Ok) b.setDefault(True) if help: - b = mb.addButton(QMessageBox.Help) + b = mb.addButton(QMessageBox.StandardButton.Help) qconnect(b.clicked, lambda: openHelp(help)) b.setAutoDefault(False) return mb.exec() @@ -152,7 +152,7 @@ def showText( # used by the importer text = QPlainTextEdit() text.setReadOnly(True) - text.setWordWrapMode(QTextOption.NoWrap) + text.setWordWrapMode(QTextOption.WrapMode.NoWrap) text.setPlainText(txt) else: text = QTextBrowser() @@ -162,7 +162,7 @@ def showText( else: text.setHtml(txt) layout.addWidget(text) - box = QDialogButtonBox(QDialogButtonBox.Close) + box = QDialogButtonBox(QDialogButtonBox.StandardButton.Close) layout.addWidget(box) if copyBtn: @@ -171,7 +171,7 @@ def showText( btn = QPushButton(tr.qt_misc_copy_to_clipboard()) qconnect(btn.clicked, onCopy) - box.addButton(btn, QDialogButtonBox.ActionRole) + box.addButton(btn, QDialogButtonBox.ButtonRole.ActionRole) def onReject() -> None: if geomKey: @@ -209,20 +209,20 @@ def askUser( parent = aqt.mw.app.activeWindow() if not msgfunc: msgfunc = QMessageBox.question - sb = QMessageBox.Yes | QMessageBox.No + sb = QMessageBox.StandardButton.Yes | QMessageBox.StandardButton.No if help: - sb |= QMessageBox.Help + sb |= QMessageBox.StandardButton.Help while 1: if defaultno: - default = QMessageBox.No + default = QMessageBox.StandardButton.No else: - default = QMessageBox.Yes - r = msgfunc(parent, title, text, cast(QMessageBox.StandardButtons, sb), default) - if r == QMessageBox.Help: + default = QMessageBox.StandardButton.Yes + r = msgfunc(parent, title, text, sb, default) + if r == QMessageBox.StandardButton.Help: openHelp(help) else: break - return r == QMessageBox.Yes + return r == QMessageBox.StandardButton.Yes class ButtonedDialog(QMessageBox): @@ -238,12 +238,12 @@ class ButtonedDialog(QMessageBox): self._buttons: list[QPushButton] = [] self.setWindowTitle(title) self.help = help - self.setIcon(QMessageBox.Warning) + self.setIcon(QMessageBox.Icon.Warning) self.setText(text) for b in buttons: - self._buttons.append(self.addButton(b, QMessageBox.AcceptRole)) + self._buttons.append(self.addButton(b, QMessageBox.ButtonRole.AcceptRole)) if help: - self.addButton(tr.actions_help(), QMessageBox.HelpRole) + self.addButton(tr.actions_help(), QMessageBox.ButtonRole.HelpRole) buttons.append(tr.actions_help()) def run(self) -> str: @@ -300,16 +300,21 @@ class GetTextDialog(QDialog): self.l.setText(default) self.l.selectAll() v.addWidget(self.l) - buts = QDialogButtonBox.Ok | QDialogButtonBox.Cancel + buts = ( + QDialogButtonBox.StandardButton.Ok | QDialogButtonBox.StandardButton.Cancel + ) if help: - buts |= QDialogButtonBox.Help + buts |= QDialogButtonBox.StandardButton.Help b = QDialogButtonBox(buts) # type: ignore v.addWidget(b) self.setLayout(v) - qconnect(b.button(QDialogButtonBox.Ok).clicked, self.accept) - qconnect(b.button(QDialogButtonBox.Cancel).clicked, self.reject) + qconnect(b.button(QDialogButtonBox.StandardButton.Ok).clicked, self.accept) + qconnect(b.button(QDialogButtonBox.StandardButton.Cancel).clicked, self.reject) if help: - qconnect(b.button(QDialogButtonBox.Help).clicked, self.helpRequested) + qconnect( + b.button(QDialogButtonBox.StandardButton.Help).clicked, + self.helpRequested, + ) def accept(self) -> None: return QDialog.accept(self) @@ -337,7 +342,7 @@ def getText( d = GetTextDialog( parent, prompt, help=help, edit=edit, default=default, title=title, **kwargs ) - d.setWindowModality(Qt.WindowModal) + d.setWindowModality(Qt.WindowModality.WindowModal) if geomKey: restoreGeom(d, geomKey) ret = d.exec() @@ -363,7 +368,7 @@ def chooseList( parent = aqt.mw.app.activeWindow() d = QDialog(parent) disable_help_button(d) - d.setWindowModality(Qt.WindowModal) + d.setWindowModality(Qt.WindowModality.WindowModal) l = QVBoxLayout() d.setLayout(l) t = QLabel(prompt) @@ -372,7 +377,7 @@ def chooseList( c.addItems(choices) c.setCurrentRow(startrow) l.addWidget(c) - bb = QDialogButtonBox(QDialogButtonBox.Ok) + bb = QDialogButtonBox(QDialogButtonBox.StandardButton.Ok) qconnect(bb.accepted, d.accept) l.addWidget(bb) d.exec() @@ -393,9 +398,9 @@ def getTag( def disable_help_button(widget: QWidget) -> None: "Disable the help button in the window titlebar." - flags_int = int(widget.windowFlags()) & ~Qt.WindowContextHelpButtonHint - flags = Qt.WindowFlags(flags_int) # type: ignore - widget.setWindowFlags(flags) + widget.setWindowFlags( + widget.windowFlags() & ~Qt.WindowType.WindowContextHelpButtonHint + ) # File handling @@ -420,7 +425,11 @@ def getFile( else: dirkey = None d = QFileDialog(parent) - mode = QFileDialog.ExistingFiles if multi else QFileDialog.ExistingFile + mode = ( + QFileDialog.FileMode.ExistingFiles + if multi + else QFileDialog.FileMode.ExistingFile + ) d.setFileMode(mode) if os.path.exists(dir): d.setDirectory(dir) @@ -459,7 +468,9 @@ def getSaveFile( variable. The file dialog will default to open with FNAME.""" config_key = f"{dir_description}Directory" - defaultPath = QStandardPaths.writableLocation(QStandardPaths.DocumentsLocation) + defaultPath = QStandardPaths.writableLocation( + QStandardPaths.StandardLocation.DocumentsLocation + ) base = aqt.mw.pm.profile.get(config_key, defaultPath) path = os.path.join(base, fname) file = QFileDialog.getSaveFileName( @@ -467,7 +478,7 @@ def getSaveFile( title, path, f"{key} (*{ext})", - options=QFileDialog.DontConfirmOverwrite, + options=QFileDialog.Option.DontConfirmOverwrite, )[0] if file: # add extension @@ -485,7 +496,7 @@ def getSaveFile( def saveGeom(widget: QWidget, key: str) -> None: key += "Geom" - if isMac and int(widget.windowState()) & Qt.WindowFullScreen: + if isMac and (widget.windowState() & Qt.WindowState.WindowFullScreen): geom = None else: geom = widget.saveGeometry() @@ -646,7 +657,7 @@ def shortcut(key: str) -> str: def maybeHideClose(bbox: QDialogButtonBox) -> None: if isMac: - b = bbox.button(QDialogButtonBox.Close) + b = bbox.button(QDialogButtonBox.StandardButton.Close) if b: bbox.removeButton(b) @@ -706,13 +717,13 @@ def tooltip( """, aw, ) - lab.setFrameStyle(QFrame.Panel) + lab.setFrameStyle(QFrame.Shape.Panel) lab.setLineWidth(2) - lab.setWindowFlags(Qt.ToolTip) + lab.setWindowFlags(Qt.WindowType.ToolTip) if not theme_manager.night_mode: p = QPalette() - p.setColor(QPalette.Window, QColor("#feffc4")) - p.setColor(QPalette.WindowText, QColor("#000000")) + p.setColor(QPalette.ColorRole.Window, QColor("#feffc4")) + p.setColor(QPalette.ColorRole.WindowText, QColor("#000000")) lab.setPalette(p) lab.move(aw.mapToGlobal(QPoint(0 + x_offset, aw.height() - y_offset))) lab.show() @@ -888,7 +899,7 @@ def opengl_vendor() -> str | None: # Can't use versionFunctions there return None - vp = QOpenGLVersionProfile() # type: ignore + vp = QOpenGLVersionProfile() # type: ignore # pylint: disable=undefined-variable vp.setVersion(2, 0) try: @@ -969,16 +980,16 @@ class KeyboardModifiersPressed: def __init__(self) -> None: from aqt import mw - self._modifiers = int(mw.app.keyboardModifiers()) + self._modifiers = mw.app.keyboardModifiers() @property def shift(self) -> bool: - return bool(self._modifiers & Qt.ShiftModifier) + return bool(self._modifiers & Qt.KeyboardModifier.ShiftModifier) @property def control(self) -> bool: - return bool(self._modifiers & Qt.ControlModifier) + return bool(self._modifiers & Qt.KeyboardModifier.ControlModifier) @property def alt(self) -> bool: - return bool(self._modifiers & Qt.AltModifier) + return bool(self._modifiers & Qt.KeyboardModifier.AltModifier) diff --git a/qt/aqt/webview.py b/qt/aqt/webview.py index 9b7399489..72c0cb976 100644 --- a/qt/aqt/webview.py +++ b/qt/aqt/webview.py @@ -48,7 +48,7 @@ class AnkiWebPage(QWebEnginePage): qwebchannel = ":/qtwebchannel/qwebchannel.js" jsfile = QFile(qwebchannel) - if not jsfile.open(QIODevice.ReadOnly): + if not jsfile.open(QIODevice.OpenModeFlag.ReadOnly): print(f"Error opening '{qwebchannel}': {jsfile.error()}", file=sys.stderr) jstext = bytes(cast(bytes, jsfile.readAll())).decode("utf-8") jsfile.close() @@ -74,8 +74,8 @@ class AnkiWebPage(QWebEnginePage): }); """ ) - script.setWorldId(QWebEngineScript.MainWorld) - script.setInjectionPoint(QWebEngineScript.DocumentReady) + script.setWorldId(QWebEngineScript.ScriptWorldId.MainWorld) + script.setInjectionPoint(QWebEngineScript.InjectionPoint.DocumentReady) script.setRunsOnSubFrames(False) self.profile().scripts().insert(script) @@ -92,11 +92,11 @@ class AnkiWebPage(QWebEnginePage): srcID = "" else: srcID = serverbaseurl.sub("", srcID[:80], 1) - if level == QWebEnginePage.InfoMessageLevel: + if level == QWebEnginePage.JavaScriptConsoleMessageLevel.InfoMessageLevel: level_str = "info" - elif level == QWebEnginePage.WarningMessageLevel: + elif level == QWebEnginePage.JavaScriptConsoleMessageLevel.WarningMessageLevel: level_str = "warning" - elif level == QWebEnginePage.ErrorMessageLevel: + elif level == QWebEnginePage.JavaScriptConsoleMessageLevel.ErrorMessageLevel: level_str = "error" else: level_str = str(level) @@ -135,7 +135,9 @@ class AnkiWebPage(QWebEnginePage): # catch buggy links from aqt import mw - if url.matches(QUrl(mw.serverURL()), cast(Any, QUrl.RemoveFragment)): + if url.matches( + QUrl(mw.serverURL()), cast(Any, QUrl.UrlFormattingOption.RemoveFragment) + ): print("onclick handler needs to return false") return False # load all other links in browser @@ -240,14 +242,14 @@ class AnkiWebView(QWebEngineView): self.requiresCol = True self.setPage(self._page) - self._page.profile().setHttpCacheType(QWebEngineProfile.NoCache) + self._page.profile().setHttpCacheType(QWebEngineProfile.HttpCacheType.NoCache) self.resetHandlers() self.allowDrops = False self._filterSet = False QShortcut( # type: ignore QKeySequence("Esc"), self, - context=Qt.WidgetWithChildrenShortcut, + context=Qt.ShortcutContext.WidgetWithChildrenShortcut, activated=self.onEsc, ) @@ -258,8 +260,11 @@ class AnkiWebView(QWebEngineView): # disable pinch to zoom gesture if isinstance(evt, QNativeGestureEvent): return True - elif isinstance(evt, QMouseEvent) and evt.type() == QEvent.MouseButtonRelease: - if evt.button() == Qt.MidButton and isLin: + elif ( + isinstance(evt, QMouseEvent) + and evt.type() == QEvent.Type.MouseButtonRelease + ): + if evt.button() == Qt.MouseButton.MiddleButton and isLin: self.onMiddleClickPaste() return True return False @@ -286,19 +291,19 @@ class AnkiWebView(QWebEngineView): w = w.parent() def onCopy(self) -> None: - self.triggerPageAction(QWebEnginePage.Copy) + self.triggerPageAction(QWebEnginePage.WebAction.Copy) def onCut(self) -> None: - self.triggerPageAction(QWebEnginePage.Cut) + self.triggerPageAction(QWebEnginePage.WebAction.Cut) def onPaste(self) -> None: - self.triggerPageAction(QWebEnginePage.Paste) + self.triggerPageAction(QWebEnginePage.WebAction.Paste) def onMiddleClickPaste(self) -> None: - self.triggerPageAction(QWebEnginePage.Paste) + self.triggerPageAction(QWebEnginePage.WebAction.Paste) def onSelectAll(self) -> None: - self.triggerPageAction(QWebEnginePage.SelectAll) + self.triggerPageAction(QWebEnginePage.WebAction.SelectAll) def contextMenuEvent(self, evt: QContextMenuEvent) -> None: m = QMenu(self) @@ -386,11 +391,11 @@ class AnkiWebView(QWebEngineView): # standard palette does not return correct window color on macOS return QColor("#ececec") else: - return theme_manager.default_palette.color(QPalette.Window) + return theme_manager.default_palette.color(QPalette.ColorRole.Window) def standard_css(self) -> str: palette = theme_manager.default_palette - color_hl = palette.color(QPalette.Highlight).name() + color_hl = palette.color(QPalette.ColorRole.Highlight).name() if isWin: # T: include a font for your language on Windows, eg: "Segoe UI", "MS Mincho" @@ -406,8 +411,8 @@ button { -webkit-appearance: none; background: #fff; border: 1px solid #ccc; border-radius:5px; font-family: Helvetica }""" else: family = self.font().family() - color_hl_txt = palette.color(QPalette.HighlightedText).name() - color_btn = palette.color(QPalette.Button).name() + color_hl_txt = palette.color(QPalette.ColorRole.HighlightedText).name() + color_btn = palette.color(QPalette.ColorRole.Button).name() font = f'font-size:14px;font-family:"{family}";' button_style = """ /* Buttons */ diff --git a/qt/dmypy.py b/qt/dmypy.py index 968061146..f8c420c35 100755 --- a/qt/dmypy.py +++ b/qt/dmypy.py @@ -36,7 +36,7 @@ if subprocess.run( os.path.abspath("pip/stubs/extendsitepkgs"), ], env={ - "MYPYPATH": "bazel-bin/qt/dmypy.runfiles/pyqt5", + "MYPYPATH": "bazel-bin/qt/dmypy.runfiles/pyqt6", "EXTRA_SITE_PACKAGES": os.path.abspath(os.getenv("EXTRA_SITE_PACKAGES")), }, cwd=workspace, diff --git a/qt/mypy.ini b/qt/mypy.ini index c8dcf12e9..cff9c7490 100644 --- a/qt/mypy.ini +++ b/qt/mypy.ini @@ -54,6 +54,7 @@ ignore_missing_imports = True ignore_missing_imports = True [mypy-PyQt5.*] ignore_errors = True +ignore_missing_imports = True [mypy-win32com.client] ignore_missing_imports = True [mypy-darkdetect]