mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
add types to utils.py
The function signatures for things like getFile() are awful, but sadly are used by a bunch of add-ons.
This commit is contained in:
parent
08b76e4489
commit
98f4b3db81
8 changed files with 210 additions and 121 deletions
|
@ -867,9 +867,10 @@ class AddonsDialog(QDialog):
|
|||
def onInstallFiles(self, paths: Optional[List[str]] = None) -> Optional[bool]:
|
||||
if not paths:
|
||||
key = tr(TR.ADDONS_PACKAGED_ANKI_ADDON) + " (*{})".format(self.mgr.ext)
|
||||
paths = getFile(
|
||||
paths_ = getFile(
|
||||
self, tr(TR.ADDONS_INSTALL_ADDONS), None, key, key="addons", multi=True
|
||||
)
|
||||
paths = paths_ # type: ignore
|
||||
if not paths:
|
||||
return False
|
||||
|
||||
|
|
|
@ -607,14 +607,14 @@ class CardLayout(QDialog):
|
|||
n = len(self.templates)
|
||||
template = self.current_template()
|
||||
current_pos = self.templates.index(template) + 1
|
||||
pos = getOnlyText(
|
||||
pos_txt = getOnlyText(
|
||||
tr(TR.CARD_TEMPLATES_ENTER_NEW_CARD_POSITION_1, val=n),
|
||||
default=str(current_pos),
|
||||
)
|
||||
if not pos:
|
||||
if not pos_txt:
|
||||
return
|
||||
try:
|
||||
pos = int(pos)
|
||||
pos = int(pos_txt)
|
||||
except ValueError:
|
||||
return
|
||||
if pos < 1 or pos > n:
|
||||
|
|
|
@ -256,7 +256,8 @@ class DeckBrowser:
|
|||
self.mw.col.decks.rename(deck, newName)
|
||||
gui_hooks.sidebar_should_refresh_decks()
|
||||
except DeckRenameError as e:
|
||||
return showWarning(e.description)
|
||||
showWarning(e.description)
|
||||
return
|
||||
self.show()
|
||||
|
||||
def _options(self, did):
|
||||
|
|
|
@ -12,7 +12,7 @@ import urllib.parse
|
|||
import urllib.request
|
||||
import warnings
|
||||
from random import randrange
|
||||
from typing import Any, Callable, Dict, List, Match, Optional, Tuple
|
||||
from typing import Any, Callable, Dict, List, Match, Optional, Tuple, cast
|
||||
|
||||
import bs4
|
||||
import requests
|
||||
|
@ -750,7 +750,13 @@ class Editor:
|
|||
def accept(file: str) -> None:
|
||||
self.addMedia(file, canDelete=True)
|
||||
|
||||
file = getFile(self.widget, tr(TR.EDITING_ADD_MEDIA), accept, key, key="media")
|
||||
file = getFile(
|
||||
self.widget,
|
||||
tr(TR.EDITING_ADD_MEDIA),
|
||||
cast(Callable[[Any], None], accept),
|
||||
key,
|
||||
key="media",
|
||||
)
|
||||
self.parentWindow.activateWindow()
|
||||
|
||||
def addMedia(self, path: str, canDelete: bool = False) -> None:
|
||||
|
|
|
@ -1530,14 +1530,15 @@ title="%s" %s>%s</button>""" % (
|
|||
def setupAppMsg(self) -> None:
|
||||
qconnect(self.app.appMsg, self.onAppMsg)
|
||||
|
||||
def onAppMsg(self, buf: str) -> Optional[QTimer]:
|
||||
def onAppMsg(self, buf: str) -> None:
|
||||
is_addon = self._isAddon(buf)
|
||||
|
||||
if self.state == "startup":
|
||||
# try again in a second
|
||||
return self.progress.timer(
|
||||
self.progress.timer(
|
||||
1000, lambda: self.onAppMsg(buf), False, requiresCollection=False
|
||||
)
|
||||
return
|
||||
elif self.state == "profileManager":
|
||||
# can't raise window while in profile manager
|
||||
if buf == "raise":
|
||||
|
@ -1547,7 +1548,8 @@ title="%s" %s>%s</button>""" % (
|
|||
msg = tr(TR.QT_MISC_ADDON_WILL_BE_INSTALLED_WHEN_A)
|
||||
else:
|
||||
msg = tr(TR.QT_MISC_DECK_WILL_BE_IMPORTED_WHEN_A)
|
||||
return tooltip(msg)
|
||||
tooltip(msg)
|
||||
return
|
||||
if not self.interactiveState() or self.progress.busy():
|
||||
# we can't raise the main window while in profile dialog, syncing, etc
|
||||
if buf != "raise":
|
||||
|
|
|
@ -696,7 +696,8 @@ class SidebarTreeView(QTreeView):
|
|||
try:
|
||||
self.mw.col.decks.rename(deck, new_name)
|
||||
except DeckRenameError as e:
|
||||
return showWarning(e.description)
|
||||
showWarning(e.description)
|
||||
return
|
||||
self.refresh()
|
||||
self.mw.deckBrowser.refresh()
|
||||
|
||||
|
|
296
qt/aqt/utils.py
296
qt/aqt/utils.py
|
@ -8,12 +8,35 @@ import re
|
|||
import subprocess
|
||||
import sys
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Any, List, Literal, Optional, Union, cast
|
||||
from typing import (
|
||||
TYPE_CHECKING,
|
||||
Any,
|
||||
Callable,
|
||||
List,
|
||||
Literal,
|
||||
Optional,
|
||||
Sequence,
|
||||
Tuple,
|
||||
Union,
|
||||
cast,
|
||||
)
|
||||
|
||||
from markdown import markdown
|
||||
from PyQt5.QtWidgets import (
|
||||
QAction,
|
||||
QDialog,
|
||||
QDialogButtonBox,
|
||||
QFileDialog,
|
||||
QHeaderView,
|
||||
QMenu,
|
||||
QPushButton,
|
||||
QSplitter,
|
||||
QWidget,
|
||||
)
|
||||
|
||||
import anki
|
||||
import aqt
|
||||
from anki import Collection
|
||||
from anki.errors import InvalidInput
|
||||
from anki.lang import TR # pylint: disable=unused-import
|
||||
from anki.utils import invalidFilename, isMac, isWin, noBundledLibs, versionWithBuild
|
||||
|
@ -77,7 +100,7 @@ argument. However, add-on may use string, and we want to accept this.
|
|||
"""
|
||||
|
||||
|
||||
def openHelp(section: HelpPageArgument):
|
||||
def openHelp(section: HelpPageArgument) -> None:
|
||||
link = aqt.appHelpSite
|
||||
if section:
|
||||
if isinstance(section, HelpPage):
|
||||
|
@ -87,27 +110,35 @@ def openHelp(section: HelpPageArgument):
|
|||
openLink(link)
|
||||
|
||||
|
||||
def openLink(link):
|
||||
def openLink(link: str) -> None:
|
||||
tooltip(tr(TR.QT_MISC_LOADING), period=1000)
|
||||
with noBundledLibs():
|
||||
QDesktopServices.openUrl(QUrl(link))
|
||||
|
||||
|
||||
def showWarning(
|
||||
text, parent=None, help="", title="Anki", textFormat: Optional[TextFormat] = None
|
||||
):
|
||||
text: str,
|
||||
parent: Optional[QDialog] = None,
|
||||
help: HelpPageArgument = "",
|
||||
title: str = "Anki",
|
||||
textFormat: Optional[TextFormat] = None,
|
||||
) -> int:
|
||||
"Show a small warning with an OK button."
|
||||
return showInfo(text, parent, help, "warning", title=title, textFormat=textFormat)
|
||||
|
||||
|
||||
def showCritical(
|
||||
text, parent=None, help="", title="Anki", textFormat: Optional[TextFormat] = None
|
||||
):
|
||||
text: str,
|
||||
parent: Optional[QDialog] = None,
|
||||
help: str = "",
|
||||
title: str = "Anki",
|
||||
textFormat: Optional[TextFormat] = None,
|
||||
) -> int:
|
||||
"Show a small critical error with an OK button."
|
||||
return showInfo(text, parent, help, "critical", title=title, textFormat=textFormat)
|
||||
|
||||
|
||||
def show_invalid_search_error(err: Exception):
|
||||
def show_invalid_search_error(err: Exception) -> None:
|
||||
"Render search errors in markdown, then display a warning."
|
||||
text = str(err)
|
||||
if isinstance(err, InvalidInput):
|
||||
|
@ -116,24 +147,27 @@ def show_invalid_search_error(err: Exception):
|
|||
|
||||
|
||||
def showInfo(
|
||||
text,
|
||||
parent=False,
|
||||
help="",
|
||||
type="info",
|
||||
title="Anki",
|
||||
text: str,
|
||||
parent: Union[Literal[False], QDialog] = False,
|
||||
help: HelpPageArgument = "",
|
||||
type: str = "info",
|
||||
title: str = "Anki",
|
||||
textFormat: Optional[TextFormat] = None,
|
||||
customBtns=None,
|
||||
customBtns: Optional[List[QMessageBox.StandardButton]] = None,
|
||||
) -> int:
|
||||
"Show a small info window with an OK button."
|
||||
parent_widget: QWidget
|
||||
if parent is False:
|
||||
parent = aqt.mw.app.activeWindow() or aqt.mw
|
||||
parent_widget = aqt.mw.app.activeWindow() or aqt.mw
|
||||
else:
|
||||
parent_widget = parent
|
||||
if type == "warning":
|
||||
icon = QMessageBox.Warning
|
||||
elif type == "critical":
|
||||
icon = QMessageBox.Critical
|
||||
else:
|
||||
icon = QMessageBox.Information
|
||||
mb = QMessageBox(parent)
|
||||
mb = QMessageBox(parent_widget) #
|
||||
if textFormat == "plain":
|
||||
mb.setTextFormat(Qt.PlainText)
|
||||
elif textFormat == "rich":
|
||||
|
@ -161,16 +195,16 @@ def showInfo(
|
|||
|
||||
|
||||
def showText(
|
||||
txt,
|
||||
parent=None,
|
||||
type="text",
|
||||
run=True,
|
||||
geomKey=None,
|
||||
minWidth=500,
|
||||
minHeight=400,
|
||||
title="Anki",
|
||||
copyBtn=False,
|
||||
):
|
||||
txt: str,
|
||||
parent: Optional[QWidget] = None,
|
||||
type: str = "text",
|
||||
run: bool = True,
|
||||
geomKey: Optional[str] = None,
|
||||
minWidth: int = 500,
|
||||
minHeight: int = 400,
|
||||
title: str = "Anki",
|
||||
copyBtn: bool = False,
|
||||
) -> Optional[Tuple[QDialog, QDialogButtonBox]]:
|
||||
if not parent:
|
||||
parent = aqt.mw.app.activeWindow() or aqt.mw
|
||||
diag = QDialog(parent)
|
||||
|
@ -189,21 +223,21 @@ def showText(
|
|||
layout.addWidget(box)
|
||||
if copyBtn:
|
||||
|
||||
def onCopy():
|
||||
def onCopy() -> None:
|
||||
QApplication.clipboard().setText(text.toPlainText())
|
||||
|
||||
btn = QPushButton(tr(TR.QT_MISC_COPY_TO_CLIPBOARD))
|
||||
qconnect(btn.clicked, onCopy)
|
||||
box.addButton(btn, QDialogButtonBox.ActionRole)
|
||||
|
||||
def onReject():
|
||||
def onReject() -> None:
|
||||
if geomKey:
|
||||
saveGeom(diag, geomKey)
|
||||
QDialog.reject(diag)
|
||||
|
||||
qconnect(box.rejected, onReject)
|
||||
|
||||
def onFinish():
|
||||
def onFinish() -> None:
|
||||
if geomKey:
|
||||
saveGeom(diag, geomKey)
|
||||
|
||||
|
@ -214,18 +248,19 @@ def showText(
|
|||
restoreGeom(diag, geomKey)
|
||||
if run:
|
||||
diag.exec_()
|
||||
return None
|
||||
else:
|
||||
return diag, box
|
||||
|
||||
|
||||
def askUser(
|
||||
text,
|
||||
parent=None,
|
||||
text: str,
|
||||
parent: QDialog = None,
|
||||
help: HelpPageArgument = None,
|
||||
defaultno=False,
|
||||
msgfunc=None,
|
||||
title="Anki",
|
||||
):
|
||||
defaultno: bool = False,
|
||||
msgfunc: Optional[Callable] = None,
|
||||
title: str = "Anki",
|
||||
) -> bool:
|
||||
"Show a yes/no question. Return true if yes."
|
||||
if not parent:
|
||||
parent = aqt.mw.app.activeWindow()
|
||||
|
@ -239,7 +274,7 @@ def askUser(
|
|||
default = QMessageBox.No
|
||||
else:
|
||||
default = QMessageBox.Yes
|
||||
r = msgfunc(parent, title, text, sb, default)
|
||||
r = msgfunc(parent, title, text, cast(QMessageBox.StandardButtons, sb), default)
|
||||
if r == QMessageBox.Help:
|
||||
|
||||
openHelp(help)
|
||||
|
@ -250,10 +285,15 @@ def askUser(
|
|||
|
||||
class ButtonedDialog(QMessageBox):
|
||||
def __init__(
|
||||
self, text, buttons, parent=None, help: HelpPageArgument = None, title="Anki"
|
||||
self,
|
||||
text: str,
|
||||
buttons: List[str],
|
||||
parent: Optional[QDialog] = None,
|
||||
help: HelpPageArgument = None,
|
||||
title: str = "Anki",
|
||||
):
|
||||
QMessageBox.__init__(self, parent)
|
||||
self._buttons = []
|
||||
self._buttons: List[QPushButton] = []
|
||||
self.setWindowTitle(title)
|
||||
self.help = help
|
||||
self.setIcon(QMessageBox.Warning)
|
||||
|
@ -264,7 +304,7 @@ class ButtonedDialog(QMessageBox):
|
|||
self.addButton(tr(TR.ACTIONS_HELP), QMessageBox.HelpRole)
|
||||
buttons.append(tr(TR.ACTIONS_HELP))
|
||||
|
||||
def run(self):
|
||||
def run(self) -> str:
|
||||
self.exec_()
|
||||
but = self.clickedButton().text()
|
||||
if but == "Help":
|
||||
|
@ -274,13 +314,17 @@ class ButtonedDialog(QMessageBox):
|
|||
# work around KDE 'helpfully' adding accelerators to button text of Qt apps
|
||||
return txt.replace("&", "")
|
||||
|
||||
def setDefault(self, idx):
|
||||
def setDefault(self, idx: int) -> None:
|
||||
self.setDefaultButton(self._buttons[idx])
|
||||
|
||||
|
||||
def askUserDialog(
|
||||
text, buttons, parent=None, help: HelpPageArgument = None, title="Anki"
|
||||
):
|
||||
text: str,
|
||||
buttons: List[str],
|
||||
parent: Optional[QDialog] = None,
|
||||
help: HelpPageArgument = None,
|
||||
title: str = "Anki",
|
||||
) -> ButtonedDialog:
|
||||
if not parent:
|
||||
parent = aqt.mw
|
||||
diag = ButtonedDialog(text, buttons, parent, help, title=title)
|
||||
|
@ -290,14 +334,14 @@ def askUserDialog(
|
|||
class GetTextDialog(QDialog):
|
||||
def __init__(
|
||||
self,
|
||||
parent,
|
||||
question,
|
||||
parent: Optional[QDialog],
|
||||
question: str,
|
||||
help: HelpPageArgument = None,
|
||||
edit=None,
|
||||
default="",
|
||||
title="Anki",
|
||||
minWidth=400,
|
||||
):
|
||||
edit: Optional[QLineEdit] = None,
|
||||
default: str = "",
|
||||
title: str = "Anki",
|
||||
minWidth: int = 400,
|
||||
) -> None:
|
||||
QDialog.__init__(self, parent)
|
||||
self.setWindowTitle(title)
|
||||
disable_help_button(self)
|
||||
|
@ -325,26 +369,26 @@ class GetTextDialog(QDialog):
|
|||
if help:
|
||||
qconnect(b.button(QDialogButtonBox.Help).clicked, self.helpRequested)
|
||||
|
||||
def accept(self):
|
||||
def accept(self) -> None:
|
||||
return QDialog.accept(self)
|
||||
|
||||
def reject(self):
|
||||
def reject(self) -> None:
|
||||
return QDialog.reject(self)
|
||||
|
||||
def helpRequested(self):
|
||||
def helpRequested(self) -> None:
|
||||
openHelp(self.help)
|
||||
|
||||
|
||||
def getText(
|
||||
prompt,
|
||||
parent=None,
|
||||
prompt: str,
|
||||
parent: Optional[QDialog] = None,
|
||||
help: HelpPageArgument = None,
|
||||
edit=None,
|
||||
default="",
|
||||
title="Anki",
|
||||
geomKey=None,
|
||||
**kwargs,
|
||||
):
|
||||
edit: Optional[QLineEdit] = None,
|
||||
default: str = "",
|
||||
title: str = "Anki",
|
||||
geomKey: Optional[str] = None,
|
||||
**kwargs: Any,
|
||||
) -> Tuple[str, int]:
|
||||
if not parent:
|
||||
parent = aqt.mw.app.activeWindow() or aqt.mw
|
||||
d = GetTextDialog(
|
||||
|
@ -359,7 +403,7 @@ def getText(
|
|||
return (str(d.l.text()), ret)
|
||||
|
||||
|
||||
def getOnlyText(*args, **kwargs):
|
||||
def getOnlyText(*args: Any, **kwargs: Any) -> str:
|
||||
(s, r) = getText(*args, **kwargs)
|
||||
if r:
|
||||
return s
|
||||
|
@ -368,7 +412,10 @@ def getOnlyText(*args, **kwargs):
|
|||
|
||||
|
||||
# fixme: these utilities could be combined into a single base class
|
||||
def chooseList(prompt, choices, startrow=0, parent=None):
|
||||
# unused by Anki, but used by add-ons
|
||||
def chooseList(
|
||||
prompt: str, choices: List[str], startrow: int = 0, parent: Any = None
|
||||
) -> int:
|
||||
if not parent:
|
||||
parent = aqt.mw.app.activeWindow()
|
||||
d = QDialog(parent)
|
||||
|
@ -389,7 +436,9 @@ def chooseList(prompt, choices, startrow=0, parent=None):
|
|||
return c.currentRow()
|
||||
|
||||
|
||||
def getTag(parent, deck, question, tags="user", **kwargs):
|
||||
def getTag(
|
||||
parent: QDialog, deck: Collection, question: str, **kwargs: Any
|
||||
) -> Tuple[str, int]:
|
||||
from aqt.tagedit import TagEdit
|
||||
|
||||
te = TagEdit(parent)
|
||||
|
@ -409,7 +458,15 @@ def disable_help_button(widget: QWidget) -> None:
|
|||
######################################################################
|
||||
|
||||
|
||||
def getFile(parent, title, cb, filter="*.*", dir=None, key=None, multi=False):
|
||||
def getFile(
|
||||
parent: QDialog,
|
||||
title: str,
|
||||
cb: Optional[Callable[[Union[str, Sequence[str]]], None]],
|
||||
filter: str = "*.*",
|
||||
dir: Optional[str] = None,
|
||||
key: Optional[str] = None,
|
||||
multi: bool = False, # controls whether a single or multiple files is returned
|
||||
) -> Optional[Union[Sequence[str], str]]:
|
||||
"Ask the user for a file."
|
||||
assert not dir or not key
|
||||
if not dir:
|
||||
|
@ -426,7 +483,7 @@ def getFile(parent, title, cb, filter="*.*", dir=None, key=None, multi=False):
|
|||
d.setNameFilter(filter)
|
||||
ret = []
|
||||
|
||||
def accept():
|
||||
def accept() -> None:
|
||||
files = list(d.selectedFiles())
|
||||
if dirkey:
|
||||
dir = os.path.dirname(files[0])
|
||||
|
@ -442,10 +499,17 @@ def getFile(parent, title, cb, filter="*.*", dir=None, key=None, multi=False):
|
|||
d.exec_()
|
||||
if key:
|
||||
saveState(d, key)
|
||||
return ret and ret[0]
|
||||
return ret[0] if ret else None
|
||||
|
||||
|
||||
def getSaveFile(parent, title, dir_description, key, ext, fname=None):
|
||||
def getSaveFile(
|
||||
parent: QDialog,
|
||||
title: str,
|
||||
dir_description: str,
|
||||
key: str,
|
||||
ext: str,
|
||||
fname: Optional[str] = None,
|
||||
) -> str:
|
||||
"""Ask the user for a file to save. Use DIR_DESCRIPTION as config
|
||||
variable. The file dialog will default to open with FNAME."""
|
||||
config_key = dir_description + "Directory"
|
||||
|
@ -474,7 +538,7 @@ def getSaveFile(parent, title, dir_description, key, ext, fname=None):
|
|||
return file
|
||||
|
||||
|
||||
def saveGeom(widget, key: str):
|
||||
def saveGeom(widget: QDialog, key: str) -> None:
|
||||
key += "Geom"
|
||||
if isMac and widget.windowState() & Qt.WindowFullScreen:
|
||||
geom = None
|
||||
|
@ -483,7 +547,9 @@ def saveGeom(widget, key: str):
|
|||
aqt.mw.pm.profile[key] = geom
|
||||
|
||||
|
||||
def restoreGeom(widget, key: str, offset=None, adjustSize=False):
|
||||
def restoreGeom(
|
||||
widget: QWidget, key: str, offset: Optional[int] = None, adjustSize: bool = False
|
||||
) -> None:
|
||||
key += "Geom"
|
||||
if aqt.mw.pm.profile.get(key):
|
||||
widget.restoreGeometry(aqt.mw.pm.profile[key])
|
||||
|
@ -498,7 +564,7 @@ def restoreGeom(widget, key: str, offset=None, adjustSize=False):
|
|||
widget.adjustSize()
|
||||
|
||||
|
||||
def ensureWidgetInScreenBoundaries(widget):
|
||||
def ensureWidgetInScreenBoundaries(widget: QWidget) -> None:
|
||||
handle = widget.window().windowHandle()
|
||||
if not handle:
|
||||
# window has not yet been shown, retry later
|
||||
|
@ -524,58 +590,60 @@ def ensureWidgetInScreenBoundaries(widget):
|
|||
widget.move(x, y)
|
||||
|
||||
|
||||
def saveState(widget, key: str):
|
||||
def saveState(widget: QFileDialog, key: str) -> None:
|
||||
key += "State"
|
||||
aqt.mw.pm.profile[key] = widget.saveState()
|
||||
|
||||
|
||||
def restoreState(widget, key: str):
|
||||
def restoreState(widget: Union[aqt.AnkiQt, QFileDialog], key: str) -> None:
|
||||
key += "State"
|
||||
if aqt.mw.pm.profile.get(key):
|
||||
widget.restoreState(aqt.mw.pm.profile[key])
|
||||
|
||||
|
||||
def saveSplitter(widget, key):
|
||||
def saveSplitter(widget: QSplitter, key: str) -> None:
|
||||
key += "Splitter"
|
||||
aqt.mw.pm.profile[key] = widget.saveState()
|
||||
|
||||
|
||||
def restoreSplitter(widget, key):
|
||||
def restoreSplitter(widget: QSplitter, key: str) -> None:
|
||||
key += "Splitter"
|
||||
if aqt.mw.pm.profile.get(key):
|
||||
widget.restoreState(aqt.mw.pm.profile[key])
|
||||
|
||||
|
||||
def saveHeader(widget, key):
|
||||
def saveHeader(widget: QHeaderView, key: str) -> None:
|
||||
key += "Header"
|
||||
aqt.mw.pm.profile[key] = widget.saveState()
|
||||
|
||||
|
||||
def restoreHeader(widget, key):
|
||||
def restoreHeader(widget: QHeaderView, key: str) -> None:
|
||||
key += "Header"
|
||||
if aqt.mw.pm.profile.get(key):
|
||||
widget.restoreState(aqt.mw.pm.profile[key])
|
||||
|
||||
|
||||
def save_is_checked(widget, key: str):
|
||||
def save_is_checked(widget: QWidget, key: str) -> None:
|
||||
key += "IsChecked"
|
||||
aqt.mw.pm.profile[key] = widget.isChecked()
|
||||
|
||||
|
||||
def restore_is_checked(widget, key: str):
|
||||
def restore_is_checked(widget: QWidget, key: str) -> None:
|
||||
key += "IsChecked"
|
||||
if aqt.mw.pm.profile.get(key) is not None:
|
||||
widget.setChecked(aqt.mw.pm.profile[key])
|
||||
|
||||
|
||||
def save_combo_index_for_session(widget: QComboBox, key: str):
|
||||
def save_combo_index_for_session(widget: QComboBox, key: str) -> None:
|
||||
textKey = key + "ComboActiveText"
|
||||
indexKey = key + "ComboActiveIndex"
|
||||
aqt.mw.pm.session[textKey] = widget.currentText()
|
||||
aqt.mw.pm.session[indexKey] = widget.currentIndex()
|
||||
|
||||
|
||||
def restore_combo_index_for_session(widget: QComboBox, history: List[str], key: str):
|
||||
def restore_combo_index_for_session(
|
||||
widget: QComboBox, history: List[str], key: str
|
||||
) -> None:
|
||||
textKey = key + "ComboActiveText"
|
||||
indexKey = key + "ComboActiveIndex"
|
||||
text = aqt.mw.pm.session.get(textKey)
|
||||
|
@ -585,7 +653,7 @@ def restore_combo_index_for_session(widget: QComboBox, history: List[str], key:
|
|||
widget.setCurrentIndex(index)
|
||||
|
||||
|
||||
def save_combo_history(comboBox: QComboBox, history: List[str], name: str):
|
||||
def save_combo_history(comboBox: QComboBox, history: List[str], name: str) -> str:
|
||||
name += "BoxHistory"
|
||||
text_input = comboBox.lineEdit().text()
|
||||
if text_input in history:
|
||||
|
@ -599,7 +667,7 @@ def save_combo_history(comboBox: QComboBox, history: List[str], name: str):
|
|||
return text_input
|
||||
|
||||
|
||||
def restore_combo_history(comboBox: QComboBox, name: str):
|
||||
def restore_combo_history(comboBox: QComboBox, name: str) -> List[str]:
|
||||
name += "BoxHistory"
|
||||
history = aqt.mw.pm.profile.get(name, [])
|
||||
comboBox.addItems([""] + history)
|
||||
|
@ -611,13 +679,13 @@ def restore_combo_history(comboBox: QComboBox, name: str):
|
|||
return history
|
||||
|
||||
|
||||
def mungeQA(col, txt):
|
||||
def mungeQA(col: Collection, txt: str) -> str:
|
||||
print("mungeQA() deprecated; use mw.prepare_card_text_for_display()")
|
||||
txt = col.media.escape_media_filenames(txt)
|
||||
return txt
|
||||
|
||||
|
||||
def openFolder(path):
|
||||
def openFolder(path: str) -> None:
|
||||
if isWin:
|
||||
subprocess.Popen(["explorer", "file://" + path])
|
||||
else:
|
||||
|
@ -625,27 +693,27 @@ def openFolder(path):
|
|||
QDesktopServices.openUrl(QUrl("file://" + path))
|
||||
|
||||
|
||||
def shortcut(key):
|
||||
def shortcut(key: str) -> str:
|
||||
if isMac:
|
||||
return re.sub("(?i)ctrl", "Command", key)
|
||||
return key
|
||||
|
||||
|
||||
def maybeHideClose(bbox):
|
||||
def maybeHideClose(bbox: QDialogButtonBox) -> None:
|
||||
if isMac:
|
||||
b = bbox.button(QDialogButtonBox.Close)
|
||||
if b:
|
||||
bbox.removeButton(b)
|
||||
|
||||
|
||||
def addCloseShortcut(widg):
|
||||
def addCloseShortcut(widg: QDialog) -> None:
|
||||
if not isMac:
|
||||
return
|
||||
widg._closeShortcut = QShortcut(QKeySequence("Ctrl+W"), widg)
|
||||
qconnect(widg._closeShortcut.activated, widg.reject)
|
||||
|
||||
|
||||
def downArrow():
|
||||
def downArrow() -> str:
|
||||
if isWin:
|
||||
return "▼"
|
||||
# windows 10 is lacking the smaller arrow on English installs
|
||||
|
@ -659,13 +727,19 @@ _tooltipTimer: Optional[QTimer] = None
|
|||
_tooltipLabel: Optional[QLabel] = None
|
||||
|
||||
|
||||
def tooltip(msg, period=3000, parent=None, x_offset=0, y_offset=100):
|
||||
def tooltip(
|
||||
msg: str,
|
||||
period: int = 3000,
|
||||
parent: Optional[aqt.AnkiQt] = None,
|
||||
x_offset: int = 0,
|
||||
y_offset: int = 100,
|
||||
) -> None:
|
||||
global _tooltipTimer, _tooltipLabel
|
||||
|
||||
class CustomLabel(QLabel):
|
||||
silentlyClose = True
|
||||
|
||||
def mousePressEvent(self, evt):
|
||||
def mousePressEvent(self, evt: QMouseEvent) -> None:
|
||||
evt.accept()
|
||||
self.hide()
|
||||
|
||||
|
@ -697,7 +771,7 @@ def tooltip(msg, period=3000, parent=None, x_offset=0, y_offset=100):
|
|||
_tooltipLabel = lab
|
||||
|
||||
|
||||
def closeTooltip():
|
||||
def closeTooltip() -> None:
|
||||
global _tooltipLabel, _tooltipTimer
|
||||
if _tooltipLabel:
|
||||
try:
|
||||
|
@ -712,7 +786,7 @@ def closeTooltip():
|
|||
|
||||
|
||||
# true if invalid; print warning
|
||||
def checkInvalidFilename(str, dirsep=True):
|
||||
def checkInvalidFilename(str: str, dirsep: bool = True) -> bool:
|
||||
bad = invalidFilename(str, dirsep)
|
||||
if bad:
|
||||
showWarning(tr(TR.QT_MISC_THE_FOLLOWING_CHARACTER_CAN_NOT_BE, val=bad))
|
||||
|
@ -723,28 +797,30 @@ def checkInvalidFilename(str, dirsep=True):
|
|||
# Menus
|
||||
######################################################################
|
||||
|
||||
MenuListChild = Union["SubMenu", QAction, "MenuItem", "MenuList"]
|
||||
|
||||
|
||||
class MenuList:
|
||||
def __init__(self):
|
||||
self.children = []
|
||||
def __init__(self) -> None:
|
||||
self.children: List[MenuListChild] = []
|
||||
|
||||
def addItem(self, title, func):
|
||||
def addItem(self, title: str, func: Callable) -> MenuItem:
|
||||
item = MenuItem(title, func)
|
||||
self.children.append(item)
|
||||
return item
|
||||
|
||||
def addSeparator(self):
|
||||
def addSeparator(self) -> None:
|
||||
self.children.append(None)
|
||||
|
||||
def addMenu(self, title):
|
||||
def addMenu(self, title: str) -> SubMenu:
|
||||
submenu = SubMenu(title)
|
||||
self.children.append(submenu)
|
||||
return submenu
|
||||
|
||||
def addChild(self, child):
|
||||
def addChild(self, child: Union[SubMenu, QAction, MenuList]) -> None:
|
||||
self.children.append(child)
|
||||
|
||||
def renderTo(self, qmenu):
|
||||
def renderTo(self, qmenu: QMenu) -> None:
|
||||
for child in self.children:
|
||||
if child is None:
|
||||
qmenu.addSeparator()
|
||||
|
@ -753,33 +829,33 @@ class MenuList:
|
|||
else:
|
||||
child.renderTo(qmenu)
|
||||
|
||||
def popupOver(self, widget):
|
||||
def popupOver(self, widget: QPushButton) -> None:
|
||||
qmenu = QMenu()
|
||||
self.renderTo(qmenu)
|
||||
qmenu.exec_(widget.mapToGlobal(QPoint(0, 0)))
|
||||
|
||||
|
||||
class SubMenu(MenuList):
|
||||
def __init__(self, title):
|
||||
def __init__(self, title: str) -> None:
|
||||
super().__init__()
|
||||
self.title = title
|
||||
|
||||
def renderTo(self, menu):
|
||||
def renderTo(self, menu: QMenu) -> None:
|
||||
submenu = menu.addMenu(self.title)
|
||||
super().renderTo(submenu)
|
||||
|
||||
|
||||
class MenuItem:
|
||||
def __init__(self, title, func):
|
||||
def __init__(self, title: str, func: Callable) -> None:
|
||||
self.title = title
|
||||
self.func = func
|
||||
|
||||
def renderTo(self, qmenu):
|
||||
def renderTo(self, qmenu: QMenu) -> None:
|
||||
a = qmenu.addAction(self.title)
|
||||
qconnect(a.triggered, self.func)
|
||||
|
||||
|
||||
def qtMenuShortcutWorkaround(qmenu):
|
||||
def qtMenuShortcutWorkaround(qmenu: QMenu) -> None:
|
||||
if qtminor < 10:
|
||||
return
|
||||
for act in qmenu.actions():
|
||||
|
@ -789,7 +865,7 @@ def qtMenuShortcutWorkaround(qmenu):
|
|||
######################################################################
|
||||
|
||||
|
||||
def supportText():
|
||||
def supportText() -> str:
|
||||
import platform
|
||||
import time
|
||||
|
||||
|
@ -802,9 +878,9 @@ def supportText():
|
|||
else:
|
||||
platname = "Linux"
|
||||
|
||||
def schedVer():
|
||||
def schedVer() -> str:
|
||||
try:
|
||||
return mw.col.schedVer()
|
||||
return str(mw.col.schedVer())
|
||||
except:
|
||||
return "?"
|
||||
|
||||
|
@ -832,7 +908,7 @@ Add-ons, last update check: {}
|
|||
######################################################################
|
||||
|
||||
# adapted from version detection in qutebrowser
|
||||
def opengl_vendor():
|
||||
def opengl_vendor() -> Optional[str]:
|
||||
old_context = QOpenGLContext.currentContext()
|
||||
old_surface = None if old_context is None else old_context.surface()
|
||||
|
||||
|
@ -871,7 +947,7 @@ def opengl_vendor():
|
|||
old_context.makeCurrent(old_surface)
|
||||
|
||||
|
||||
def gfxDriverIsBroken():
|
||||
def gfxDriverIsBroken() -> bool:
|
||||
driver = opengl_vendor()
|
||||
return driver == "nouveau"
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@ disallow_untyped_defs=true
|
|||
disallow_untyped_defs=true
|
||||
[mypy-aqt.editor]
|
||||
disallow_untyped_defs=true
|
||||
[mypy-aqt.utils]
|
||||
disallow_untyped_defs=true
|
||||
|
||||
|
||||
[mypy-aqt.mpv]
|
||||
|
|
Loading…
Reference in a new issue