From c0c7462a337bf8b061c7e9af1f0c210a2faadfc5 Mon Sep 17 00:00:00 2001 From: chriskiehl Date: Mon, 25 May 2015 20:14:49 -0400 Subject: [PATCH] Refactored to pubsub --- gooey/gui/controller.py | 94 ++++++++++++++++++-------------- gooey/gui/events.py | 18 ++++++ gooey/gui/windows/base_window.py | 4 +- gooey/gui/windows/footer.py | 59 +++++++------------- 4 files changed, 93 insertions(+), 82 deletions(-) create mode 100644 gooey/gui/events.py diff --git a/gooey/gui/controller.py b/gooey/gui/controller.py index fbd32f4..f70be73 100644 --- a/gooey/gui/controller.py +++ b/gooey/gui/controller.py @@ -7,7 +7,11 @@ Created on Dec 22, 2013 import wx import sys import subprocess + +from wx.lib.pubsub import pub + from multiprocessing.dummy import Pool +from gooey.gui import events from gooey.gui.lang import i18n @@ -31,7 +35,23 @@ class Controller(object): self.core_gui = base_frame self.build_spec = build_spec - def OnCancelButton(self, widget, event): + # wire up all the observers + pub.subscribe(self.on_cancel, events.WINDOW_CANCEL) + pub.subscribe(self.on_start, events.WINDOW_START) + pub.subscribe(self.on_restart, events.WINDOW_RESTART) + pub.subscribe(self.on_close, events.WINDOW_CLOSE) + + def on_close(self): + self.core_gui.Destroy() + sys.exit() + + def on_restart(self): + self.on_start() + + def manual_restart(self): + self.on_start() + + def on_cancel(self): msg = i18n._('sure_you_want_to_exit') dlg = wx.MessageDialog(None, msg, i18n._('close_program'), wx.YES_NO) result = dlg.ShowModal() @@ -41,61 +61,51 @@ class Controller(object): sys.exit() dlg.Destroy() - def OnStartButton(self, widget, event): - cmd_line_args = self.core_gui.GetOptions() - - if not self.build_spec['manual_start']: - _required = self.core_gui.GetRequiredArgs() - if _required and any(req == '' for req in _required): - self.ShowDialog(i18n._('error_title'), "Must fill in all fields in the Required section!", wx.ICON_ERROR) - return + def on_start(self): + if not self.skipping_config() and not self.required_section_complete(): + return self.show_dialog(i18n._('error_title'), i18n._('error_required_fields'), wx.ICON_ERROR) + cmd_line_args = self.core_gui.GetOptions() command = '{0} {1}'.format(self.build_spec['target'], cmd_line_args) self.core_gui.NextPage() - self.RunClientCode(command) - - def RunClientCode(self, command): - def doInBackground(process, callback): - while True: - line = process.stdout.readline() - if not line: - break - wx.CallAfter(self.core_gui.PublishConsoleMsg, line) - wx.CallAfter(callback, process) - p = subprocess.Popen(command, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) - _pool = Pool(1) - _pool.apply_async(doInBackground, (p, self.HandleResult)) + self.run_client_code(command) - def HandleResult(self, process): + def run_client_code(self, command): + p = subprocess.Popen(command, bufsize=1, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) + pool = Pool(1) + pool.apply_async(self.read_stdout, (p, self.process_result)) + + def read_stdout(self, process, callback): + while True: + line = process.stdout.readline() + if not line: + break + wx.CallAfter(self.core_gui.PublishConsoleMsg, line) + wx.CallAfter(callback, process) + + def process_result(self, process): _stdout, _stderr = process.communicate() if process.returncode == 0: self.core_gui.NextPage() - self.ShowGoodFinishedDialog() + self.success_dialog() else: self.core_gui.NextPage() - self.ShowBadFinishedDialog(_stderr) + self.error_dialog(_stderr) - def OnRestartButton(self, widget, event): - self.OnStartButton(None, event) - - def ManualStart(self): - self.OnStartButton(None, None) - - def OnCloseButton(self, widget, event): - self.core_gui.Destroy() - sys.exit() + def skipping_config(self): + return self.build_spec['manual_start'] - def ShowGoodFinishedDialog(self): - self.ShowDialog(i18n._("execution_finished"), - i18n._('success_message'), - wx.ICON_INFORMATION) + def required_section_complete(self): + _required = self.core_gui.GetRequiredArgs() + return _required and not any(req == '' for req in _required) - def ShowBadFinishedDialog(self, error_msg): - msg = i18n._('uh_oh').format(error_msg) - self.ShowDialog(i18n._('error_title'), msg, wx.ICON_ERROR) + def success_dialog(self): + self.show_dialog(i18n._("execution_finished"), i18n._('success_message'), wx.ICON_INFORMATION) + def error_dialog(self, error_msg): + self.show_dialog(i18n._('error_title'), i18n._('uh_oh').format(error_msg), wx.ICON_ERROR) - def ShowDialog(self, title, content, style): + def show_dialog(self, title, content, style): a = wx.MessageDialog(None, content, title, style) a.ShowModal() a.Destroy() diff --git a/gooey/gui/events.py b/gooey/gui/events.py new file mode 100644 index 0000000..f857092 --- /dev/null +++ b/gooey/gui/events.py @@ -0,0 +1,18 @@ +""" +App wide event registry + +Everything in the application is communitcated via pubsub. These are the events that +tie everythign together. +""" +import wx + +new_id = lambda: str(wx.NewId()) + +WINDOW_STOP = new_id() +WINDOW_CANCEL = new_id() +WINDOW_CLOSE = new_id() +WINDOW_START = new_id() +WINDOW_RESTART = new_id() + + + diff --git a/gooey/gui/windows/base_window.py b/gooey/gui/windows/base_window.py index fd9753d..cd0afd3 100644 --- a/gooey/gui/windows/base_window.py +++ b/gooey/gui/windows/base_window.py @@ -56,7 +56,7 @@ class BaseWindow(wx.Frame): parent=self) self.config_panel = AdvancedConfigPanel(self, self.build_spec) self.runtime_display = RuntimeDisplay(self) - self.foot_panel = footer.Footer(self, self._controller) + self.foot_panel = footer.Footer(self) self.panels = [self.head_panel, self.config_panel, self.foot_panel] def _do_layout(self): @@ -117,7 +117,7 @@ class BaseWindow(wx.Frame): self.Layout() def ManualStart(self): - self._controller.ManualStart() + self._controller.manual_restart() def onResize(self, evt): evt.Skip() diff --git a/gooey/gui/windows/footer.py b/gooey/gui/windows/footer.py index 6074cd8..2af1bc9 100644 --- a/gooey/gui/windows/footer.py +++ b/gooey/gui/windows/footer.py @@ -7,8 +7,10 @@ Created on Dec 23, 2013 import wx import wx.animate -from gooey.gui import imageutil, image_repository +from wx.lib.pubsub import pub + from gooey.gui.lang import i18n +from gooey.gui import imageutil, image_repository, events class AbstractFooter(wx.Panel): @@ -29,6 +31,7 @@ class AbstractFooter(wx.Panel): self.close_button = None self.stop_button = None self.restart_button = None + self.buttons = None self._init_components() self._init_pages() @@ -36,19 +39,14 @@ class AbstractFooter(wx.Panel): def _init_components(self): - ''' - initialize all of the gui used in the footer - TODO: - Add Checkmark image for when the program has finished running. - Refactor image tools into their own module. The resize code is - getting spread around a bit. - ''' - self.cancel_button = self._Button(i18n._('cancel'), wx.ID_CANCEL) - self.start_button = self._Button(i18n._('start'), wx.ID_OK) - self.running_animation = wx.animate.GIFAnimationCtrl(self, -1, image_repository.loader) - self.close_button = self._Button(i18n._("close"), wx.ID_OK) - self.stop_button = self._Button('Stop', wx.ID_OK) # TODO: i18n - self.restart_button = self._Button('Restart', wx.ID_OK) # TODO: i18n + self.cancel_button = self.button(i18n._('cancel'), wx.ID_CANCEL, event_id=int(events.WINDOW_CANCEL)) + self.stop_button = self.button(i18n._('stop'), wx.ID_OK, event_id=int(events.WINDOW_STOP)) + self.start_button = self.button(i18n._('start'), wx.ID_OK, event_id=int(events.WINDOW_START)) + self.close_button = self.button(i18n._("close"), wx.ID_OK, event_id=int(events.WINDOW_CLOSE)) + self.restart_button = self.button(i18n._('restart'), wx.ID_OK, event_id=int(events.WINDOW_RESTART)) + self.running_animation = wx.animate.GIFAnimationCtrl(self, -1, image_repository.loader) + + self.buttons = [self.cancel_button, self.start_button, self.stop_button, self.close_button, self.restart_button] def _init_pages(self): if self.restart_button.IsShown(): self.restart_button.Hide() @@ -96,10 +94,10 @@ class AbstractFooter(wx.Panel): v_sizer.AddStretchSpacer(1) self.SetSizer(v_sizer) - def _Button(self, label=None, style=None): + def button(self, label=None, style=None, event_id=-1): return wx.Button( parent=self, - id=-1, + id=event_id, size=(90, 24), label=label, style=style) @@ -116,10 +114,7 @@ class AbstractFooter(wx.Panel): next(self._pages)() def _load_image(self, img_path, height=70): - return imageutil.resize_bitmap( - self, - imageutil._load_image(img_path), - height) + return imageutil.resize_bitmap(self, imageutil._load_image(img_path), height) class Footer(AbstractFooter): @@ -132,27 +127,15 @@ class Footer(AbstractFooter): controller: controller class used in delagating all the commands ''' - def __init__(self, parent, controller, **kwargs): + def __init__(self, parent, **kwargs): AbstractFooter.__init__(self, parent, **kwargs) + for button in self.buttons: + print button.GetId() + self.Bind(wx.EVT_BUTTON, self.dispatch_click, button) - self.Bind(wx.EVT_BUTTON, self.OnCancelButton, self.cancel_button) - self.Bind(wx.EVT_BUTTON, self.OnStartButton, self.start_button) - self.Bind(wx.EVT_BUTTON, self.OnCloseButton, self.close_button) - self.Bind(wx.EVT_BUTTON, self.OnRestartButton, self.restart_button) - - def OnCancelButton(self, event): - self._controller.OnCancelButton(self, event) + def dispatch_click(self, event): + pub.sendMessage(str(event.GetId())) event.Skip() - def OnCloseButton(self, event): - self._controller.OnCloseButton(self, event) - event.Skip() - - def OnStartButton(self, event): - self._controller.OnStartButton(event, self) - event.Skip() - def OnRestartButton(self, event): - self._controller.OnStartButton(event, self) - event.Skip()