mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Drop remaining qt5 code
This commit is contained in:
parent
cd411927cc
commit
8e20973c52
55 changed files with 71 additions and 973 deletions
|
@ -38,7 +38,6 @@ fn build_forms(build: &mut Build) -> Result<()> {
|
|||
let mut py_files = vec![];
|
||||
for path in ui_files.resolve() {
|
||||
let outpath = outdir.join(path.file_name().unwrap()).into_string();
|
||||
py_files.push(outpath.replace(".ui", "_qt5.py"));
|
||||
py_files.push(outpath.replace(".ui", "_qt6.py"));
|
||||
}
|
||||
build.add_action(
|
||||
|
|
|
@ -51,13 +51,8 @@ Anki requires a recent glibc.
|
|||
|
||||
If you are using a distro that uses musl, Anki will not work.
|
||||
|
||||
If your glibc version is 2.35+ on AMD64 or 2.39+ on ARM64, you can skip the rest of this section.
|
||||
|
||||
If your system has an older glibc, you won't be able to use the PyQt wheels that are
|
||||
available in pip/PyPy, and will need to use your system-installed PyQt instead.
|
||||
Your distro will also need to have Python 3.9 or later.
|
||||
|
||||
After installing the system libraries (eg:
|
||||
You can use your system's Qt libraries if they are Qt 6.2 or later, if
|
||||
you wish. After installing the system libraries (eg:
|
||||
'sudo apt install python3-pyqt6.qt{quick,webengine} python3-venv pyqt6-dev-tools'),
|
||||
find the place they are installed (eg '/usr/lib/python3/dist-packages'). On modern Ubuntu, you'll
|
||||
also need 'sudo apt remove python3-protobuf'. Then before running any commands like './run', tell Anki where
|
||||
|
@ -68,12 +63,6 @@ export PYTHONPATH=/usr/lib/python3/dist-packages
|
|||
export PYTHON_BINARY=/usr/bin/python3
|
||||
```
|
||||
|
||||
There are a few things to be aware of:
|
||||
|
||||
- You should use ./run and not tools/run-qt5\*, even if your system libraries are Qt5.
|
||||
- If your system libraries are Qt5, when creating an aqt wheel, the wheel will not work
|
||||
on Qt6 environments.
|
||||
|
||||
## Packaging considerations
|
||||
|
||||
Python, node and protoc are downloaded as part of the build. You can optionally define
|
||||
|
|
|
@ -284,7 +284,7 @@ def setupLangAndBackend(
|
|||
class NativeEventFilter(QAbstractNativeEventFilter):
|
||||
def nativeEventFilter(
|
||||
self, eventType: Any, message: Any
|
||||
) -> tuple[bool, sip.voidptr | None]:
|
||||
) -> tuple[bool, Any | None]:
|
||||
|
||||
if eventType == "windows_generic_MSG":
|
||||
import ctypes.wintypes
|
||||
|
@ -376,6 +376,8 @@ class AnkiApp(QApplication):
|
|||
|
||||
def onRecv(self) -> None:
|
||||
sock = self._srv.nextPendingConnection()
|
||||
if sock is None:
|
||||
return
|
||||
if not sock.waitForReadyRead(self.TMOUT):
|
||||
sys.stderr.write(sock.errorString())
|
||||
return
|
||||
|
@ -406,14 +408,12 @@ class AnkiApp(QApplication):
|
|||
QRadioButton,
|
||||
QMenu,
|
||||
QSlider,
|
||||
# classes with PyQt5 compatibility proxy
|
||||
without_qt5_compat_wrapper(QToolButton),
|
||||
without_qt5_compat_wrapper(QTabBar),
|
||||
QToolButton,
|
||||
QTabBar,
|
||||
)
|
||||
if evt.type() in [QEvent.Type.Enter, QEvent.Type.HoverEnter]:
|
||||
if (isinstance(src, pointer_classes) and src.isEnabled()) or (
|
||||
isinstance(src, without_qt5_compat_wrapper(QComboBox))
|
||||
and not src.isEditable()
|
||||
isinstance(src, QComboBox) and not src.isEditable()
|
||||
):
|
||||
self.setOverrideCursor(QCursor(Qt.CursorShape.PointingHandCursor))
|
||||
else:
|
||||
|
@ -525,15 +525,12 @@ def setupGL(pm: aqt.profiles.ProfileManager) -> None:
|
|||
QQuickWindow.setGraphicsApi(QSGRendererInterface.GraphicsApi.OpenGL)
|
||||
elif driver in (VideoDriver.Software, VideoDriver.ANGLE):
|
||||
if is_win:
|
||||
# on Windows, this appears to be sufficient on Qt5/Qt6.
|
||||
# on Windows, this appears to be sufficient
|
||||
# On Qt6, ANGLE is excluded by the enum.
|
||||
os.environ["QT_OPENGL"] = driver.value
|
||||
elif is_mac:
|
||||
QCoreApplication.setAttribute(Qt.ApplicationAttribute.AA_UseSoftwareOpenGL)
|
||||
elif is_lin:
|
||||
# Qt5 only
|
||||
os.environ["QT_XCB_FORCE_SOFTWARE_OPENGL"] = "1"
|
||||
# Required on Qt6
|
||||
if "QTWEBENGINE_CHROMIUM_FLAGS" not in os.environ:
|
||||
os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = "--disable-gpu"
|
||||
if qtmajor > 5:
|
||||
|
@ -663,12 +660,6 @@ def _run(argv: list[str] | None = None, exec: bool = True) -> AnkiApp | None:
|
|||
if is_win and "QT_QPA_PLATFORM" not in os.environ:
|
||||
os.environ["QT_QPA_PLATFORM"] = "windows:altgr"
|
||||
|
||||
# Disable sandbox on Qt5 PyPi/packaged builds, as it causes blank screens on modern
|
||||
# glibc versions. We check for specific patch versions, because distros may have
|
||||
# fixed the issue in their own Qt builds.
|
||||
if is_lin and qtfullversion in ([5, 15, 2], [5, 14, 1]):
|
||||
os.environ["QTWEBENGINE_DISABLE_SANDBOX"] = "1"
|
||||
|
||||
# create the app
|
||||
QCoreApplication.setApplicationName("Anki")
|
||||
QGuiApplication.setDesktopFileName("anki")
|
||||
|
|
|
@ -325,15 +325,13 @@ class DataModel(QAbstractTableModel):
|
|||
return 0
|
||||
return self.len_columns()
|
||||
|
||||
_QFont = without_qt5_compat_wrapper(QFont)
|
||||
|
||||
def data(self, index: QModelIndex = QModelIndex(), role: int = 0) -> Any:
|
||||
if not index.isValid():
|
||||
return QVariant()
|
||||
if role == Qt.ItemDataRole.FontRole:
|
||||
if not self.column_at(index).uses_cell_font:
|
||||
return QVariant()
|
||||
qfont = self._QFont()
|
||||
qfont = QFont()
|
||||
row = self.get_row(index)
|
||||
qfont.setFamily(row.font_name)
|
||||
qfont.setPixelSize(row.font_size)
|
||||
|
|
|
@ -382,10 +382,7 @@ class Table:
|
|||
hh.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
|
||||
self._restore_header()
|
||||
qconnect(hh.customContextMenuRequested, self._on_header_context)
|
||||
if qtmajor == 5:
|
||||
qconnect(hh.sortIndicatorChanged, self._on_sort_column_changed_qt5)
|
||||
else:
|
||||
qconnect(hh.sortIndicatorChanged, self._on_sort_column_changed)
|
||||
qconnect(hh.sortIndicatorChanged, self._on_sort_column_changed)
|
||||
qconnect(hh.sectionMoved, self._on_column_moved)
|
||||
|
||||
# Slots
|
||||
|
@ -495,12 +492,6 @@ class Table:
|
|||
if checked:
|
||||
self._scroll_to_column(self._model.len_columns() - 1)
|
||||
|
||||
def _on_sort_column_changed_qt5(self, section: int, order: int) -> None:
|
||||
self._on_sort_column_changed(
|
||||
section,
|
||||
Qt.SortOrder.AscendingOrder if not order else Qt.SortOrder.DescendingOrder,
|
||||
)
|
||||
|
||||
def _on_sort_column_changed(self, section: int, order: Qt.SortOrder) -> None:
|
||||
column = self._model.column_at_section(section)
|
||||
sorting = column.sorting_notes if self.is_notes_mode() else column.sorting_cards
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.about_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.about_qt5 import * # type: ignore
|
||||
from _aqt.forms.about_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.addcards_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.addcards_qt5 import * # type: ignore
|
||||
from _aqt.forms.addcards_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.addfield_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.addfield_qt5 import * # type: ignore
|
||||
from _aqt.forms.addfield_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.addmodel_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.addmodel_qt5 import * # type: ignore
|
||||
from _aqt.forms.addmodel_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.addonconf_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.addonconf_qt5 import * # type: ignore
|
||||
from _aqt.forms.addonconf_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.addons_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.addons_qt5 import * # type: ignore
|
||||
from _aqt.forms.addons_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.browser_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.browser_qt5 import * # type: ignore
|
||||
from _aqt.forms.browser_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.browserdisp_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.browserdisp_qt5 import * # type: ignore
|
||||
from _aqt.forms.browserdisp_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.browseropts_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.browseropts_qt5 import * # type: ignore
|
||||
from _aqt.forms.browseropts_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.changemap_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.changemap_qt5 import * # type: ignore
|
||||
from _aqt.forms.changemap_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.changemodel_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.changemodel_qt5 import * # type: ignore
|
||||
from _aqt.forms.changemodel_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.clayout_top_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.clayout_top_qt5 import * # type: ignore
|
||||
from _aqt.forms.clayout_top_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.customstudy_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.customstudy_qt5 import * # type: ignore
|
||||
from _aqt.forms.customstudy_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.dconf_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.dconf_qt5 import * # type: ignore
|
||||
from _aqt.forms.dconf_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.debug_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.debug_qt5 import * # type: ignore
|
||||
from _aqt.forms.debug_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.editcurrent_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.editcurrent_qt5 import * # type: ignore
|
||||
from _aqt.forms.editcurrent_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.edithtml_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.edithtml_qt5 import * # type: ignore
|
||||
from _aqt.forms.edithtml_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.emptycards_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.emptycards_qt5 import * # type: ignore
|
||||
from _aqt.forms.emptycards_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.exporting_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.exporting_qt5 import * # type: ignore
|
||||
from _aqt.forms.exporting_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.fields_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.fields_qt5 import * # type: ignore
|
||||
from _aqt.forms.fields_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.filtered_deck_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.filtered_deck_qt5 import * # type: ignore
|
||||
from _aqt.forms.filtered_deck_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.finddupes_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.finddupes_qt5 import * # type: ignore
|
||||
from _aqt.forms.finddupes_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.findreplace_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.findreplace_qt5 import * # type: ignore
|
||||
from _aqt.forms.findreplace_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.forget_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.forget_qt5 import * # type: ignore
|
||||
from _aqt.forms.forget_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.getaddons_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.getaddons_qt5 import * # type: ignore
|
||||
from _aqt.forms.getaddons_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.importing_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.importing_qt5 import * # type: ignore
|
||||
from _aqt.forms.importing_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.main_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.main_qt5 import * # type: ignore
|
||||
from _aqt.forms.main_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.modelopts_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.modelopts_qt5 import * # type: ignore
|
||||
from _aqt.forms.modelopts_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.models_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.models_qt5 import * # type: ignore
|
||||
from _aqt.forms.models_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.preferences_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.preferences_qt5 import * # type: ignore
|
||||
from _aqt.forms.preferences_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.preview_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.preview_qt5 import * # type: ignore
|
||||
from _aqt.forms.preview_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.profiles_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.profiles_qt5 import * # type: ignore
|
||||
from _aqt.forms.profiles_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.progress_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.progress_qt5 import * # type: ignore
|
||||
from _aqt.forms.progress_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.reposition_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.reposition_qt5 import * # type: ignore
|
||||
from _aqt.forms.reposition_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.setgroup_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.setgroup_qt5 import * # type: ignore
|
||||
from _aqt.forms.setgroup_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.setlang_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.setlang_qt5 import * # type: ignore
|
||||
from _aqt.forms.setlang_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.stats_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.stats_qt5 import * # type: ignore
|
||||
from _aqt.forms.stats_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.studydeck_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.studydeck_qt5 import * # type: ignore
|
||||
from _aqt.forms.studydeck_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.synclog_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.synclog_qt5 import * # type: ignore
|
||||
from _aqt.forms.synclog_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.taglimit_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.taglimit_qt5 import * # type: ignore
|
||||
from _aqt.forms.taglimit_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.template_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.template_qt5 import * # type: ignore
|
||||
from _aqt.forms.template_qt6 import *
|
||||
|
|
|
@ -1,8 +1 @@
|
|||
from typing import TYPE_CHECKING
|
||||
|
||||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5 or TYPE_CHECKING:
|
||||
from _aqt.forms.widgets_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.widgets_qt5 import * # type: ignore
|
||||
from _aqt.forms.widgets_qt6 import *
|
||||
|
|
|
@ -189,11 +189,8 @@ class ProfileManager:
|
|||
# return the bytes directly
|
||||
return args[0]
|
||||
elif name == "_unpickle_enum":
|
||||
if qtmajor == 5:
|
||||
return sip._unpickle_enum(module, klass, args) # type: ignore
|
||||
else:
|
||||
# old style enums can't be unpickled
|
||||
return None
|
||||
# old style enums can't be unpickled
|
||||
return None
|
||||
else:
|
||||
return sip._unpickle_type(module, klass, args) # type: ignore
|
||||
|
||||
|
|
|
@ -300,8 +300,7 @@ class ProgressManager:
|
|||
def _closeWin(self) -> None:
|
||||
# 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):
|
||||
assert self._win is not None
|
||||
if self._win and not sip.isdeleted(self._win):
|
||||
self._win.cancel()
|
||||
self._win = None
|
||||
self._shown = 0
|
||||
|
|
|
@ -11,20 +11,12 @@ import traceback
|
|||
from collections.abc import Callable
|
||||
from typing import TypeVar, Union
|
||||
|
||||
try:
|
||||
import PyQt6
|
||||
except Exception:
|
||||
from .qt5 import * # type: ignore
|
||||
else:
|
||||
if os.getenv("ENABLE_QT5_COMPAT"):
|
||||
print("Running with temporary Qt5 compatibility shims.")
|
||||
from . import qt5_compat # needs to be imported first
|
||||
from .qt6 import *
|
||||
from anki._legacy import deprecated
|
||||
|
||||
# legacy code depends on these re-exports
|
||||
from anki.utils import is_mac, is_win
|
||||
|
||||
# fix buggy ubuntu12.04 display of language selector
|
||||
os.environ["LIBOVERLAY_SCROLLBAR"] = "0"
|
||||
from .qt6 import *
|
||||
|
||||
|
||||
def debug() -> None:
|
||||
|
@ -52,7 +44,7 @@ qtminor = _version.minorVersion()
|
|||
qtpoint = _version.microVersion()
|
||||
qtfullversion = _version.segments()
|
||||
|
||||
if qtmajor < 5 or (qtmajor == 5 and qtminor < 14):
|
||||
if qtmajor == 6 and qtminor < 2:
|
||||
raise Exception("Anki does not support your Qt version.")
|
||||
|
||||
|
||||
|
@ -64,11 +56,6 @@ def qconnect(signal: Callable | pyqtSignal | pyqtBoundSignal, func: Callable) ->
|
|||
_T = TypeVar("_T")
|
||||
|
||||
|
||||
@deprecated(info="no longer required, and now a no-op")
|
||||
def without_qt5_compat_wrapper(cls: _T) -> _T:
|
||||
"""Remove Qt5 compat wrapper from Qt class, if active.
|
||||
|
||||
Only needed for a few Qt APIs that deal with QVariants."""
|
||||
if fn := getattr(cls, "_without_compat_wrapper", None):
|
||||
return fn()
|
||||
else:
|
||||
return cls
|
||||
return cls
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
# Copyright: Ankitects Pty Ltd and contributors
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
# make sure not to optimize imports on this file
|
||||
# pylint: skip-file
|
||||
|
||||
"""
|
||||
PyQt5 imports
|
||||
"""
|
||||
|
||||
from PyQt5.QtCore import * # type: ignore
|
||||
from PyQt5.QtGui import * # type: ignore
|
||||
from PyQt5.QtNetwork import QLocalServer, QLocalSocket, QNetworkProxy # type: ignore
|
||||
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
|
|
@ -1,99 +0,0 @@
|
|||
# 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 audio code
|
||||
"""
|
||||
|
||||
import wave
|
||||
from collections.abc import Callable
|
||||
from concurrent.futures import Future
|
||||
from typing import cast
|
||||
|
||||
import aqt
|
||||
|
||||
from . import * # isort:skip
|
||||
from ..sound import Recorder # isort:skip
|
||||
from ..utils import showWarning # isort:skip
|
||||
|
||||
|
||||
class QtAudioInputRecorder(Recorder):
|
||||
def __init__(self, output_path: str, mw: aqt.AnkiQt, parent: QWidget) -> None:
|
||||
super().__init__(output_path)
|
||||
|
||||
self.mw = mw
|
||||
self._parent = parent
|
||||
|
||||
from PyQt5.QtMultimedia import ( # type: ignore
|
||||
QAudioDeviceInfo,
|
||||
QAudioFormat,
|
||||
QAudioInput,
|
||||
)
|
||||
|
||||
format = QAudioFormat()
|
||||
format.setChannelCount(1)
|
||||
format.setSampleRate(44100)
|
||||
format.setSampleSize(16)
|
||||
format.setCodec("audio/pcm")
|
||||
format.setByteOrder(QAudioFormat.LittleEndian)
|
||||
format.setSampleType(QAudioFormat.SignedInt)
|
||||
|
||||
device = QAudioDeviceInfo.defaultInputDevice()
|
||||
if not device.isFormatSupported(format):
|
||||
format = device.nearestFormat(format)
|
||||
print("format changed")
|
||||
print("channels", format.channelCount())
|
||||
print("rate", format.sampleRate())
|
||||
print("size", format.sampleSize())
|
||||
self._format = format
|
||||
|
||||
self._audio_input = QAudioInput(device, format, parent)
|
||||
|
||||
def start(self, on_done: Callable[[], None]) -> None:
|
||||
self._iodevice = self._audio_input.start()
|
||||
self._buffer = bytearray()
|
||||
qconnect(self._iodevice.readyRead, self._on_read_ready)
|
||||
super().start(on_done)
|
||||
|
||||
def _on_read_ready(self) -> None:
|
||||
self._buffer.extend(cast(bytes, self._iodevice.readAll()))
|
||||
|
||||
def stop(self, on_done: Callable[[str], None]) -> None:
|
||||
def on_stop_timer() -> None:
|
||||
# read anything remaining in buffer & stop
|
||||
self._on_read_ready()
|
||||
self._audio_input.stop()
|
||||
|
||||
if err := self._audio_input.error():
|
||||
showWarning(f"recording failed: {err}")
|
||||
return
|
||||
|
||||
def write_file() -> None:
|
||||
# swallow the first 300ms to allow audio device to quiesce
|
||||
wait = int(44100 * self.STARTUP_DELAY)
|
||||
if len(self._buffer) <= wait:
|
||||
return
|
||||
self._buffer = self._buffer[wait:]
|
||||
|
||||
# write out the wave file
|
||||
wf = wave.open(self.output_path, "wb")
|
||||
wf.setnchannels(self._format.channelCount())
|
||||
wf.setsampwidth(self._format.sampleSize() // 8)
|
||||
wf.setframerate(self._format.sampleRate())
|
||||
wf.writeframes(self._buffer)
|
||||
wf.close()
|
||||
|
||||
def and_then(fut: Future) -> None:
|
||||
fut.result()
|
||||
Recorder.stop(self, on_done)
|
||||
|
||||
self.mw.taskman.run_in_background(write_file, and_then)
|
||||
|
||||
# schedule the stop for half a second in the future,
|
||||
# to avoid truncating the end of the recording
|
||||
self._stop_timer = t = QTimer(self._parent)
|
||||
t.timeout.connect(on_stop_timer) # type: ignore
|
||||
t.setSingleShot(True)
|
||||
t.start(500)
|
|
@ -1,411 +0,0 @@
|
|||
# Copyright: Ankitects Pty Ltd and contributors
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
# type: ignore
|
||||
# pylint: disable=unused-import
|
||||
|
||||
"""
|
||||
Patches and aliases that provide a PyQt5 → PyQt6 compatibility shim for add-ons
|
||||
"""
|
||||
|
||||
import sys
|
||||
import types
|
||||
import typing
|
||||
|
||||
import PyQt6.QtCore
|
||||
import PyQt6.QtDBus
|
||||
import PyQt6.QtGui
|
||||
import PyQt6.QtNetwork
|
||||
import PyQt6.QtPrintSupport
|
||||
import PyQt6.QtWebChannel
|
||||
import PyQt6.QtWebEngineCore
|
||||
import PyQt6.QtWebEngineWidgets
|
||||
import PyQt6.QtWidgets
|
||||
|
||||
from anki._legacy import print_deprecation_warning
|
||||
|
||||
# Globally alias PyQt5 to PyQt6
|
||||
# #########################################################################
|
||||
|
||||
sys.modules["PyQt5"] = PyQt6
|
||||
# Need to alias QtCore explicitly as sip otherwise complains about repeat registration
|
||||
sys.modules["PyQt5.QtCore"] = PyQt6.QtCore
|
||||
# Need to alias QtWidgets and QtGui explicitly to facilitate patches
|
||||
sys.modules["PyQt5.QtGui"] = PyQt6.QtGui
|
||||
sys.modules["PyQt5.QtWidgets"] = PyQt6.QtWidgets
|
||||
# Needed to maintain import order between QtWebEngineWidgets and QCoreApplication:
|
||||
sys.modules["PyQt5.QtWebEngineWidgets"] = PyQt6.QtWebEngineWidgets
|
||||
# Register other aliased top-level Qt modules just to be safe:
|
||||
sys.modules["PyQt5.QtWebEngineCore"] = PyQt6.QtWebEngineCore
|
||||
sys.modules["PyQt5.QtWebChannel"] = PyQt6.QtWebChannel
|
||||
sys.modules["PyQt5.QtNetwork"] = PyQt6.QtNetwork
|
||||
# Alias sip
|
||||
sys.modules["sip"] = PyQt6.sip
|
||||
|
||||
# Restore QWebEnginePage.view()
|
||||
# ########################################################################
|
||||
|
||||
from PyQt6.QtWebEngineCore import QWebEnginePage
|
||||
from PyQt6.QtWebEngineWidgets import QWebEngineView
|
||||
|
||||
|
||||
def qwebenginepage_view(page: QWebEnginePage) -> QWebEnginePage:
|
||||
print_deprecation_warning(
|
||||
"'QWebEnginePage.view()' is deprecated. "
|
||||
"Please use 'QWebEngineView.forPage(page)'"
|
||||
)
|
||||
return QWebEngineView.forPage(page)
|
||||
|
||||
|
||||
PyQt6.QtWebEngineCore.QWebEnginePage.view = qwebenginepage_view
|
||||
|
||||
# Alias removed exec_ methods to exec
|
||||
# ########################################################################
|
||||
|
||||
from PyQt6.QtCore import QCoreApplication, QEventLoop, QThread
|
||||
from PyQt6.QtGui import QDrag, QGuiApplication
|
||||
from PyQt6.QtWidgets import QApplication, QDialog, QMenu
|
||||
|
||||
|
||||
# This helper function is needed as aliasing exec_ to exec directly will cause
|
||||
# an unbound method error, even when wrapped with types.MethodType
|
||||
def qt_exec_(object, *args, **kwargs):
|
||||
class_name = object.__class__.__name__
|
||||
print_deprecation_warning(
|
||||
f"'{class_name}.exec_()' is deprecated. Please use '{class_name}.exec()'"
|
||||
)
|
||||
return object.exec(*args, **kwargs)
|
||||
|
||||
|
||||
QCoreApplication.exec_ = qt_exec_
|
||||
QEventLoop.exec_ = qt_exec_
|
||||
QThread.exec_ = qt_exec_
|
||||
QDrag.exec_ = qt_exec_
|
||||
QGuiApplication.exec_ = qt_exec_
|
||||
QApplication.exec_ = qt_exec_
|
||||
QDialog.exec_ = qt_exec_
|
||||
QMenu.exec_ = qt_exec_
|
||||
|
||||
# Graciously handle removed Qt resource system
|
||||
# ########################################################################
|
||||
|
||||
# Given that add-ons mostly use the Qt resource system to equip UI elements with
|
||||
# icons – which oftentimes are not essential to the core UX –, printing a warning
|
||||
# instead of preventing the add-on from loading seems appropriate.
|
||||
|
||||
|
||||
def qt_resource_system_call(*args, **kwargs):
|
||||
print_deprecation_warning(
|
||||
"The Qt resource system no longer works on PyQt6. "
|
||||
"Use QDir.addSearchPath() or mw.addonManager.setWebExports() instead."
|
||||
)
|
||||
|
||||
|
||||
PyQt6.QtCore.qRegisterResourceData = qt_resource_system_call
|
||||
PyQt6.QtCore.qUnregisterResourceData = qt_resource_system_call
|
||||
|
||||
# Patch unscoped enums back in, aliasing them to scoped enums
|
||||
# ########################################################################
|
||||
|
||||
PyQt6.QtWidgets.QDockWidget.AllDockWidgetFeatures = (
|
||||
PyQt6.QtWidgets.QDockWidget.DockWidgetFeature.DockWidgetClosable
|
||||
| PyQt6.QtWidgets.QDockWidget.DockWidgetFeature.DockWidgetMovable
|
||||
| PyQt6.QtWidgets.QDockWidget.DockWidgetFeature.DockWidgetFloatable
|
||||
)
|
||||
|
||||
# when we subclass QIcon, icons fail to show when returned by getData()
|
||||
# in a tableview/treeview, so we need to manually alias these
|
||||
PyQt6.QtGui.QIcon.Active = PyQt6.QtGui.QIcon.Mode.Active
|
||||
PyQt6.QtGui.QIcon.Disabled = PyQt6.QtGui.QIcon.Mode.Disabled
|
||||
PyQt6.QtGui.QIcon.Normal = PyQt6.QtGui.QIcon.Mode.Normal
|
||||
PyQt6.QtGui.QIcon.Selected = PyQt6.QtGui.QIcon.Mode.Selected
|
||||
PyQt6.QtGui.QIcon.Off = PyQt6.QtGui.QIcon.State.Off
|
||||
PyQt6.QtGui.QIcon.On = PyQt6.QtGui.QIcon.State.On
|
||||
|
||||
# This is the subset of enums used in all public Anki add-ons as of 2021-10-19.
|
||||
# Please note that this list is likely to be incomplete as the process used to
|
||||
# find them probably missed dynamically constructed enums.
|
||||
# Also, as mostly only public Anki add-ons were taken into consideration,
|
||||
# some enums in other add-ons might not be included. In those cases please
|
||||
# consider filing a PR to extend the assignments below.
|
||||
|
||||
# Important: These patches are not meant to provide compatibility for all
|
||||
# add-ons going forward, but simply to maintain support with already
|
||||
# existing add-ons. Add-on authors should take heed to use scoped enums
|
||||
# in any future code changes.
|
||||
|
||||
# (module, [(type_name, enums)])
|
||||
_enum_map = (
|
||||
(
|
||||
PyQt6.QtCore,
|
||||
[
|
||||
("QEvent", ("Type",)),
|
||||
("QEventLoop", ("ProcessEventsFlag",)),
|
||||
("QIODevice", ("OpenModeFlag",)),
|
||||
("QItemSelectionModel", ("SelectionFlag",)),
|
||||
("QLocale", ("Country", "Language")),
|
||||
("QMetaType", ("Type",)),
|
||||
("QProcess", ("ProcessState", "ProcessChannel")),
|
||||
("QStandardPaths", ("StandardLocation",)),
|
||||
(
|
||||
"Qt",
|
||||
(
|
||||
"AlignmentFlag",
|
||||
"ApplicationAttribute",
|
||||
"ArrowType",
|
||||
"AspectRatioMode",
|
||||
"BrushStyle",
|
||||
"CaseSensitivity",
|
||||
"CheckState",
|
||||
"ConnectionType",
|
||||
"ContextMenuPolicy",
|
||||
"CursorShape",
|
||||
"DateFormat",
|
||||
"DayOfWeek",
|
||||
"DockWidgetArea",
|
||||
"FindChildOption",
|
||||
"FocusPolicy",
|
||||
"FocusReason",
|
||||
"GlobalColor",
|
||||
"HighDpiScaleFactorRoundingPolicy",
|
||||
"ImageConversionFlag",
|
||||
"InputMethodHint",
|
||||
"ItemDataRole",
|
||||
"ItemFlag",
|
||||
"KeyboardModifier",
|
||||
"LayoutDirection",
|
||||
"MatchFlag",
|
||||
"Modifier",
|
||||
"MouseButton",
|
||||
"Orientation",
|
||||
"PenCapStyle",
|
||||
"PenJoinStyle",
|
||||
"PenStyle",
|
||||
"ScrollBarPolicy",
|
||||
"ShortcutContext",
|
||||
"SortOrder",
|
||||
"TextElideMode",
|
||||
"TextFlag",
|
||||
"TextFormat",
|
||||
"TextInteractionFlag",
|
||||
"ToolBarArea",
|
||||
"ToolButtonStyle",
|
||||
"TransformationMode",
|
||||
"WidgetAttribute",
|
||||
"WindowModality",
|
||||
"WindowState",
|
||||
"WindowType",
|
||||
"Key",
|
||||
),
|
||||
),
|
||||
("QThread", ("Priority",)),
|
||||
],
|
||||
),
|
||||
(PyQt6.QtDBus, [("QDBus", ("CallMode",))]),
|
||||
(
|
||||
PyQt6.QtGui,
|
||||
[
|
||||
("QAction", ("MenuRole", "ActionEvent")),
|
||||
("QClipboard", ("Mode",)),
|
||||
("QColor", ("NameFormat",)),
|
||||
("QFont", ("Style", "Weight", "StyleHint")),
|
||||
("QFontDatabase", ("WritingSystem", "SystemFont")),
|
||||
("QImage", ("Format",)),
|
||||
("QKeySequence", ("SequenceFormat", "StandardKey")),
|
||||
("QMovie", ("CacheMode",)),
|
||||
("QPageLayout", ("Orientation",)),
|
||||
("QPageSize", ("PageSizeId",)),
|
||||
("QPainter", ("RenderHint",)),
|
||||
("QPalette", ("ColorRole", "ColorGroup")),
|
||||
("QTextCharFormat", ("UnderlineStyle",)),
|
||||
("QTextCursor", ("MoveOperation", "MoveMode", "SelectionType")),
|
||||
("QTextFormat", ("Property",)),
|
||||
("QTextOption", ("WrapMode",)),
|
||||
("QValidator", ("State",)),
|
||||
],
|
||||
),
|
||||
(PyQt6.QtNetwork, [("QHostAddress", ("SpecialAddress",))]),
|
||||
(PyQt6.QtPrintSupport, [("QPrinter", ("Unit",))]),
|
||||
(
|
||||
PyQt6.QtWebEngineCore,
|
||||
[
|
||||
("QWebEnginePage", ("WebWindowType", "FindFlag", "WebAction")),
|
||||
("QWebEngineProfile", ("PersistentCookiesPolicy", "HttpCacheType")),
|
||||
("QWebEngineScript", ("ScriptWorldId", "InjectionPoint")),
|
||||
("QWebEngineSettings", ("FontSize", "WebAttribute")),
|
||||
],
|
||||
),
|
||||
(
|
||||
PyQt6.QtWidgets,
|
||||
[
|
||||
(
|
||||
"QAbstractItemView",
|
||||
(
|
||||
"CursorAction",
|
||||
"DropIndicatorPosition",
|
||||
"ScrollMode",
|
||||
"EditTrigger",
|
||||
"SelectionMode",
|
||||
"SelectionBehavior",
|
||||
"DragDropMode",
|
||||
"ScrollHint",
|
||||
),
|
||||
),
|
||||
("QAbstractScrollArea", ("SizeAdjustPolicy",)),
|
||||
("QAbstractSpinBox", ("ButtonSymbols",)),
|
||||
("QBoxLayout", ("Direction",)),
|
||||
("QColorDialog", ("ColorDialogOption",)),
|
||||
("QComboBox", ("SizeAdjustPolicy", "InsertPolicy")),
|
||||
("QCompleter", ("CompletionMode",)),
|
||||
("QDateTimeEdit", ("Section",)),
|
||||
("QDialog", ("DialogCode",)),
|
||||
("QDialogButtonBox", ("StandardButton", "ButtonRole")),
|
||||
("QDockWidget", ("DockWidgetFeature",)),
|
||||
("QFileDialog", ("Option", "FileMode", "AcceptMode", "DialogLabel")),
|
||||
("QFormLayout", ("FieldGrowthPolicy", "ItemRole")),
|
||||
("QFrame", ("Shape", "Shadow")),
|
||||
("QGraphicsItem", ("GraphicsItemFlag",)),
|
||||
("QGraphicsPixmapItem", ("ShapeMode",)),
|
||||
("QGraphicsView", ("ViewportAnchor", "DragMode")),
|
||||
("QHeaderView", ("ResizeMode",)),
|
||||
("QLayout", ("SizeConstraint",)),
|
||||
("QLineEdit", ("EchoMode",)),
|
||||
(
|
||||
"QListView",
|
||||
("Flow", "BrowserLayout", "ResizeMode", "Movement", "ViewMode"),
|
||||
),
|
||||
("QListWidgetItem", ("ItemType",)),
|
||||
("QMessageBox", ("StandardButton", "Icon", "ButtonRole")),
|
||||
("QPlainTextEdit", ("LineWrapMode",)),
|
||||
("QProgressBar", ("Direction",)),
|
||||
("QRubberBand", ("Shape",)),
|
||||
("QSizePolicy", ("ControlType", "Policy")),
|
||||
("QSlider", ("TickPosition",)),
|
||||
(
|
||||
"QStyle",
|
||||
(
|
||||
"SubElement",
|
||||
"ComplexControl",
|
||||
"StandardPixmap",
|
||||
"ControlElement",
|
||||
"PixelMetric",
|
||||
"StateFlag",
|
||||
"SubControl",
|
||||
),
|
||||
),
|
||||
("QSystemTrayIcon", ("MessageIcon", "ActivationReason")),
|
||||
("QTabBar", ("ButtonPosition",)),
|
||||
("QTabWidget", ("TabShape", "TabPosition")),
|
||||
("QTextEdit", ("LineWrapMode",)),
|
||||
("QToolButton", ("ToolButtonPopupMode",)),
|
||||
("QWizard", ("WizardStyle", "WizardOption")),
|
||||
],
|
||||
),
|
||||
)
|
||||
|
||||
_renamed_enum_cases = {
|
||||
"QComboBox": {
|
||||
"AdjustToMinimumContentsLength": "AdjustToMinimumContentsLengthWithIcon"
|
||||
},
|
||||
"QDialogButtonBox": {"No": "NoButton"},
|
||||
"QPainter": {"HighQualityAntialiasing": "Antialiasing"},
|
||||
"QPalette": {"Background": "Window", "Foreground": "WindowText"},
|
||||
"Qt": {"MatchRegExp": "MatchRegularExpression", "MidButton": "MiddleButton"},
|
||||
}
|
||||
|
||||
|
||||
# This works by wrapping each enum-containing Qt class (eg QAction) in a proxy.
|
||||
# When an attribute is missing from the underlying Qt class, __getattr__ is
|
||||
# called, and we try fetching the attribute from each of the declared enums
|
||||
# for that module. If a match is found, a deprecation warning is printed.
|
||||
#
|
||||
# Looping through enumerations is not particularly efficient on a large type like
|
||||
# Qt, but we only pay the cost when an attribute is not found. In the worst case,
|
||||
# it's about 50ms per 1000 failed lookups on the Qt module.
|
||||
|
||||
|
||||
def _instrument_type(
|
||||
module: types.ModuleType, type_name: str, enums: list[str]
|
||||
) -> None:
|
||||
type = getattr(module, type_name)
|
||||
renamed_attrs = _renamed_enum_cases.get(type_name, {})
|
||||
|
||||
class QtClassProxyType(type.__class__):
|
||||
def __getattr__(cls, provided_name): # pylint: disable=no-self-argument
|
||||
# we know this is not an enum
|
||||
if provided_name == "__pyqtSignature__":
|
||||
raise AttributeError
|
||||
|
||||
name = renamed_attrs.get(provided_name) or provided_name
|
||||
|
||||
for enum_name in enums:
|
||||
enum = getattr(type, enum_name)
|
||||
try:
|
||||
val = getattr(enum, name)
|
||||
except AttributeError:
|
||||
continue
|
||||
|
||||
print_deprecation_warning(
|
||||
f"'{type_name}.{provided_name}' will stop working. Please use '{type_name}.{enum_name}.{name}' instead."
|
||||
)
|
||||
return val
|
||||
|
||||
return getattr(type, name)
|
||||
|
||||
class QtClassProxy(
|
||||
type, metaclass=QtClassProxyType
|
||||
): # pylint: disable=invalid-metaclass
|
||||
@staticmethod
|
||||
def _without_compat_wrapper():
|
||||
return type
|
||||
|
||||
setattr(module, type_name, QtClassProxy)
|
||||
|
||||
|
||||
for module, type_to_enum_list in _enum_map:
|
||||
for type_name, enums in type_to_enum_list:
|
||||
_instrument_type(module, type_name, enums)
|
||||
|
||||
# Alias classes shifted between QtWidgets and QtGui
|
||||
##########################################################################
|
||||
|
||||
PyQt6.QtWidgets.QAction = PyQt6.QtGui.QAction
|
||||
PyQt6.QtWidgets.QActionGroup = PyQt6.QtGui.QActionGroup
|
||||
PyQt6.QtWidgets.QShortcut = PyQt6.QtGui.QShortcut
|
||||
|
||||
# Alias classes shifted between QtWebEngineWidgets and QtWebEngineCore
|
||||
##########################################################################
|
||||
|
||||
PyQt6.QtWebEngineWidgets.QWebEnginePage = PyQt6.QtWebEngineCore.QWebEnginePage
|
||||
PyQt6.QtWebEngineWidgets.QWebEngineHistory = PyQt6.QtWebEngineCore.QWebEngineHistory
|
||||
PyQt6.QtWebEngineWidgets.QWebEngineProfile = PyQt6.QtWebEngineCore.QWebEngineProfile
|
||||
PyQt6.QtWebEngineWidgets.QWebEngineScript = PyQt6.QtWebEngineCore.QWebEngineScript
|
||||
PyQt6.QtWebEngineWidgets.QWebEngineScriptCollection = (
|
||||
PyQt6.QtWebEngineCore.QWebEngineScriptCollection
|
||||
)
|
||||
PyQt6.QtWebEngineWidgets.QWebEngineClientCertificateSelection = (
|
||||
PyQt6.QtWebEngineCore.QWebEngineClientCertificateSelection
|
||||
)
|
||||
PyQt6.QtWebEngineWidgets.QWebEngineSettings = PyQt6.QtWebEngineCore.QWebEngineSettings
|
||||
PyQt6.QtWebEngineWidgets.QWebEngineFullScreenRequest = (
|
||||
PyQt6.QtWebEngineCore.QWebEngineFullScreenRequest
|
||||
)
|
||||
PyQt6.QtWebEngineWidgets.QWebEngineContextMenuData = (
|
||||
PyQt6.QtWebEngineCore.QWebEngineContextMenuRequest
|
||||
)
|
||||
PyQt6.QtWebEngineWidgets.QWebEngineDownloadItem = (
|
||||
PyQt6.QtWebEngineCore.QWebEngineDownloadRequest
|
||||
)
|
||||
|
||||
# Aliases for other miscellaneous class changes
|
||||
##########################################################################
|
||||
|
||||
PyQt6.QtCore.QRegExp = PyQt6.QtCore.QRegularExpression
|
||||
|
||||
|
||||
# Mock the removed PyQt5.Qt module
|
||||
##########################################################################
|
||||
|
||||
sys.modules["PyQt5.Qt"] = sys.modules["aqt.qt"]
|
||||
# support 'from PyQt5 import Qt', as it's an alias to PyQt6
|
||||
PyQt6.Qt = sys.modules["aqt.qt"]
|
|
@ -772,19 +772,14 @@ class RecordDialog(QDialog):
|
|||
saveGeom(self, "audioRecorder2")
|
||||
|
||||
def _start_recording(self) -> None:
|
||||
if qtmajor > 5:
|
||||
if macos_helper and platform.machine() == "arm64":
|
||||
self._recorder = NativeMacRecorder(
|
||||
namedtmp("rec.wav"),
|
||||
)
|
||||
else:
|
||||
self._recorder = QtAudioInputRecorder(
|
||||
namedtmp("rec.wav"), self.mw, self._parent
|
||||
)
|
||||
if macos_helper and platform.machine() == "arm64":
|
||||
self._recorder = NativeMacRecorder(
|
||||
namedtmp("rec.wav"),
|
||||
)
|
||||
else:
|
||||
from aqt.qt.qt5_audio import QtAudioInputRecorder as Qt5Recorder
|
||||
|
||||
self._recorder = Qt5Recorder(namedtmp("rec.wav"), self.mw, self._parent)
|
||||
self._recorder = QtAudioInputRecorder(
|
||||
namedtmp("rec.wav"), self.mw, self._parent
|
||||
)
|
||||
self._recorder.start(self._start_timer)
|
||||
|
||||
def _start_timer(self) -> None:
|
||||
|
|
|
@ -6,16 +6,10 @@ from __future__ import annotations
|
|||
import io
|
||||
import re
|
||||
import sys
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
from PyQt6.uic import compileUi
|
||||
except ImportError:
|
||||
# ARM64 Linux builds may not have access to PyQt6, and may have aliased
|
||||
# it to PyQt5. We allow fallback, but the _qt6.py files will not be valid.
|
||||
from PyQt5.uic import compileUi # type: ignore
|
||||
|
||||
from dataclasses import dataclass
|
||||
from PyQt6.uic import compileUi
|
||||
|
||||
|
||||
def compile(ui_file: str | Path) -> str:
|
||||
|
@ -53,21 +47,9 @@ def with_fixes_for_qt6(code: str) -> str:
|
|||
return "\n".join(outlines)
|
||||
|
||||
|
||||
def with_fixes_for_qt5(code: str) -> str:
|
||||
code = code.replace(
|
||||
"from PyQt5 import QtCore, QtGui, QtWidgets",
|
||||
"from PyQt5 import QtCore, QtGui, QtWidgets\nfrom aqt.utils import tr\n",
|
||||
)
|
||||
code = code.replace("Qt6", "Qt5")
|
||||
code = code.replace("QtGui.QAction", "QtWidgets.QAction")
|
||||
code = code.replace("import icons_rc", "")
|
||||
return code
|
||||
|
||||
|
||||
@dataclass
|
||||
class UiFileAndOutputs:
|
||||
ui_file: Path
|
||||
qt5_file: str
|
||||
qt6_file: str
|
||||
|
||||
|
||||
|
@ -82,7 +64,6 @@ def get_files() -> list[UiFileAndOutputs]:
|
|||
out.append(
|
||||
UiFileAndOutputs(
|
||||
ui_file=path,
|
||||
qt5_file=outpath.replace(".ui", "_qt5.py"),
|
||||
qt6_file=outpath.replace(".ui", "_qt6.py"),
|
||||
)
|
||||
)
|
||||
|
@ -93,8 +74,5 @@ if __name__ == "__main__":
|
|||
for entry in get_files():
|
||||
stock = compile(entry.ui_file)
|
||||
for_qt6 = with_fixes_for_qt6(stock)
|
||||
for_qt5 = with_fixes_for_qt5(for_qt6)
|
||||
with open(entry.qt5_file, "w") as file:
|
||||
file.write(for_qt5)
|
||||
with open(entry.qt6_file, "w") as file:
|
||||
file.write(for_qt6)
|
||||
|
|
Loading…
Reference in a new issue