Adding support for highlighing compiling errors from matiec
authorlbessard
Tue, 12 Aug 2008 18:16:09 +0200
changeset 231 fc2d6cbb8b39
parent 230 45d70748e45a
child 232 cbdfef9b2020
Adding support for highlighing compiling errors from matiec
DataTypeEditor.py
PLCOpenEditor.py
RessourceEditor.py
TextViewer.py
Viewer.py
graphics/FBD_Objects.py
graphics/GraphicCommons.py
graphics/LD_Objects.py
graphics/SFC_Objects.py
--- a/DataTypeEditor.py	Tue Aug 12 18:15:35 2008 +0200
+++ b/DataTypeEditor.py	Tue Aug 12 18:16:09 2008 +0200
@@ -25,7 +25,7 @@
 import wx
 import wx.grid
 import wx.gizmos
-from plcopen.structures import GetDataTypeRange, IEC_KEYWORDS
+from plcopen.structures import IEC_KEYWORDS
 
 import re
 
@@ -165,7 +165,7 @@
 
         self.staticbox = wx.StaticBox(id=ID_DATATYPEEDITORSTATICBOX,
               label='Type infos:', name='staticBox1', parent=self,
-              pos=wx.Point(0, 0), size=wx.Size(0, 0), style=0)
+              pos=wx.Point(0, 0), size=wx.Size(10, 0), style=0)
 
         self.staticText1 = wx.StaticText(id=ID_DATATYPEEDITORSTATICTEXT1,
               label='Derivation Type:', name='staticText1', parent=self,
@@ -197,8 +197,8 @@
 
         self.DirectlyInitialValue = wx.TextCtrl(id=ID_DATATYPEEDITORDIRECTLYINITIALVALUE, 
               name='DirectlyInitialValue', parent=self.DirectlyPanel, pos=wx.Point(0, 0),
-              size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL|wx.TE_PROCESS_ENTER)
-        self.Bind(wx.EVT_TEXT_ENTER, self.OnInfosChanged, id=ID_DATATYPEEDITORDIRECTLYINITIALVALUE)
+              size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL|wx.TE_PROCESS_ENTER|wx.TE_MULTILINE|wx.TE_RICH)
+        self.Bind(wx.EVT_TEXT_ENTER, self.OnReturnKeyPressed, id=ID_DATATYPEEDITORDIRECTLYINITIALVALUE)
 
         # Panel for Subrange data types
 
@@ -296,8 +296,8 @@
 
         self.ArrayInitialValue = wx.TextCtrl(id=ID_DATATYPEEDITORARRAYINITIALVALUE, 
               name='ArrayInitialValue', parent=self.ArrayPanel, pos=wx.Point(0, 0),
-              size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL|wx.TE_PROCESS_ENTER)
-        self.Bind(wx.EVT_TEXT_ENTER, self.OnInfosChanged, id=ID_DATATYPEEDITORARRAYINITIALVALUE)
+              size=wx.Size(0, 24), style=wx.TAB_TRAVERSAL|wx.TE_PROCESS_ENTER|wx.TE_MULTILINE|wx.TE_RICH)
+        self.Bind(wx.EVT_TEXT_ENTER, self.OnReturnKeyPressed, id=ID_DATATYPEEDITORARRAYINITIALVALUE)
         
         self._init_sizers()
 
@@ -312,6 +312,7 @@
         self.EnumeratedPanel.Hide()
         self.ArrayPanel.Hide()
         self.CurrentPanel = "Directly"
+        self.Errors = []
         self.Initializing = False
         
         self.ParentWindow = window
@@ -371,7 +372,7 @@
         self.DirectlyBaseType.SetSelection(0)
         self.SubrangeBaseType.Clear()
         words = self.TagName.split("::")
-        for base_type in self.Controler.GetSubrangeTypes():
+        for base_type in self.Controler.GetSubrangeBaseTypes(words[1]):
             self.SubrangeBaseType.Append(base_type)
         self.SubrangeBaseType.SetSelection(0)
         self.RefreshBoundsRange()
@@ -400,6 +401,7 @@
                 self.ArrayDimensions.SetStrings(map(lambda x : "..".join(map(str, x)), type_infos["dimensions"]))
                 self.ArrayInitialValue.SetValue(type_infos["initial"])
             self.RefreshDisplayedInfos()
+        self.ShowErrors()
         self.Initializing = False
 
     def RefreshScaling(self, refresh=True):
@@ -410,6 +412,9 @@
         self.RefreshTypeInfos()
         event.Skip()
 
+    def OnReturnKeyPressed(self, event):
+        self.RefreshTypeInfos()
+        
     def OnInfosChanged(self, event):
         self.RefreshTypeInfos()
         event.Skip()
@@ -468,7 +473,7 @@
         self.EnumeratedInitialValue.SetStringSelection(selected)
 
     def RefreshBoundsRange(self):
-        range = GetDataTypeRange(self.SubrangeBaseType.GetStringSelection())
+        range = self.Controler.GetDataTypeRange(self.SubrangeBaseType.GetStringSelection())
         if range is not None:
             min_value, max_value = range
             self.SubrangeMinimum.SetRange(min_value, max_value)
@@ -521,3 +526,64 @@
         self.ParentWindow.RefreshTitle()
         self.ParentWindow.RefreshEditMenu()
 
+#-------------------------------------------------------------------------------
+#                        Errors showing functions
+#-------------------------------------------------------------------------------
+
+    def ClearErrors(self):
+        self.Errors = []
+        self.RefreshView()
+
+    def AddShownError(self, infos, start, end):
+        self.Errors.append((infos, start, end))
+
+    def ShowErrors(self):
+        type_infos = self.Controler.GetDataTypeInfos(self.TagName)
+        for infos, start, end in self.Errors:
+            if infos[0] == "base":
+                if type_infos["type"] == "Directly":
+                    self.DirectlyBaseType.SetBackgroundColour(wx.Colour(255, 255, 0))
+                    self.DirectlyBaseType.SetForegroundColour(wx.RED)
+                elif type_infos["type"] == "Subrange":
+                    self.SubrangeBaseType.SetBackgroundColour(wx.Colour(255, 255, 0))
+                    self.SubrangeBaseType.SetForegroundColour(wx.RED)
+                elif type_infos["type"] == "Array":
+                    self.ArrayBaseType.SetBackgroundColour(wx.Colour(255, 255, 0))
+                    self.ArrayBaseType.SetForegroundColour(wx.RED)
+            elif infos[0] == "lower":
+                self.SubrangeMinimum.SetBackgroundColour(wx.Colour(255, 255, 0))
+                self.SubrangeMaximum.SetForegroundColour(wx.RED)
+            elif infos[0] == "upper":
+                self.SubrangeMinimum.SetBackgroundColour(wx.Colour(255, 255, 0))
+                self.SubrangeMaximum.SetForegroundColour(wx.RED)
+            elif infos[0] == "value":
+                listctrl = self.EnumeratedValues.GetListCtrl()
+                listctrl.SetItemBackgroundColour(infos[1], wx.Colour(255, 255, 0))
+                listctrl.SetItemTextColour(infos[1], wx.RED)
+                listctrl.Select(listctrl.FocusedItem, False)
+            elif infos[0] == "range":
+                listctrl = self.EnumeratedValues.GetListCtrl()
+                listctrl.SetItemBackgroundColour(infos[1], wx.Colour(255, 255, 0))
+                listctrl.SetItemTextColour(infos[1], wx.RED)
+                listctrl.SetStringSelection("")
+            elif infos[0] == "initial":
+                if type_infos["type"] == "Directly":
+                    text = self.DirectlyInitialValue.GetValue()
+                    self.DirectlyInitialValue.SetValue(text[:start[1]])
+                    self.DirectlyInitialValue.SetDefaultStyle(wx.TextAttr(wx.RED, wx.Colour(255, 255, 0)))
+                    self.DirectlyInitialValue.AppendText(text[start[1]:end[1] + 1])
+                    self.DirectlyInitialValue.SetDefaultStyle(wx.TextAttr(wx.BLACK, wx.WHITE))
+                    self.DirectlyInitialValue.AppendText(text[end[1] + 1:])
+                elif type_infos["type"] == "Subrange":
+                    self.SubrangeInitialValue.SetBackgroundColour(wx.Colour(255, 255, 0))
+                    self.SubrangeInitialValue.SetForegroundColour(wx.RED)
+                elif type_infos["type"] == "Enumerated":
+                    self.EnumeratedInitialValue.SetBackgroundColour(wx.Colour(255, 255, 0))
+                    self.EnumeratedInitialValue.SetForegroundColour(wx.RED)
+                elif type_infos["type"] == "Array":
+                    text = self.ArrayInitialValue.GetValue()
+                    self.ArrayInitialValue.SetValue(text[:start[1]])
+                    self.ArrayInitialValue.SetDefaultStyle(wx.TextAttr(wx.RED, wx.Colour(255, 255, 0)))
+                    self.ArrayInitialValue.AppendText(text[start[1]:end[1] + 1])
+                    self.ArrayInitialValue.SetDefaultStyle(wx.TextAttr(wx.BLACK, wx.WHITE))
+                    self.ArrayInitialValue.AppendText(text[end[1] + 1:])
--- a/PLCOpenEditor.py	Tue Aug 12 18:15:35 2008 +0200
+++ b/PLCOpenEditor.py	Tue Aug 12 18:16:09 2008 +0200
@@ -265,6 +265,9 @@
     def _init_coll_EditMenu_Items(self, parent):
         AppendMenu(parent, help='', id=wx.ID_REFRESH,
               kind=wx.ITEM_NORMAL, text=u'Refresh\tCTRL+R')
+        if not self.ModeSolo:
+            AppendMenu(parent, help='', id=wx.ID_CLEAR,
+                  kind=wx.ITEM_NORMAL, text=u'Clear Errors\tCTRL+K')
         AppendMenu(parent, help='', id=wx.ID_UNDO,
               kind=wx.ITEM_NORMAL, text=u'Undo\tCTRL+Z')
         AppendMenu(parent, help='', id=wx.ID_REDO,
@@ -292,6 +295,8 @@
         AppendMenu(parent, help='', id=wx.ID_DELETE,
               kind=wx.ITEM_NORMAL, text=u'Delete')
         self.Bind(wx.EVT_MENU, self.OnRefreshMenu, id=wx.ID_REFRESH)
+        if not self.ModeSolo:
+            self.Bind(wx.EVT_MENU, self.OnClearErrorsMenu, id=wx.ID_CLEAR)
         self.Bind(wx.EVT_MENU, self.OnUndoMenu, id=wx.ID_UNDO)
         self.Bind(wx.EVT_MENU, self.OnRedoMenu, id=wx.ID_REDO)
         self.Bind(wx.EVT_MENU, self.OnCutMenu, id=wx.ID_CUT)
@@ -489,6 +494,7 @@
         self.CurrentToolBar = []
         self.CurrentLanguage = ""
         self.SelectedItem = None
+        self.Errors = []
         self.DrawingMode = FREEDRAWING_MODE
         #self.DrawingMode = DRIVENDRAWING_MODE
         
@@ -936,6 +942,10 @@
             self.VariablePanelIndexer.RefreshVariablePanel(window.GetTagName())
         event.Skip()
 
+    def OnClearErrorsMenu(self, event):
+        self.ClearErrors()
+        event.Skip()
+
     def OnUndoMenu(self, event):
         self.Controler.LoadPrevious()
         idxs = range(self.GetPageCount())
@@ -1085,19 +1095,7 @@
                 else:
                     window = None
             if window:
-                if self.ProjectTree:
-                    root = self.ProjectTree.GetRootItem()
-                    words = window.GetTagName().split("::")
-                    if words[0] == "P":
-                        self.SelectProjectTreeItem(root, [(words[1], ITEM_POU)])
-                    elif words[0] == "T":
-                        self.SelectProjectTreeItem(root, [(words[1], ITEM_POU), (words[2], ITEM_TRANSITION)])
-                    elif words[0] == "A":
-                        self.SelectProjectTreeItem(root, [(words[1], ITEM_POU), (words[2], ITEM_ACTION)])
-                    elif words[0] == "C":
-                        self.SelectProjectTreeItem(root, [(words[1], ITEM_CONFIGURATION)])
-                    elif words[0] == "R":
-                        self.SelectProjectTreeItem(root, [(words[1], ITEM_CONFIGURATION), (words[2], ITEM_RESOURCE)])
+                self.SelectProjectTreeItem(window.GetTagName())
                 window.RefreshView()
                 self.VariablePanelIndexer.ChangeVariablePanel(window.GetTagName())
                 self.RefreshFileMenu()
@@ -1168,6 +1166,12 @@
         to_delete = []
         self.ProjectTree.SetItemText(root, infos["name"])
         self.ProjectTree.SetPyData(root, infos["type"])
+        if infos["tagname"] in self.Errors:
+            self.ProjectTree.SetItemBackgroundColour(root, wx.Colour(255, 255, 0))
+            self.ProjectTree.SetItemTextColour(root, wx.RED)
+        else:
+            self.ProjectTree.SetItemBackgroundColour(root, wx.WHITE)
+            self.ProjectTree.SetItemTextColour(root, wx.BLACK)
         if infos["type"] == ITEM_POU :
             self.ProjectTree.SetItemImage(root,self.TreeImageDict[self.Controler.GetPouBodyType(infos["name"])])
         else:
@@ -1190,7 +1194,25 @@
         for item in to_delete:
             self.ProjectTree.Delete(item)
 
-    def SelectProjectTreeItem(self, root, items):
+    def SelectProjectTreeItem(self, tagname):
+        if self.ProjectTree:
+            root = self.ProjectTree.GetRootItem()
+            words = tagname.split("::")
+            if words[0] == "D":
+                return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_DATATYPE)])
+            elif words[0] == "P":
+                return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU)])
+            elif words[0] == "T":
+                return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_TRANSITION)])
+            elif words[0] == "A":
+                return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_POU), (words[2], ITEM_ACTION)])
+            elif words[0] == "C":
+                return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION)])
+            elif words[0] == "R":
+                return self.RecursiveProjectTreeItemSelection(root, [(words[1], ITEM_CONFIGURATION), (words[2], ITEM_RESOURCE)])
+        return False
+
+    def RecursiveProjectTreeItemSelection(self, root, items):
         found = False
         if self.ProjectTree:
             if wx.VERSION >= (2, 6, 0):
@@ -1205,9 +1227,9 @@
                         wx.CallAfter(self.ResetSelectedItem)
                         return True
                     else:
-                        found = self.SelectProjectTreeItem(item, items[1:])
+                        found = self.RecursiveProjectTreeItemSelection(item, items[1:])
                 else:
-                    found = self.SelectProjectTreeItem(item, items)
+                    found = self.RecursiveProjectTreeItemSelection(item, items)
                 item, root_cookie = self.ProjectTree.GetNextChild(root, root_cookie)
         return found
 
@@ -1697,7 +1719,7 @@
 
 
 #-------------------------------------------------------------------------------
-#                           Tool Bar Items Functions
+#                           ToolBar Items Functions
 #-------------------------------------------------------------------------------
 
     def ResetCurrentMode(self):
@@ -2072,7 +2094,36 @@
     def OnAboutMenu(self, event):
         OpenHtmlFrame(self,"About PLCOpenEditor", os.path.join(CWD, "doc","about.html"), wx.Size(350, 350))
         event.Skip()
-        
+
+
+#-------------------------------------------------------------------------------
+#                        Errors showing functions
+#-------------------------------------------------------------------------------
+
+    def ShowError(self, infos, start, end):
+        print infos
+        self.EditProjectElement(self.Controler.GetElementType(infos[0]), infos[0])
+        self.SelectProjectTreeItem(infos[0])
+        if infos[1] == "name":
+            self.Errors.append(infos[0])
+            self.RefreshProjectTree()
+            self.ProjectTree.Unselect()
+        elif infos[1] == "variable":
+            self.VariablePanelIndexer.AddVariableError(infos)
+        else:
+            selected = self.GetPageSelection()
+            if selected != -1:
+                viewer = self.GetPage(selected)
+                viewer.AddShownError(infos[1:], start, end)
+                viewer.RefreshView()
+    
+    def ClearErrors(self):
+        self.Errors = []
+        self.RefreshProjectTree()
+        self.VariablePanelIndexer.ClearErrors()
+        for i in xrange(self.GetPageCount()):
+            viewer = self.GetPage(i)
+            viewer.ClearErrors()
         
 current_num = 0
 def GetNewNum():
@@ -3228,6 +3279,15 @@
         if tagname in self.VariablePanelList:
             self.VariablePanelList[self.CurrentPanel].RefreshView()
 
+    def AddVariableError(self, infos):
+        self.ChangeVariablePanel(infos[0])
+        if self.CurrentPanel is not None:
+            self.VariablePanelList[self.CurrentPanel].AddVariableError(infos[2:])
+
+    def ClearErrors(self):
+        for panel in self.VariablePanelList.values():
+            panel.ClearErrors()
+
 #-------------------------------------------------------------------------------
 #                            Variables Editor Panel
 #-------------------------------------------------------------------------------
@@ -3243,6 +3303,7 @@
         self.data = data
         self.old_value = None
         self.colnames = colnames
+        self.Errors = {}
         self.Parent = parent
         # XXX
         # we need to store the row length and collength to
@@ -3374,7 +3435,13 @@
                 grid.SetCellEditor(row, col, editor)
                 grid.SetCellRenderer(row, col, renderer)
                 
-                grid.SetCellBackgroundColour(row, col, wx.WHITE)
+                if row in self.Errors and self.Errors[row][0] == colname.lower():
+                    grid.SetCellBackgroundColour(row, col, wx.Colour(255, 255, 0))
+                    grid.SetCellTextColour(row, col, wx.RED)
+                    grid.MakeCellVisible(row, col)
+                else:
+                    grid.SetCellTextColour(row, col, wx.BLACK)
+                    grid.SetCellBackgroundColour(row, col, wx.WHITE)
     
     def SetData(self, data):
         self.data = data
@@ -3401,6 +3468,12 @@
         self.data = []
         self.editors = []
 
+    def AddError(self, infos):
+        self.Errors[infos[0]] = infos[1:]
+
+    def ClearErrors(self):
+        self.Errors = {}
+
 class VariableDropTarget(wx.TextDropTarget):
     
     def __init__(self, parent):
@@ -3891,6 +3964,18 @@
             self.ParentWindow.RefreshTitle()
             self.ParentWindow.RefreshEditMenu()
 
+    def AddVariableError(self, infos):
+        if isinstance(infos[0], TupleType):
+            for i in xrange(*infos[0]):
+                self.Table.AddError((i,) + infos[1:])
+        else:
+            self.Table.AddError(infos)
+        self.Table.ResetView(self.VariablesGrid)
+
+    def ClearErrors(self):
+        self.Table.ClearErrors()
+        self.Table.ResetView(self.VariablesGrid)
+
 UPPER_DIV = lambda x, y: (x / y) + {True : 0, False : 1}[(x % y) == 0]
 
 class GraphicPrintout(wx.Printout):
--- a/RessourceEditor.py	Tue Aug 12 18:15:35 2008 +0200
+++ b/RessourceEditor.py	Tue Aug 12 18:16:09 2008 +0200
@@ -113,6 +113,7 @@
         wx.grid.PyGridTableBase.__init__(self)
         self.data = data
         self.colnames = colnames
+        self.Errors = {}
         self.Parent = parent
         
         self.ColAlignements = []
@@ -241,7 +242,13 @@
                 grid.SetCellEditor(row, col, editor)
                 grid.SetCellRenderer(row, col, renderer)
                 
-                grid.SetCellBackgroundColour(row, col, wx.WHITE)
+                if row in self.Errors and self.Errors[row][0] == colname.lower():
+                    grid.SetCellBackgroundColour(row, col, wx.Colour(255, 255, 0))
+                    grid.SetCellTextColour(row, col, wx.RED)
+                    grid.MakeCellVisible(row, col)
+                else:
+                    grid.SetCellTextColour(row, col, wx.BLACK)
+                    grid.SetCellBackgroundColour(row, col, wx.WHITE)
     
     def SetData(self, data):
         self.data = data
@@ -271,6 +278,11 @@
         self.data = []
         self.editors = []
 
+    def AddError(self, infos):
+        self.Errors[infos[0]] = infos[1:]
+
+    def ClearErrors(self):
+        self.Errors = {}
 
 [ID_RESOURCEEDITOR, ID_RESOURCEEDITORSTATICTEXT1,
  ID_RESOURCEEDITORSTATICTEXT2, ID_RESOURCEEDITORINSTANCESGRID,
@@ -589,3 +601,20 @@
         self.RefreshModel()
         self.RefreshView()
         event.Skip()
+
+#-------------------------------------------------------------------------------
+#                        Errors showing functions
+#-------------------------------------------------------------------------------
+
+    def ClearErrors(self):
+        self.TasksTable.ClearErrors()
+        self.InstancesTable.ClearErrors()
+        self.TasksTable.ResetView(self.TasksGrid)
+        self.InstancesTable.ResetView(self.InstancesGrid)
+
+    def AddShownError(self, infos, start, end):
+        if infos[0] == "task":
+            self.TasksTable.AddError(infos[1:])
+        elif infos[0] == "instance":
+            self.InstancesTable.AddError(infos[1:])
+        
\ No newline at end of file
--- a/TextViewer.py	Tue Aug 12 18:15:35 2008 +0200
+++ b/TextViewer.py	Tue Aug 12 18:16:09 2008 +0200
@@ -41,7 +41,7 @@
     LETTERS.append(chr(ord('A') + i))
 
 [STC_PLC_WORD, STC_PLC_COMMENT, STC_PLC_NUMBER, STC_PLC_VARIABLE, 
- STC_PLC_FUNCTION, STC_PLC_JUMP] = range(6)
+ STC_PLC_FUNCTION, STC_PLC_JUMP, STC_PLC_ERROR] = range(7)
 [SPACE, WORD, NUMBER, COMMENT] = range(4)
 
 [ID_TEXTVIEWER,
@@ -140,6 +140,7 @@
         self.StyleSetSpec(STC_PLC_COMMENT, "fore:#7F7F7F,size:%(size)d" % faces)
         self.StyleSetSpec(STC_PLC_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
         self.StyleSetSpec(STC_PLC_JUMP, "fore:#007F00,size:%(size)d" % faces)
+        self.StyleSetSpec(STC_PLC_ERROR, "fore:#FF0000,back:#FFFF00,size:%(size)d" % faces)
         
         # Indicators styles
         self.IndicatorSetStyle(0, wx.stc.STC_INDIC_SQUIGGLE)
@@ -165,6 +166,7 @@
         self.TextSyntax = "ST"
         self.CurrentAction = None
         self.TagName = tagname
+        self.Errors = []
         
         self.ParentWindow = window
         self.Controler = controler
@@ -294,7 +296,7 @@
             self.EnumeratedValues.append(value.upper())
         
         self.Colourise(0, -1)
-    
+        
     def RefreshScaling(self, refresh=True):
         pass
     
@@ -302,118 +304,119 @@
         self.TextChanged = True
         line = self.LineFromPosition(self.GetEndStyled())
         if line == 0:
-            start_pos = 0
-        else:
-            start_pos = self.GetLineEndPosition(line - 1) + 1
+            start_pos = last_styled_pos = 0
+        else:
+            start_pos = last_styled_pos = self.GetLineEndPosition(line - 1) + 1
         end_pos = event.GetPosition()
         self.StartStyling(start_pos, 0xff)
         
-        i = start_pos
+        current_pos = last_styled_pos
         state = SPACE
         line = ""
         word = ""
-        while i < end_pos:
-            char = chr(self.GetCharAt(i)).upper()
+        while current_pos < end_pos:
+            char = chr(self.GetCharAt(current_pos)).upper()
             line += char
             if char == NEWLINE:
                 if state == COMMENT:
-                    self.SetStyling(i - start_pos + 1, STC_PLC_COMMENT)
+                    self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_COMMENT)
                 elif state == NUMBER:
-                    self.SetStyling(i - start_pos, STC_PLC_NUMBER)
+                    self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
                 elif state == WORD:
                     if word in self.Keywords:
-                        self.SetStyling(i - start_pos, STC_PLC_WORD)
+                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD)
                     elif word in self.Variables:
-                        self.SetStyling(i - start_pos, STC_PLC_VARIABLE)
+                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE)
                     elif word in self.Functions:
-                        self.SetStyling(i - start_pos, STC_PLC_FUNCTION)
+                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION)
                     elif word in self.Jumps:
-                        self.SetStyling(i - start_pos, STC_PLC_JUMP)
+                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP)
                     elif word in self.EnumeratedValues:
-                        self.SetStyling(i - start_pos, STC_PLC_NUMBER)
+                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
                     else:
-                        self.SetStyling(i - start_pos, 31)
-                        if self.GetCurrentPos() < start_pos or self.GetCurrentPos() > i:
-                            self.StartStyling(start_pos, wx.stc.STC_INDICS_MASK)
-                            self.SetStyling(i - start_pos, wx.stc.STC_INDIC0_MASK)
-                            self.StartStyling(i, 0xff)    
+                        self.SetStyling(current_pos - last_styled_pos, 31)
+                        if self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos:
+                            self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK)
+                            self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK)
+                            self.StartStyling(current_pos, 0xff)
                 else:
-                    self.SetStyling(i - start_pos, 31)
-                start_pos = i
+                    self.SetStyling(current_pos - last_styled_pos, 31)
+                last_styled_pos = current_pos
                 state = SPACE
                 line = ""
             elif line.endswith("(*") and state != COMMENT:
-                self.SetStyling(i - start_pos - 1, 31)
-                start_pos = i
+                self.SetStyling(current_pos - last_styled_pos - 1, 31)
+                last_styled_pos = current_pos
                 state = COMMENT
             elif state == COMMENT:
                 if line.endswith("*)"):
-                    self.SetStyling(i - start_pos + 2, STC_PLC_COMMENT)
-                    start_pos = i + 1
+                    self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT)
+                    last_styled_pos = current_pos + 1
                     state = SPACE
             elif char in LETTERS:
                 if state == NUMBER:
                     word = "#"
                     state = WORD
                 elif state == SPACE:
-                    self.SetStyling(i - start_pos, 31)
+                    self.SetStyling(current_pos - last_styled_pos, 31)
                     word = char
-                    start_pos = i
+                    last_styled_pos = current_pos
                     state = WORD
                 else:
                     word += char
             elif char in NUMBERS or char == '.' and state != WORD:
                 if state == SPACE:
-                    self.SetStyling(i - start_pos, 31)
-                    start_pos = i
+                    self.SetStyling(current_pos - last_styled_pos, 31)
+                    last_styled_pos = current_pos
                     state = NUMBER
                 if state == WORD and char != '.':
                     word += char
             else:
                 if state == WORD:
                     if word in self.Keywords:
-                        self.SetStyling(i - start_pos, STC_PLC_WORD)
+                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD)
                     elif word in self.Variables:
-                        self.SetStyling(i - start_pos, STC_PLC_VARIABLE)
+                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE)
                     elif word in self.Functions:
-                        self.SetStyling(i - start_pos, STC_PLC_FUNCTION)
+                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION)
                     elif word in self.Jumps:
-                        self.SetStyling(i - start_pos, STC_PLC_JUMP)
+                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP)
                     elif word in self.EnumeratedValues:
-                        self.SetStyling(i - start_pos, STC_PLC_NUMBER)
+                        self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
                     else:
-                        self.SetStyling(i - start_pos, 31)
-                        if self.GetCurrentPos() < start_pos or self.GetCurrentPos() > i:
-                            self.StartStyling(start_pos, wx.stc.STC_INDICS_MASK)
-                            self.SetStyling(i - start_pos, wx.stc.STC_INDIC0_MASK)
-                            self.StartStyling(i, 0xff)
+                        self.SetStyling(current_pos - last_styled_pos, 31)
+                        if self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos:
+                            self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK)
+                            self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK)
+                            self.StartStyling(current_pos, 0xff)
                     word = ""
-                    start_pos = i
+                    last_styled_pos = current_pos
                     state = SPACE
                 elif state == NUMBER:
-                    self.SetStyling(i - start_pos, STC_PLC_NUMBER)
-                    start_pos = i
+                    self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
+                    last_styled_pos = current_pos
                     state = SPACE
-            i += 1
+            current_pos += 1
         if state == COMMENT:
-            self.SetStyling(i - start_pos + 2, STC_PLC_COMMENT)
+            self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT)
         elif state == NUMBER:
-            self.SetStyling(i - start_pos, STC_PLC_NUMBER)
+            self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
         elif state == WORD:
             if word in self.Keywords:
-                self.SetStyling(i - start_pos, STC_PLC_WORD)
+                self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD)
             elif word in self.Variables:
-                self.SetStyling(i - start_pos, STC_PLC_VARIABLE)
+                self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE)
             elif word in self.Functions:
-                self.SetStyling(i - start_pos, STC_PLC_FUNCTION)
+                self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION)
             elif word in self.Jumps:
-                self.SetStyling(i - start_pos, STC_PLC_JUMP)
+                self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP)
             elif word in self.EnumeratedValues:
-                self.SetStyling(i - start_pos, STC_PLC_NUMBER)
-            else:
-                self.SetStyling(i - start_pos, 31)
-        else:
-            self.SetStyling(i - start_pos, 31)
+                self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
+            else:
+                self.SetStyling(current_pos - last_styled_pos, 31)
+        else:
+            self.SetStyling(current_pos - start_pos, 31)
+        self.ShowErrors(start_pos, end_pos)
         event.Skip()
     
     def Cut(self):
@@ -480,3 +483,28 @@
         self.AutoCompCancel()
         event.Skip()
 
+#-------------------------------------------------------------------------------
+#                        Errors showing functions
+#-------------------------------------------------------------------------------
+
+    def ClearErrors(self):
+        self.Errors = []
+        self.RefreshView()
+
+    def AddShownError(self, infos, start, end):
+        if infos[0] == "body":
+            self.Errors.append((infos[1], start, end))
+
+    def ShowErrors(self, start_pos, end_pos):
+        for indent, start, end in self.Errors:
+            if start[0] == 0:
+                error_start_pos = start[1] - indent
+            else:
+                error_start_pos = self.GetLineEndPosition(start[0] - 1) + start[1] - indent + 1
+            if end[0] == 0:
+                error_end_pos = end[1] - indent + 1
+            else:
+                error_end_pos = self.GetLineEndPosition(end[0] - 1) + end[1] - indent + 2
+            if start_pos <= error_start_pos <= end_pos or start_pos <= error_end_pos <= end_pos:
+                self.StartStyling(error_start_pos, 0xff)
+                self.SetStyling(error_end_pos - error_start_pos, STC_PLC_ERROR)
--- a/Viewer.py	Tue Aug 12 18:15:35 2008 +0200
+++ b/Viewer.py	Tue Aug 12 18:16:09 2008 +0200
@@ -316,6 +316,7 @@
         self.DrawingWire = False
         self.current_id = 0
         self.TagName = tagname
+        self.Errors = []
         
         # Initialize Block, Wire and Comment numbers
         self.block_id = self.wire_id = self.comment_id = 0
@@ -533,6 +534,7 @@
             if not wire.IsConnectedCompatible():
                 wire.MarkAsInvalid()
         
+        self.ShowErrors()
         self.Refresh(False)
     
     def GetMaxSize(self):
@@ -823,6 +825,15 @@
                         wire.ConnectEndPoint(None, end_connector)
                         self.AddWire(wire)
 
+    def IsOfType(self, type, reference):
+        return self.Controler.IsOfType(type, reference)
+    
+    def IsEndType(self, type):
+        return self.Controler.IsEndType(type)
+
+    def GetBlockType(self, type, inputs = None):
+        return self.Controler.GetBlockType(type, inputs)
+
 #-------------------------------------------------------------------------------
 #                          Search Element functions
 #-------------------------------------------------------------------------------
@@ -1417,7 +1428,7 @@
         return width, height
 
     def AddNewBlock(self, bbox):
-        dialog = BlockPropertiesDialog(self.ParentWindow)
+        dialog = BlockPropertiesDialog(self.ParentWindow, self.Controler)
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetBlockList(self.Controler.GetBlockTypes(self.TagName))
         dialog.SetPouNames(self.Controler.GetProjectPouNames())
@@ -1442,7 +1453,7 @@
         dialog.Destroy()
     
     def AddNewVariable(self, bbox):
-        dialog = VariablePropertiesDialog(self.ParentWindow)
+        dialog = VariablePropertiesDialog(self.ParentWindow, self.Controler)
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetMinVariableSize((bbox.width, bbox.height))
         varlist = []
@@ -1470,7 +1481,7 @@
         dialog.Destroy()
 
     def AddNewConnection(self, bbox):
-        dialog = ConnectionPropertiesDialog(self.ParentWindow)
+        dialog = ConnectionPropertiesDialog(self.ParentWindow, self.Controler)
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetMinConnectionSize((bbox.width, bbox.height))
         if dialog.ShowModal() == wx.ID_OK:
@@ -1508,7 +1519,7 @@
         dialog.Destroy()
 
     def AddNewContact(self, bbox):
-        dialog = LDElementDialog(self.ParentWindow, "contact")
+        dialog = LDElementDialog(self.ParentWindow, self.Controler, "contact")
         dialog.SetPreviewFont(self.GetFont())
         varlist = []
         vars = self.Controler.GetEditedElementInterfaceVars(self.TagName)
@@ -1534,7 +1545,7 @@
         dialog.Destroy()
 
     def AddNewCoil(self, bbox):
-        dialog = LDElementDialog(self.ParentWindow, "coil")
+        dialog = LDElementDialog(self.ParentWindow, self.Controler, "coil")
         dialog.SetPreviewFont(self.GetFont())
         varlist = []
         vars = self.Controler.GetEditedElementInterfaceVars(self.TagName)
@@ -1563,7 +1574,7 @@
         dialog.Destroy()
 
     def AddNewPowerRail(self, bbox):
-        dialog = LDPowerRailDialog(self.ParentWindow)
+        dialog = LDPowerRailDialog(self.ParentWindow, self.Controler)
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetMinSize((bbox.width, bbox.height))
         if dialog.ShowModal() == wx.ID_OK:
@@ -1581,7 +1592,7 @@
         dialog.Destroy()
 
     def AddNewStep(self, bbox, initial = False):
-        dialog = StepContentDialog(self.ParentWindow, initial)
+        dialog = StepContentDialog(self.ParentWindow, self.Controler, initial)
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetPouNames(self.Controler.GetProjectPouNames())
         dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName))
@@ -1615,7 +1626,7 @@
         dialog.Destroy()
 
     def AddNewTransition(self, bbox):
-        dialog = TransitionContentDialog(self.ParentWindow, self.GetDrawingMode() == FREEDRAWING_MODE)
+        dialog = TransitionContentDialog(self.ParentWindow, self.Controler, self.GetDrawingMode() == FREEDRAWING_MODE)
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetTransitions(self.Controler.GetEditedElementTransitions(self.TagName))
         if dialog.ShowModal() == wx.ID_OK:
@@ -1634,7 +1645,7 @@
         dialog.Destroy()
 
     def AddNewDivergence(self, bbox):
-        dialog = DivergenceCreateDialog(self.ParentWindow)
+        dialog = DivergenceCreateDialog(self.ParentWindow, self.Controler)
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetMinSize((bbox.width, bbox.height))
         if dialog.ShowModal() == wx.ID_OK:
@@ -1698,7 +1709,7 @@
 #-------------------------------------------------------------------------------
 
     def EditBlockContent(self, block):
-        dialog = BlockPropertiesDialog(self.ParentWindow)
+        dialog = BlockPropertiesDialog(self.ParentWindow, self.Controler)
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetBlockList(self.Controler.GetBlockTypes(self.TagName))
         dialog.SetPouNames(self.Controler.GetProjectPouNames())
@@ -1731,7 +1742,7 @@
         dialog.Destroy()
 
     def EditVariableContent(self, variable):
-        dialog = VariablePropertiesDialog(self.ParentWindow)
+        dialog = VariablePropertiesDialog(self.ParentWindow, self.Controler)
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetMinVariableSize(variable.GetSize())
         varlist = []
@@ -1768,7 +1779,7 @@
         dialog.Destroy()
 
     def EditConnectionContent(self, connection):
-        dialog = ConnectionPropertiesDialog(self.ParentWindow)
+        dialog = ConnectionPropertiesDialog(self.ParentWindow, self.Controler)
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetMinConnectionSize(connection.GetSize())
         values = {"name" : connection.GetName(), "type" : connection.GetType()}
@@ -1792,7 +1803,7 @@
         dialog.Destroy()
 
     def EditContactContent(self, contact):
-        dialog = LDElementDialog(self.ParentWindow, "contact")
+        dialog = LDElementDialog(self.ParentWindow, self.Controler, "contact")
         dialog.SetPreviewFont(self.GetFont())
         varlist = []
         vars = self.Controler.GetEditedElementInterfaceVars(self.TagName)
@@ -1818,7 +1829,7 @@
         dialog.Destroy()
 
     def EditCoilContent(self, coil):
-        dialog = LDElementDialog(self.ParentWindow, "coil")
+        dialog = LDElementDialog(self.ParentWindow, self.Controler, "coil")
         dialog.SetPreviewFont(self.GetFont())
         varlist = []
         vars = self.Controler.GetEditedElementInterfaceVars(self.TagName)
@@ -1847,7 +1858,7 @@
         dialog.Destroy()
 
     def EditPowerRailContent(self, powerrail):
-        dialog = LDPowerRailDialog(self.ParentWindow, powerrail.GetType(), len(powerrail.GetConnectors()))
+        dialog = LDPowerRailDialog(self.ParentWindow, self.Controler, powerrail.GetType(), len(powerrail.GetConnectors()))
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetMinSize(powerrail.GetSize())
         if dialog.ShowModal() == wx.ID_OK:
@@ -1868,7 +1879,7 @@
         dialog.Destroy()
 
     def EditStepContent(self, step):
-        dialog = StepContentDialog(self.ParentWindow, step.GetInitial())
+        dialog = StepContentDialog(self.ParentWindow, self.Controler, step.GetInitial())
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetPouNames(self.Controler.GetProjectPouNames())
         dialog.SetVariables(self.Controler.GetEditedElementInterfaceVars(self.TagName))
@@ -1904,7 +1915,7 @@
             step.Refresh(rect)
         
     def EditTransitionContent(self, transition):
-        dialog = TransitionContentDialog(self.ParentWindow, self.GetDrawingMode() == FREEDRAWING_MODE)
+        dialog = TransitionContentDialog(self.ParentWindow, self.Controler, self.GetDrawingMode() == FREEDRAWING_MODE)
         dialog.SetPreviewFont(self.GetFont())
         dialog.SetTransitions(self.Controler.GetEditedElementTransitions(self.TagName))
         dialog.SetValues({"type":transition.GetType(),"value":transition.GetCondition(), "priority":transition.GetPriority()})
@@ -2328,8 +2339,26 @@
                 self.Controler.AddEditedElementActionBlock(self.TagName, id)
                 self.RefreshActionBlockModel(block)
         return block
-            
-
+
+
+#-------------------------------------------------------------------------------
+#                        Errors showing functions
+#-------------------------------------------------------------------------------
+
+    def ClearErrors(self):
+        self.Errors = []
+        self.RefreshView()
+
+    def AddShownError(self, infos, start, end):
+        self.Errors.append((infos, start, end))
+
+    def ShowErrors(self):
+        for infos, start, end in self.Errors:
+            if infos[0] in ["io_variable", "block", "coil", "contact", "transition", "step", "action_block"]:
+                block = self.FindElementById(infos[1])
+                if block is not None:
+                    block.AddError(infos[2:], start, end)    
+        
 #-------------------------------------------------------------------------------
 #                            Drawing functions
 #-------------------------------------------------------------------------------
--- a/graphics/FBD_Objects.py	Tue Aug 12 18:15:35 2008 +0200
+++ b/graphics/FBD_Objects.py	Tue Aug 12 18:16:09 2008 +0200
@@ -26,7 +26,6 @@
 
 from GraphicCommons import *
 from plcopen.structures import *
-from plcopen.structures import IsOfType
 
 #-------------------------------------------------------------------------------
 #                         Function Block Diagram Block
@@ -51,6 +50,7 @@
         self.Colour = wx.BLACK
         self.Pen = wx.BLACK_PEN
         self.SetType(type, extension, inputs, connectors)
+        self.Errors = {}
     
     # Make a clone of this FBD_Block
     def Clone(self, parent, id = None, name = "", pos = None):
@@ -183,13 +183,13 @@
             name = input.GetName()
             if input != connector and (name.startswith("IN") or name in ["MN", "MX"]):
                 inputtype = input.GetConnectedType()
-                if resulttype is None or inputtype is not None and IsOfType(inputtype, resulttype):
+                if resulttype is None or inputtype is not None and self.IsOfType(inputtype, resulttype):
                     resulttype = inputtype
         for output in self.Outputs:
             name = output.GetName()
-            if output != connector and name == "OUT" and not IsEndType(output.GetType()):
+            if output != connector and name == "OUT" and not self.IsEndType(output.GetType()):
                 outputtype = output.GetConnectedType()
-                if resulttype is None or outputtype is not None and IsOfType(outputtype, resulttype):
+                if resulttype is None or outputtype is not None and self.IsOfType(outputtype, resulttype):
                     resulttype = outputtype
         return resulttype
     
@@ -218,7 +218,7 @@
             self.Extension = extension
             # Find the block definition from type given and create the corresponding
             # inputs and outputs
-            blocktype = GetBlockType(type, inputs)
+            blocktype = self.Parent.GetBlockType(type, inputs)
             if blocktype:
                 self.Colour = wx.BLACK
                 inputs = [input for input in blocktype["inputs"]]
@@ -350,6 +350,14 @@
             for output in self.Outputs:
                 output.RefreshWires()
     
+    def AddError(self, infos, start, end):
+        if infos[0] in ["type", "name"] and start[0] == 0 and end[0] == 0:
+            self.Errors[infos[0]] = (start, end)
+        elif infos[0] == "input" and infos[1] < len(self.Inputs):
+            self.Inputs[infos[1]].AddError(infos[2:], start, end)
+        elif infos[0] == "output" and infos[1] < len(self.Outputs):
+            self.Outputs[infos[1]].AddError(infos[2:], start, end)
+    
     # Draws block
     def Draw(self, dc):
         Graphic_Element.Draw(self, dc)
@@ -369,10 +377,12 @@
         # Draw a rectangle with the block size
         dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
         # Draw block name and block type
-        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - name_size[0]) / 2,
-                self.Pos.y - (name_size[1] + 2))
-        dc.DrawText(self.Type, self.Pos.x + (self.Size[0] - type_size[0]) / 2,
-                self.Pos.y + 5)
+        name_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2,
+                    self.Pos.y - (name_size[1] + 2))
+        type_pos = (self.Pos.x + (self.Size[0] - type_size[0]) / 2,
+                    self.Pos.y + 5)
+        dc.DrawText(self.Name, name_pos[0], name_pos[1])
+        dc.DrawText(self.Type, type_pos[0], type_pos[1])
         # Draw inputs and outputs connectors
         for input in self.Inputs:
             input.Draw(dc)
@@ -382,6 +392,10 @@
             # Draw block execution order
             dc.DrawText(str(self.ExecutionOrder), self.Pos.x + self.Size[0] - executionorder_size[0],
                     self.Pos.y + self.Size[1] + 2)
+        if "name" in self.Errors:
+            HighlightErrorZone(dc, name_pos[0], name_pos[1], name_size[0], name_size[1])
+        if "type" in self.Errors:
+            HighlightErrorZone(dc, type_pos[0], type_pos[1], type_size[0], type_size[1])    
         dc.SetTextForeground(wx.BLACK)
         
 
@@ -406,6 +420,7 @@
         self.Input = None
         self.Output = None
         self.SetType(type, value_type)
+        self.Errors = []
     
     # Make a clone of this FBD_Variable
     def Clone(self, parent, id = None, pos = None):
@@ -594,6 +609,10 @@
             if self.Output:
                 self.Output.RefreshWires()
     
+    def AddError(self, infos, start, end):
+        if infos[0] == "expression" and start[0] == 0 and end[0] == 0:
+            self.Errors.append((start[1], end[1]))
+    
     # Draws variable
     def Draw(self, dc):
         Graphic_Element.Draw(self, dc)
@@ -607,11 +626,12 @@
             name_size = self.NameSize
             executionorder_size = self.ExecutionOrderSize
         
+        text_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2, 
+                    self.Pos.y + (self.Size[1] - name_size[1]) / 2)
         # Draw a rectangle with the variable size
         dc.DrawRectangle(self.Pos.x, self.Pos.y, self.Size[0] + 1, self.Size[1] + 1)
         # Draw variable name
-        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - name_size[0]) / 2,
-                self.Pos.y + (self.Size[1] - name_size[1]) / 2)
+        dc.DrawText(self.Name, text_pos[0], text_pos[1])
         # Draw connectors
         if self.Input:
             self.Input.Draw(dc)
@@ -621,7 +641,10 @@
             # Draw variable execution order
             dc.DrawText(str(self.ExecutionOrder), self.Pos.x + self.Size[0] - executionorder_size[0],
                     self.Pos.y + self.Size[1] + 2)
-
+        for start, end in self.Errors:
+            offset = dc.GetTextExtent(self.Name[:start])
+            size = dc.GetTextExtent(self.Name[start:end + 1])
+            HighlightErrorZone(dc, text_pos[0] + offset[0], text_pos[1], size[0], size[1])
 
 #-------------------------------------------------------------------------------
 #                        Function Block Diagram Connector
--- a/graphics/GraphicCommons.py	Tue Aug 12 18:15:35 2008 +0200
+++ b/graphics/GraphicCommons.py	Tue Aug 12 18:16:09 2008 +0200
@@ -24,7 +24,6 @@
 
 import wx
 from math import *
-from plcopen.structures import IsOfType, IsEndType
 
 #-------------------------------------------------------------------------------
 #                               Common constants
@@ -275,6 +274,20 @@
                 self.currentBox.height)
 
 #-------------------------------------------------------------------------------
+#                    Helper for highlighting error in drawn text
+#-------------------------------------------------------------------------------
+
+def HighlightErrorZone(dc, x, y, width, height):
+    dc.SetPen(wx.TRANSPARENT_PEN)
+    dc.SetLogicalFunction(wx.AND)
+    dc.SetBrush(wx.Brush(wx.Colour(0,255,0)))
+    dc.DrawRectangle(x, y, width, height)
+    dc.SetLogicalFunction(wx.XOR)
+    dc.SetBrush(wx.Brush(wx.Colour(255,0,0)))
+    dc.DrawRectangle(x, y, width, height)
+    dc.SetLogicalFunction(wx.COPY)
+
+#-------------------------------------------------------------------------------
 #                           Graphic element base class
 #-------------------------------------------------------------------------------
 
@@ -299,6 +312,12 @@
         self.CurrentCursor = 0
         ResetCursors()
     
+    def IsOfType(self, type, reference):
+        return self.Parent.IsOfType(type, reference)
+    
+    def IsEndType(self, type):
+        return self.Parent.IsEndType(type)
+        
     def GetDragging(self):
         return self.Dragging
     
@@ -586,6 +605,9 @@
             return movex, movey
         return 0, 0
     
+    def AddError(self, infos, start, end):
+        pass
+    
     # Override this method for defining the method to call for refreshing the model of this element
     def RefreshModel(self, move=True):
         pass
@@ -833,7 +855,7 @@
         self.Pos = position
         self.Direction = direction
         self.Wires = []
-        if IsOfType("BOOL", type):
+        if self.ParentBlock.IsOfType("BOOL", type):
             self.Negated = negated
             self.Edge = edge
         else:
@@ -841,6 +863,7 @@
             self.Edge = "none"
         self.OneConnected = onlyone
         self.Pen = wx.BLACK_PEN
+        self.Errors = {}
         self.RefreshNameSize()
     
     # Returns the RedrawRect
@@ -875,16 +898,16 @@
     
     # Returns the connector type
     def GetType(self, raw = False):
-        if IsEndType(self.Type) or raw:
+        if self.ParentBlock.IsEndType(self.Type) or raw:
             return self.Type
-        elif (self.Negated or self.Edge != "none") and IsOfType("BOOL", self.Type):
+        elif (self.Negated or self.Edge != "none") and self.ParentBlock.IsOfType("BOOL", self.Type):
             return "BOOL"
         else:
             return self.ParentBlock.GetConnectionResultType(self, self.Type)
     
     # Returns the connector type
     def GetConnectedType(self):
-        if IsEndType(self.Type):
+        if self.ParentBlock.IsEndType(self.Type):
             return self.Type
         elif len(self.Wires) == 1:
             return self.Wires[0][0].GetOtherConnectedType(self.Wires[0][1])
@@ -903,7 +926,7 @@
     # Returns if connector type is compatible with type given
     def IsCompatible(self, type):
         reference = self.GetType()
-        return IsOfType(type, reference) or IsOfType(reference, type)
+        return self.ParentBlock.IsOfType(type, reference) or self.ParentBlock.IsOfType(reference, type)
     
     # Changes the connector name
     def SetType(self, type):
@@ -1065,7 +1088,7 @@
     
     # Changes the connector negated property
     def SetNegated(self, negated):
-        if IsOfType("BOOL", self.Type):
+        if self.ParentBlock.IsOfType("BOOL", self.Type):
             self.Negated = negated
             self.Edge = "none"
     
@@ -1075,7 +1098,7 @@
     
     # Changes the connector edge property
     def SetEdge(self, edge):
-        if IsOfType("BOOL", self.Type):
+        if self.ParentBlock.IsOfType("BOOL", self.Type):
             self.Edge = edge    
             self.Negated = False
     
@@ -1115,10 +1138,21 @@
         dc.DrawRectangle(posx, posy, width, height)
         dc.SetLogicalFunction(wx.COPY)
     
+    def AddError(self, infos, start, end):
+        if len(infos) == 0:
+            for wire, handle in self.Wires:
+                wire.MarkAsInvalid()
+        else:
+            self.Errors[infos[0]] = (start, end)
+    
     # Draws the connector
     def Draw(self, dc):
-        dc.SetPen(self.Pen)
-        dc.SetBrush(wx.WHITE_BRUSH)
+        if len(self.Errors) > 0:
+            dc.SetPen(wx.RED_PEN)
+            dc.SetBrush(wx.Brush(wx.Colour(255, 255, 0)))
+        else:
+            dc.SetPen(self.Pen)
+            dc.SetBrush(wx.WHITE_BRUSH)
         parent_pos = self.ParentBlock.GetPosition()
         
         if getattr(dc, "printing", False):
@@ -1145,6 +1179,9 @@
             xend = xstart + CONNECTOR_SIZE * self.Direction[0]
             yend = ystart + CONNECTOR_SIZE * self.Direction[1]
             dc.DrawLine(xstart + self.Direction[0], ystart + self.Direction[1], xend, yend)
+        if len(self.Errors) > 0:
+            dc.SetPen(self.Pen)
+            dc.SetBrush(wx.WHITE_BRUSH)
         if self.Direction[0] != 0:
             ytext = parent_pos[1] + self.Pos.y - name_size[1] / 2
             if self.Direction[0] < 0:
--- a/graphics/LD_Objects.py	Tue Aug 12 18:15:35 2008 +0200
+++ b/graphics/LD_Objects.py	Tue Aug 12 18:16:09 2008 +0200
@@ -372,6 +372,7 @@
         self.Name = name
         self.Id = id
         self.Size = wx.Size(LD_ELEMENT_SIZE[0], LD_ELEMENT_SIZE[1])
+        self.Errors = {}
         # Create an input and output connector
         self.Input = Connector(self, "", "BOOL", wx.Point(0, self.Size[1] / 2 + 1), WEST)
         self.Output = Connector(self, "", "BOOL", wx.Point(self.Size[0], self.Size[1] / 2 + 1), EAST)
@@ -558,6 +559,10 @@
         dc.DrawRectangle(self.Pos.x + self.Size[0] - 3, self.Pos.y - 2, 6, self.Size[1] + 5)
         dc.SetLogicalFunction(wx.COPY)
     
+    def AddError(self, infos, start, end):
+        print infos
+        self.Errors[infos[0]] = (start[1], end[1])
+    
     # Draws contact
     def Draw(self, dc):
         Graphic_Element.Draw(self, dc)
@@ -586,15 +591,21 @@
         dc.DrawRectangle(self.Pos.x, self.Pos.y, 2, self.Size[1] + 1)
         dc.DrawRectangle(self.Pos.x + self.Size[0] - 1, self.Pos.y, 2, self.Size[1] + 1)
         # Draw contact name
-        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - name_size[0]) / 2,
-                self.Pos.y - (name_size[1] + 2))
+        name_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2,
+                    self.Pos.y - (name_size[1] + 2))
+        dc.DrawText(self.Name, name_pos[0], name_pos[1])
         # Draw the modifier symbol in the middle of contact
         if typetext != "":
-            dc.DrawText(typetext, self.Pos.x + (self.Size[0] - type_size[0]) / 2 + 1,
-                    self.Pos.y + (self.Size[1] - type_size[1]) / 2)
+            type_pos = (self.Pos.x + (self.Size[0] - type_size[0]) / 2 + 1,
+                        self.Pos.y + (self.Size[1] - type_size[1]) / 2)
+            dc.DrawText(typetext, type_pos[0], type_pos[1])
         # Draw input and output connectors
         self.Input.Draw(dc)
         self.Output.Draw(dc)
+        if "reference" in self.Errors:
+            HighlightErrorZone(dc, name_pos[0], name_pos[1], name_size[0], name_size[1])
+        if typetext != "" and ("negated" in self.Errors or "rising" in self.Errors or "falling" in self.Errors):
+            HighlightErrorZone(dc, type_pos[0], type_pos[1], type_size[0], type_size[1])
         
 
 #-------------------------------------------------------------------------------
@@ -614,6 +625,7 @@
         self.Name = name
         self.Id = id
         self.Size = wx.Size(LD_ELEMENT_SIZE[0], LD_ELEMENT_SIZE[1])
+        self.Errors = {}
         # Create an input and output connector
         self.Input = Connector(self, "", "BOOL", wx.Point(0, self.Size[1] / 2 + 1), WEST)
         self.Output = Connector(self, "", "BOOL", wx.Point(self.Size[0], self.Size[1] / 2 + 1), EAST)
@@ -800,6 +812,9 @@
         dc.DrawEllipticArc(self.Pos.x, self.Pos.y - int(self.Size[1] * (sqrt(2) - 1.) / 2.) + 1, self.Size[0], int(self.Size[1] * sqrt(2)) - 1, -45, 45)
         dc.SetLogicalFunction(wx.COPY)
     
+    def AddError(self, infos, start, end):
+        self.Errors[infos[0]] = (start[1], end[1])
+    
     # Draws coil
     def Draw(self, dc):
         Graphic_Element.Draw(self, dc)
@@ -839,13 +854,20 @@
                 type_size = self.TypeSize
             
         # Draw coil name
-        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - name_size[0]) / 2,
-                self.Pos.y - (name_size[1] + 2))
+        name_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2,
+                    self.Pos.y - (name_size[1] + 2))
+        dc.DrawText(self.Name, name_pos[0], name_pos[1])
         # Draw the modifier symbol in the middle of coil
         if typetext != "":
-            dc.DrawText(typetext, self.Pos.x + (self.Size[0] - type_size[0]) / 2 + 1,
-                    self.Pos.y + (self.Size[1] - type_size[1]) / 2)
+            type_pos = (self.Pos.x + (self.Size[0] - type_size[0]) / 2 + 1,
+                        self.Pos.y + (self.Size[1] - type_size[1]) / 2)
+            dc.DrawText(typetext, type_pos[0], type_pos[1])
         # Draw input and output connectors
         self.Input.Draw(dc)
         self.Output.Draw(dc)
-        
+        if "reference" in self.Errors:
+            HighlightErrorZone(dc, name_pos[0], name_pos[1], name_size[0], name_size[1])
+        if typetext != "" and ("negated" in self.Errors or "rising" in self.Errors or "falling" in self.Errors):
+            HighlightErrorZone(dc, type_pos[0], type_pos[1], type_size[0], type_size[1])
+            
+        
--- a/graphics/SFC_Objects.py	Tue Aug 12 18:15:35 2008 +0200
+++ b/graphics/SFC_Objects.py	Tue Aug 12 18:16:09 2008 +0200
@@ -49,6 +49,7 @@
         self.SetName(name)
         self.Initial = initial
         self.Id = id
+        self.Error = None
         self.Size = wx.Size(SFC_STEP_DEFAULT_SIZE[0], SFC_STEP_DEFAULT_SIZE[1])
         # Create an input and output connector
         if not self.Initial:
@@ -459,6 +460,10 @@
             elif self.Output:
                 self.Output.RefreshWires()
     
+    def AddError(self, infos, start, end):
+        if infos[0] == "name" and start[0] == 0 and end[0] == 0:
+            self.Error = (start[1], end[1])
+    
     # Draws step
     def Draw(self, dc):
         Graphic_Element.Draw(self, dc)
@@ -475,8 +480,9 @@
         if self.Initial:
             dc.DrawRectangle(self.Pos.x + 2, self.Pos.y + 2, self.Size[0] - 3, self.Size[1] - 3)
         # Draw step name
-        dc.DrawText(self.Name, self.Pos.x + (self.Size[0] - name_size[0]) / 2,
+        name_pos = (self.Pos.x + (self.Size[0] - name_size[0]) / 2,
                     self.Pos.y + (self.Size[1] - name_size[1]) / 2)
+        dc.DrawText(self.Name, name_pos[0], name_pos[1])
         # Draw input and output connectors
         if self.Input:
             self.Input.Draw(dc)
@@ -484,6 +490,8 @@
             self.Output.Draw(dc)
         if self.Action:
             self.Action.Draw(dc)
+        if self.Error is not None:
+            HighlightErrorZone(dc, name_pos[0], name_pos[1], name_size[0], name_size[1])
         
 
 #-------------------------------------------------------------------------------
@@ -508,6 +516,7 @@
         self.Output = Connector(self, "", None, wx.Point(self.Size[0] / 2, self.Size[1]), SOUTH, onlyone = True)
         self.SetType(type, condition)
         self.SetPriority(priority)
+        self.Errors = {}
     
     # Destructor
     def __del__(self):
@@ -820,6 +829,16 @@
             else:
                 self.Output.RefreshWires()
     
+    def AddError(self, infos, start, end):
+        if infos[0] == "priority" and start[0] == 0 and start[1] == 0:
+            self.Errors[infos[0]] = (start[1], end[1])
+        elif infos[0] == "inline":
+            if infos[0] not in self.Errors:
+                self.Errors[infos[0]] = []
+            self.Errors[infos[0]].append((start[1], end[1]))
+        else:
+            pass
+    
     # Draws transition
     def Draw(self, dc):
         Graphic_Element.Draw(self, dc)
@@ -850,17 +869,26 @@
                 condition = self.Condition
             else:
                 condition = "Transition"
-            dc.DrawText(condition, self.Pos.x + self.Size[0] + 5,
-                        self.Pos.y + (self.Size[1] - condition_size[1]) / 2)
+            condition_pos = (self.Pos.x + self.Size[0] + 5,
+                             self.Pos.y + (self.Size[1] - condition_size[1]) / 2)
+            dc.DrawText(condition, condition_pos[0], condition_pos[1])
         # Draw priority number
         if self.Priority != 0:
-            dc.DrawText(str(self.Priority), self.Pos.x, self.Pos.y - priority_size[1] - 2)
+            priority_pos = (self.Pos.x, self.Pos.y - priority_size[1] - 2)
+            dc.DrawText(str(self.Priority), priority_pos[0], priority_pos[1])
         # Draw input and output connectors
         self.Input.Draw(dc)
         self.Output.Draw(dc)
         if self.Type == "connection":
             self.Condition.Draw(dc)
-        
+        if "priority" in self.Errors:
+            HighlightErrorZone(dc, priority_pos[0], priority_pos[1], priority_size[0], priority_size[1])
+        if "inline" in self.Errors:
+            for start, end in self.Errors["inline"]:
+                offset = dc.GetTextExtent(self.Condition[:start])
+                size = dc.GetTextExtent(self.Condition[start:end + 1])
+                HighlightErrorZone(dc, condition_pos[0] + offset[0], condition_pos[1], size[0], size[1])
+
 
 #-------------------------------------------------------------------------------
 #                Sequencial Function Chart Divergence and Convergence
@@ -1306,6 +1334,7 @@
         self.SetTarget(target)
         self.Id = id
         self.Size = wx.Size(SFC_JUMP_SIZE[0], SFC_JUMP_SIZE[1])
+        self.Errors = {}
         # Create an input and output connector
         self.Input = Connector(self, "", None, wx.Point(self.Size[0] / 2, 0), NORTH, onlyone = True)
         
@@ -1471,6 +1500,10 @@
             if self.Parent.GetDrawingMode() != FREEDRAWING_MODE:
                 self.RefreshInputModel()
     
+    def AddError(self, infos, start, end):
+        if infos[0] == "target" and start[0] == 0 and end[0] == 0:
+            self.Errors[infos[0]] = (start[1], end[1])
+    
     # Draws the highlightment of this element if it is highlighted
     def DrawHighlightment(self, dc):
         dc.SetPen(wx.Pen(HIGHLIGHTCOLOR))
@@ -1500,11 +1533,14 @@
                   wx.Point(self.Pos.x + self.Size[0], self.Pos.y),
                   wx.Point(self.Pos.x + self.Size[0] / 2, self.Pos.y + self.Size[1])]
         dc.DrawPolygon(points)
-        dc.DrawText(self.Target, self.Pos.x + self.Size[0] + 2,
-                    self.Pos.y + (self.Size[1] - target_size[1]) / 2)
+        target_pos = (self.Pos.x + self.Size[0] + 2,
+                      self.Pos.y + (self.Size[1] - target_size[1]) / 2)
+        dc.DrawText(self.Target, target_pos[0], target_pos[1])
         # Draw input connector
         if self.Input:
             self.Input.Draw(dc)
+        if "target" in self.Errors:
+            HighlightErrorZone(dc, target_pos[0], target_pos[1], target_size[0], target_size[1])
         
 
 #-------------------------------------------------------------------------------
@@ -1523,6 +1559,7 @@
         self.Id = id
         self.Size = wx.Size(SFC_ACTION_MIN_SIZE[0], SFC_ACTION_MIN_SIZE[1])
         self.MinSize = wx.Size(SFC_ACTION_MIN_SIZE[0], SFC_ACTION_MIN_SIZE[1])
+        self.Errors = {}
         # Create an input and output connector
         self.Input = Connector(self, "", None, wx.Point(0, SFC_ACTION_MIN_SIZE[1] / 2), WEST, onlyone = True)
         self.SetActions(actions)
@@ -1686,6 +1723,17 @@
     def RefreshModel(self, move=True):
         self.Parent.RefreshActionBlockModel(self)
     
+    def AddError(self, infos, start, end):
+        if infos[0] == "action" and infos[1] < len(self.Actions):
+            if infos[1] not in self.Errors:
+                self.Errors[infos[1]] = {}
+            if infos[2] == "inline":
+                if infos[2] not in self.Errors[infos[1]]:
+                    self.Errors[infos[1]][infos[2]] = []
+                self.Errors[infos[1]][infos[2]].append((start[1], end[1]))
+            else:
+                self.Errors[infos[1]][infos[2]] = (start[1], end[1])
+    
     # Draws divergence
     def Draw(self, dc):
         Graphic_Element.Draw(self, dc)
@@ -1703,23 +1751,41 @@
             if i != 0:
                 dc.DrawLine(self.Pos.x, self.Pos.y + i * line_size, 
                     self.Pos.x + self.Size[0], self.Pos.y + i * line_size)
-            text_width, text_height = dc.GetTextExtent(action["qualifier"])
+            qualifier_size = dc.GetTextExtent(action["qualifier"])
             if "duration" in action:
-                dc.DrawText(action["qualifier"], self.Pos.x + (colsize[0] - text_width) / 2,
-                    self.Pos.y + i * line_size + line_size / 2 - text_height)
-                text_width, text_height = dc.GetTextExtent(action["duration"])
-                dc.DrawText(action["duration"], self.Pos.x + (colsize[0] - text_width) / 2,
-                    self.Pos.y + i * line_size + line_size / 2)
+                qualifier_pos = (self.Pos.x + (colsize[0] - qualifier_size[0]) / 2,
+                                 self.Pos.y + i * line_size + line_size / 2 - qualifier_size[1])
+                duration_size = dc.GetTextExtent(action["duration"])
+                duration_pos = (self.Pos.x + (colsize[0] - duration_size[0]) / 2,
+                                self.Pos.y + i * line_size + line_size / 2)
+                dc.DrawText(action["duration"], duration_pos[0], duration_pos[1])
             else:
-                dc.DrawText(action["qualifier"], self.Pos.x + (colsize[0] - text_width) / 2,
-                        self.Pos.y + i * line_size + (line_size - text_height) / 2)
-            text_width, text_height = dc.GetTextExtent(action["value"])
-            dc.DrawText(action["value"], self.Pos.x + colsize[0] + (colsize[1] - text_width) / 2,
-                    self.Pos.y + i * line_size + (line_size - text_height) / 2)
+                qualifier_pos = (self.Pos.x + (colsize[0] - qualifier_size[0]) / 2,
+                                 self.Pos.y + i * line_size + (line_size - qualifier_size[1]) / 2)
+            dc.DrawText(action["qualifier"], qualifier_pos[0], qualifier_pos[1])
+            content_size = dc.GetTextExtent(action["value"])
+            content_pos = (self.Pos.x + colsize[0] + (colsize[1] - content_size[0]) / 2,
+                           self.Pos.y + i * line_size + (line_size - content_size[1]) / 2)
+            dc.DrawText(action["value"], content_pos[0], content_pos[1])
             if "indicator" in action:
-                text_width, text_height = dc.GetTextExtent(action["indicator"])
-                dc.DrawText(action["indicator"], self.Pos.x + colsize[0] + colsize[1] + (colsize[2] - text_width) / 2,
-                        self.Pos.y + i * line_size + (line_size - text_height) / 2)
+                indicator_size = dc.GetTextExtent(action["indicator"])
+                indicator_pos = (self.Pos.x + colsize[0] + colsize[1] + (colsize[2] - indicator_size[0]) / 2,
+                                 self.Pos.y + i * line_size + (line_size - indicator_size[1]) / 2)
+                dc.DrawText(action["indicator"], indicator_pos[0], indicator_pos[1])
+            if i in self.Errors:
+                if "duration" in self.Errors[i] and "duration" in action:
+                    HighlightErrorZone(dc, duration_pos[0], duration_pos[1], duration_size[0], duration_size[1])
+                if "qualifier" in self.Errors[i]:
+                    HighlightErrorZone(dc, qualifier_pos[0], qualifier_pos[1], qualifier_size[0], qualifier_size[1])
+                if "reference" in self.Errors[i]:
+                    HighlightErrorZone(dc, content_pos[0], content_pos[1], content_size[0], content_size[1])
+                elif "inline" in self.Errors[i]:
+                    for start, end in self.Errors[i]["inline"]:
+                        offset = dc.GetTextExtent(action["value"][:start])
+                        size = dc.GetTextExtent(action["value"][start:end + 1])
+                        HighlightErrorZone(dc, content_pos[0] + offset[0], content_pos[1], size[0], size[1])
+                if "indicator" in self.Errors[i]:
+                    HighlightErrorZone(dc, indicator_pos[0], indicator_pos[1], indicator_size[0], indicator_size[1])
         # Draw input connector
         self.Input.Draw(dc)