Skip to content

Persist machine-local layout state via QSettings (Tier 2) #85

Description

@pecomyint

Problem

PR #82 introduced user_config.py, which dumps a .dashpva_data.json file into the repository root to persist dock layout and window geometry. This has several problems:

  • Dirties the git working tree
  • Breaks with multiple users sharing one install
  • Reimplements what PyQt's native QSettings already provides

Scope — Tier 2: Machine-Local Layout Only

This issue covers physical/machine-specific UI state that should NOT travel in TOML exports. Semantic viewer preferences (colormap, autoscale, etc.) are handled by #77 via ConfigSource.

Decision rule

"Would I want this setting to travel with my TOML config to another machine?"

What to persist (Tier 2)

Key QSettings path Current location
Window geometry geometry user_config.py → JSON
Dock layout (saveState) dock_state user_config.py → JSON
Dock state version dock_state_version Hard-coded constant
Last-typed PV prefix last_prefix user_config.py → JSON
Splitter positions splitter_sizes Not persisted
Last file browser dirs last_poni_dir, last_cif_dir settings.py globals (reset on restart)

Why these do NOT belong in ConfigSource/TOML:

  • Window geometry saved on a 32" 4K monitor would spawn off-screen on a 13" laptop
  • Dock layout depends on monitor arrangement and window size
  • Last-typed prefix is convenience state for one user on one machine

Implementation

Add to BaseWindow (so all viewers get it for free)

# base_window.py
from PyQt5.QtCore import QSettings

def _qsettings(self) -> QSettings:
    """Return a QSettings scoped to this viewer type."""
    viewer_key = type(self).__name__
    return QSettings("DashPVA", viewer_key)

def save_layout(self) -> None:
    s = self._qsettings()
    s.setValue("geometry", self.saveGeometry())
    s.setValue("dock_state", self.saveState())

def restore_layout(self) -> None:
    s = self._qsettings()
    geom = s.value("geometry")
    if geom:
        self.restoreGeometry(geom)
    state = s.value("dock_state")
    if state:
        self.restoreState(state)

Wire into BaseWindow.closeEvent()

def closeEvent(self, event):
    self.save_layout()
    event.accept()

Area detector viewer changes

  • Replace from dashpva.utils.user_config import load_last, save_last with self._qsettings()
  • Call self.restore_layout() in __init__ after docks are created
  • Call self.save_layout() in closeEvent
  • Last-typed prefix: self._qsettings().setValue("last_prefix", prefix)

Storage locations (automatic, no custom code)

  • macOS: ~/Library/Preferences/com.dashpva.DiffractionImageWindow.plist
  • Linux: ~/.config/DashPVA/DiffractionImageWindow.conf

Delete

  • src/dashpva/utils/user_config.py — replaced entirely by QSettings
  • .dashpva_data.json — no longer generated; add to .gitignore as safety net

Acceptance criteria

  • save_layout() and restore_layout() added to BaseWindow
  • Area detector viewer uses QSettings instead of user_config.py
  • Window geometry and dock layout survive application restart
  • Last-typed PV prefix is remembered between sessions
  • user_config.py and .dashpva_data.json are deleted
  • Works on both macOS and Linux
  • No repo-root files are created or modified at runtime

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions