mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 22:12:21 -04:00
Store separate state/geometry for each Qt minor version
Quite a few users have been experiencing crashes recently that were resolved by resetting their window positions/states. I presume this is related to Qt updates, as there have been previous instances where old state caused glitchy behaviour or crashes after a Qt upgrade. The browser headers are now also reset when resetting window positions in the preferences.
This commit is contained in:
parent
4e65793966
commit
19b08eb280
3 changed files with 38 additions and 28 deletions
|
@ -321,17 +321,11 @@ class Table:
|
||||||
hh.setCascadingSectionResizes(False)
|
hh.setCascadingSectionResizes(False)
|
||||||
|
|
||||||
def _save_header(self) -> None:
|
def _save_header(self) -> None:
|
||||||
saveHeader(
|
saveHeader(self._view.horizontalHeader(), self._state.GEOMETRY_KEY_PREFIX)
|
||||||
self._view.horizontalHeader(), self._state.GEOMETRY_KEY_PREFIX + "31"
|
|
||||||
)
|
|
||||||
|
|
||||||
def _restore_header(self) -> None:
|
def _restore_header(self) -> None:
|
||||||
self._view.horizontalHeader().blockSignals(True)
|
self._view.horizontalHeader().blockSignals(True)
|
||||||
# Qt 6.3.1 won't allow headers to be clicked when restoring state from a previous
|
restoreHeader(self._view.horizontalHeader(), self._state.GEOMETRY_KEY_PREFIX)
|
||||||
# version, so we need to bump the key.
|
|
||||||
restoreHeader(
|
|
||||||
self._view.horizontalHeader(), self._state.GEOMETRY_KEY_PREFIX + "31"
|
|
||||||
)
|
|
||||||
self._set_column_sizes()
|
self._set_column_sizes()
|
||||||
self._set_sort_indicator()
|
self._set_sort_indicator()
|
||||||
self._view.horizontalHeader().blockSignals(False)
|
self._view.horizontalHeader().blockSignals(False)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
# Copyright: Ankitects Pty Ltd and contributors
|
# Copyright: Ankitects Pty Ltd and contributors
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
|
|
||||||
|
import re
|
||||||
from typing import Any, cast
|
from typing import Any, cast
|
||||||
|
|
||||||
import anki.lang
|
import anki.lang
|
||||||
|
@ -311,9 +312,9 @@ class Preferences(QDialog):
|
||||||
self.mw.set_theme(Theme(index))
|
self.mw.set_theme(Theme(index))
|
||||||
|
|
||||||
def on_reset_window_sizes(self) -> None:
|
def on_reset_window_sizes(self) -> None:
|
||||||
suffixes = ["Geom", "State", "Splitter"]
|
regexp = re.compile(r"(Geom(etry)?|State|Splitter|Header)(\d+.\d+)?$")
|
||||||
for key in list(self.prof.keys()):
|
for key in list(self.prof.keys()):
|
||||||
if any(key.endswith(suffix) for suffix in suffixes):
|
if regexp.search(key):
|
||||||
del self.prof[key]
|
del self.prof[key]
|
||||||
showInfo(tr.preferences_reset_window_sizes_complete())
|
showInfo(tr.preferences_reset_window_sizes_complete())
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import enum
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
@ -693,11 +694,29 @@ def getSaveFile(
|
||||||
return file
|
return file
|
||||||
|
|
||||||
|
|
||||||
|
class _QtStateKeyKind(enum.Enum):
|
||||||
|
HEADER = enum.auto()
|
||||||
|
SPLITTER = enum.auto()
|
||||||
|
STATE = enum.auto()
|
||||||
|
GEOMETRY = enum.auto()
|
||||||
|
|
||||||
|
|
||||||
|
def _qt_state_key(kind: _QtStateKeyKind, key: str) -> str:
|
||||||
|
"""Construct a key used to save/restore geometry, state, etc.
|
||||||
|
|
||||||
|
Adds Qt version number to key so that different data is saved per Qt version,
|
||||||
|
preventing crashes and bugs when restoring data saved with a different Qt version.
|
||||||
|
"""
|
||||||
|
qt_suffix = f"{qtmajor}.{qtminor}" if qtmajor > 5 else ""
|
||||||
|
return f"{key}{kind.name.capitalize()}{qt_suffix}"
|
||||||
|
|
||||||
|
|
||||||
def saveGeom(widget: QWidget, key: str) -> None:
|
def saveGeom(widget: QWidget, key: str) -> None:
|
||||||
# restoring a fullscreen window is buggy
|
# restoring a fullscreen window is buggy
|
||||||
# (at the time of writing; Qt 6.2.2 and 5.15)
|
# (at the time of writing; Qt 6.2.2 and 5.15)
|
||||||
if not widget.isFullScreen():
|
if not widget.isFullScreen():
|
||||||
aqt.mw.pm.profile[f"{key}Geom"] = widget.saveGeometry()
|
key = _qt_state_key(_QtStateKeyKind.GEOMETRY, key)
|
||||||
|
aqt.mw.pm.profile[key] = widget.saveGeometry()
|
||||||
|
|
||||||
|
|
||||||
def restoreGeom(
|
def restoreGeom(
|
||||||
|
@ -706,7 +725,7 @@ def restoreGeom(
|
||||||
adjustSize: bool = False,
|
adjustSize: bool = False,
|
||||||
default_size: tuple[int, int] | None = None,
|
default_size: tuple[int, int] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
key += "Geom"
|
key = _qt_state_key(_QtStateKeyKind.GEOMETRY, key)
|
||||||
if existing_geom := aqt.mw.pm.profile.get(key):
|
if existing_geom := aqt.mw.pm.profile.get(key):
|
||||||
widget.restoreGeometry(existing_geom)
|
widget.restoreGeometry(existing_geom)
|
||||||
ensureWidgetInScreenBoundaries(widget)
|
ensureWidgetInScreenBoundaries(widget)
|
||||||
|
@ -745,39 +764,35 @@ def ensureWidgetInScreenBoundaries(widget: QWidget) -> None:
|
||||||
|
|
||||||
|
|
||||||
def saveState(widget: QFileDialog | QMainWindow, key: str) -> None:
|
def saveState(widget: QFileDialog | QMainWindow, key: str) -> None:
|
||||||
key += "State"
|
key = _qt_state_key(_QtStateKeyKind.STATE, key)
|
||||||
aqt.mw.pm.profile[key] = widget.saveState()
|
aqt.mw.pm.profile[key] = widget.saveState()
|
||||||
|
|
||||||
|
|
||||||
def restoreState(widget: QFileDialog | QMainWindow, key: str) -> None:
|
def restoreState(widget: QFileDialog | QMainWindow, key: str) -> None:
|
||||||
key += "State"
|
key = _qt_state_key(_QtStateKeyKind.STATE, key)
|
||||||
if aqt.mw.pm.profile.get(key):
|
if data := aqt.mw.pm.profile.get(key):
|
||||||
widget.restoreState(aqt.mw.pm.profile[key])
|
widget.restoreState(data)
|
||||||
|
|
||||||
|
|
||||||
def saveSplitter(widget: QSplitter, key: str) -> None:
|
def saveSplitter(widget: QSplitter, key: str) -> None:
|
||||||
key += "Splitter"
|
key = _qt_state_key(_QtStateKeyKind.SPLITTER, key)
|
||||||
aqt.mw.pm.profile[key] = widget.saveState()
|
aqt.mw.pm.profile[key] = widget.saveState()
|
||||||
|
|
||||||
|
|
||||||
def restoreSplitter(widget: QSplitter, key: str) -> None:
|
def restoreSplitter(widget: QSplitter, key: str) -> None:
|
||||||
key += "Splitter"
|
key = _qt_state_key(_QtStateKeyKind.SPLITTER, key)
|
||||||
if aqt.mw.pm.profile.get(key):
|
if data := aqt.mw.pm.profile.get(key):
|
||||||
widget.restoreState(aqt.mw.pm.profile[key])
|
widget.restoreState(data)
|
||||||
|
|
||||||
|
|
||||||
def _header_key(key: str) -> str:
|
|
||||||
# not compatible across major versions
|
|
||||||
qt_suffix = f"Qt{qtmajor}" if qtmajor > 5 else ""
|
|
||||||
return f"{key}Header{qt_suffix}"
|
|
||||||
|
|
||||||
|
|
||||||
def saveHeader(widget: QHeaderView, key: str) -> None:
|
def saveHeader(widget: QHeaderView, key: str) -> None:
|
||||||
aqt.mw.pm.profile[_header_key(key)] = widget.saveState()
|
key = _qt_state_key(_QtStateKeyKind.HEADER, key)
|
||||||
|
aqt.mw.pm.profile[key] = widget.saveState()
|
||||||
|
|
||||||
|
|
||||||
def restoreHeader(widget: QHeaderView, key: str) -> None:
|
def restoreHeader(widget: QHeaderView, key: str) -> None:
|
||||||
if state := aqt.mw.pm.profile.get(_header_key(key)):
|
key = _qt_state_key(_QtStateKeyKind.HEADER, key)
|
||||||
|
if state := aqt.mw.pm.profile.get(key):
|
||||||
widget.restoreState(state)
|
widget.restoreState(state)
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue