gui: add a persisted user config; remember the last Sud file dialog dir
New client/user_config.py - a small JSON-backed key/value store at ~/.config/brewpi/gui.json for GUI preferences that should survive restarts (distinct from the server's config.json and from sude/*.json schedules). First use: Save/Load Sud's file dialogs now open in whichever directory was last used, instead of always starting at cwd.
This commit is contained in:
@@ -5,6 +5,7 @@ import json
|
|||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
|
from pathlib import Path
|
||||||
import matplotlib
|
import matplotlib
|
||||||
matplotlib.use("Qt5Agg")
|
matplotlib.use("Qt5Agg")
|
||||||
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
|
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg
|
||||||
@@ -15,6 +16,7 @@ from ws.client.ws_client import WsClient
|
|||||||
from ws.message import MessageDispatcherSync
|
from ws.message import MessageDispatcherSync
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
import asyncio
|
import asyncio
|
||||||
|
from user_config import UserConfig
|
||||||
|
|
||||||
# str(SudState.X) values (as sent in the 'State' message) that count as
|
# str(SudState.X) values (as sent in the 'State' message) that count as
|
||||||
# "running" for enabling/disabling the Start/Pause/Stop toolbar actions.
|
# "running" for enabling/disabling the Start/Pause/Stop toolbar actions.
|
||||||
@@ -234,6 +236,7 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
QtWidgets.QMainWindow.__init__(self)
|
QtWidgets.QMainWindow.__init__(self)
|
||||||
self.setWindowIcon(QtGui.QIcon('res/beer.png'))
|
self.setWindowIcon(QtGui.QIcon('res/beer.png'))
|
||||||
self.user_message_signal.connect(self.on_user_message_signal)
|
self.user_message_signal.connect(self.on_user_message_signal)
|
||||||
|
self.user_config = UserConfig()
|
||||||
|
|
||||||
loop = asyncio.new_event_loop()
|
loop = asyncio.new_event_loop()
|
||||||
asyncio.set_event_loop(loop)
|
asyncio.set_event_loop(loop)
|
||||||
@@ -569,16 +572,20 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
# Pick the destination up front, on the GUI thread - the actual
|
# Pick the destination up front, on the GUI thread - the actual
|
||||||
# write happens in on_sud_changed(), which runs off a worker thread
|
# write happens in on_sud_changed(), which runs off a worker thread
|
||||||
# and must not touch Qt (e.g. open a file dialog) itself.
|
# and must not touch Qt (e.g. open a file dialog) itself.
|
||||||
path, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Save Sud", filter="JSON files (*.json)")
|
start_dir = self.user_config.get('sud_dir', '')
|
||||||
|
path, _ = QtWidgets.QFileDialog.getSaveFileName(self, "Save Sud", start_dir, filter="JSON files (*.json)")
|
||||||
if not path:
|
if not path:
|
||||||
return
|
return
|
||||||
|
self.user_config.set('sud_dir', str(Path(path).parent))
|
||||||
self.sud_save_path = path
|
self.sud_save_path = path
|
||||||
self.msg_sud.send({'Save': True})
|
self.msg_sud.send({'Save': True})
|
||||||
|
|
||||||
def on_action_sud_load(self):
|
def on_action_sud_load(self):
|
||||||
path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Load Sud", filter="JSON files (*.json)")
|
start_dir = self.user_config.get('sud_dir', '')
|
||||||
|
path, _ = QtWidgets.QFileDialog.getOpenFileName(self, "Load Sud", start_dir, filter="JSON files (*.json)")
|
||||||
if not path:
|
if not path:
|
||||||
return
|
return
|
||||||
|
self.user_config.set('sud_dir', str(Path(path).parent))
|
||||||
with open(path) as f:
|
with open(path) as f:
|
||||||
data = json.load(f)
|
data = json.load(f)
|
||||||
self.msg_sud.send({'Load': data})
|
self.msg_sud.send({'Load': data})
|
||||||
|
|||||||
@@ -0,0 +1,27 @@
|
|||||||
|
import json
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
DEFAULT_PATH = Path.home() / ".config" / "brewpi" / "gui.json"
|
||||||
|
|
||||||
|
|
||||||
|
class UserConfig:
|
||||||
|
"""Small persisted key/value store for GUI preferences that should
|
||||||
|
survive across restarts (e.g. the last directory used for a file
|
||||||
|
dialog) - local user state, not version-controlled config."""
|
||||||
|
|
||||||
|
def __init__(self, path=DEFAULT_PATH):
|
||||||
|
self.path = path
|
||||||
|
self.data = {}
|
||||||
|
if self.path.exists():
|
||||||
|
try:
|
||||||
|
self.data = json.loads(self.path.read_text())
|
||||||
|
except (json.JSONDecodeError, OSError):
|
||||||
|
self.data = {}
|
||||||
|
|
||||||
|
def get(self, key, default=None):
|
||||||
|
return self.data.get(key, default)
|
||||||
|
|
||||||
|
def set(self, key, value):
|
||||||
|
self.data[key] = value
|
||||||
|
self.path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
self.path.write_text(json.dumps(self.data, indent='\t'))
|
||||||
Reference in New Issue
Block a user