lpcmanager

Variable Options : fixed parsing, add On Load fix
som6
2020-11-12, Edouard Tisserant
fecb8381e105
Variable Options : fixed parsing, add On Load fix
- fixed parsing to deal with dblquotes and old bugs better, use intermediate representation once parsed, and add function to generate options string from that representation,
- add On Load fix to be backward compatible with previous options syntax and onchange column
from __future__ import absolute_import
import re
import wx
import wx.grid
import controls
from collections import namedtuple
from OptionsParsing import ParseOptions, VARIABLETYPE, GenOptions, OptionsType
[ID_OPTIONSWIZARDDIALOG,ID_ONCHANGE,ID_OPTIONSTYPECHOICE,ID_SUBGROUPTEXT,ID_UNITTEXT,ID_VALUECHECKBOX,ID_MINSPIN,ID_MAXSPIN,ID_PRECISIONSPIN, ID_INITIALSPIN,ID_SCADACHECKBOX,ID_OTHERTEXT,ID_DESCRIPTION,ID_STATIC] = [wx.NewId() for _init_ctrls in range(14)]
excluded_chars = [ord(i) for i in '\n"']
sanitizer = "".join([chr(i if i not in excluded_chars else ord(' ')) for i in xrange(256)])
eraser = '\r'
class WampOptionsEditor(wx.Dialog):
def _init_sizers(self):
self.MainSizer = wx.BoxSizer(wx.VERTICAL)
self.PropertySizer = wx.FlexGridSizer(cols=2, hgap=10, rows=13, vgap=10)
self.PropertySizer.AddWindow(wx.StaticText(self,wx.ID_ANY,_("Type:")), flag=wx.ALIGN_CENTER_VERTICAL | wx.GROW | wx.LEFT, border=15)
self.PropertySizer.AddWindow(self.OptionsTypeChoice, 1, flag= wx.EXPAND)
self.PropertySizer.AddWindow(self.OnChangeCheckbox, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
self.PropertySizer.AddWindow(wx.StaticText(self, wx.ID_ANY, _("On Change")), 1, flag=wx.GROW | wx.EXPAND)
self.PropertySizer.AddWindow(self.ScadaCheckbox, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
self.PropertySizer.AddWindow(wx.StaticText(self, wx.ID_ANY, _("Scada")), 1, flag=wx.GROW | wx.EXPAND)
self.PropertySizer.AddWindow(self.StaticCheckbox, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
self.PropertySizer.AddWindow(wx.StaticText(self, wx.ID_ANY, _("Static")), 1, flag=wx.GROW | wx.EXPAND)
self.PropertySizer.AddWindow(wx.StaticText(self,wx.ID_ANY, _("Subgroup:")), flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
self.PropertySizer.AddWindow(self.SubgroupText, 1, flag=wx.GROW | wx.EXPAND)
self.PropertySizer.AddWindow(wx.StaticText(self,wx.ID_ANY, _("Unit:")), flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
self.PropertySizer.AddWindow(self.UnitText, 1, flag=wx.GROW | wx.EXPAND)
self.PropertySizer.AddWindow(self.ValueCheckbox, flag=wx.GROW | wx.LEFT, border=15)
self.PropertySizer.AddWindow(wx.StaticText(self,wx.ID_ANY, _("Enable min/max value")), flag=wx.ALIGN_CENTER_VERTICAL)
self.minValue=wx.StaticText(self, wx.ID_ANY, _("Min value:"))
self.maxValue=wx.StaticText(self, wx.ID_ANY, _("Max value:"))
self.PrecisionValue = wx.StaticText(self, wx.ID_ANY, _("Precision:"))
self.PropertySizer.AddWindow(self.minValue, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
self.PropertySizer.AddWindow(self.MinSpin, flag=wx.GROW)
self.PropertySizer.AddWindow(self.maxValue, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
self.PropertySizer.AddWindow(self.MaxSpin, flag=wx.GROW)
self.PropertySizer.AddWindow(self.PrecisionValue, flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
self.PropertySizer.AddWindow(self.PrecisionSpin, flag=wx.GROW)
self.PropertySizer.AddWindow(wx.StaticText(self, wx.ID_ANY, _("Other:")), flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
self.PropertySizer.AddWindow(self.OtherText, flag=wx.GROW)
self.PropertySizer.AddWindow(wx.StaticText(self, wx.ID_ANY, _("Tags:")), flag=wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=15)
self.PropertySizer.AddWindow(self.Tags, flag=wx.GROW)
self.PropertySizer.AddGrowableCol(1, 1)
self.MainSizer.AddSizer(self.PropertySizer, flag=wx.GROW | wx.UP | wx.RIGHT, border=15)
self.ButtonSizer.AddWindow(self.ClearButton)
self.MainSizer.AddSizer(self.ButtonSizer,
flag=wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 10)
self.SetSizer(self.MainSizer)
self.Fit()
self.CenterOnScreen()
def _init_ctrls(self, prnt, opt):
wx.Dialog.__init__(self, id=ID_OPTIONSWIZARDDIALOG,
name='OptionsWizard', parent=prnt,
size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE,
title=_('Options'))
self.OptionsTypeChoice = wx.Choice(parent=self, id=ID_OPTIONSWIZARDDIALOG,
choices=VARIABLETYPE)
self.Bind(wx.EVT_CHOICE, self.OnTypeChoice, self.OptionsTypeChoice)
self.OnChangeCheckbox = wx.CheckBox(parent=self, id=ID_ONCHANGE)
self.SubgroupText = wx.TextCtrl(parent=self, id=ID_SUBGROUPTEXT)
self.UnitText = wx.TextCtrl(parent=self, id=ID_UNITTEXT)
self.ValueCheckbox = wx.CheckBox(parent=self, id=ID_VALUECHECKBOX)
self.MinSpin = wx.SpinCtrl(parent=self, id=ID_MINSPIN, style=wx.SP_VERTICAL)
self.MaxSpin = wx.SpinCtrl(parent=self, id=ID_MAXSPIN, style=wx.SP_VERTICAL)
self.PrecisionSpin = wx.SpinCtrl(parent=self, id=ID_PRECISIONSPIN, style=wx.SP_VERTICAL)
self.MinSpin.SetRange(-1000000, 1000000)
self.MaxSpin.SetRange(-1000000, 1000000)
self.ScadaCheckbox = wx.CheckBox(parent=self, id=ID_SCADACHECKBOX)
self.StaticCheckbox = wx.CheckBox(parent=self, id=ID_STATIC)
self.OtherText = wx.TextCtrl(parent=self, id=ID_OTHERTEXT)
self.Tags = wx.TextCtrl(parent=self, id=ID_DESCRIPTION, size=(-1, 100), style=wx.TE_MULTILINE|wx.SUNKEN_BORDER)
self.ClearButton = wx.Button(self, wx.ID_CLEAR, _("Clear"))
self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL)
self.ValueCheckbox.Bind(wx.EVT_CHECKBOX, self.EnableValue)
self.OnChangeCheckbox.Enable(False)
self.OtherText.Enable(False)
self.UnitText.Enable(False)
self.ScadaCheckbox.Enable(False)
self.SubgroupText.Enable(False)
self.ValueCheckbox.Enable(False)
self.MinSpin.Enable(False)
self.MaxSpin.Enable(False)
self.PrecisionSpin.Enable(False)
self.StaticCheckbox.Enable(False)
self.Bind(wx.EVT_CHOICE, self.Enabler, self.OptionsTypeChoice)
self.Bind(wx.EVT_BUTTON, self.clearOptions, self.ClearButton)
self.Bind(wx.EVT_CHECKBOX, self.Enabler, self.ScadaCheckbox)
def __init__(self, parent, opt):
self.options = opt
self.value = ""
self.OnChange = False
self._init_ctrls(parent, opt)
self._init_sizers()
self.SetOptions(opt)
self.Enabler(None)
def Enabler(self, event):
if self.OptionsTypeChoice.GetSelection() == 0:
self.clearOptions(event)
elif self.OptionsTypeChoice.GetSelection() in [1,3]:
self.ScadaCheckbox.Enable(True)
self.OtherText.Enable(True)
self.SubgroupText.Enable(True)
self.UnitText.Enable(True)
self.OnChangeCheckbox.Enable(True)
self.ValueCheckbox.Enable(True)
self.PrecisionSpin.Enable(True)
else:
self.ScadaCheckbox.Enable(True)
self.OtherText.Enable(True)
self.SubgroupText.Enable(True)
self.UnitText.Enable(True)
self.OnChangeCheckbox.SetValue(False)
self.OnChangeCheckbox.Enable(False)
self.ValueCheckbox.Enable(True)
self.PrecisionSpin.Enable(True)
if self.OptionsTypeChoice.GetSelection() == 3 and self.ScadaCheckbox.GetValue():
self.StaticCheckbox.Enable(True)
self.OnChangeCheckbox.SetValue(True)
else:
self.StaticCheckbox.SetValue(False)
self.StaticCheckbox.Enable(False)
def clearOptions(self, event):
"""Zbrisi vsebino"""
self.OptionsTypeChoice.SetSelection(0)
self.SubgroupText.SetValue("")
self.UnitText.SetValue("")
self.MinSpin.SetValue(0)
self.MaxSpin.SetValue(0)
self.ValueCheckbox.SetValue(False)
self.ScadaCheckbox.SetValue(False)
self.StaticCheckbox.SetValue(False)
self.OtherText.SetValue("")
self.MinSpin.Enable(False)
self.MaxSpin.Enable(False)
self.StaticCheckbox.Enable(False)
self.PrecisionSpin.SetValue(0)
self.OnChangeCheckbox.SetValue(False)
self.Tags.SetValue("")
self.OnChangeCheckbox.Enable(False)
self.OtherText.Enable(False)
self.SubgroupText.Enable(False)
self.UnitText.Enable(False)
self.ScadaCheckbox.Enable(False)
self.ValueCheckbox.Enable(False)
self.MinSpin.Enable(False)
self.MaxSpin.Enable(False)
self.PrecisionSpin.Enable(False)
self.Tags.Enable(False)
self.StaticCheckbox.Enable(False)
def OnTypeChoice(self, event):
self.selected = event.GetSelection()
def EnableValue(self, event):
self.MinSpin.Enable(self.ValueCheckbox.GetValue())
self.MaxSpin.Enable(self.ValueCheckbox.GetValue())
event.Skip()
def SetOptions(self, opts):
res = ParseOptions(opts)
self.OptionsTypeChoice.SetSelection(res.variable_type_selection)
self.OnChangeCheckbox.SetValue(res.is_onchange)
self.ScadaCheckbox.SetValue(res.is_scada)
self.StaticCheckbox.SetValue(res.is_static)
self.StaticCheckbox.Enable(
res.is_static or (res.variable_type_selection == 3 and res.is_scada))
if res.subgroup is not None:
self.SubgroupText.SetValue(res.subgroup)
if res.unit is not None:
self.UnitText.SetValue(res.unit)
if res.min is not None or res.max is not None:
self.ValueCheckbox.SetValue(True)
self.MinSpin.Enable(True)
self.MaxSpin.Enable(True)
self.MinSpin.SetValue(res.min if res.min else 0)
self.MaxSpin.SetValue(res.max if res.max else 0)
if res.other is not None:
self.OtherText.SetValue(res.other)
if res.precision is not None:
self.PrecisionSpin.SetValue(res.precision)
if res.tags is not None:
self.Tags.SetValue(res.tags)
def GetOptions(self):
opts = OptionsType()
opts.variable_type_selection = max(self.OptionsTypeChoice.GetSelection(), 0)
opts.is_onchange = self.OnChangeCheckbox.GetValue()
opts.is_scada = self.ScadaCheckbox.GetValue()
opts.is_static = self.StaticCheckbox.GetValue()
if self.MinSpin.IsEnabled():
opts.min = self.MinSpin.GetValue()
opts.max = self.MaxSpin.GetValue()
opts.precision = self.PrecisionSpin.GetValue()
for name, ctrl in [('subgroup', self.SubgroupText),
('unit', self.UnitText),
('other', self.OtherText),
('tags', self.Tags)]:
content = ctrl.GetValue().encode('ascii','ignore')
if content:
opts[name] = content
return GenOptions(opts)
class WampOptionsCellControl(wx.PyControl):
'''
Custom cell editor control with a text box and a button that launches
the WampOptionsEditor.
'''
def __init__(self, parent, table, row):
wx.Control.__init__(self, parent, row)
main_sizer = wx.FlexGridSizer(cols=2, hgap=0, rows=1, vgap=0)
main_sizer.AddGrowableCol(0)
main_sizer.AddGrowableRow(0)
self.parent = parent
# create location text control
self.Options = wx.TextCtrl(self, size=wx.Size(0, -1),
style=wx.TE_PROCESS_ENTER)
self.Options.Bind(wx.EVT_KEY_DOWN, self.OnChar)
main_sizer.AddWindow(self.Options, flag=wx.GROW)
# create browse button
self.EditButton = wx.Button(self, label='...', size=wx.Size(30, -1))
self.Bind(wx.EVT_BUTTON, self.OnEditButtonClick, self.EditButton)
main_sizer.AddWindow(self.EditButton, flag=wx.GROW)
self.Bind(wx.EVT_SIZE, self.OnSize)
self.SetSizer(main_sizer)
self.Default = None
self.table = table
self.row = row
def SetValue(self, value):
self.Default = value
self.Options.SetValue(value)
def GetValue(self):
return self.Options.GetValue()
def OnSize(self, event):
self.Layout()
def OnEditButtonClick(self, event):
# pop up the Duration Editor dialog
options = self.GetValue()
# backward compatibility
dialog = WampOptionsEditor(self.parent, options)
answer = dialog.ShowModal()
opt = dialog.GetOptions()
if answer == wx.ID_OK:
self.SetValue(opt)
dialog.Destroy()
self.Options.SetFocus()
def OnChar(self, event):
keycode = event.GetKeyCode()
if keycode in [wx.WXK_RETURN]:
self.Parent.Parent.ProcessEvent(event)
elif keycode == wx.WXK_ESCAPE:
self.Options.SetValue(self.Default)
self.Parent.Parent.CloseEditControl()
else:
event.Skip()
def SetFocus(self):
self.Options.SetFocus()
class WampOptionsCellEditor(wx.grid.PyGridCellEditor):
'''
Grid cell editor that uses WampOptionsCellControl to display an edit button.
'''
def __init__(self, table, row, col):
wx.grid.PyGridCellEditor.__init__(self)
self.table = table
self.colname = self.table.GetColLabelValue(col, False)
self.row = row
def __del__(self):
self.CellControl = None
def Create(self, parent, id, evt_handler):
self.CellControl = WampOptionsCellControl(parent, self.table, self.row)
self.SetControl(self.CellControl)
if evt_handler:
self.CellControl.PushEventHandler(evt_handler)
def BeginEdit(self, row, col, grid):
self.CellControl.Enable()
self.CellControl.SetValue(self.table.GetValueByName(self.row, self.colname))
self.CellControl.SetFocus()
def EndEditInternal(self, row, col, grid, old_duration):
duration = self.CellControl.GetValue()
changed = duration != old_duration
if changed:
self.table.SetValueByName(row, self.colname, duration)
self.CellControl.Disable()
return changed
if wx.VERSION >= (3, 0, 0):
def EndEdit(self, row, col, grid, oldval):
return self.EndEditInternal(row, col, grid, oldval)
else:
def EndEdit(self, row, col, grid):
oldval = self.table.GetValueByName(row, self.colname)
return self.EndEditInternal(row, col, grid, oldval)
def SetSize(self, rect):
self.CellControl.SetDimensions(rect.x + 1, rect.y,
rect.width, rect.height,
wx.SIZE_ALLOW_MINUS_ONE)