Browse Source

Refactoring to PresentationModel

pull/150/head
chriskiehl 9 years ago
parent
commit
b17f575842
7 changed files with 303 additions and 116 deletions
  1. 55
      gooey/gui/model.py
  2. 148
      gooey/gui/presenter.py
  3. 12
      gooey/gui/widgets/components.py
  4. 3
      gooey/gui/windows/advanced_config.py
  5. 57
      gooey/gui/windows/base_window.py
  6. 62
      gooey/gui/windows/footer.py
  7. 82
      gooey/gui/windows/header.py

55
gooey/gui/model.py

@ -1,10 +1,6 @@
import os
from collections import namedtuple
from itertools import chain
from gooey.gui.lang.i18n import _
# MyWidget = namedtuple('MyWidget', 'type title help nargs commands choices')
from gooey.gui.util.quoting import quote
@ -77,14 +73,28 @@ class MyWidget(object):
class States(object):
CONFIGURING = 'configuring'
RUNNNING = 'running'
SUCCESS = 'success'
ERROR = 'error'
STOPPED = 'stopped'
class MyModel(object):
'''
Needs to:
- sort the args based on a strategy
-
'''
def __init__(self, build_spec):
self.current_state = States.CONFIGURING
self.build_spec = build_spec
self.progress_regex = self.build_spec['progress_regex']
self.progress_expr = self.build_spec['progress_expr']
self.program_name = self.build_spec['program_name']
self.default_size = self.build_spec['default_size']
@ -98,6 +108,33 @@ class MyModel(object):
self.required_args = reqs
self.optional_args = opts
self.text_states = {
States.CONFIGURING: {
'title': _("settings_title"),
'subtitle': self.build_spec['program_description'] or ''
},
States.RUNNNING: {
'title': _("running_title"),
'subtitle': _('running_msg')
},
States.SUCCESS: {
'title': _('finished_title'),
'subtitle': _('finished_msg')
},
States.ERROR: {
'title': _('finished_title'),
'subtitle': _('finished_error')
}
}
def update_state(self, state):
self.current_state = state
text = self.text_states[state]
self.heading_title = text['title']
self.heading_subtitle = text['subtitle']
def is_valid(self):
# TODO: fix skipping_config.. whatever that did
# currently breaks when you supply it as a decorator option
@ -112,16 +149,13 @@ class MyModel(object):
return len(self.required_args) == len(completed_values)
def build_command_line_string(self):
"""
returns the collective values from all of the
widgets contained in the panel"""
# _f = lambda lst: [x for x in lst if x is not None]
optional_args = [arg.value for arg in self.optional_args]
required_args = [c.value for c in self.required_args if c.commands]
position_args = [c.value for c in self.required_args if not c.commands]
if position_args:
position_args.insert(0, "--")
return ' '.join(filter(None, chain(required_args, optional_args, position_args)))
cmd_string = ' '.join(filter(None, chain(required_args, optional_args, position_args)))
return '{} --ignore-gooey {}'.format(self.build_spec['target'], cmd_string)
def group_arguments(self, widget_list):
is_required = lambda widget: widget['required']
@ -160,6 +194,3 @@ class MyModel(object):

148
gooey/gui/presenter.py

@ -1,16 +1,33 @@
import re
from collections import namedtuple
import subprocess
from gooey.gui import component_builder
from gooey.gui.controller2 import ProcessController
from gooey.gui.lang.i18n import _
from gooey.gui.model import States
from gooey.gui.pubsub import pub
from gooey.gui import events
from gooey.gui.windows import views
from multiprocessing.dummy import Pool
class Presenter(object):
def __init__(self, view, model):
self.view = view
self.model = model
self.client_runner = ProcessController(
self.model.progress_regex,
self.model.progress_expr
)
pub.subscribe(self.on_start, events.WINDOW_START)
# console statuses from the other thread
pub.subscribe(self.on_new_message, 'console_update')
pub.subscribe(self.on_progress_change, 'progress_update')
pub.subscribe(self.on_client_done, 'execution_complete')
pub.subscribe(self.on_start, events.WINDOW_START)
def initialize_view(self):
self.view.window_title = self.model.program_name
@ -29,38 +46,149 @@ class Presenter(object):
self.syncronize_from_model()
def on_start(self):
self.update_model()
if not self.model.is_valid():
self.view.show_missing_args_dialog()
cmd_line_args = self.model.build_command_line_string()
print cmd_line_args
command = self.model.build_command_line_string()
self.client_runner.run(command)
self.model.update_state(States.RUNNNING)
self.syncronize_from_model()
def on_new_message(self, msg):
# observes changes coming from the subprocess
self.view.update_console_async(msg)
def on_progress_change(self, progress):
# observes changes coming from the subprocess
print 'Progress:', progress
self.view.update_progress_aync(progress)
def on_client_done(self):
if self.client_runner.was_success():
self.model.update_state(States.SUCCESS)
else:
self.model.update_state(States.ERROR)
self.syncronize_from_model()
# cmd_line_args = self.view.GetOptions()
# command = '{} --ignore-gooey {}'.format(self.build_spec['target'], cmd_line_args)
# pub.send_message(events.WINDOW_CHANGE, view_name=views.RUNNING_SCREEN)
# self.run_client_code(command)
def update_model(self):
self.update_list(self.model.required_args, self.view.required_section.get_values())
self.update_list(self.model.optional_args, self.view.optional_section.get_values())
self.syncronize_from_model()
def update_list(self, collection, new_values):
for index, val in enumerate(new_values):
collection[index].value = val
@staticmethod
def partition(collection, condition):
return filter(condition, collection), filter(lambda x: not condition(x), collection)
def syncronize_from_model(self):
# update heading titles
self.view.heading_title = self.model.heading_title
self.view.heading_subtitle = self.model.heading_subtitle
def should_disable_stop_button(self):
return self.model.stop_button_disabled
# refresh the widgets
for index, widget in enumerate(self.view.required_section):
widget.set_value(self.model.required_args[index]._value)
for index, widget in enumerate(self.view.optional_section):
widget.set_value(self.model.optional_args[index]._value)
# swap the views
getattr(self, self.model.current_state)()
def should_disable_stop_button(self):
return self.model.stop_button_disabled
def configuring(self):
self.view.hide_all_buttons()
self.view.hide('check_mark', 'running_img', 'error_symbol', 'runtime_display')
self.view.show('settings_img', 'cancel_button', 'start_button', 'config_panel')
self.view.Layout()
def running(self):
self.view.hide_all_buttons()
self.view.hide('check_mark', 'settings_img', 'error_symbol', 'config_panel')
self.view.show('running_img', 'stop_button', 'progress_bar', 'runtime_display')
self.view.progress_bar.Pulse()
self.view.Layout()
def success(self):
self.view.hide_all_buttons()
self.view.hide('running_img', 'progress_bar', 'config_panel')
self.view.show('check_mark', 'edit_button', 'restart_button', 'close_button', 'runtime_display')
self.view.Layout()
def error(self):
self.view.hide_all_buttons()
self.view.hide('running_img', 'progress_bar', 'config_panel')
self.view.show('error_symbol', 'edit_button', 'restart_button', 'close_button', 'runtime_display')
self.view.Layout()
# def process_result(self, process):
# _stdout, _ = process.communicate()
# if process.returncode == 0:
# self.model.update_state(States.SUCCESS)
# self.syncronize_from_model()
# # pub.send_message(events.WINDOW_CHANGE, view_name=views.SUCCESS_SCREEN)
# # self.success_dialog()
# else:
# self.model.update_state(States.ERROR)
# self.syncronize_from_model()
# # pub.send_message(events.WINDOW_CHANGE, view_name=views.ERROR_SCREEN)
# # self.error_dialog()
# # FOOTER
# def _init_pages(self):
# def config():
# self.hide_all_buttons()
# self.cancel_button.Show()
# self.start_button.Show()
# self.Layout()
#
# def running():
# self.hide_all_buttons()
# self.stop_button.Show()
# self.progress_bar.Show()
# self.progress_bar.Pulse()
# self.Layout()
#
# def success():
# self.hide_all_buttons()
# self.progress_bar.Hide()
# self.edit_button.Show()
# self.restart_button.Show()
# self.close_button.Show()
# self.Layout()
#
# def error():
# success()
#
# self.layouts = locals()
#
# # BODY
# def _init_pages(self):
#
# def config():
# self.config_panel.Show()
# self.runtime_display.Hide()
#
# def running():
# self.config_panel.Hide()
# self.runtime_display.Show()
# self.Layout()
#
# def success():
# running()
#
# def error():
# running()
#
# self.layouts = locals()

12
gooey/gui/widgets/components.py

@ -101,6 +101,10 @@ class BaseGuiComponent(object):
def get_value(self):
return self.widget_pack.get_value()
def set_value(self, val):
if val:
self.widget_pack.widget.SetValue(str(val))
# def HasOptionString(self):
# return bool(self.widget_pack.option_string)
#
@ -153,6 +157,11 @@ class CheckBox(BaseGuiComponent):
def get_value(self):
return self.widget.GetValue()
def set_value(self, val):
self.widget.SetValue(val)
# def GetValue(self):
# return self.option_strings if self.widget.GetValue() else ''
#
@ -223,6 +232,9 @@ class RadioGroup(object):
def get_value(self):
return [button.GetValue() for button in self.radio_buttons]
def set_value(self, val):
pass
# def GetValue(self):
# vals = [button.GetValue() for button in self.radio_buttons]
# try:

3
gooey/gui/windows/advanced_config.py

@ -71,6 +71,9 @@ class WidgetContainer(wx.Panel):
args = [iter(iterable)] * n
return izip_longest(fillvalue=fillvalue, *args)
def __iter__(self):
return iter(self.widgets)
class ConfigPanel(ScrolledPanel, OptionReader):

57
gooey/gui/windows/base_window.py

@ -39,7 +39,7 @@ class BaseWindow(wx.Frame):
self._init_properties()
self._init_components()
self._do_layout()
self._init_pages()
# self._init_pages()
self.Bind(wx.EVT_SIZE, self.onResize)
self.Bind(wx.EVT_CLOSE, self.onClose)
@ -84,6 +84,9 @@ class BaseWindow(wx.Frame):
def optional_section(self):
return self.config_panel.main_content.optional_section
@property
def progress_bar(self):
return self.foot_panel.progress_bar
def set_display_font_style(self, style):
'''
@ -143,6 +146,8 @@ class BaseWindow(wx.Frame):
for panel in [self, self.head_panel, self.foot_panel, self.config_panel]:
_set_visibility(panel, args)
def hide_all_buttons(self):
self.foot_panel.hide_all_buttons()
def _init_components(self):
# init gui
@ -184,7 +189,7 @@ class BaseWindow(wx.Frame):
self.sizer = sizer
pub.subscribe(self.myListener, "panelListener")
pub.subscribe(self.load_view, events.WINDOW_CHANGE)
# pub.subscribe(self.load_view, events.WINDOW_CHANGE)
@ -201,27 +206,35 @@ class BaseWindow(wx.Frame):
def GetOptionalArgs(self):
return self.config_panel.GetOptionalArgs()
def _init_pages(self):
def config():
self.config_panel.Show()
self.runtime_display.Hide()
def running():
self.config_panel.Hide()
self.runtime_display.Show()
self.Layout()
def success():
running()
def error():
running()
self.layouts = locals()
def load_view(self, view_name=None):
self.layouts.get(view_name, lambda: None)()
def update_console_async(self, msg):
wx.CallAfter(self.PublishConsoleMsg, msg)
def update_progress_aync(self, progress):
wx.CallAfter(self.UpdateProgressBar, progress)
# def _init_pages(self):
#
# def config():
# self.config_panel.Show()
# self.runtime_display.Hide()
#
# def running():
# self.config_panel.Hide()
# self.runtime_display.Show()
# self.Layout()
#
# def success():
# running()
#
# def error():
# running()
#
# self.layouts = locals()
#
# def load_view(self, view_name=None):
# self.layouts.get(view_name, lambda: None)()
def onResize(self, evt):
evt.Skip()

62
gooey/gui/windows/footer.py

@ -39,10 +39,10 @@ class Footer(wx.Panel):
self.layouts = {}
self._init_components()
self._init_pages()
# self._init_pages()
self._do_layout()
pub.subscribe(self.load_view, events.WINDOW_CHANGE)
# pub.subscribe(self.load_view, events.WINDOW_CHANGE)
for button in self.buttons:
self.Bind(wx.EVT_BUTTON, self.dispatch_click, button)
@ -66,35 +66,35 @@ class Footer(wx.Panel):
pub.send_message(str(event.GetId()))
event.Skip()
def _init_pages(self):
def config():
self.hide_all_buttons()
self.cancel_button.Show()
self.start_button.Show()
self.Layout()
def running():
self.hide_all_buttons()
self.stop_button.Show()
self.progress_bar.Show()
self.progress_bar.Pulse()
self.Layout()
def success():
self.hide_all_buttons()
self.progress_bar.Hide()
self.edit_button.Show()
self.restart_button.Show()
self.close_button.Show()
self.Layout()
def error():
success()
self.layouts = locals()
def load_view(self, view_name=None):
self.layouts.get(view_name, lambda: None)()
# def _init_pages(self):
# def config():
# self.hide_all_buttons()
# self.cancel_button.Show()
# self.start_button.Show()
# self.Layout()
#
# def running():
# self.hide_all_buttons()
# self.stop_button.Show()
# self.progress_bar.Show()
# self.progress_bar.Pulse()
# self.Layout()
#
# def success():
# self.hide_all_buttons()
# self.progress_bar.Hide()
# self.edit_button.Show()
# self.restart_button.Show()
# self.close_button.Show()
# self.Layout()
#
# def error():
# success()
#
# self.layouts = locals()
#
# def load_view(self, view_name=None):
# self.layouts.get(view_name, lambda: None)()
def hide_all_buttons(self):
for button in self.buttons:

82
gooey/gui/windows/header.py

@ -27,15 +27,15 @@ class FrameHeader(wx.Panel):
self.check_mark = None
self.error_symbol = None
self.layouts = {}
# self.layouts = {}
self._init_properties()
# self._init_components(heading, subheading)
self._init_components()
self._init_pages()
# self._init_pages()
self._do_layout()
pub.subscribe(self.load_view, events.WINDOW_CHANGE)
# pub.subscribe(self.load_view, events.WINDOW_CHANGE)
@property
def title(self):
@ -94,42 +94,42 @@ class FrameHeader(wx.Panel):
sizer.AddStretchSpacer(1)
return sizer
def _init_pages(self):
def config():
self._header.SetLabel(self.heading_msg)
self._subheader.SetLabel(self.subheading_msg)
self.settings_img.Show()
self.check_mark.Hide()
self.running_img.Hide()
self.error_symbol.Hide()
self.Layout()
def running():
self._header.SetLabel(i18n._("running_title"))
self._subheader.SetLabel(i18n._('running_msg'))
self.check_mark.Hide()
self.settings_img.Hide()
self.running_img.Show()
self.error_symbol.Hide()
self.Layout()
def success():
self._header.SetLabel(i18n._('finished_title'))
self._subheader.SetLabel(i18n._('finished_msg'))
self.running_img.Hide()
self.check_mark.Show()
self.Layout()
def error():
self._header.SetLabel(i18n._('finished_title'))
self._subheader.SetLabel(i18n._('finished_error'))
self.running_img.Hide()
self.error_symbol.Show()
self.Layout()
self.layouts = locals()
def load_view(self, view_name=None):
self.layouts.get(view_name, lambda: None)()
# def _init_pages(self):
#
# def config():
# self._header.SetLabel(self.heading_msg)
# self._subheader.SetLabel(self.subheading_msg)
# self.settings_img.Show()
# self.check_mark.Hide()
# self.running_img.Hide()
# self.error_symbol.Hide()
# self.Layout()
#
# def running():
# self._header.SetLabel(i18n._("running_title"))
# self._subheader.SetLabel(i18n._('running_msg'))
# self.check_mark.Hide()
# self.settings_img.Hide()
# self.running_img.Show()
# self.error_symbol.Hide()
# self.Layout()
#
# def success():
# self._header.SetLabel(i18n._('finished_title'))
# self._subheader.SetLabel(i18n._('finished_msg'))
# self.running_img.Hide()
# self.check_mark.Show()
# self.Layout()
#
# def error():
# self._header.SetLabel(i18n._('finished_title'))
# self._subheader.SetLabel(i18n._('finished_error'))
# self.running_img.Hide()
# self.error_symbol.Show()
# self.Layout()
#
# self.layouts = locals()
#
# def load_view(self, view_name=None):
# self.layouts.get(view_name, lambda: None)()
Loading…
Cancel
Save