2019-09-10 00:54:28 +00:00
|
|
|
# Created By: Virgil Dupras
|
|
|
|
# Created On: 2009-05-03
|
|
|
|
# Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
|
|
|
|
#
|
|
|
|
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
|
|
|
|
# which should be included with this package. The terms are also available at
|
|
|
|
# http://www.gnu.org/licenses/gpl-3.0.html
|
|
|
|
|
2020-12-30 18:43:10 +00:00
|
|
|
from PyQt5.QtCore import Qt, QSettings, QRect, QObject, pyqtSignal, QStandardPaths
|
2020-07-30 18:25:20 +00:00
|
|
|
from PyQt5.QtWidgets import QDockWidget
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
from hscommon.trans import trget
|
|
|
|
from hscommon.util import tryint
|
2020-12-30 18:43:10 +00:00
|
|
|
from hscommon.plat import ISWINDOWS
|
2021-08-18 02:04:09 +00:00
|
|
|
from core.util import executable_folder
|
2020-12-30 18:43:10 +00:00
|
|
|
|
|
|
|
from os import path as op
|
2019-09-10 00:54:28 +00:00
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
tr = trget("qtlib")
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def get_langnames():
|
|
|
|
return {
|
2021-08-07 02:39:02 +00:00
|
|
|
"cs": tr("Czech"),
|
2020-01-01 02:16:27 +00:00
|
|
|
"de": tr("German"),
|
|
|
|
"el": tr("Greek"),
|
2021-08-07 02:39:02 +00:00
|
|
|
"en": tr("English"),
|
|
|
|
"es": tr("Spanish"),
|
|
|
|
"fr": tr("French"),
|
2020-01-01 02:16:27 +00:00
|
|
|
"hy": tr("Armenian"),
|
2021-08-07 02:39:02 +00:00
|
|
|
"it": tr("Italian"),
|
|
|
|
"ja": tr("Japanese"),
|
2020-01-01 02:16:27 +00:00
|
|
|
"ko": tr("Korean"),
|
|
|
|
"nl": tr("Dutch"),
|
|
|
|
"pl_PL": tr("Polish"),
|
|
|
|
"pt_BR": tr("Brazilian"),
|
2021-08-07 02:39:02 +00:00
|
|
|
"ru": tr("Russian"),
|
|
|
|
"tr": tr("Turkish"),
|
|
|
|
"uk": tr("Ukrainian"),
|
2020-01-01 02:16:27 +00:00
|
|
|
"vi": tr("Vietnamese"),
|
2021-08-07 02:39:02 +00:00
|
|
|
"zh_CN": tr("Chinese (Simplified)"),
|
2019-09-10 00:54:28 +00:00
|
|
|
}
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def normalize_for_serialization(v):
|
|
|
|
# QSettings doesn't consider set/tuple as "native" typs for serialization, so if we don't
|
|
|
|
# change them into a list, we get a weird serialized QVariant value which isn't a very
|
|
|
|
# "portable" value.
|
|
|
|
if isinstance(v, (set, tuple)):
|
|
|
|
v = list(v)
|
|
|
|
if isinstance(v, list):
|
|
|
|
v = [normalize_for_serialization(item) for item in v]
|
|
|
|
return v
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
def adjust_after_deserialization(v):
|
|
|
|
# In some cases, when reading from prefs, we end up with strings that are supposed to be
|
|
|
|
# bool or int. Convert these.
|
|
|
|
if isinstance(v, list):
|
|
|
|
return [adjust_after_deserialization(sub) for sub in v]
|
|
|
|
if isinstance(v, str):
|
|
|
|
# might be bool or int, try them
|
2020-01-01 02:16:27 +00:00
|
|
|
if v == "true":
|
2019-09-10 00:54:28 +00:00
|
|
|
return True
|
2020-01-01 02:16:27 +00:00
|
|
|
elif v == "false":
|
2019-09-10 00:54:28 +00:00
|
|
|
return False
|
|
|
|
else:
|
|
|
|
return tryint(v, v)
|
|
|
|
return v
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2021-08-18 02:04:09 +00:00
|
|
|
def create_qsettings():
|
2021-01-12 03:41:14 +00:00
|
|
|
# Create a QSettings instance with the correct arguments.
|
2021-08-18 02:04:09 +00:00
|
|
|
config_location = op.join(executable_folder(), "settings.ini")
|
|
|
|
if op.isfile(config_location):
|
|
|
|
settings = QSettings(config_location, QSettings.IniFormat)
|
|
|
|
settings.setValue("Portable", True)
|
|
|
|
elif ISWINDOWS:
|
|
|
|
# On windows use an ini file in the AppDataLocation instead of registry if possible as it
|
|
|
|
# makes it easier for a user to clear it out when there are issues.
|
|
|
|
locations = QStandardPaths.standardLocations(QStandardPaths.AppDataLocation)
|
|
|
|
if locations:
|
|
|
|
settings = QSettings(op.join(locations[0], "settings.ini"), QSettings.IniFormat)
|
2021-01-12 03:41:14 +00:00
|
|
|
else:
|
2021-08-18 02:04:09 +00:00
|
|
|
settings = QSettings()
|
|
|
|
settings.setValue("Portable", False)
|
2021-01-12 03:41:14 +00:00
|
|
|
else:
|
2021-08-18 02:04:09 +00:00
|
|
|
settings = QSettings()
|
|
|
|
settings.setValue("Portable", False)
|
|
|
|
return settings
|
2021-01-12 03:41:14 +00:00
|
|
|
|
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
# About QRect conversion:
|
|
|
|
# I think Qt supports putting basic structures like QRect directly in QSettings, but I prefer not
|
|
|
|
# to rely on it and stay with generic structures.
|
|
|
|
|
2020-01-01 02:16:27 +00:00
|
|
|
|
2019-09-10 00:54:28 +00:00
|
|
|
class Preferences(QObject):
|
|
|
|
prefsChanged = pyqtSignal()
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
QObject.__init__(self)
|
|
|
|
self.reset()
|
2021-08-18 02:04:09 +00:00
|
|
|
self._settings = create_qsettings()
|
2019-09-10 00:54:28 +00:00
|
|
|
|
2021-08-21 23:02:02 +00:00
|
|
|
def _load_values(self, settings):
|
|
|
|
# Implemented in subclasses
|
2019-09-10 00:54:28 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
def get_rect(self, name, default=None):
|
|
|
|
r = self.get_value(name, default)
|
|
|
|
if r is not None:
|
|
|
|
return QRect(*r)
|
|
|
|
else:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def get_value(self, name, default=None):
|
|
|
|
if self._settings.contains(name):
|
|
|
|
result = adjust_after_deserialization(self._settings.value(name))
|
|
|
|
if result is not None:
|
|
|
|
return result
|
|
|
|
else:
|
|
|
|
# If result is None, but still present in self._settings, it usually means a value
|
|
|
|
# like "@Invalid".
|
|
|
|
return default
|
|
|
|
else:
|
|
|
|
return default
|
|
|
|
|
|
|
|
def load(self):
|
|
|
|
self.reset()
|
|
|
|
self._load_values(self._settings)
|
|
|
|
|
|
|
|
def reset(self):
|
2021-08-21 23:02:02 +00:00
|
|
|
# Implemented in subclasses
|
2019-09-10 00:54:28 +00:00
|
|
|
pass
|
|
|
|
|
2021-08-21 23:02:02 +00:00
|
|
|
def _save_values(self, settings):
|
|
|
|
# Implemented in subclasses
|
2019-09-10 00:54:28 +00:00
|
|
|
pass
|
|
|
|
|
|
|
|
def save(self):
|
|
|
|
self._save_values(self._settings)
|
|
|
|
self._settings.sync()
|
|
|
|
|
|
|
|
def set_rect(self, name, r):
|
|
|
|
if isinstance(r, QRect):
|
2021-08-21 23:02:02 +00:00
|
|
|
rect_as_list = [r.x(), r.y(), r.width(), r.height()]
|
|
|
|
self.set_value(name, rect_as_list)
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def set_value(self, name, value):
|
|
|
|
self._settings.setValue(name, normalize_for_serialization(value))
|
|
|
|
|
|
|
|
def saveGeometry(self, name, widget):
|
2020-10-28 00:45:03 +00:00
|
|
|
# We save geometry under a 7-sized int array: first item is a flag
|
|
|
|
# for whether the widget is maximized, second item is a flag for whether
|
|
|
|
# the widget is docked, third item is a Qt::DockWidgetArea enum value,
|
|
|
|
# and the other 4 are (x, y, w, h).
|
2019-09-10 00:54:28 +00:00
|
|
|
m = 1 if widget.isMaximized() else 0
|
2020-07-30 18:25:20 +00:00
|
|
|
d = 1 if isinstance(widget, QDockWidget) and not widget.isFloating() else 0
|
|
|
|
area = widget.parent.dockWidgetArea(widget) if d else 0
|
2019-09-10 00:54:28 +00:00
|
|
|
r = widget.geometry()
|
2021-08-21 23:02:02 +00:00
|
|
|
rect_as_list = [r.x(), r.y(), r.width(), r.height()]
|
|
|
|
self.set_value(name, [m, d, area] + rect_as_list)
|
2019-09-10 00:54:28 +00:00
|
|
|
|
|
|
|
def restoreGeometry(self, name, widget):
|
2020-01-01 02:16:27 +00:00
|
|
|
geometry = self.get_value(name)
|
2020-07-30 18:25:20 +00:00
|
|
|
if geometry and len(geometry) == 7:
|
|
|
|
m, d, area, x, y, w, h = geometry
|
2019-09-10 00:54:28 +00:00
|
|
|
if m:
|
|
|
|
widget.setWindowState(Qt.WindowMaximized)
|
|
|
|
else:
|
|
|
|
r = QRect(x, y, w, h)
|
|
|
|
widget.setGeometry(r)
|
2020-07-30 18:25:20 +00:00
|
|
|
if isinstance(widget, QDockWidget):
|
|
|
|
# Inform of the previous dock state and the area used
|
|
|
|
return bool(d), area
|
|
|
|
return False, 0
|