You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

190 lines
6.2 KiB

8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
8 years ago
  1. import sys
  2. from gooey.gui.processor import ProcessController
  3. from gooey.gui.model import States
  4. from gooey.gui.pubsub import pub
  5. from gooey.gui import events
  6. from gooey.gui.windows import layouts
  7. import wx
  8. class Presenter(object):
  9. def __init__(self, view, model):
  10. self.view = view
  11. self.model = model
  12. self.client_runner = ProcessController(
  13. self.model.progress_regex,
  14. self.model.progress_expr
  15. )
  16. pub.subscribe(self.on_cancel, events.WINDOW_CANCEL)
  17. pub.subscribe(self.on_stop, events.WINDOW_STOP)
  18. pub.subscribe(self.on_start, events.WINDOW_START)
  19. pub.subscribe(self.on_restart, events.WINDOW_RESTART)
  20. pub.subscribe(self.on_edit, events.WINDOW_EDIT)
  21. pub.subscribe(self.on_close, events.WINDOW_CLOSE)
  22. # console statuses from the other thread
  23. pub.subscribe(self.on_new_message, 'console_update')
  24. pub.subscribe(self.on_progress_change, 'progress_update')
  25. pub.subscribe(self.on_client_done, 'execution_complete')
  26. pub.subscribe(self.on_selection_change, events.LIST_BOX)
  27. def on_selection_change(self, selection):
  28. self.update_model()
  29. self.model.active_group = selection
  30. self.redraw_from_model()
  31. self.syncronize_from_model()
  32. def initialize_view(self):
  33. self.view.window_title = self.model.program_name
  34. self.view.window_size = self.model.default_size
  35. self.view.required_section.clear()
  36. self.view.optional_section.clear()
  37. self.view.required_section.populate(self.model.required_args, self.model.num_required_cols)
  38. self.view.optional_section.populate(self.model.optional_args, self.model.num_optional_cols)
  39. if self.model.use_monospace_font:
  40. self.view.set_display_font_style('monospace')
  41. if self.should_disable_stop_button():
  42. self.view.disable_stop_button()
  43. else:
  44. self.view.enable_stop_button()
  45. if self.model.layout_type == layouts.COLUMN:
  46. self.view.set_list_contents(self.model.argument_groups.keys())
  47. if self.model.auto_start:
  48. self.model.update_state(States.RUNNNING)
  49. self.on_start()
  50. self.syncronize_from_model()
  51. def update_model(self):
  52. self.update_list(self.model.required_args, self.view.required_section.get_values())
  53. self.update_list(self.model.optional_args, self.view.optional_section.get_values())
  54. self.syncronize_from_model()
  55. def syncronize_from_model(self):
  56. #TODO move this out of the presenter
  57. #TODO Make all view interactions thread safe
  58. wx.CallAfter(self.syncronize_from_model_async)
  59. def syncronize_from_model_async(self):
  60. # update heading titles
  61. self.view.heading_title = self.model.heading_title
  62. self.view.heading_subtitle = self.model.heading_subtitle
  63. # refresh the widgets
  64. for index, widget in enumerate(self.view.required_section):
  65. widget.set_value(self.model.required_args[index]._value)
  66. for index, widget in enumerate(self.view.optional_section):
  67. widget.set_value(self.model.optional_args[index]._value)
  68. # swap the views
  69. getattr(self, self.model.current_state)()
  70. def redraw_from_model(self):
  71. self.view.freeze()
  72. self.view.required_section.clear()
  73. self.view.optional_section.clear()
  74. self.view.required_section.populate(self.model.required_args)
  75. self.view.optional_section.populate(self.model.optional_args)
  76. getattr(self, self.model.current_state)()
  77. self.view.thaw()
  78. def should_disable_stop_button(self):
  79. return self.model.stop_button_disabled
  80. def on_start(self):
  81. self.update_model()
  82. if not self.model.is_valid():
  83. return self.view.show_missing_args_dialog()
  84. command = self.model.build_command_line_string()
  85. self.client_runner.run(command)
  86. self.model.update_state(States.RUNNNING)
  87. self.syncronize_from_model()
  88. def on_stop(self):
  89. self.ask_stop()
  90. def on_edit(self):
  91. self.model.update_state(States.CONFIGURING)
  92. self.syncronize_from_model()
  93. def on_restart(self):
  94. self.on_start()
  95. def on_cancel(self):
  96. if self.view.confirm_exit_dialog():
  97. self.view.Destroy()
  98. sys.exit()
  99. def on_close(self):
  100. self.view.Destroy()
  101. sys.exit()
  102. def on_new_message(self, msg):
  103. # observes changes coming from the subprocess
  104. self.view.update_console_async(msg)
  105. def on_progress_change(self, progress):
  106. # observes changes coming from the subprocess
  107. self.view.update_progress_aync(progress, self.model.disable_progress_bar_animation)
  108. def on_client_done(self):
  109. if self.client_runner.was_success():
  110. self.model.update_state(States.SUCCESS)
  111. else:
  112. self.model.update_state(States.ERROR)
  113. self.syncronize_from_model()
  114. def ask_stop(self):
  115. if self.view.confirm_stop_dialog():
  116. self.stop()
  117. return True
  118. return False
  119. def stop(self):
  120. self.client_runner.stop()
  121. def configuring(self):
  122. self.view.hide_all_buttons()
  123. self.view.hide('check_mark', 'running_img', 'error_symbol', 'runtime_display')
  124. self.view.show('settings_img', 'cancel_button', 'start_button', 'config_panel')
  125. self.view.Layout()
  126. def running(self):
  127. self.view.hide_all_buttons()
  128. self.view.hide('check_mark', 'settings_img', 'error_symbol', 'config_panel')
  129. self.view.show('running_img', 'stop_button', 'progress_bar', 'runtime_display')
  130. self.view.progress_bar.Pulse()
  131. self.view.Layout()
  132. def success(self):
  133. self.view.hide_all_buttons()
  134. self.view.hide('running_img', 'progress_bar', 'config_panel')
  135. self.view.show('check_mark', 'edit_button', 'restart_button', 'close_button', 'runtime_display')
  136. self.view.Layout()
  137. def error(self):
  138. self.view.hide_all_buttons()
  139. self.view.hide('running_img', 'progress_bar', 'config_panel')
  140. self.view.show('error_symbol', 'edit_button', 'restart_button', 'close_button', 'runtime_display')
  141. self.view.Layout()
  142. @staticmethod
  143. def partition(collection, condition):
  144. return filter(condition, collection), filter(lambda x: not condition(x), collection)
  145. def update_list(self, collection, new_values):
  146. # convenience method for syncronizing the model -> widget list collections
  147. for index, val in enumerate(new_values):
  148. collection[index].value = val