import sys from gooey.gui.processor import ProcessController from gooey.gui.model import States from gooey.gui.pubsub import pub from gooey.gui import events from gooey.gui.windows import layouts import wx 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_cancel, events.WINDOW_CANCEL) pub.subscribe(self.on_stop, events.WINDOW_STOP) pub.subscribe(self.on_start, events.WINDOW_START) pub.subscribe(self.on_restart, events.WINDOW_RESTART) pub.subscribe(self.on_edit, events.WINDOW_EDIT) pub.subscribe(self.on_close, events.WINDOW_CLOSE) # 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_selection_change, events.LIST_BOX) def on_selection_change(self, selection): self.update_model() self.model.active_group = selection self.redraw_from_model() self.syncronize_from_model() def initialize_view(self): self.view.window_title = self.model.program_name self.view.window_size = self.model.default_size self.view.required_section.clear() self.view.optional_section.clear() self.view.required_section.populate(self.model.required_args, self.model.num_required_cols) self.view.optional_section.populate(self.model.optional_args, self.model.num_optional_cols) if self.model.use_monospace_font: self.view.set_display_font_style('monospace') if self.should_disable_stop_button(): self.view.disable_stop_button() else: self.view.enable_stop_button() if self.model.layout_type == layouts.COLUMN: self.view.set_list_contents(list(self.model.argument_groups.keys())) if self.model.auto_start: self.model.update_state(States.RUNNNING) self.on_start() self.syncronize_from_model() 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 syncronize_from_model(self): #TODO move this out of the presenter #TODO Make all view interactions thread safe wx.CallAfter(self.syncronize_from_model_async) def syncronize_from_model_async(self): # update heading titles self.view.heading_title = self.model.heading_title self.view.heading_subtitle = self.model.heading_subtitle # 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 redraw_from_model(self): self.view.freeze() self.view.required_section.clear() self.view.optional_section.clear() self.view.required_section.populate(self.model.required_args, self.model.num_required_cols) self.view.optional_section.populate(self.model.optional_args, self.model.num_optional_cols) getattr(self, self.model.current_state)() self.view.thaw() def should_disable_stop_button(self): return self.model.stop_button_disabled def on_start(self): self.update_model() if not self.model.is_valid(): return self.view.show_missing_args_dialog() command = self.model.build_command_line_string() self.client_runner.run(command) self.model.update_state(States.RUNNNING) self.syncronize_from_model() def on_stop(self): self.ask_stop() def on_edit(self): self.model.update_state(States.CONFIGURING) self.syncronize_from_model() def on_restart(self): self.on_start() def on_cancel(self): if self.view.confirm_exit_dialog(): self.view.Destroy() sys.exit() def on_close(self): self.view.Destroy() sys.exit() 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 self.view.update_progress_aync(progress, self.model.disable_progress_bar_animation) 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() def ask_stop(self): if self.view.confirm_stop_dialog(): self.stop() return True return False def stop(self): self.client_runner.stop() 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() @staticmethod def partition(collection, condition): return filter(condition, collection), filter(lambda x: not condition(x), collection) def update_list(self, collection, new_values): # convenience method for syncronizing the model -> widget list collections for index, val in enumerate(new_values): collection[index].value = val