--- a/PLCOpenEditor.py Thu Aug 23 09:50:35 2007 +0200
+++ b/PLCOpenEditor.py Mon Aug 27 17:37:50 2007 +0200
@@ -64,10 +64,7 @@
sys.exit()
elif len(args) == 1:
fileOpen = args[0]
-CWD = ""
-for path in sys.path:
- if os.path.isfile(os.path.join(path, "PLCOpenEditor.py")):
- CWD = path
+CWD = os.path.split(__file__)[0]
[ID_PLCOPENEDITOR, ID_PLCOPENEDITORPROJECTTREE,
ID_PLCOPENEDITORSPLITTERWINDOW1, ID_PLCOPENEDITOREDITORPANEL,
@@ -352,17 +349,17 @@
self.splitterWindow1 = wx.SplitterWindow(id=ID_PLCOPENEDITORSPLITTERWINDOW1,
name='splitterWindow1', parent=self, point=wx.Point(0, 0),
- size=wx.Size(-1, -1), style=wx.SP_3D)
+ size=wx.Size(0, 0), style=wx.SP_3D)
self.splitterWindow1.SetNeedUpdating(True)
self.splitterWindow1.SetMinimumPaneSize(1)
self.EditorPanel = wx.Panel(id=ID_PLCOPENEDITOREDITORPANEL,
name='TabPanel', parent=self.splitterWindow1, pos=wx.Point(0, 0),
- size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL)
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
self.TabsOpened = wx.Notebook(id=ID_PLCOPENEDITORTABSOPENED,
name='TabsOpened', parent=self.EditorPanel, pos=wx.Point(0,
- 0), size=wx.Size(-1, -1), style=0)
+ 0), size=wx.Size(0, 0), style=0)
self.TabsOpened.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED,
self.OnPouSelectedChanged, id=ID_PLCOPENEDITORTABSOPENED)
@@ -500,14 +497,18 @@
def OnCloseFrame(self, event):
if not self.Controler.ProjectIsSaved():
- dialog = wx.MessageDialog(self, "There are changes, do you want to save?", "Close Application", wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
+ dialog = wx.MessageDialog(self, "There are changes, do you want to save?", "Close Application", wx.YES_NO|wx.CANCEL|wx.ICON_QUESTION)
answer = dialog.ShowModal()
dialog.Destroy()
if answer == wx.ID_YES:
self.SaveProject()
event.Skip()
elif answer == wx.ID_NO:
+ self.Controler.Reset()
+ wx.CallAfter(self.Close)
event.Skip()
+ else:
+ event.Veto()
else:
event.Skip()
@@ -631,8 +632,6 @@
event.Skip()
def OnQuitMenu(self, event):
- self.ToolBar.Reparent(self)
- self.Controler.Reset()
self.Close()
event.Skip()
@@ -895,6 +894,7 @@
if name == "Properties":
self.ShowProperties()
elif data in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION, ITEM_RESOURCE, ITEM_CONFIGURATION]:
+ idx = None
if data == ITEM_CONFIGURATION:
idx = self.Controler.OpenConfigurationEditing(name)
if idx != None:
@@ -916,31 +916,33 @@
else:
idx = self.Controler.ChangeConfigurationResourceEditing(config_name, name)
elif data == ITEM_POU:
- idx = self.Controler.OpenElementEditing(name)
+ idx = self.Controler.OpenPouEditing(name)
if idx != None:
new_window = PouEditorPanel(self.TabsOpened, self, self.Controler, self.Controler.GetPouType(name), pou_name = name)
self.TabsOpened.AddPage(new_window, "")
else:
- idx = self.Controler.ChangeElementEditing(name)
+ idx = self.Controler.ChangePouEditing(name)
else:
- parent = self.ProjectTree.GetItemParent(selected)
- parent_name = self.ProjectTree.GetItemText(parent)
- grandparent = self.ProjectTree.GetItemParent(parent)
- grandparent_name = self.ProjectTree.GetItemText(grandparent)
+ item = self.ProjectTree.GetItemParent(selected)
+ item_type = self.ProjectTree.GetPyData(item)
+ while item_type != ITEM_POU:
+ item = self.ProjectTree.GetItemParent(item)
+ item_type = self.ProjectTree.GetPyData(item)
+ pou_name = self.ProjectTree.GetItemText(item)
if data == ITEM_TRANSITION:
- idx = self.Controler.OpenPouTransitionEditing(grandparent_name, name)
+ idx = self.Controler.OpenPouTransitionEditing(pou_name, name)
if idx != None:
- new_window = PouEditorPanel(self.TabsOpened, self, self.Controler, "transition", pou_name = grandparent_name, transition_name = name)
+ new_window = PouEditorPanel(self.TabsOpened, self, self.Controler, "transition", pou_name = pou_name, transition_name = name)
self.TabsOpened.AddPage(new_window, "")
else:
- idx = self.Controler.ChangePouTransitionEditing(grandparent_name, name)
+ idx = self.Controler.ChangePouTransitionEditing(pou_name, name)
elif data == ITEM_ACTION:
- idx = self.Controler.OpenPouActionEditing(grandparent_name, name)
+ idx = self.Controler.OpenPouActionEditing(pou_name, name)
if idx != None:
- new_window = PouEditorPanel(self.TabsOpened, self, self.Controler, "action", pou_name = grandparent_name, action_name = name)
+ new_window = PouEditorPanel(self.TabsOpened, self, self.Controler, "action", pou_name = pou_name, action_name = name)
self.TabsOpened.AddPage(new_window, "")
else:
- idx = self.Controler.ChangePouActionEditing(grandparent_name, name)
+ idx = self.Controler.ChangePouActionEditing(pou_name, name)
if idx != None:
old_selected = self.TabsOpened.GetSelection()
if old_selected >= 0:
@@ -966,34 +968,48 @@
def OnProjectTreeItemSelected(self, event):
selected = event.GetItem()
name = self.ProjectTree.GetItemText(selected)
- if self.ProjectTree.GetItemParent(selected) == self.ProjectTree.GetRootItem() and name != "Properties":
- if self.Controler.IsElementEditing(name):
- idx = self.Controler.ChangeElementEditing(name)
- if idx != None:
- self.TabsOpened.SetSelection(idx)
- self.RefreshFileMenu()
- self.RefreshEditMenu()
- self.RefreshToolBar()
- else:
- name = self.ProjectTree.GetItemText(selected)
- parent = self.ProjectTree.GetItemParent(selected)
- parent_name = self.ProjectTree.GetItemText(parent)
- grandparent = self.ProjectTree.GetItemParent(parent)
- grandparent_name = self.ProjectTree.GetItemText(grandparent)
- if parent_name == "Transitions":
- idx = self.Controler.ChangePouTransitionEditing(grandparent_name, name)
- if idx != None:
- self.TabsOpened.SetSelection(idx)
- self.RefreshFileMenu()
- self.RefreshEditMenu()
- self.RefreshToolBar()
- elif parent_name == "Action":
- idx = self.Controler.ChangePouActionEditing(grandparent_name, name)
- if idx != None:
- self.TabsOpened.SetSelection(idx)
- self.RefreshFileMenu()
- self.RefreshEditMenu()
- self.RefreshToolBar()
+ data = self.ProjectTree.GetPyData(selected)
+ if data in [ITEM_POU, ITEM_TRANSITION, ITEM_ACTION, ITEM_RESOURCE, ITEM_CONFIGURATION]:
+ idx = None
+ if data == ITEM_CONFIGURATION:
+ if self.Controler.IsConfigurationEditing(name):
+ idx = self.Controler.ChangeConfigurationEditing(name)
+ elif data == ITEM_RESOURCE:
+ item = self.ProjectTree.GetItemParent(selected)
+ item_type = self.ProjectTree.GetPyData(item)
+ while item_type != ITEM_CONFIGURATION:
+ item = self.ProjectTree.GetItemParent(item)
+ item_type = self.ProjectTree.GetPyData(item)
+ config_name = self.ProjectTree.GetItemText(item)
+ if self.Controler.IsConfigurationResourceEditing(config_name, name):
+ idx = self.Controler.ChangeConfigurationResourceEditing(config_name, name)
+ elif data == ITEM_POU:
+ if self.Controler.IsPouEditing(name):
+ idx = self.Controler.ChangePouEditing(name)
+ else:
+ item = self.ProjectTree.GetItemParent(selected)
+ item_type = self.ProjectTree.GetPyData(item)
+ while item_type != ITEM_POU:
+ item = self.ProjectTree.GetItemParent(item)
+ item_type = self.ProjectTree.GetPyData(item)
+ pou_name = self.ProjectTree.GetItemText(item)
+ if data == ITEM_TRANSITION:
+ if self.Controler.IsPouTransitionEditing(pou_name, name):
+ idx = self.Controler.ChangePouTransitionEditing(pou_name, name)
+ elif data == ITEM_ACTION:
+ if self.Controler.IsPouActionEditing(pou_name, name):
+ idx = self.Controler.ChangePouActionEditing(pou_name, name)
+ if idx != None:
+ old_selected = self.TabsOpened.GetSelection()
+ if old_selected >= 0:
+ self.TabsOpened.GetPage(old_selected).ResetBuffer()
+ self.TabsOpened.SetSelection(idx)
+ window = self.TabsOpened.GetPage(idx)
+ window.RefreshView()
+ self.RefreshTabsOpenedTitles()
+ self.RefreshFileMenu()
+ self.RefreshEditMenu()
+ self.RefreshToolBar()
event.Skip()
def RefreshProjectTree(self):
@@ -1066,6 +1082,7 @@
self.TabsOpened.GetPage(selected).Refresh()
self.RefreshTitle()
self.RefreshEditMenu()
+ self.RefreshProjectTree()
event.Skip()
def OnRedoMenu(self, event):
@@ -1076,6 +1093,7 @@
self.TabsOpened.GetPage(selected).Refresh()
self.RefreshTitle()
self.RefreshEditMenu()
+ self.RefreshProjectTree()
event.Skip()
def OnCutMenu(self, event):
@@ -1112,6 +1130,8 @@
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
self.Controler.ProjectAddPou(values["pouName"], values["pouType"], values["language"])
+ self.RefreshTitle()
+ self.RefreshEditMenu()
self.RefreshProjectTree()
dialog.Destroy()
event.Skip()
@@ -1129,6 +1149,8 @@
deleted = i
if deleted != None:
self.TabsOpened.DeletePage(i)
+ self.RefreshTitle()
+ self.RefreshEditMenu()
self.RefreshProjectTree()
self.RefreshToolBar()
else:
@@ -1138,20 +1160,26 @@
event.Skip()
def OnAddConfigurationMenu(self, event):
- dialog = wx.TextEntryDialog(self, "Enter configuration name:", "Create new configuration", "", wx.OK|wx.CANCEL)
+ dialog = ConfigurationNameDialog(self, "Please enter configuration name", "Add new configuration")
+ dialog.SetPouNames(self.Controler.GetProjectPouNames())
+ dialog.SetPouElementNames(self.Controler.GetProjectPouVariables())
if dialog.ShowModal() == wx.ID_OK:
value = dialog.GetValue()
self.Controler.ProjectAddConfiguration(value)
+ self.RefreshTitle()
+ self.RefreshEditMenu()
self.RefreshProjectTree()
dialog.Destroy()
event.Skip()
def OnRemoveConfigurationMenu(self, event):
configs = self.Controler.GetProjectConfigNames()
- dialog = wx.SingleChoiceDialog(self, "Select Configuration to remove:", "Remove configuration", configs, wx.OK|wx.CANCEL)
+ dialog = wx.SingleChoiceDialog(self, "Please select a configuration", "Remove configuration", configs, wx.OK|wx.CANCEL)
if dialog.ShowModal() == wx.ID_OK:
selected = dialog.GetStringSelection()
self.Controler.ProjectRemoveConfiguration(selected)
+ self.RefreshTitle()
+ self.RefreshEditMenu()
self.RefreshProjectTree()
event.Skip()
@@ -1166,6 +1194,8 @@
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
self.Controler.ProjectAddPouTransition(pouname, values["transitionName"], values["language"])
+ self.RefreshTitle()
+ self.RefreshEditMenu()
self.RefreshProjectTree()
dialog.Destroy()
event.Skip()
@@ -1180,6 +1210,8 @@
if dialog.ShowModal() == wx.ID_OK:
selected = dialog.GetStringSelection()
self.Controler.ProjectRemovePouTransition(pouname, selected)
+ self.RefreshTitle()
+ self.RefreshEditMenu()
self.RefreshProjectTree()
dialog.Destroy()
event.Skip()
@@ -1195,6 +1227,8 @@
if dialog.ShowModal() == wx.ID_OK:
values = dialog.GetValues()
self.Controler.ProjectAddPouAction(pouname, values["actionName"], values["language"])
+ self.RefreshTitle()
+ self.RefreshEditMenu()
self.RefreshProjectTree()
dialog.Destroy()
event.Skip()
@@ -1209,6 +1243,8 @@
if dialog.ShowModal() == wx.ID_OK:
selected = dialog.GetStringSelection()
self.Controler.ProjectRemovePouAction(pouname, selected)
+ self.RefreshTitle()
+ self.RefreshEditMenu()
self.RefreshProjectTree()
dialog.Destroy()
event.Skip()
@@ -1217,10 +1253,14 @@
selected = self.ProjectTree.GetSelection()
if self.ProjectTree.GetPyData(selected) == ITEM_CONFIGURATION:
config_name = self.ProjectTree.GetItemText(selected)
- dialog = wx.TextEntryDialog(self, "Enter Resource name:", "Create new Resource", "", wx.OK|wx.CANCEL)
+ dialog = ResourceNameDialog(self, "Please enter resource name", "Add new resource")
+ dialog.SetPouNames(self.Controler.GetProjectPouNames())
+ dialog.SetPouElementNames(self.Controler.GetProjectPouVariables())
if dialog.ShowModal() == wx.ID_OK:
value = dialog.GetValue()
self.Controler.ProjectAddConfigurationResource(config_name, value)
+ self.RefreshTitle()
+ self.RefreshEditMenu()
self.RefreshProjectTree()
dialog.Destroy()
event.Skip()
@@ -1238,6 +1278,8 @@
if dialog.ShowModal() == wx.ID_OK:
resource = dialog.GetStringSelection()
self.Controler.ProjectRemoveConfigurationResource(config_name, resource)
+ self.RefreshTitle()
+ self.RefreshEditMenu()
self.RefreshProjectTree()
dialog.Destroy()
event.Skip()
@@ -1867,6 +1909,108 @@
return values
#-------------------------------------------------------------------------------
+# Configuration Name Dialog
+#-------------------------------------------------------------------------------
+
+class ConfigurationNameDialog(wx.TextEntryDialog):
+
+ def __init__(self, parent, message, caption = "Please enter configuration name", defaultValue = "",
+ style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition):
+ wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos)
+
+ self.PouNames = []
+ self.PouElementNames = []
+
+ self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId())
+
+ def OnOK(self, event):
+ config_name = self.GetSizer().GetItem(1).GetWindow().GetValue()
+ if config_name == "":
+ message = wx.MessageDialog(self, "You must type a name!", "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ elif not TestIdentifier(config_name):
+ message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%config_name, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ elif config_name.upper() in IEC_KEYWORDS:
+ message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%config_name, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ elif config_name.upper() in self.PouNames:
+ message = wx.MessageDialog(self, "A pou with \"%s\" as name exists!"%config_name, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ elif config_name.upper() in self.PouElementNames:
+ message = wx.MessageDialog(self, "A pou has an element with \"%s\" for name. It can generate a conflict. Do you wish to continue?"%config_name, "Warning", wx.YES_NO|wx.ICON_EXCLAMATION)
+ result = message.ShowModal()
+ message.Destroy()
+ if result == wx.ID_YES:
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_OK)
+
+ def SetPouNames(self, pou_names):
+ self.PouNames = [pou_name.upper() for pou_name in pou_names]
+
+ def SetPouElementNames(self, pou_names):
+ self.PouElementNames = [pou_name.upper() for pou_name in pou_names]
+
+ def GetValue(self):
+ return self.GetSizer().GetItem(1).GetWindow().GetValue()
+
+#-------------------------------------------------------------------------------
+# Resource Name Dialog
+#-------------------------------------------------------------------------------
+
+class ResourceNameDialog(wx.TextEntryDialog):
+
+ def __init__(self, parent, message, caption = "Please enter resource name", defaultValue = "",
+ style = wx.OK|wx.CANCEL|wx.CENTRE, pos = wx.DefaultPosition):
+ wx.TextEntryDialog.__init__(self, parent, message, caption, defaultValue, style, pos)
+
+ self.PouNames = []
+ self.PouElementNames = []
+
+ self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.GetSizer().GetItem(3).GetSizer().GetAffirmativeButton().GetId())
+
+ def OnOK(self, event):
+ resource_name = self.GetSizer().GetItem(1).GetWindow().GetValue()
+ if resource_name == "":
+ message = wx.MessageDialog(self, "You must type a name!", "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ elif not TestIdentifier(resource_name):
+ message = wx.MessageDialog(self, "\"%s\" is not a valid identifier!"%resource_name, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ elif resource_name.upper() in IEC_KEYWORDS:
+ message = wx.MessageDialog(self, "\"%s\" is a keyword. It can't be used!"%resource_name, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ elif resource_name.upper() in self.PouNames:
+ message = wx.MessageDialog(self, "A pou with \"%s\" as name exists!"%resource_name, "Error", wx.OK|wx.ICON_ERROR)
+ message.ShowModal()
+ message.Destroy()
+ elif resource_name.upper() in self.PouElementNames:
+ message = wx.MessageDialog(self, "A pou has an element with \"%s\" for name. It can generate a conflict. Do you wish to continue?"%resource_name, "Warning", wx.YES_NO|wx.ICON_EXCLAMATION)
+ result = message.ShowModal()
+ message.Destroy()
+ if result == wx.ID_YES:
+ self.EndModal(wx.ID_OK)
+ else:
+ self.EndModal(wx.ID_OK)
+
+ def SetPouNames(self, pou_names):
+ self.PouNames = [pou_name.upper() for pou_name in pou_names]
+
+ def SetPouElementNames(self, pou_names):
+ self.PouElementNames = [pou_name.upper() for pou_name in pou_names]
+
+ def GetValue(self):
+ return self.GetSizer().GetItem(1).GetWindow().GetValue()
+
+#-------------------------------------------------------------------------------
# Pou Editor Panel
#-------------------------------------------------------------------------------
@@ -1904,7 +2048,7 @@
def GetValue(self, row, col):
if row < self.GetNumberRows():
if col == 0:
- return self.Parent.Values.index(self.data[row]) + 1
+ return self.data[row]["Number"]
name = str(self.data[row].get(self.GetColLabelValue(col), ""))
return name
@@ -2134,14 +2278,15 @@
def _init_ctrls(self, prnt, element_type):
wx.SplitterWindow.__init__(self, id=ID_POUEDITORPANEL,
name='EditVariablePanel', parent=prnt, pos=wx.Point(0, 0),
- size=wx.Size(-1, -1), style=wx.SP_3D)
+ size=wx.Size(0, 0), style=wx.SP_3D)
self.SetNeedUpdating(True)
self.SetMinimumPaneSize(1)
if element_type == "config":
self.Viewer = wx.Panel(id=ID_POUEDITORPANELVIEWER,
name='ConfigPanel', parent=self, pos=wx.Point(0, 0),
- size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL)
+ size=wx.Size(0, 0), style=0)
+ self.Viewer.SetSizer(wx.BoxSizer(wx.VERTICAL))
self.Viewer.ResetBuffer = lambda: None
self.Viewer.RefreshView = lambda: None
elif element_type == "resource":
@@ -2162,7 +2307,7 @@
self.VariablePanel = wx.Panel(id=ID_POUEDITORPANELVIEWER,
name='VariablePanel', parent=self, pos=wx.Point(0, 0),
- size=wx.Size(-1, -1), style=wx.TAB_TRAVERSAL)
+ size=wx.Size(0, 0), style=wx.TAB_TRAVERSAL)
self.staticText1 = wx.StaticText(id=ID_POUEDITORPANELSTATICTEXT1,
label='Return Type:', name='staticText1', parent=self.VariablePanel,
@@ -2171,6 +2316,7 @@
self.ReturnType = wx.Choice(id=ID_POUEDITORPANELRETURNTYPE,
name='ReturnType', parent=self.VariablePanel, pos=wx.Point(0, 0),
size=wx.Size(145, 24), style=0)
+ self.Bind(wx.EVT_CHOICE, self.OnReturnTypeChanged, id=ID_POUEDITORPANELRETURNTYPE)
self.staticText2 = wx.StaticText(id=ID_POUEDITORPANELSTATICTEXT2,
label='Class Filter:', name='staticText2', parent=self.VariablePanel,
@@ -2252,10 +2398,10 @@
if pou_type in ["config", "resource"]:
self.DefaultTypes = {"All" : "Global"}
- self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : "True"}
+ self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : True}
else:
self.DefaultTypes = {"All" : "Local", "Interface" : "Input", "Variables" : "Local"}
- self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : "True"}
+ self.DefaultValue = {"Name" : "", "Class" : "", "Type" : "INT", "Location" : "", "Initial Value" : "", "Retain" : "No", "Constant" : "No", "Edit" : True}
if pou_type in ["config", "resource"] or pou_type == "program":
self.Table = VariableTable(self, [], ["#", "Name", "Class", "Type", "Location", "Initial Value", "Retain", "Constant"])
if pou_type not in ["config", "resource"]:
@@ -2347,6 +2493,13 @@
self.Viewer.SetVariables(varlist)
self.Viewer.SetFunctions(self.Controler.GetBlockTypes())
+ def OnReturnTypeChanged(self, event):
+ self.Controler.SetPouInterfaceReturnType(self.PouName, self.ReturnType.GetStringSelection())
+ self.Controler.BufferProject()
+ self.Parent.RefreshTitle()
+ self.Parent.RefreshEditMenu()
+ event.Skip()
+
def OnClassFilter(self, event):
self.Filter = self.FilterChoiceTransfer[self.ClassFilter.GetStringSelection()]
self.RefreshTypeList()
@@ -2519,8 +2672,9 @@
if len(self.Table.data) > 0:
self.VariablesGrid.SetGridCursor(0, 1)
data = []
- for variable in self.Values:
+ for num, variable in enumerate(self.Values):
if variable["Class"] in self.ClassList:
+ variable["Number"] = num + 1
data.append(variable)
self.Table.SetData(data)
self.Table.ResetView(self.VariablesGrid)