123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412 |
- # -*- coding: utf-8 -*-
- '''
- A drop-in replacement for optparse ("import optparse_gui as optparse")
- Provides an identical interface to optparse(.OptionParser),
- But displays an automatically generated wx dialog in order to enter the
- options/args, instead of parsing command line arguments
- Classes:
- * :class:`OptparseDialog`
- * :class:`UserCancelledError`
- * :class:`Option`
- * :class:`OptionParser`
- Functions:
- * :func:`checkLabel`
- '''
- # python 2 and 3 compatibility
- from builtins import dict
- import os
- import sys
- import optparse
- try:
- import wx
- import wx.lib.filebrowsebutton as filebrowse
- except:
- pass
- __version__ = 0.2
- __revision__ = '$Id$'
- # for required options
- from .optparse_required import STREQUIRED
- TEXTCTRL_SIZE = (400, -1)
- def checkLabel(option):
- """Create the label for an option, it add the required string if needed
- :param option: and Option object
- """
- label = option.dest
- label = label.replace('_', ' ')
- label = label.replace('--', '')
- label = label.capitalize()
- if option.required is True:
- return "{lab} [{req}]".format(lab=label, req=STREQUIRED)
- else:
- return label
- class OptparseDialog(wx.Dialog):
- '''The dialog presented to the user with dynamically generated controls,
- to fill in the required options.
- :param optParser: the optparse object
- :param str title: the title to add in the GUI
- :param parent: the parent GUI
- :param int ID: the ID of GUI
- :param pos: the position of GUI
- :param size: the dimension of GUI
- :param style: the style of GUI
- Based on the wx.Dialog sample from wx Docs & Demos
- '''
- def __init__(self, optParser, title, parent=None, ID=0,
- pos=wx.DefaultPosition, size=wx.DefaultSize,
- style=wx.DEFAULT_DIALOG_STYLE|wx.THICK_FRAME):
- """Function for initialization"""
- # TODO fix icon
- # modis_icon = wx.Icon('/home/lucadelu/github/pyModis/pyModis.ico',
- # wx.BITMAP_TYPE_ICO)
- # self.SetIcon(modis_icon)
- provider = wx.SimpleHelpProvider()
- wx.HelpProvider_Set(provider)
- pre = wx.PreDialog()
- pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP)
- pre.Create(parent, ID, title, pos, size, style)
- self.PostCreate(pre)
- self.CenterOnScreen()
- sizer = wx.BoxSizer(wx.VERTICAL)
- self.args_ctrl = []
- self.option_controls = dict()
- # IN THE TOP OF GUI THERE WAS THE NAME OF THE SCRIPT, BUT NOW IT IS IN
- # THE TITLE
- # top_label_text = '%s %s' % (optParser.get_prog_name(),
- # optParser.get_version())
- # label = wx.StaticText(self, -1, top_label_text)
- # sizer.Add(label, 0, wx.ALIGN_CENTRE | wx.ALL, 5)
- # Add a text control for entering args
- arg = self._checkArg(optParser.get_prog_name())
- sizer.Add(arg, 0, wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.RIGHT |
- wx.TOP, 5)
- self.browse_option_map = dict()
- # Add controls for all the options
- for option in optParser.list_of_option:
- if option.dest is None:
- continue
- if option.help is None:
- option.help = ''
- if checkLabel(option) == 'Formats':
- continue
- box = wx.BoxSizer(wx.HORIZONTAL)
- if 'store' == option.action:
- label = wx.StaticText(self, -1, checkLabel(option))
- label.SetHelpText(option.help.replace(' [default=%default]',
- ''))
- box.Add(label, 0, wx.ALIGN_CENTRE | wx.ALL, 5)
- if 'choice' == option.type:
- choices = list(set(option.choices))
- if optparse.NO_DEFAULT == option.default:
- option.default = choices[0]
- ctrl = wx.ComboBox(self, -1, choices=choices,
- value=option.default,
- size=TEXTCTRL_SIZE,
- style=wx.CB_DROPDOWN | wx.CB_READONLY |
- wx.CB_SORT)
- elif option.type in ['file', 'output']:
- if option.type == 'file':
- fmode = wx.OPEN
- elif option.type == 'output':
- fmode = wx.SAVE
- ctrl = filebrowse.FileBrowseButton(self, id=wx.ID_ANY,
- fileMask='*',
- labelText='',
- dialogTitle='Choose output file',
- buttonText='Browse',
- startDirectory=os.getcwd(),
- fileMode=fmode,
- size=TEXTCTRL_SIZE)
- elif option.type == 'directory':
- ctrl = filebrowse.DirBrowseButton(self, id=wx.ID_ANY,
- labelText='',
- dialogTitle='Choose output file',
- buttonText='Browse',
- startDirectory=os.getcwd(),
- size=TEXTCTRL_SIZE)
- else:
- if 'MULTILINE' in option.help:
- ctrl = wx.TextCtrl(self, -1, "", size=(400, 100),
- style=wx.TE_MULTILINE |
- wx.TE_PROCESS_ENTER)
- else:
- ctrl = wx.TextCtrl(self, -1, "", size=TEXTCTRL_SIZE)
- if (option.default != optparse.NO_DEFAULT) and \
- (option.default is not None):
- ctrl.Value = str(option.default)
- box.Add(ctrl, 1, wx.ALIGN_RIGHT | wx.ALL, 5)
- elif option.action in ('store_true', 'store_false'):
- ctrl = wx.CheckBox(self, -1, checkLabel(option),
- size=(300, -1))
- box.Add(ctrl, 0, wx.ALIGN_CENTRE | wx.ALL, 5)
- elif option.action == 'group_name':
- label = wx.StaticText(self, -1, checkLabel(option))
- font = wx.Font(12, wx.DECORATIVE, wx.NORMAL, wx.BOLD)
- label.SetFont(font)
- box.Add(label, 0, wx.ALIGN_CENTRE | wx.ALL, 5)
- ctrl = None
- else:
- raise NotImplementedError('Unknown option action: '
- '{act}'.format(act=repr(option.action)))
- if ctrl:
- ctrl.SetHelpText(option.help.replace(' [default=%default]',
- ''))
- self.option_controls[option] = ctrl
- sizer.Add(box, 0, wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
- line = wx.StaticLine(self, -1, size=(20, -1), style=wx.LI_HORIZONTAL)
- sizer.Add(line, 0,
- wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.TOP, 5)
- btnsizer = wx.StdDialogButtonSizer()
- if wx.Platform != "__WXMSW__":
- btn = wx.ContextHelpButton(self)
- btnsizer.AddButton(btn)
- btn = wx.Button(self, wx.ID_OK)
- btn.SetHelpText("The OK button completes the dialog")
- btn.SetDefault()
- btnsizer.AddButton(btn)
- btn = wx.Button(self, wx.ID_CANCEL)
- btn.SetHelpText("The Cancel button cancels the dialog. (Cool, huh?)")
- btnsizer.AddButton(btn)
- btnsizer.Realize()
- sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
- self.SetSizer(sizer)
- sizer.Fit(self)
- def _getOptions(self):
- """Return a dictionary with the options and their values"""
- option_values = dict()
- for option, ctrl in self.option_controls.items():
- try:
- option_values[option] = ctrl.Value
- except:
- option_values[option] = ctrl.GetValue()
- return option_values
- def _checkArg(self, name):
- """Create an option in WX
- :param str name: the name of command to parse
- """
- sizer = wx.BoxSizer(wx.HORIZONTAL)
- # check what is the module
- if name == 'modis_convert.py' or name == 'modis_parse.py' or \
- name == 'modis_quality.py':
- ltext = 'File HDF [%s]' % STREQUIRED
- self.htext = 'Select HDF file'
- self.typecont = 'file'
- elif name == 'modis_download.py' or \
- name == 'modis_download_from_list.py':
- ltext = 'Destination Folder [%s]' % STREQUIRED
- self.htext = 'Select directory where save MODIS files'
- self.typecont = 'dir'
- elif name == 'modis_mosaic.py':
- ltext = 'File containig HDF list [%s]' % STREQUIRED
- self.htext = 'Select file containig a list of MODIS file'
- self.typecont = 'file'
- elif name == 'modis_multiparse.py':
- ltext = 'List of HDF file [%s]' % STREQUIRED
- self.htext = 'List of MODIS files'
- self.typecont = 'mfile'
- else:
- ltext = 'Test'
- self.htext = 'Test'
- label = wx.StaticText(self, -1, ltext)
- label.SetHelpText(self.htext)
- sizer.Add(item=label, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTRE_VERTICAL |
- wx.ALL, border=5)
- if self.typecont == 'dir':
- self.arg_ctrl = filebrowse.DirBrowseButton(self, id=wx.ID_ANY,
- labelText='',
- dialogTitle=self.htext,
- buttonText='Browse',
- startDirectory=os.getcwd(),
- changeCallback=self.onText,
- size=TEXTCTRL_SIZE)
- elif self.typecont in ['file', 'mfile']:
- self.arg_ctrl = filebrowse.FileBrowseButton(self, id=wx.ID_ANY,
- fileMask='*',
- labelText='',
- dialogTitle=self.htext,
- buttonText='Browse',
- startDirectory=os.getcwd(),
- fileMode=wx.OPEN,
- changeCallback=self.onText,
- size=TEXTCTRL_SIZE)
- sizer.Add(item=self.arg_ctrl, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
- return sizer
- def onText(self, event):
- """File changed"""
- myId = event.GetId()
- me = wx.FindWindowById(myId)
- wktfile = me.GetValue()
- if len(wktfile) > 0:
- if self.typecont == 'mfile':
- self.args_ctrl.append(wktfile.split(','))
- else:
- self.args_ctrl.append(wktfile)
- event.Skip()
- def onBrowse(self, event):
- """Choose file"""
- dlg = wx.FileDialog(parent=self, message=self.htext,
- defaultDir=os.getcwd(), style=wx.OPEN)
- if dlg.ShowModal() == wx.ID_OK:
- path = dlg.GetPath()
- self.args_ctrl.SetValue(path)
- dlg.Destroy()
- event.Skip()
- def getOptionsAndArgs(self):
- '''Parse the options and args
- :return: a dictionary of option names and values, a sequence of args
- '''
- option_values = self._getOptions()
- args = self.args_ctrl
- return option_values, args
- class UserCancelledError(Exception):
- """??"""
- pass
- class Option(optparse.Option):
- """Extended optparse.Option class"""
- SUPER = optparse.Option
- TYPES = SUPER.TYPES + ('file', 'output', 'directory', 'group_name')
- ACTIONS = SUPER.ACTIONS + ('group_name',)
- TYPED_ACTIONS = SUPER.TYPED_ACTIONS + ('group_name',)
- # for required options
- ATTRS = optparse.Option.ATTRS + [STREQUIRED]
- def __init__(self, *opts, **attrs):
- if attrs.get(STREQUIRED, False):
- attrs['help'] = '(Required) ' + attrs.get('help', "")
- optparse.Option.__init__(self, *opts, **attrs)
- class OptionParser(optparse.OptionParser):
- """Extended optparse.OptionParser to create the GUI for the module"""
- SUPER = optparse.OptionParser
- def __init__(self, *args, **kwargs):
- """Function to initialize the object"""
- if wx.GetApp() is None:
- self.app = wx.App(False)
- if 'option_class' not in kwargs:
- kwargs['option_class'] = Option
- self.SUPER.__init__(self, *args, **kwargs)
- def parse_args(self, args=None, values=None):
- '''This is the heart of it all overrides
- optparse.OptionParser.parse_args
- :param arg: is irrelevant and thus ignored, it's here only for
- interface compatibility
- :param values: is irrelevant and thus ignored, it's here only for
- interface compatibility
- '''
- # preprocess command line arguments and set to defaults
- option_values, args = self.SUPER.parse_args(self, args, values)
- self.list_of_option = self.option_list
- for group in self.option_groups:
- title = "--{n}".format(n=group.title.replace(" ", "_"))
- o = Option(title, type='group_name', dest=title, help=title,
- metavar=title, action='group_name')
- self.list_of_option.append(o)
- for option in group.option_list:
- self.list_of_option.append(option)
- for option in self.list_of_option:
- if option.dest and hasattr(option_values, option.dest):
- default = getattr(option_values, option.dest)
- if default is not None:
- option.default = default
- dlg = OptparseDialog(optParser=self,
- title="{name} GUI".format(name=self.description))
- if args:
- dlg.args_ctrl.Value = ' '.join(args)
- dlg_result = dlg.ShowModal()
- if wx.ID_OK != dlg_result:
- sys.exit()
- if values is None:
- values = self.get_default_values()
- option_values, args = dlg.getOptionsAndArgs()
- for option, value in option_values.items():
- if option.required and value == "":
- self.error("The option %s is mandatory" % option)
- if ('store_true' == option.action) and (value is False):
- setattr(values, option.dest, False)
- continue
- if ('store_false' == option.action) and (value is True):
- setattr(values, option.dest, False)
- continue
- if option.takes_value() is False:
- value = None
- if isinstance(value, str):
- value = str(value)
- option.process(option, value, values, self)
- return values, args
- def error(self, msg):
- """Return an error message with wx.MessageDialog
- :param str msg: is the error string to pass to message dialog
- """
- wx.MessageDialog(None, msg, 'Error!', wx.ICON_ERROR).ShowModal()
- sys.exit()
|