mirror of https://github.com/chriskiehl/Gooey.git
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
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
|
|
|
|
|
|
|