[gui] When starting app, load config in GUI, not CLI (#149)

If loading invalid config via command line,
show error via GUI dialog instead of CLI stacktrace/etc.
pull/357/head
nyanpasu64 2019-01-20 16:42:44 -08:00 zatwierdzone przez GitHub
rodzic 80ec450dc9
commit e058a6caa0
2 zmienionych plików z 72 dodań i 48 usunięć

Wyświetl plik

@ -115,9 +115,8 @@ def main(
show_gui = not any([write, play, render])
# Create cfg: Config object.
cfg: Optional[Config] = None
cfg_path: Optional[Path] = None
# Gather data for cfg: Config object.
cfg_or_path: Union[Config, Path, None] = None
cfg_dir: Optional[str] = None
wav_list: List[Path] = []
@ -144,8 +143,7 @@ def main(
if len(files) > 1:
raise click.ClickException(
f'Cannot supply multiple arguments when providing config {path}')
cfg = yaml.load(path)
cfg_path = path
cfg_or_path = path
cfg_dir = str(path.parent)
break
@ -159,11 +157,11 @@ def main(
f'Supplied nonexistent file or wildcard: {path}')
wav_list += matches
if not cfg:
if not cfg_or_path:
# cfg and cfg_dir are always initialized together.
channels = [ChannelConfig(str(wav_path)) for wav_path in wav_list]
cfg = default_config(
cfg_or_path = default_config(
master_audio=audio,
# fps=default,
channels=channels,
@ -172,10 +170,11 @@ def main(
)
cfg_dir = '.'
assert cfg_or_path is not None
if show_gui:
def command():
from corrscope import gui
return gui.gui_main(cfg, cfg_path)
return gui.gui_main(cfg_or_path)
if profile:
import cProfile
@ -189,6 +188,16 @@ def main(
else:
if not files:
raise click.UsageError('Must specify files or folders to play')
if isinstance(cfg_or_path, Config):
cfg = cfg_or_path
cfg_path = None
elif isinstance(cfg_or_path, Path):
cfg = yaml.load(cfg_or_path)
cfg_path = cfg_or_path
else:
assert False, cfg_or_path
if write:
write_path = get_path(audio, YAML_NAME)
yaml.dump(cfg, write_path)

Wyświetl plik

@ -48,8 +48,7 @@ def res(file: str) -> str:
return str(APP_DIR / file)
def gui_main(cfg: Config, cfg_path: Optional[Path]):
# TODO read config within MainWindow, and show popup if loading fails.
def gui_main(cfg_or_path: Union[Config, Path]):
# qw.QApplication.setStyle('fusion')
QApp = qw.QApplication
QApp.setAttribute(qc.Qt.AA_EnableHighDpiScaling)
@ -63,7 +62,7 @@ def gui_main(cfg: Config, cfg_path: Optional[Path]):
QApp.setFont(font)
app = qw.QApplication(sys.argv)
window = MainWindow(cfg, cfg_path)
window = MainWindow(cfg_or_path)
sys.exit(app.exec_())
@ -72,14 +71,15 @@ class MainWindow(qw.QMainWindow):
Main window.
Control flow:
__init__
load_cfg
__init__: either
- load_cfg
- load_cfg_from_path
# Opening a document
load_cfg
Opening a document:
- load_cfg_from_path
"""
def __init__(self, cfg: Config, cfg_path: Optional[Path]):
def __init__(self, cfg_or_path: Union[Config, Path]):
super().__init__()
# Load UI.
@ -109,7 +109,14 @@ class MainWindow(qw.QMainWindow):
self.corr_thread: Optional[CorrThread] = None
# Bind config to UI.
self.load_cfg(cfg, cfg_path)
if isinstance(cfg_or_path, Config):
self.load_cfg(cfg_or_path, None)
elif isinstance(cfg_or_path, Path):
self.load_cfg_from_path(cfg_or_path)
else:
raise TypeError(
f"argument cfg={cfg_or_path} has invalid type {obj_name(cfg_or_path)}"
)
self.show()
@ -133,37 +140,6 @@ class MainWindow(qw.QMainWindow):
channel_view: "ChannelTableView"
channelsGroup: qw.QGroupBox
def closeEvent(self, event: QCloseEvent) -> None:
"""Called on closing window."""
if self.prompt_save():
event.accept()
else:
event.ignore()
def on_action_new(self):
if not self.prompt_save():
return
cfg = default_config()
self.load_cfg(cfg, None)
def on_action_open(self):
if not self.prompt_save():
return
name, file_type = qw.QFileDialog.getOpenFileName(
self, "Open config", self.cfg_dir, "YAML files (*.yaml)"
)
if name != "":
cfg_path = Path(name)
try:
# Raises YAML structural exceptions
cfg = yaml.load(cfg_path)
# Raises color getter exceptions
# ISSUE: catching an exception will leave UI in undefined state?
self.load_cfg(cfg, cfg_path)
except Exception as e:
qw.QMessageBox.critical(self, "Error loading file", str(e))
return
def prompt_save(self) -> bool:
"""
Called when user is closing document
@ -188,6 +164,45 @@ class MainWindow(qw.QMainWindow):
else:
return self.on_action_save()
def closeEvent(self, event: QCloseEvent) -> None:
"""Called on closing window."""
if self.prompt_save():
event.accept()
else:
event.ignore()
def on_action_new(self):
if not self.prompt_save():
return
cfg = default_config()
self.load_cfg(cfg, None)
def on_action_open(self):
if not self.prompt_save():
return
name, file_type = qw.QFileDialog.getOpenFileName(
self, "Open config", self.cfg_dir, "YAML files (*.yaml)"
)
if name != "":
cfg_path = Path(name)
self.load_cfg_from_path(cfg_path)
def load_cfg_from_path(self, cfg_path: Path):
# Bind GUI to dummy config, in case loading cfg_path raises Exception.
if self.model is None:
self.load_cfg(default_config(), None)
try:
# Raises YAML structural exceptions
cfg = yaml.load(cfg_path)
# Raises color getter exceptions
self.load_cfg(cfg, cfg_path)
except Exception as e:
qw.QMessageBox.critical(self, "Error loading file", str(e))
return
def load_cfg(self, cfg: Config, cfg_path: Optional[Path]):
self._cfg_path = cfg_path
self._any_unsaved = False