diff --git a/gooey/gui/util/quoting.py b/gooey/gui/util/quoting.py index f47ca13..f97fd31 100644 --- a/gooey/gui/util/quoting.py +++ b/gooey/gui/util/quoting.py @@ -8,7 +8,3 @@ if sys.platform.startswith("win"): else: # POSIX shell def quote(value): return "'{}'".format('{}'.format(value).replace("'", "'\\''")) - - -def maybe_quote(string): - return '"{}"'.format(string) if not re.match(r'^".*"$', string) else string diff --git a/gooey/gui/widgets/components.py b/gooey/gui/widgets/components.py index 95deb3b..eab4ee0 100644 --- a/gooey/gui/widgets/components.py +++ b/gooey/gui/widgets/components.py @@ -97,6 +97,9 @@ class BaseGuiComponent(object): def GetValue(self): return self.widget_pack.getValue() + def HasOptionString(self): + return bool(self.widget_pack.option_string) + def _GetWidget(self): # used only for unittesting return self.widget_pack.widget @@ -142,7 +145,7 @@ class CheckBox(BaseGuiComponent): return self.panel def onSetter(self, evt): - self.getValue() + self.GetValue() def onResize(self, evt): msg = self.help_msg @@ -157,6 +160,9 @@ class CheckBox(BaseGuiComponent): def GetValue(self): return self.option_strings if self.widget.GetValue() else '' + def HasOptionString(self): + return bool(self.option_strings) + def _GetWidget(self): return self.widget @@ -168,7 +174,7 @@ class RadioGroup(object): self.data = data self.radio_buttons = [] - self.option_stings = [] + self.option_strings = [] self.help_msgs = [] self.btn_names = [] @@ -181,7 +187,7 @@ class RadioGroup(object): self.radio_buttons = [wx.RadioButton(self.panel, -1) for _ in self.data] self.btn_names = [wx.StaticText(self.panel, label=btn_data['display_name'].title()) for btn_data in self.data] self.help_msgs = [wx.StaticText(self.panel, label=btn_data['help'].title()) for btn_data in self.data] - self.option_stings = [btn_data['commands'] for btn_data in self.data] + self.option_strings = [btn_data['commands'] for btn_data in self.data] # box = wx.StaticBox(self.panel, -1, label=self.data['group_name']) box = wx.StaticBox(self.panel, -1, label='') @@ -205,7 +211,7 @@ class RadioGroup(object): return self.panel def onSetter(self, evt): - self.getValue() + self.GetValue() def onResize(self, evt): msg = self.help_msgs[0] @@ -224,6 +230,9 @@ class RadioGroup(object): except: return '' + def HasOptionString(self): + return bool(self.option_strings) + def _GetWidget(self): return self.radio_buttons @@ -234,6 +243,7 @@ DirChooser = lambda data: BaseGuiComponent(data=data, widget_pack=widget_ FileSaver = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.FileSaverPayload()) DateChooser = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.DateChooserPayload()) TextField = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.TextInputPayload()) +CommandField = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.TextInputPayload(no_qouting=True)) Dropdown = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.DropdownPayload()) Counter = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.CounterPayload()) MultiDirChooser = lambda data: BaseGuiComponent(data=data, widget_pack=widget_pack.MultiDirChooserPayload()) diff --git a/gooey/gui/widgets/widget_pack.py b/gooey/gui/widgets/widget_pack.py index cdbefa6..b12697a 100644 --- a/gooey/gui/widgets/widget_pack.py +++ b/gooey/gui/widgets/widget_pack.py @@ -1,8 +1,7 @@ from functools import partial -import re from gooey.gui.lang import i18n from gooey.gui.util.filedrop import FileDrop -from gooey.gui.util.quoting import maybe_quote +from gooey.gui.util.quoting import quote __author__ = 'Chris' @@ -37,7 +36,12 @@ class WidgetPack(object): def get_command(data): return data['commands'][0] if data['commands'] else '' - + @staticmethod + def disable_quoting(data): + nargs = data.get('nargs', None) + if not nargs: + return False + return nargs not in (1, '?') class BaseChooser(WidgetPack): @@ -48,9 +52,9 @@ class BaseChooser(WidgetPack): self.text_box = None self.button = None - def build(self, parent, data=None): + def build(self, parent, data): self.parent = parent - self.option_string = data['commands'][0] if data['commands'] else '' + self.option_string = self.get_command(data) self.text_box = wx.TextCtrl(self.parent) self.text_box.AppendText(safe_default(data, '')) self.text_box.SetMinSize((0, -1)) @@ -69,14 +73,13 @@ class BaseChooser(WidgetPack): def getValue(self): value = self.text_box.GetValue() if self.option_string and value: - return '{0} {1}'.format(self.option_string, maybe_quote(value)) + return '{0} {1}'.format(self.option_string, quote(value)) else: - return maybe_quote(value) if value else '' + return quote(value) if value else '' def onButton(self, evt): raise NotImplementedError - def __repr__(self): return self.__class__.__name__ @@ -95,15 +98,26 @@ class BaseFileChooser(BaseChooser): self.text_box.SetValue(result) def get_path(self, dlg): - if isinstance(dlg, wx.DirDialog) or isinstance(dlg, CalendarDlg): - return maybe_quote(dlg.GetPath()) - else: - paths = dlg.GetPaths() - return maybe_quote(paths[0]) if len(paths) < 2 else ' '.join(map(maybe_quote, paths)) + return dlg.GetPath() + + +class BaseMultiFileChooser(BaseFileChooser): + def __init__(self, dialog): + BaseFileChooser.__init__(self, dialog) + + def getValue(self): + value = ' '.join(quote(x) for x in self.text_box.GetValue().split(os.pathsep) if x) + if self.option_string and value: + return '{} {}'.format(self.option_string, value) + return value or '' + + def get_path(self, dlg): + return os.pathsep.join(dlg.GetPaths()) + class MyMultiDirChooser(MDD.MultiDirDialog): - def __init(self, *args, **kwargs): - super(MyMultiDirChooser,self).__init__(*args, **kwargs) + def __init__(self, *args, **kwargs): + super(MyMultiDirChooser, self).__init__(*args, **kwargs) def GetPaths(self): return self.dirCtrl.GetPaths() @@ -117,18 +131,21 @@ def build_dialog(style, exist_constraint=True, **kwargs): FileChooserPayload = partial(BaseFileChooser, dialog=build_dialog(wx.FD_OPEN)) FileSaverPayload = partial(BaseFileChooser, dialog=build_dialog(wx.FD_SAVE, False, defaultFile="Enter Filename")) -MultiFileSaverPayload = partial(BaseFileChooser, dialog=build_dialog(wx.FD_MULTIPLE, False)) +MultiFileSaverPayload = partial(BaseMultiFileChooser, dialog=build_dialog(wx.FD_MULTIPLE, False)) DirChooserPayload = partial(BaseFileChooser, dialog=lambda parent: wx.DirDialog(parent, 'Select Directory', style=wx.DD_DEFAULT_STYLE)) DateChooserPayload = partial(BaseFileChooser, dialog=CalendarDlg) -MultiDirChooserPayload = partial(BaseFileChooser, dialog=lambda parent: MyMultiDirChooser(parent, title="Select Directories", defaultPath=os.getcwd(), agwStyle=MDD.DD_MULTIPLE|MDD.DD_DIR_MUST_EXIST)) +MultiDirChooserPayload = partial(BaseMultiFileChooser, dialog=lambda parent: MyMultiDirChooser(parent, title="Select Directories", defaultPath=os.getcwd(), agwStyle=MDD.DD_MULTIPLE|MDD.DD_DIR_MUST_EXIST)) class TextInputPayload(WidgetPack): - def __init__(self): + def __init__(self, no_quoting=False): self.widget = None self.option_string = None + self.no_quoting = no_quoting def build(self, parent, data): self.option_string = self.get_command(data) + if self.disable_quoting(data): + self.no_quoting = True self.widget = wx.TextCtrl(parent) dt = FileDrop(self.widget) self.widget.SetDropTarget(dt) @@ -138,11 +155,15 @@ class TextInputPayload(WidgetPack): return self.widget def getValue(self): + if self.no_quoting: + _quote = lambda value: value + else: + _quote = quote value = self.widget.GetValue() if value and self.option_string: - return '{} {}'.format(self.option_string, value) + return '{} {}'.format(self.option_string, _quote(value)) else: - return '"{}"'.format(value) if value else '' + return _quote(value) if value else '' def _SetValue(self, text): # used for testing @@ -152,12 +173,15 @@ class TextInputPayload(WidgetPack): class DropdownPayload(WidgetPack): default_value = 'Select Option' - def __init__(self): - self.option_string = None + def __init__(self, no_quoting=False): self.widget = None + self.option_string = None + self.no_quoting = no_quoting def build(self, parent, data): self.option_string = self.get_command(data) + if self.disable_quoting(data): + self.no_quoting = True self.widget = wx.ComboBox( parent=parent, id=-1, @@ -168,12 +192,17 @@ class DropdownPayload(WidgetPack): return self.widget def getValue(self): - if self.widget.GetValue() == self.default_value: + if self.no_quoting: + _quote = lambda value: value + else: + _quote = quote + value = self.widget.GetValue() + if value == self.default_value: return '' - elif self.widget.GetValue() and self.option_string: - return '{} {}'.format(self.option_string, self.widget.GetValue()) + elif value and self.option_string: + return '{} {}'.format(self.option_string, _quote(value)) else: - return self.widget.GetValue() + return _quote(value) if value else '' def _SetValue(self, text): # used for testing @@ -212,4 +241,4 @@ class CounterPayload(WidgetPack): def safe_default(data, default): # str(None) is 'None'!? Whaaaaat...? - return str(data['default']) if data['default'] else '' + return str(data['default']) if data['default'] else default diff --git a/gooey/gui/windows/advanced_config.py b/gooey/gui/windows/advanced_config.py index 21bbcf2..c4276e9 100644 --- a/gooey/gui/windows/advanced_config.py +++ b/gooey/gui/windows/advanced_config.py @@ -93,10 +93,12 @@ class ConfigPanel(ScrolledPanel, OptionReader): """ returns the collective values from all of the widgets contained in the panel""" - values = [c.GetValue() - for c in chain(*self.widgets) - if c.GetValue() is not None] - return ' '.join(values) + _f = lambda lst: [x for x in lst if x is not None] + optional_args = _f([c.GetValue() for c in self.widgets.optional_args]) + required_args = _f([c.GetValue() for c in self.widgets.required_args if c.HasOptionString()]) + position_args = _f([c.GetValue() for c in self.widgets.required_args if not c.HasOptionString()]) + if position_args: position_args.insert(0, "--") + return ' '.join(chain(required_args, optional_args, position_args)) def GetRequiredArgs(self): return [arg.GetValue() for arg in self.widgets.required_args] diff --git a/gooey/gui/windows/layouts.py b/gooey/gui/windows/layouts.py index 67393fe..ae8deca 100644 --- a/gooey/gui/windows/layouts.py +++ b/gooey/gui/windows/layouts.py @@ -6,10 +6,12 @@ from gooey.gui import events from gooey.gui.windows.advanced_config import ConfigPanel from gooey.gui.windows.sidebar import Sidebar from gooey.gui.util import wx_util +from gooey.gui.util.quoting import quote + basic_config = { 'required': [{ - 'type': 'TextField', + 'type': 'CommandField', 'data': { 'display_name': 'Enter Commands', 'help': 'Enter command line arguments', @@ -77,7 +79,7 @@ class ColumnLayout(wx.Panel): return panels def GetOptions(self): - return '{} {}'.format(self.active_panel, self.config_panels[self.active_panel].GetOptions()) + return '{} {}'.format(quote(self.active_panel), self.config_panels[self.active_panel].GetOptions()) def GetRequiredArgs(self): return self.config_panels[self.active_panel].GetRequiredArgs()