# -*- 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)
[docs]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
[docs]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.RESIZE_BORDER):
"""Function for initialization"""
# TODO fix icon
# modis_icon = wx.Icon('/home/lucadelu/github/pyModis/pyModis.ico',
# wx.BITMAP_TYPE_ICO)
# self.SetIcon(modis_icon)
try:
pre = wx.PreDialog()
pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP)
pre.Create(parent, ID, title, pos, size, style)
self.PostCreate(pre)
except:
wx.Dialog.__init__(self)
self.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP)
self.Create(parent, ID, title, pos, size, style)
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(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(self.arg_ctrl, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
return sizer
[docs] 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()
[docs] 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()
[docs] 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
[docs]class UserCancelledError(Exception):
"""??"""
pass
[docs]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)
[docs]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)
[docs] 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
[docs] 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()