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.

277 lines
8.6 KiB

import os
from collections import OrderedDict, namedtuple
from itertools import chain
from gooey.gui.lang.i18n import _
from gooey.gui.util.quoting import quote
import wx
ArgumentGroup = namedtuple('ArgumentGroup', 'name command required_args optional_args')
class MyWidget(object):
# TODO: Undumbify damn
# TODO: Undumbify _value/value access
def __init__(self, type, title, help, default, nargs, commands, choices):
self.type = type
self.title = title
self.help = help
self.default = default
self._value = default
self.nargs = nargs
self.commands = commands
self.choices = choices
@property
def value(self):
# TODO: split into stategy or subclass thingie
if self.type == 'CheckBox':
return self.commands[0] if self._value else None
if self.type == 'RadioGroup':
try:
return self.commands[self._value.index(True)][0]
except ValueError:
return None
if self.type == 'MultiFileChooser':
value = ' '.join(quote(x) for x in self._value.split(os.pathsep) if x)
if self.commands and value:
return u'{} {}'.format(self.commands[0], value)
return value or None
if self.type == 'Textarea':
if self.commands and self._value:
return '{} {}'.format(self.commands[0], quote(self._value.encode('unicode_escape')))
else:
return quote(self._value.encode('unicode_escape')) if self._value else ''
if self.type == 'CommandField':
if self.commands and self._value:
return u'{} {}'.format(self.commands[0], self._value)
else:
return self._value or None
if self.type == 'Counter':
'''
Returns
str(option_string * DropDown Value)
e.g.
-vvvvv
'''
if not str(self._value).isdigit():
return None
arg = str(self.commands[0]).replace('-', '')
repeated_args = arg * int(self._value)
return '-' + repeated_args
if self.type == 'Listbox':
if self.commands and self._value:
return u'{} {}'.format(self.commands[0], ' '.join(map(quote, self._value)))
else:
return ' '.join(map(quote, self._value)) if self._value else ''
if self.type == 'Dropdown':
if self._value == 'Select Option':
return None
elif self.commands and self._value:
return u'{} {}'.format(self.commands[0], quote(self._value))
else:
return quote(self._value) if self._value else ''
else:
if self.commands and self._value:
if not self.nargs:
v = quote(self._value)
else:
v = self._value
return u'{0} {1}'.format(self.commands[0], v)
else:
if not self._value:
return None
elif not self.nargs:
return quote(self._value)
else:
return self._value
@value.setter
def value(self, val):
self._value = val
@classmethod
def from_dict(cls, data):
def maybe_unpack(collection, attr):
# TODO: RadioGroups need to support defaults
try:
if isinstance(collection, list):
return [item[attr] for item in collection]
return collection[attr]
except:
return None
details = data['data']
return cls(
data['type'],
maybe_unpack(details, 'display_name'),
maybe_unpack(details, 'help'),
maybe_unpack(details, 'default'),
maybe_unpack(details, 'nargs'),
maybe_unpack(details, 'commands'),
maybe_unpack(details, 'choices')
)
class States(object):
CONFIGURING = 'configuring'
RUNNNING = 'running'
SUCCESS = 'success'
ERROR = 'error'
STOPPED = 'stopped'
class MyModel(object):
'''
'''
def wrap(self, groups):
output = OrderedDict()
for name, group in groups.items():
output[name] = ArgumentGroup(
name,
group['command'],
*self.group_arguments(group['contents'])
)
return output
def __init__(self, build_spec):
self.current_state = States.CONFIGURING
self.build_spec = build_spec
self.layout_type = self.build_spec.get('layout_type')
self.auto_start = self.build_spec.get('auto_start')
self.progress_regex = self.build_spec.get('progress_regex')
self.progress_expr = self.build_spec.get('progress_expr')
self.disable_progress_bar_animation = self.build_spec['disable_progress_bar_animation']
self.program_name = self.build_spec.get('program_name')
self.default_size = self.build_spec.get('default_size')
self.heading_title = _("settings_title")
self.heading_subtitle = self.build_spec['program_description'] or ''
self.use_monospace_font = self.build_spec.get('monospace_display')
self.stop_button_disabled = self.build_spec['disable_stop_button']
self.argument_groups = self.wrap(self.build_spec.get('widgets', {}))
self.active_group = next(iter(self.argument_groups))
self.num_required_cols = self.build_spec['num_required_cols']
self.num_optional_cols = self.build_spec['num_optional_cols']
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')
}
}
@property
def required_args(self):
return self.argument_groups[self.active_group].required_args
@property
def optional_args(self):
return self.argument_groups[self.active_group].optional_args
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
# return self.skipping_config() and self.required_section_complete()
return self.is_required_section_complete()
def skipping_config(self):
return self.build_spec['manual_start']
def is_required_section_complete(self):
error_found = False
for arg in self.required_args:
widget = arg.widget_instance.widget_pack.widget
if arg.value:
widget.SetBackgroundColour(wx.NullColour)
else:
if not error_found:
error_found = True
widget.SetFocus()
widget.SetBackgroundColour("#EF9A9A")
widget.Refresh()
return not error_found
def build_command_line_string(self):
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, "--")
cmd_string = ' '.join(list(filter(None, chain(required_args, optional_args, position_args))))
if self.layout_type == 'column':
cmd_string = u'{} {}'.format(self.argument_groups[self.active_group].command, cmd_string)
return u'{} --ignore-gooey {}'.format(self.build_spec['target'], cmd_string)
def group_arguments(self, widget_list):
is_required = lambda widget: widget['required']
not_checkbox = lambda widget: widget['type'] != 'CheckBox'
required_args, optional_args = self.partition(widget_list, is_required)
if self.build_spec['group_by_type']:
optional_args = chain(*self.partition(optional_args, not_checkbox))
return list(map(self.to_object, required_args)), list(map(self.to_object, optional_args))
@staticmethod
def partition(collection, condition):
return list(filter(condition, collection)), list(filter(lambda x: not condition(x), collection))
def to_object(self, data):
details = data['data']
return MyWidget(
data['type'],
self.maybe_unpack(details, 'display_name'),
self.maybe_unpack(details, 'help'),
self.maybe_unpack(details, 'default'),
self.maybe_unpack(details, 'nargs'),
self.maybe_unpack(details, 'commands'),
self.maybe_unpack(details, 'choices')
)
@staticmethod
def maybe_unpack(collection, attr):
# TODO: RadioGroups need to support defaults
try:
if isinstance(collection, list):
return [item[attr] for item in collection]
return collection[attr]
except:
return None