Files
slimbootloader/BootloaderCorePkg/Tools/ConfigEditor.py
T
Maurice Ma fb33d7dbf0 Format the CFGDATA values in generated DLT file
This patch formats the CFGDATA value string into a standard format
for the generated DLT file. It will format the array string using
its structure type including UINT8/16/32/64.

Signed-off-by: Maurice Ma <maurice.ma@intel.com>
2019-09-30 17:07:26 -07:00

918 lines
31 KiB
Python

## @ ConfigEditor.py
#
# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
#
##
import os
import re
import sys
import marshal
sys.dont_write_bytecode = True
if sys.hexversion >= 0x3000000:
# for Python3
from tkinter import * ## notice lowercase 't' in tkinter here
import tkinter.ttk as ttk
import tkinter.messagebox as messagebox
import tkinter.filedialog as filedialog
else:
# for Python2
from Tkinter import * ## notice capitalized T in Tkinter
import ttk
import tkMessageBox as messagebox
import tkFileDialog as filedialog
from GenCfgData import CGenCfgData, Bytes2Str, Bytes2Val, Val2Bytes, Array2Val
class CreateToolTip(object):
'''
create a tooltip for a given widget
'''
InProgress = False
def __init__(self, Widget, Text=''):
self.TopWin = None
self.Widget = Widget
self.Text = Text
self.Widget.bind("<Enter>", self.Enter)
self.Widget.bind("<Leave>", self.Leave)
def Enter(self, event=None):
if self.InProgress:
return
x, y, cx, cy = self.Widget.bbox("insert")
Cursor = self.Widget.winfo_pointerxy()
x += self.Widget.winfo_rootx() + 35
y = self.Widget.winfo_rooty() + 20
if Cursor[1] > y and Cursor[1] < y + 20:
y += 20
# creates a toplevel window
self.TopWin = Toplevel(self.Widget)
# Leaves only the label and removes the app window
self.TopWin.wm_overrideredirect(True)
self.TopWin.wm_geometry("+%d+%d" % (x, y))
label = Label(self.TopWin,
text=self.Text,
justify='left',
background='bisque',
relief='solid',
borderwidth=1,
font=("times", "9", "normal"))
label.pack(ipadx=1)
self.InProgress = True
def Leave(self, event=None):
if self.TopWin:
self.TopWin.destroy()
self.InProgress = False
class ValidatingEntry(Entry):
_Padding = 2
_CharWidth = 1
def __init__(self, master, value="", **kw):
Entry.__init__(*(self, master), **kw)
self.Value = value
self.Variable = StringVar()
self.Variable.set(value)
self.Variable.trace("w", self.Callback)
self.config(textvariable=self.Variable)
self.bind("<FocusOut>", self.FocusOut)
@staticmethod
def ToCellWidth (ByteLen):
return ByteLen * 2 * ValidatingEntry._CharWidth + ValidatingEntry._Padding
@staticmethod
def ToByteLen (CellWidth):
return (CellWidth - ValidatingEntry._Padding) // (ValidatingEntry._CharWidth * 2)
def GetByteLen (self):
return ValidatingEntry.ToByteLen (self['width'])
def FocusOut(self, Event):
Value = self.Variable.get()
if len(Value) == 0:
self.Value = '00'
else:
self.Value = '%02X' % int(Value, 16)
self.Variable.set(self.Value)
def Callback(self, *Args):
CurVal = self.Variable.get()
NewVal = self.Validate(CurVal)
if NewVal is None:
self.Variable.set(self.Value)
else:
self.Value = NewVal
self.Variable.set(self.Value)
def Validate(self, Value):
if len(Value) > 0:
try:
int(Value, 16)
except:
return None
MaxLen = self.GetByteLen() * 2
if len(Value) > MaxLen:
Value = Value[:MaxLen]
return Value.upper()
class CustomTable(Frame):
def __init__(self, Parent, ColHdr, Bins):
Frame.__init__(self, Parent)
Idx = 0
Cols = len(ColHdr)
if Cols > 0:
Rows = (len(Bins) + Cols - 1) // Cols
self.Row = Rows
self.Col = Cols
ColAdj = 2
RowAdj = 1
for Col in range(Cols): #Columns
Text = ColHdr[Col].split(':')[0]
Header = Label(self, text=Text)
Header.grid(row=0, column=Col + ColAdj)
for Row in range(Rows): #Rows
Text = '%04X' % (Row * len(ColHdr))
Header = Label(self, text=Text)
Header.grid(row=Row + RowAdj,
column=0,
columnspan=1,
sticky='ewsn')
for Col in range(Cols): #Columns
if Idx >= len(Bins):
break
ByteLen = int(ColHdr[Col].split(':')[1])
Value = Bytes2Val (Bins[Idx:Idx+ByteLen])
Hex = ("%%0%dX" % (ByteLen * 2) ) % Value
ValidatingEntry(self, width=ValidatingEntry.ToCellWidth(ByteLen),
justify=CENTER, value=Hex).grid(row=Row + RowAdj, column=Col + ColAdj)
Idx += ByteLen
if Idx >= len(Bins):
break
def get(self):
Bins = bytearray()
for Widget in self.winfo_children():
if not isinstance(Widget, ValidatingEntry):
continue
ByteLen = Widget.GetByteLen ()
Hex = Widget.get()
if not Hex:
break
Values = Val2Bytes (int(Hex, 16) & ((1 << ByteLen * 8) - 1), ByteLen)
Bins.extend(Values)
return Bins
def destroy(self):
for Widget in self.winfo_children():
Widget.destroy()
Frame.destroy(self)
class Application(Frame):
def __init__(self, master=None):
Root = master
self.Debug = True
self.LastDir = '.'
self.PageId = ''
self.PageList = {}
self.ConfList = {}
self.CfgDataObj = None
self.OrgCfgDataBin = None
Frame.__init__(self, master, borderwidth=2)
self.MenuString = [
'Save Config Data to Binary', 'Load Config Data from Binary',
'Load Config Changes from Delta File',
'Save Config Changes to Delta File',
'Save Full Config Data to Delta File'
]
Root.geometry("1200x800")
Paned = ttk.Panedwindow(Root, orient=HORIZONTAL)
Paned.pack(fill=BOTH, expand=True, padx=(4, 4))
Status = Label(master, text="", bd=1, relief=SUNKEN, anchor=W)
Status.pack(side=BOTTOM, fill=X)
FrameLeft = ttk.Frame(Paned, height=800, relief="groove")
self.Left = ttk.Treeview(FrameLeft, show="tree")
# Set up tree HScroller
Pady = (10, 10)
self.TreeScroll = ttk.Scrollbar(FrameLeft,
orient="vertical",
command=self.Left.yview)
self.Left.configure(yscrollcommand=self.TreeScroll.set)
self.Left.bind('<<TreeviewSelect>>', self.OnConfigPageSelectChange)
self.Left.pack(side='left',
fill=BOTH,
expand=True,
padx=(5, 0),
pady=Pady)
self.TreeScroll.pack(side='right', fill=Y, pady=Pady, padx=(0, 5))
FrameRight = ttk.Frame(Paned, relief="groove")
self.FrameRight = FrameRight
self.ConfCanvas = Canvas(FrameRight, highlightthickness=0)
self.PageScroll = ttk.Scrollbar(FrameRight,
orient="vertical",
command=self.ConfCanvas.yview)
self.RightGrid = ttk.Frame(self.ConfCanvas)
self.ConfCanvas.configure(yscrollcommand=self.PageScroll.set)
self.ConfCanvas.pack(side='left',
fill=BOTH,
expand=True,
pady=Pady,
padx=(5, 0))
self.PageScroll.pack(side='right', fill=Y, pady=Pady, padx=(0, 5))
self.ConfCanvas.create_window(0, 0, window=self.RightGrid, anchor='nw')
self.ConfCanvas.bind("<Configure>", self.OnCanvasConfigure)
Paned.add(FrameLeft, weight=2)
Paned.add(FrameRight, weight=10)
Style = ttk.Style()
Style.layout("Treeview", [('Treeview.treearea', {'sticky': 'nswe'})])
Menubar = Menu(Root)
FileMenu = Menu(Menubar, tearoff=0)
FileMenu.add_command(label="Open Config DSC file...",
command=self.LoadFromDsc)
FileMenu.add_command(label=self.MenuString[0],
command=self.SaveToBin,
state='disabled')
FileMenu.add_command(label=self.MenuString[1],
command=self.LoadFromBin,
state='disabled')
FileMenu.add_command(label=self.MenuString[2],
command=self.LoadFromDelta,
state='disabled')
FileMenu.add_command(label=self.MenuString[3],
command=self.SaveToDelta,
state='disabled')
FileMenu.add_command(label=self.MenuString[4],
command=self.SaveFullToDelta,
state='disabled')
FileMenu.add_command(label="About", command=self.About)
Menubar.add_cascade(label="File", menu=FileMenu)
self.FileMenu = FileMenu
Root.config(menu=Menubar)
if len(sys.argv) > 1:
Path = sys.argv[1]
if Path.endswith('.dlt'):
DscPath = os.path.join (os.path.dirname(Path), 'CfgDataDef.dsc')
else:
DscPath = Path
if DscPath.endswith('.dsc'):
if self.LoadDscFile (DscPath) == 0:
if DscPath != Path:
self.LoadDeltaFile (Path)
def SetObjectName(self, Widget, Name):
self.ConfList[id(Widget)] = Name
def GetObjectName(self, Widget):
if id(Widget) in self.ConfList:
return self.ConfList[id(Widget)]
else:
return None
def LimitEntrySize(self, Variable, Limit):
Value = Variable.get()
if len(Value) > Limit: Variable.set(Value[:Limit])
def OnCanvasConfigure(self, Event):
self.RightGrid.grid_columnconfigure(0, minsize=Event.width)
def OnPageScroll(self, Event):
self.ConfCanvas.yview_scroll(-1 * Event.delta, 'units')
def UpdateVisibilityForWidget(self, Widget, Args):
Visible = True
if isinstance(Widget, Label):
Item = self.GetConfigDataItemFromWidget(Widget, True)
else:
Item = self.GetConfigDataItemFromWidget(Widget, True)
if Item is None:
return Visible
elif not Item:
return Visible
if Item['condition']:
Visible = self.EvaluateCondition(Item['condition'])
if Visible:
Widget.grid()
else:
Widget.grid_remove()
return Visible
def UpdateWidgetsVisibilityOnPage(self):
self.WalkWidgetsInLayout(self.RightGrid,
self.UpdateVisibilityForWidget)
def ComboSelectChanged(self, Event):
self.UpdateConfigDataFromWidget(Event.widget, None)
self.UpdateWidgetsVisibilityOnPage()
def EditNumFinished(self, Event):
Widget = Event.widget
Item = self.GetConfigDataItemFromWidget(Widget)
if not Item:
return
Parts = Item['type'].split(',')
if len(Parts) > 3:
Min = Parts[2].lstrip()[1:]
Max = Parts[3].rstrip()[:-1]
MinVal = Array2Val(Min)
MaxVal = Array2Val(Max)
Text = Widget.get()
if ',' in Text:
Text = '{ %s }' % Text
try:
Value = Array2Val(Text)
if Value < MinVal or Value > MaxVal:
raise Exception('Invalid input!')
self.SetConfigItemValue(Item, Text)
except Exception as e:
pass
Text = Item['value'].strip('{').strip('}').strip()
Widget.delete(0, END)
Widget.insert(0, Text)
self.UpdateWidgetsVisibilityOnPage()
def UpdatePageScrollBar(self):
# Update scrollbar
self.FrameRight.update()
self.ConfCanvas.config(scrollregion=self.ConfCanvas.bbox("all"))
def OnConfigPageSelectChange(self, Event):
self.UpdateConfigDataOnPage()
Sel = self.Left.selection()
if len(Sel) > 0:
PageId = Sel[0]
self.BuildConfigDataPage(PageId)
self.UpdateWidgetsVisibilityOnPage()
self.UpdatePageScrollBar()
def WalkWidgetsInLayout(self, Parent, CallbackFunction, Args=None):
for Widget in Parent.winfo_children():
CallbackFunction(Widget, Args)
def ClearWidgetsInLayout(self, Parent=None):
if Parent is None:
Parent = self.RightGrid
for Widget in Parent.winfo_children():
Widget.destroy()
Parent.grid_forget()
self.ConfList.clear()
def BuildConfigPageTree(self, CfgPage, Parent):
for Page in CfgPage:
PageId = next(iter(Page))
# Put CFG items into related page list
self.PageList[PageId] = [
Item
for Item in self.CfgDataObj._CfgItemList
if Item['name'] and (Item['page'] == PageId)
]
self.PageList[PageId].sort (key=lambda x: x['order'])
PageName = self.CfgDataObj._CfgPageDict[PageId]
Child = self.Left.insert(
Parent, 'end',
iid=PageId, text=PageName,
value=0)
if len(Page[PageId]) > 0:
self.BuildConfigPageTree(Page[PageId], Child)
def IsConfigDataLoaded(self):
return True if len(self.PageList) else False
def SetCurrentConfigPage(self, PageId):
self.PageId = PageId
def GetCurrentConfigPage(self):
return self.PageId
def GetCurrentConfigData(self):
PageId = self.GetCurrentConfigPage()
if PageId in self.PageList:
return self.PageList[PageId]
else:
return []
def BuildConfigDataPage(self, PageId):
self.ClearWidgetsInLayout()
self.SetCurrentConfigPage(PageId)
DispList = []
for Item in self.GetCurrentConfigData():
if Item['subreg']:
for SubItem in Item['subreg']:
DispList.append(SubItem)
else:
DispList.append(Item)
Row = 0
DispList.sort(key=lambda x:x['order'])
for Item in DispList:
self.AddConfigItem (Item, Row)
Row += 2
def LoadConfigData(self, FileName):
GenCfgData = CGenCfgData()
if FileName.endswith('.pkl'):
with open(FileName, "rb") as PklFile:
GenCfgData.__dict__ = marshal.load(PklFile)
elif FileName.endswith('.dsc'):
if GenCfgData.ParseDscFile(FileName) != 0:
raise Exception(GenCfgData.Error)
if GenCfgData.CreateVarDict() != 0:
raise Exception(GenCfgData.Error)
else:
raise Exception('Unsupported file "%s" !' % FileName)
GenCfgData.UpdateDefaultValue()
return GenCfgData
def About(self):
Msg = 'Configuration Editor\n--------------------------------\nVersion 0.5\n2018'
Lines = Msg.split('\n')
Width = 30
Text = []
for Line in Lines:
Text.append(Line.center(Width, ' '))
messagebox.showinfo('Config Editor', '\n'.join(Text))
def UpdateLastDir (self, Path):
self.LastDir = os.path.dirname(Path)
def GetOpenFileName(self, Type):
if self.IsConfigDataLoaded():
if Type == 'dlt':
Question = ''
elif Type == 'bin':
Question = 'All configuration will be reloaded from BIN file, continue ?'
elif Type == 'dsc':
Question = ''
else:
raise Exception('Unsupported file type !')
if Question:
Reply = messagebox.askquestion('', Question, icon='warning')
if Reply == 'no':
return None
if Type == 'dsc':
FileType = 'DSC or PKL'
FileExt = 'pkl *Def.dsc'
else:
FileType = Type.upper()
FileExt = Type
Path = filedialog.askopenfilename(
initialdir=self.LastDir,
title="Load file",
filetypes=(("%s files" % FileType, "*.%s" % FileExt), (
"all files", "*.*")))
if Path:
self.UpdateLastDir (Path)
return Path
else:
return None
def LoadFromDelta(self):
Path = self.GetOpenFileName('dlt')
if not Path:
return
self.LoadDeltaFile (Path)
def LoadDeltaFile (self, Path):
self.ReloadConfigDataFromBin(self.OrgCfgDataBin)
try:
self.CfgDataObj.OverrideDefaultValue(Path)
self.CfgDataObj.UpdateDefaultValue()
except Exception as e:
messagebox.showerror('LOADING ERROR', str(e))
return
self.UpdateLastDir (Path)
self.RefreshConfigDataPage()
def LoadFromBin(self):
Path = self.GetOpenFileName('bin')
if not Path:
return
with open(Path, 'rb') as Fd:
BinData = bytearray(Fd.read())
self.ReloadConfigDataFromBin(BinData)
try:
self.ReloadConfigDataFromBin(BinData)
except Exception as e:
messagebox.showerror('LOADING ERROR', str(e))
return
def LoadDscFile(self, Path):
# Save current values in widget and clear database
self.ClearWidgetsInLayout()
self.Left.delete(*self.Left.get_children())
try:
self.CfgDataObj = self.LoadConfigData(Path)
except Exception as e:
messagebox.showerror('LOADING ERROR', str(e))
return -1
self.UpdateLastDir (Path)
self.OrgCfgDataBin = self.CfgDataObj.GenerateBinaryArray()
self.BuildConfigPageTree(self.CfgDataObj._CfgPageTree['root'], '')
for Menu in self.MenuString:
self.FileMenu.entryconfig(Menu, state="normal")
return 0
def LoadFromDsc(self):
Path = self.GetOpenFileName('dsc')
if not Path:
return
self.LoadDscFile(Path)
def GetSaveFileName (self, Extension):
Path = filedialog.asksaveasfilename(
initialdir=self.LastDir,
title="Save file",
defaultextension=Extension)
if Path:
self.LastDir = os.path.dirname(Path)
return Path
else:
return None
def SaveDeltaFile(self, Full=False):
Path = self.GetSaveFileName (".dlt")
if not Path:
return
self.UpdateConfigDataOnPage()
self.GenerateDeltaFile(Path, Full)
def SaveToDelta(self):
self.SaveDeltaFile()
def SaveFullToDelta(self):
self.SaveDeltaFile(True)
def SaveToBin(self):
Path = self.GetSaveFileName (".bin")
if not Path:
return
self.UpdateConfigDataOnPage()
with open(Path, 'wb') as Fd:
Bins = self.CfgDataObj.GenerateBinaryArray()
Fd.write(Bins)
def GenerateDeltaFile(self, DeltaFile, Full=False):
NewData = self.CfgDataObj.GenerateBinaryArray()
Lines = []
TagName = ''
Level = 0
PlatformId = None
DefPlatformId = 0
for Item in self.CfgDataObj._CfgItemList:
if Level == 0 and Item['embed'].endswith(':START'):
TagName = Item['embed'].split(':')[0]
Level += 1
Start = Item['offset']
End = Start + Item['length']
FullName = '%s.%s' % (TagName, Item['cname'])
if 'PLATFORMID_CFG_DATA.PlatformId' == FullName:
DefPlatformId = Bytes2Val(self.OrgCfgDataBin[Start:End])
if NewData[Start:End] != self.OrgCfgDataBin[Start:End] or (
Full and Item['name'] and (Item['cname'] != 'Dummy')):
if not Item['subreg']:
ValStr = self.CfgDataObj.FormatDeltaValue (Item)
Text = '%-40s | %s' % (FullName, ValStr)
if 'PLATFORMID_CFG_DATA.PlatformId' == FullName:
PlatformId = Array2Val(Item['value'])
else:
Lines.append(Text)
else:
OldArray = self.OrgCfgDataBin[Start:End]
NewArray = NewData[Start:End]
for SubItem in Item['subreg']:
NewBitValue = self.CfgDataObj.GetBsfBitFields(SubItem,
NewArray)
OldBitValue = self.CfgDataObj.GetBsfBitFields(SubItem,
OldArray)
if OldBitValue != NewBitValue or (
Full and Item['name'] and
(Item['cname'] != 'Dummy')):
if SubItem['cname'].startswith(Item['cname']):
Offset = len(Item['cname']) + 1
FieldName = '%s.%s' % (
FullName, SubItem['cname'][Offset:])
ValStr = self.CfgDataObj.FormatDeltaValue (SubItem)
Text = '%-40s | %s' % (FieldName, ValStr)
Lines.append(Text)
if Item['embed'].endswith(':END'):
EndTagName = Item['embed'].split(':')[0]
if EndTagName == TagName:
Level -= 1
if PlatformId is None or DefPlatformId == PlatformId:
PlatformId = DefPlatformId
print("WARNING: 'PlatformId' configuration is same as default %d!"
% PlatformId)
Lines.insert(0, '%-40s | %s\n\n' %
('PLATFORMID_CFG_DATA.PlatformId', '0x%04X' % PlatformId))
self.CfgDataObj.WriteDeltaFile(DeltaFile, PlatformId, Lines)
def RefreshConfigDataPage(self):
self.ClearWidgetsInLayout()
self.OnConfigPageSelectChange(None)
def ReloadConfigDataFromBin(self, BinDat):
self.CfgDataObj.LoadDefaultFromBinaryArray(BinDat)
self.RefreshConfigDataPage()
def NormalizeValueStr(self, Item, ValueStr):
IsArray = True if Item['value'].startswith('{') else False
if IsArray and not ValueStr.startswith('{'):
ValueStr = "{ %s }" % ValueStr
try:
OldBytes = self.CfgDataObj.ValueToByteArray(Item['value'],
Item['length'])
NewBytes = self.CfgDataObj.ValueToByteArray(ValueStr,
Item['length'])
if OldBytes == NewBytes:
NewValue = Item['value']
else:
if IsArray:
NewValue = Bytes2Str(NewBytes)
else:
if Item['value'].startswith('0x'):
HexLen = Item['length'] * 2
if len(Item['value']) == HexLen + 2:
Fmt = '0x%%0%dX' % HexLen
else:
Fmt = '0x%X'
else:
Fmt = '%d'
NewValue = Fmt % Bytes2Val(NewBytes)
except:
NewValue = Item['value']
return NewValue
def SetConfigItemValue(self, Item, ValueStr):
Type = Item['type'].split(',')[0]
if Type == "Table":
NewValue = ValueStr
elif Type == "EditText":
NewValue = ValueStr[:Item['length']]
if Item['value'].startswith("'"):
NewValue = "'%s'" % NewValue
else:
NewValue = self.NormalizeValueStr(Item, ValueStr)
if Item['value'] != NewValue:
if self.Debug:
print('Update %s from %s to %s !' % (Item['cname'],
Item['value'], NewValue))
Item['value'] = NewValue
def SyncConfigDataFromSubRegion(self):
if not len(self.PageList) or not self.PageId:
return
for Item in self.GetCurrentConfigData():
if not Item['subreg']:
continue
ValArray = self.CfgDataObj.ValueToByteArray(Item['value'],
Item['length'])
for SubItem in Item['subreg']:
Value = Array2Val(SubItem['value'])
self.CfgDataObj.UpdateBsfBitFields(SubItem, Value, ValArray)
if Item['value'].startswith('{'):
NewValue = Bytes2Str(ValArray)
else:
BitsValue = ''.join('{0:08b}'.format(i)
for i in ValArray[::-1])
NewValue = '0x%X' % (int(BitsValue, 2))
NewValue = self.NormalizeValueStr(Item, NewValue)
if NewValue != Item['value']:
if self.Debug:
print('Update Subregion %s from %s to %s' %
(Item['cname'], Item['value'], NewValue))
Item['value'] = NewValue
def GetConfigDataItemFromWidget(self, Widget, Label=False):
Name = self.GetObjectName(Widget)
if not Name or not len(self.PageList):
return None
if Label and Name.startswith('LABEL_'):
Name = Name[6:]
Item = 0
for Conf in self.GetCurrentConfigData():
if Conf['subreg']:
for SubConf in Conf['subreg']:
if SubConf['cname'] == Name:
Item = SubConf
break
else:
if Conf['cname'] == Name:
Item = Conf
break
if Item:
break
return Item
def UpdateConfigDataFromWidget(self, Widget, Args):
Item = self.GetConfigDataItemFromWidget(Widget)
if Item is None:
return
elif not Item:
if isinstance(Widget, Label):
return
raise Exception('Failed to find "%s" !' %
self.GetObjectName(Widget))
Type = Item['type'].split(',')[0]
if Type == "Combo":
if Item['option'] in self.CfgDataObj._BuidinOption:
OptList = [('0', 'Disable'), ('1', 'Enable')]
else:
OptList = self.CfgDataObj.GetItemOptionList(Item)
TmpList = [Opt[0] for Opt in OptList]
Idx = Widget.current()
self.SetConfigItemValue(Item, TmpList[Idx])
elif Type in ["EditNum", "EditText"]:
self.SetConfigItemValue(Item, Widget.get())
elif Type in ["Table"]:
NewValue = Bytes2Str(Widget.get())
self.SetConfigItemValue(Item, NewValue)
def GetConfigDataItemFromName(self, Name, InPage=True):
CfgItemList = self.GetCurrentConfigData(
) if InPage else self.CfgDataObj._CfgItemList
for Item in CfgItemList:
if not Item['length'] or not Item['name']:
continue
if Item['subreg']:
for SubItem in Item['subreg']:
if not SubItem['name']:
continue
if SubItem['cname'] == Name:
return SubItem
else:
if Item['cname'] == Name:
return Item
return None
def EvaluateCondition(self, Cond):
Item = None
ReplaceList = []
Parts = re.findall("\$(\w+)(\.\w+)?", Cond)
for Part in Parts:
if len(Part) > 1 and len(Part[1]) > 0:
Name = Part[0] + '_' + Part[1][1:]
else:
Name = Part[0]
Value = None
Item = self.GetConfigDataItemFromName(Name, False)
if Item:
try:
Value = '0x%x' % Bytes2Val(
self.CfgDataObj.ValueToByteArray(Item['value'], Item[
'length']))
except:
Value = None
ReplaceList.append(('$' + ''.join(Part), Value))
OrgCond = Cond
Result = True
ReplaceList.sort(key=lambda x: len(x[0]), reverse=True)
for Each in ReplaceList:
if Each[1] is None:
break
Cond = Cond.replace(Each[0], Each[1])
try:
Result = True if eval(Cond) else False
except:
print("WARNING: Condition '%s' is invalid!" % OrgCond)
return Result
def AddConfigItem(self, Item, Row):
Parent = self.RightGrid
Name = Label(Parent, text=Item['name'], anchor="w")
Parts = Item['type'].split(',')
Type = Parts[0]
Widget = None
if Type == "Combo":
# Build
if Item['option'] in self.CfgDataObj._BuidinOption:
OptList = [('0', 'Disable'), ('1', 'Enable')]
else:
OptList = self.CfgDataObj.GetItemOptionList(Item)
CurrentValue = self.CfgDataObj.ValueToByteArray(Item['value'],
Item['length'])
OptionList = []
Current = None
for Idx, Option in enumerate(OptList):
OptionValue = self.CfgDataObj.ValueToByteArray(Option[0],
Item['length'])
if OptionValue == CurrentValue:
Current = Idx
OptionList.append(Option[1])
Widget = ttk.Combobox(Parent, value=OptionList, state="readonly")
Widget.bind("<<ComboboxSelected>>", self.ComboSelectChanged)
if Current is None:
print('WARNING: Value "%s" is an invalid option for "%s" !' %
(Bytes2Val(CurrentValue), Item['cname']))
else:
Widget.current(Current)
elif Type in ["EditNum", "EditText"]:
TxtVal = StringVar()
Widget = Entry(Parent, textvariable=TxtVal)
Value = Item['value'].strip("'")
if Type in ["EditText"]:
TxtVal.trace(
'w',
lambda *args: self.LimitEntrySize(TxtVal, Item['length']))
elif Type in ["EditNum"]:
Value = Item['value'].strip("{").strip("}").strip()
Widget.bind("<FocusOut>", self.EditNumFinished)
TxtVal.set(Value)
elif Type in ["Table"]:
Bins = self.CfgDataObj.ValueToByteArray(Item['value'],
Item['length'])
ColHdr = Item['option'].split(',')
Widget = CustomTable(Parent, ColHdr, Bins)
if Widget:
Ttp = CreateToolTip(Widget, Item['help'])
self.SetObjectName(Name, 'LABEL_' + Item['cname'])
self.SetObjectName(Widget, Item['cname'])
Name.grid(row=Row, column=0, padx=10, pady=5, sticky="nsew")
Widget.grid(row=Row + 1, column=0, padx=10, pady=5, sticky="nsew")
def UpdateConfigDataOnPage(self):
self.WalkWidgetsInLayout(self.RightGrid,
self.UpdateConfigDataFromWidget)
self.SyncConfigDataFromSubRegion()
if __name__ == '__main__':
Root = Tk()
App = Application(master=Root)
Root.title("Config Editor")
Root.mainloop()