editors/TextViewer.py
changeset 814 5743cbdff669
child 858 daafaa8a28fd
equal deleted inserted replaced
813:1460273f40ed 814:5743cbdff669
       
     1 #!/usr/bin/env python
       
     2 # -*- coding: utf-8 -*-
       
     3 
       
     4 #This file is part of PLCOpenEditor, a library implementing an IEC 61131-3 editor
       
     5 #based on the plcopen standard. 
       
     6 #
       
     7 #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD
       
     8 #
       
     9 #See COPYING file for copyrights details.
       
    10 #
       
    11 #This library is free software; you can redistribute it and/or
       
    12 #modify it under the terms of the GNU General Public
       
    13 #License as published by the Free Software Foundation; either
       
    14 #version 2.1 of the License, or (at your option) any later version.
       
    15 #
       
    16 #This library is distributed in the hope that it will be useful,
       
    17 #but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    18 #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    19 #General Public License for more details.
       
    20 #
       
    21 #You should have received a copy of the GNU General Public
       
    22 #License along with this library; if not, write to the Free Software
       
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    24 
       
    25 import re
       
    26 from types import *
       
    27 
       
    28 import wx
       
    29 import wx.stc
       
    30 
       
    31 from graphics.GraphicCommons import ERROR_HIGHLIGHT, SEARCH_RESULT_HIGHLIGHT, REFRESH_HIGHLIGHT_PERIOD
       
    32 from plcopen.structures import ST_BLOCK_START_KEYWORDS, ST_BLOCK_END_KEYWORDS, IEC_BLOCK_START_KEYWORDS, IEC_BLOCK_END_KEYWORDS, LOCATIONDATATYPES
       
    33 from EditorPanel import EditorPanel
       
    34 
       
    35 #-------------------------------------------------------------------------------
       
    36 #                         Textual programs Viewer class
       
    37 #-------------------------------------------------------------------------------
       
    38 
       
    39 
       
    40 NEWLINE = "\n"
       
    41 NUMBERS = [str(i) for i in xrange(10)]
       
    42 LETTERS = ['_']
       
    43 for i in xrange(26):
       
    44     LETTERS.append(chr(ord('a') + i))
       
    45     LETTERS.append(chr(ord('A') + i))
       
    46 
       
    47 [STC_PLC_WORD, STC_PLC_COMMENT, STC_PLC_NUMBER, STC_PLC_STRING, 
       
    48  STC_PLC_VARIABLE, STC_PLC_PARAMETER, STC_PLC_FUNCTION, STC_PLC_JUMP, 
       
    49  STC_PLC_ERROR, STC_PLC_SEARCH_RESULT] = range(10)
       
    50 [SPACE, WORD, NUMBER, STRING, WSTRING, COMMENT, PRAGMA] = range(7)
       
    51 
       
    52 [ID_TEXTVIEWER, ID_TEXTVIEWERTEXTCTRL,
       
    53 ] = [wx.NewId() for _init_ctrls in range(2)]
       
    54 
       
    55 if wx.Platform == '__WXMSW__':
       
    56     faces = { 'times': 'Times New Roman',
       
    57               'mono' : 'Courier New',
       
    58               'helv' : 'Arial',
       
    59               'other': 'Comic Sans MS',
       
    60               'size' : 10,
       
    61              }
       
    62 else:
       
    63     faces = { 'times': 'Times',
       
    64               'mono' : 'Courier',
       
    65               'helv' : 'Helvetica',
       
    66               'other': 'new century schoolbook',
       
    67               'size' : 12,
       
    68              }
       
    69 re_texts = {}
       
    70 re_texts["letter"] = "[A-Za-z]"
       
    71 re_texts["digit"] = "[0-9]"
       
    72 re_texts["identifier"] = "((?:%(letter)s|(?:_(?:%(letter)s|%(digit)s)))(?:_?(?:%(letter)s|%(digit)s))*)"%re_texts
       
    73 IDENTIFIER_MODEL = re.compile(re_texts["identifier"])
       
    74 LABEL_MODEL = re.compile("[ \t\n]%(identifier)s:[ \t\n]"%re_texts)
       
    75 EXTENSIBLE_PARAMETER = re.compile("IN[1-9][0-9]*$")
       
    76 
       
    77 HIGHLIGHT_TYPES = {
       
    78     ERROR_HIGHLIGHT: STC_PLC_ERROR,
       
    79     SEARCH_RESULT_HIGHLIGHT: STC_PLC_SEARCH_RESULT,
       
    80 }
       
    81 
       
    82 def GetCursorPos(old, new):
       
    83     old_length = len(old)
       
    84     new_length = len(new)
       
    85     common_length = min(old_length, new_length)
       
    86     i = 0
       
    87     for i in xrange(common_length):
       
    88         if old[i] != new[i]:
       
    89             break
       
    90     if old_length < new_length:
       
    91         if common_length > 0 and old[i] != new[i]:
       
    92             return i + new_length - old_length
       
    93         else:
       
    94             return i + new_length - old_length + 1
       
    95     elif old_length > new_length or i < min(old_length, new_length) - 1:
       
    96         if common_length > 0 and old[i] != new[i]:
       
    97             return i
       
    98         else:
       
    99             return i + 1
       
   100     else:
       
   101         return None
       
   102 
       
   103 def LineStartswith(line, symbols):
       
   104     return reduce(lambda x, y: x or y, map(lambda x: line.startswith(x), symbols), False)
       
   105 
       
   106 class TextViewer(EditorPanel):
       
   107     
       
   108     ID = ID_TEXTVIEWER
       
   109     
       
   110     if wx.VERSION < (2, 6, 0):
       
   111         def Bind(self, event, function, id = None):
       
   112             if id is not None:
       
   113                 event(self, id, function)
       
   114             else:
       
   115                 event(self, function)
       
   116     
       
   117     def _init_Editor(self, prnt):
       
   118         self.Editor = wx.stc.StyledTextCtrl(id=ID_TEXTVIEWERTEXTCTRL, 
       
   119                 parent=prnt, name="TextViewer", size=wx.Size(0, 0), style=0)
       
   120         self.Editor.ParentWindow = self
       
   121         
       
   122         self.Editor.CmdKeyAssign(ord('+'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMIN)
       
   123         self.Editor.CmdKeyAssign(ord('-'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMOUT)
       
   124         
       
   125         self.Editor.SetViewWhiteSpace(False)
       
   126         
       
   127         self.Editor.SetLexer(wx.stc.STC_LEX_CONTAINER)
       
   128         
       
   129         # Global default styles for all languages
       
   130         self.Editor.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
       
   131         self.Editor.StyleClearAll()  # Reset all to be like the default
       
   132         
       
   133         self.Editor.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,  "back:#C0C0C0,size:%(size)d" % faces)
       
   134         self.Editor.SetSelBackground(1, "#E0E0E0")
       
   135         
       
   136         # Highlighting styles
       
   137         self.Editor.StyleSetSpec(STC_PLC_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
       
   138         self.Editor.StyleSetSpec(STC_PLC_VARIABLE, "fore:#7F0000,size:%(size)d" % faces)
       
   139         self.Editor.StyleSetSpec(STC_PLC_PARAMETER, "fore:#7F007F,size:%(size)d" % faces)
       
   140         self.Editor.StyleSetSpec(STC_PLC_FUNCTION, "fore:#7F7F00,size:%(size)d" % faces)
       
   141         self.Editor.StyleSetSpec(STC_PLC_COMMENT, "fore:#7F7F7F,size:%(size)d" % faces)
       
   142         self.Editor.StyleSetSpec(STC_PLC_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
       
   143         self.Editor.StyleSetSpec(STC_PLC_STRING, "fore:#007F00,size:%(size)d" % faces)
       
   144         self.Editor.StyleSetSpec(STC_PLC_JUMP, "fore:#FF7FFF,size:%(size)d" % faces)
       
   145         self.Editor.StyleSetSpec(STC_PLC_ERROR, "fore:#FF0000,back:#FFFF00,size:%(size)d" % faces)
       
   146         self.Editor.StyleSetSpec(STC_PLC_SEARCH_RESULT, "fore:#FFFFFF,back:#FFA500,size:%(size)d" % faces)
       
   147         
       
   148         # Indicators styles
       
   149         self.Editor.IndicatorSetStyle(0, wx.stc.STC_INDIC_SQUIGGLE)
       
   150         if self.ParentWindow is not None and self.Controler is not None:
       
   151             self.Editor.IndicatorSetForeground(0, wx.RED)
       
   152         else:
       
   153             self.Editor.IndicatorSetForeground(0, wx.WHITE)
       
   154         
       
   155         # Line numbers in the margin
       
   156         self.Editor.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
       
   157         self.Editor.SetMarginWidth(1, 50)
       
   158         
       
   159         # Folding
       
   160         self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPEN,    wx.stc.STC_MARK_BOXMINUS,          "white", "#808080")
       
   161         self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDER,        wx.stc.STC_MARK_BOXPLUS,           "white", "#808080")
       
   162         self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERSUB,     wx.stc.STC_MARK_VLINE,             "white", "#808080")
       
   163         self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERTAIL,    wx.stc.STC_MARK_LCORNER,           "white", "#808080")
       
   164         self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEREND,     wx.stc.STC_MARK_BOXPLUSCONNECTED,  "white", "#808080")
       
   165         self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPENMID, wx.stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080")
       
   166         self.Editor.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERMIDTAIL, wx.stc.STC_MARK_TCORNER,           "white", "#808080")
       
   167         
       
   168         # Indentation size
       
   169         self.Editor.SetTabWidth(2)
       
   170         self.Editor.SetUseTabs(0)
       
   171         
       
   172         self.Editor.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|
       
   173                                     wx.stc.STC_MOD_BEFOREDELETE|
       
   174                                     wx.stc.STC_PERFORMED_USER)
       
   175 
       
   176         self.Bind(wx.stc.EVT_STC_STYLENEEDED, self.OnStyleNeeded, id=ID_TEXTVIEWERTEXTCTRL)
       
   177         self.Editor.Bind(wx.stc.EVT_STC_MARGINCLICK, self.OnMarginClick)
       
   178         self.Editor.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
       
   179         if self.Controler is not None:
       
   180             self.Editor.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
       
   181             self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_TEXTVIEWERTEXTCTRL)
       
   182             self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_TEXTVIEWERTEXTCTRL)
       
   183         
       
   184     def __init__(self, parent, tagname, window, controler, debug = False, instancepath = ""):
       
   185         if tagname != "" and controler is not None:
       
   186             self.VARIABLE_PANEL_TYPE = controler.GetPouType(tagname.split("::")[1])
       
   187         
       
   188         EditorPanel.__init__(self, parent, tagname, window, controler, debug)
       
   189         
       
   190         self.Keywords = []
       
   191         self.Variables = {}
       
   192         self.Functions = {}
       
   193         self.TypeNames = []
       
   194         self.Jumps = []
       
   195         self.EnumeratedValues = []
       
   196         self.DisableEvents = True
       
   197         self.TextSyntax = None
       
   198         self.CurrentAction = None
       
   199         self.Highlights = []
       
   200         self.SearchParams = None
       
   201         self.SearchResults = None
       
   202         self.CurrentFindHighlight = None
       
   203         self.InstancePath = instancepath
       
   204         self.ContextStack = []
       
   205         self.CallStack = []
       
   206         
       
   207         self.RefreshHighlightsTimer = wx.Timer(self, -1)
       
   208         self.Bind(wx.EVT_TIMER, self.OnRefreshHighlightsTimer, self.RefreshHighlightsTimer)
       
   209         
       
   210     def __del__(self):
       
   211         self.RefreshHighlightsTimer.Stop()
       
   212     
       
   213     def GetTitle(self):
       
   214         if self.Debug or self.TagName == "":
       
   215             if len(self.InstancePath) > 15:
       
   216                 return "..." + self.InstancePath[-12:]
       
   217             return self.InstancePath
       
   218         return EditorPanel.GetTitle(self)
       
   219     
       
   220     def GetInstancePath(self):
       
   221         return self.InstancePath
       
   222     
       
   223     def IsViewing(self, tagname):
       
   224         if self.Debug or self.TagName == "":
       
   225             return self.InstancePath == tagname
       
   226         else:
       
   227             return self.TagName == tagname
       
   228     
       
   229     def GetText(self):
       
   230         return self.Editor.GetText()
       
   231     
       
   232     def SetText(self, text):
       
   233         self.Editor.SetText(text)
       
   234     
       
   235     def SelectAll(self):
       
   236         self.Editor.SelectAll()
       
   237     
       
   238     def Colourise(self, start, end):
       
   239         self.Editor.Colourise(start, end)
       
   240     
       
   241     def StartStyling(self, pos, mask):
       
   242         self.Editor.StartStyling(pos, mask)
       
   243     
       
   244     def SetStyling(self, length, style):
       
   245         self.Editor.SetStyling(length, style)
       
   246     
       
   247     def GetCurrentPos(self):
       
   248         return self.Editor.GetCurrentPos()
       
   249     
       
   250     def GetState(self):
       
   251         return {"cursor_pos": self.Editor.GetCurrentPos()}
       
   252     
       
   253     def SetState(self, state):
       
   254         if self and state.has_key("cursor_pos"):
       
   255             self.Editor.GotoPos(state.get("cursor_pos", 0))
       
   256         
       
   257     def OnModification(self, event):
       
   258         if not self.DisableEvents:
       
   259             mod_type = event.GetModificationType()
       
   260             if mod_type&wx.stc.STC_MOD_BEFOREINSERT:
       
   261                 if self.CurrentAction == None:
       
   262                     self.StartBuffering()
       
   263                 elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1:
       
   264                     self.Controler.EndBuffering()
       
   265                     self.StartBuffering()
       
   266                 self.CurrentAction = ("Add", event.GetPosition())
       
   267                 wx.CallAfter(self.RefreshModel)
       
   268             elif mod_type&wx.stc.STC_MOD_BEFOREDELETE:
       
   269                 if self.CurrentAction == None:
       
   270                     self.StartBuffering()
       
   271                 elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1:
       
   272                     self.Controler.EndBuffering()
       
   273                     self.StartBuffering()
       
   274                 self.CurrentAction = ("Delete", event.GetPosition())
       
   275                 wx.CallAfter(self.RefreshModel)
       
   276         event.Skip()
       
   277     
       
   278     def OnDoDrop(self, event):
       
   279         try:
       
   280             values = eval(event.GetDragText())
       
   281         except:
       
   282             values = event.GetDragText()
       
   283         if isinstance(values, tuple):
       
   284             message = None
       
   285             if values[1] in ["program", "debug"]:
       
   286                 event.SetDragText("")
       
   287             elif values[1] in ["functionBlock", "function"]:
       
   288                 blocktype = values[0]
       
   289                 blockname = values[2]
       
   290                 if len(values) > 3:
       
   291                     blockinputs = values[3]
       
   292                 else:
       
   293                     blockinputs = None
       
   294                 if values[1] != "function": 
       
   295                     if blockname == "":
       
   296                         dialog = wx.TextEntryDialog(self.ParentWindow, "Block name", "Please enter a block name", "", wx.OK|wx.CANCEL|wx.CENTRE)
       
   297                         if dialog.ShowModal() == wx.ID_OK:
       
   298                             blockname = dialog.GetValue()
       
   299                         else:
       
   300                             return
       
   301                         dialog.Destroy()
       
   302                     if blockname.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]:
       
   303                         message = _("\"%s\" pou already exists!")%blockname
       
   304                     elif blockname.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]:
       
   305                         message = _("\"%s\" element for this pou already exists!")%blockname
       
   306                     else:
       
   307                         self.Controler.AddEditedElementPouVar(self.TagName, values[0], blockname)
       
   308                         self.RefreshVariablePanel()
       
   309                         self.RefreshVariableTree()
       
   310                 blockinfo = self.Controler.GetBlockType(blocktype, blockinputs, self.Debug)
       
   311                 hint = ',\n    '.join(
       
   312                             [ " " + fctdecl[0]+" := (*"+fctdecl[1]+"*)" for fctdecl in blockinfo["inputs"]] +
       
   313                             [ " " + fctdecl[0]+" => (*"+fctdecl[1]+"*)" for fctdecl in blockinfo["outputs"]])
       
   314                 if values[1] == "function":
       
   315                     event.SetDragText(blocktype+"(\n    "+hint+")")
       
   316                 else:
       
   317                     event.SetDragText(blockname+"(\n    "+hint+")")
       
   318             elif values[1] == "location":
       
   319                 pou_name, pou_type = self.Controler.GetEditedElementType(self.TagName, self.Debug)
       
   320                 if len(values) > 2 and pou_type == "program":
       
   321                     var_name = values[3]
       
   322                     if var_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]:
       
   323                         message = _("\"%s\" pou already exists!")%var_name
       
   324                     elif var_name.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]:
       
   325                         message = _("\"%s\" element for this pou already exists!")%var_name
       
   326                     else:
       
   327                         location = values[0]
       
   328                         if not location.startswith("%"):
       
   329                             dialog = wx.SingleChoiceDialog(self.ParentWindow, 
       
   330                                   _("Select a variable class:"), _("Variable class"), 
       
   331                                   ["Input", "Output", "Memory"], 
       
   332                                   wx.DEFAULT_DIALOG_STYLE|wx.OK|wx.CANCEL)
       
   333                             if dialog.ShowModal() == wx.ID_OK:
       
   334                                 selected = dialog.GetSelection()
       
   335                             else:
       
   336                                 selected = None
       
   337                             dialog.Destroy()
       
   338                             if selected is None:
       
   339                                 event.SetDragText("")
       
   340                                 return
       
   341                             if selected == 0:
       
   342                                 location = "%I" + location
       
   343                             elif selected == 1:
       
   344                                 location = "%Q" + location
       
   345                             else:
       
   346                                 location = "%M" + location
       
   347                         if values[2] is not None:
       
   348                             var_type = values[2]
       
   349                         else:
       
   350                             var_type = LOCATIONDATATYPES.get(location[2], ["BOOL"])[0]
       
   351                         self.Controler.AddEditedElementPouVar(self.TagName, var_type, var_name, location, values[4])
       
   352                         self.RefreshVariablePanel()
       
   353                         self.RefreshVariableTree()
       
   354                         event.SetDragText(var_name)
       
   355                 else:
       
   356                     event.SetDragText("")
       
   357             elif values[1] == "Global":
       
   358                 var_name = values[0]
       
   359                 if var_name.upper() in [name.upper() for name in self.Controler.GetProjectPouNames(self.Debug)]:
       
   360                     message = _("\"%s\" pou already exists!")%var_name
       
   361                 else:
       
   362                     if not var_name.upper() in [name.upper() for name in self.Controler.GetEditedElementVariables(self.TagName, self.Debug)]:
       
   363                         self.Controler.AddEditedElementPouExternalVar(self.TagName, values[2], var_name)
       
   364                         self.RefreshVariablePanel()
       
   365                         self.RefreshVariableTree()
       
   366                     event.SetDragText(var_name)
       
   367             elif values[1] == "Constant":
       
   368                 event.SetDragText(values[0])
       
   369             elif values[3] == self.TagName:
       
   370                 self.ResetBuffer()
       
   371                 event.SetDragText(values[0])
       
   372                 wx.CallAfter(self.RefreshModel)
       
   373             else:
       
   374                 message = _("Variable don't belong to this POU!")
       
   375             if message is not None:
       
   376                 dialog = wx.MessageDialog(self, message, _("Error"), wx.OK|wx.ICON_ERROR)
       
   377                 dialog.ShowModal()
       
   378                 dialog.Destroy()
       
   379                 event.SetDragText("")
       
   380         event.Skip()
       
   381     
       
   382     def SetTextSyntax(self, syntax):
       
   383         self.TextSyntax = syntax
       
   384         if syntax in ["ST", "ALL"]:
       
   385             self.Editor.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL)
       
   386             self.Editor.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS)
       
   387             self.Editor.SetMarginSensitive(2, 1)
       
   388             self.Editor.SetMarginWidth(2, 12)
       
   389             if syntax == "ST":
       
   390                 self.BlockStartKeywords = ST_BLOCK_START_KEYWORDS
       
   391                 self.BlockEndKeywords = ST_BLOCK_START_KEYWORDS
       
   392             else:
       
   393                 self.BlockStartKeywords = IEC_BLOCK_START_KEYWORDS
       
   394                 self.BlockEndKeywords = IEC_BLOCK_START_KEYWORDS
       
   395         else:
       
   396             self.BlockStartKeywords = []
       
   397             self.BlockEndKeywords = []
       
   398     
       
   399     def SetKeywords(self, keywords):
       
   400         self.Keywords = [keyword.upper() for keyword in keywords]
       
   401         self.Colourise(0, -1)
       
   402     
       
   403     def RefreshJumpList(self):
       
   404         if self.TextSyntax != "IL":
       
   405             self.Jumps = [jump.upper() for jump in LABEL_MODEL.findall(self.GetText())]
       
   406             self.Colourise(0, -1)
       
   407     
       
   408     # Buffer the last model state
       
   409     def RefreshBuffer(self):
       
   410         self.Controler.BufferProject()
       
   411         if self.ParentWindow:
       
   412             self.ParentWindow.RefreshTitle()
       
   413             self.ParentWindow.RefreshFileMenu()
       
   414             self.ParentWindow.RefreshEditMenu()
       
   415     
       
   416     def StartBuffering(self):
       
   417         self.Controler.StartBuffering()
       
   418         if self.ParentWindow:
       
   419             self.ParentWindow.RefreshTitle()
       
   420             self.ParentWindow.RefreshFileMenu()
       
   421             self.ParentWindow.RefreshEditMenu()
       
   422     
       
   423     def ResetBuffer(self):
       
   424         if self.CurrentAction != None:
       
   425             self.Controler.EndBuffering()
       
   426             self.CurrentAction = None
       
   427     
       
   428     def GetBufferState(self):
       
   429         if not self.Debug and self.TextSyntax != "ALL":
       
   430             return self.Controler.GetBufferState()
       
   431         return False, False
       
   432     
       
   433     def Undo(self):
       
   434         if not self.Debug and self.TextSyntax != "ALL":
       
   435             self.Controler.LoadPrevious()
       
   436             self.ParentWindow.CloseTabsWithoutModel()
       
   437             
       
   438     def Redo(self):
       
   439         if not self.Debug and self.TextSyntax != "ALL":
       
   440             self.Controler.LoadNext()
       
   441             self.ParentWindow.CloseTabsWithoutModel()
       
   442         
       
   443     def HasNoModel(self):
       
   444         if not self.Debug and self.TextSyntax != "ALL":
       
   445             return self.Controler.GetEditedElement(self.TagName) is None
       
   446         return False
       
   447     
       
   448     def RefreshView(self, variablepanel=True):
       
   449         EditorPanel.RefreshView(self, variablepanel)
       
   450         
       
   451         if self.Controler is not None:
       
   452             self.ResetBuffer()
       
   453             self.DisableEvents = True
       
   454             old_cursor_pos = self.GetCurrentPos()
       
   455             old_text = self.GetText()
       
   456             new_text = self.Controler.GetEditedElementText(self.TagName, self.Debug)
       
   457             self.SetText(new_text)
       
   458             new_cursor_pos = GetCursorPos(old_text, new_text)
       
   459             if new_cursor_pos != None:
       
   460                 self.Editor.GotoPos(new_cursor_pos)
       
   461             else:
       
   462                 self.Editor.GotoPos(old_cursor_pos)
       
   463             self.Editor.ScrollToColumn(0)
       
   464             self.RefreshJumpList()
       
   465             self.Editor.EmptyUndoBuffer()
       
   466             self.DisableEvents = False
       
   467             
       
   468             self.RefreshVariableTree()
       
   469             
       
   470             self.TypeNames = [typename.upper() for typename in self.Controler.GetDataTypes(self.TagName, True, self.Debug)]
       
   471             self.EnumeratedValues = [value.upper() for value in self.Controler.GetEnumeratedDataValues()]
       
   472             
       
   473             self.Functions = {}
       
   474             for category in self.Controler.GetBlockTypes(self.TagName, self.Debug):
       
   475                 for blocktype in category["list"]:
       
   476                     blockname = blocktype["name"].upper()
       
   477                     if blocktype["type"] == "function" and blockname not in self.Keywords and blockname not in self.Variables.keys():
       
   478                         interface = dict([(name, {}) for name, type, modifier in blocktype["inputs"] + blocktype["outputs"] if name != ''])
       
   479                         for param in ["EN", "ENO"]:
       
   480                             if not interface.has_key(param):
       
   481                                 interface[param] = {}
       
   482                         if self.Functions.has_key(blockname):
       
   483                             self.Functions[blockname]["interface"].update(interface)
       
   484                             self.Functions[blockname]["extensible"] |= blocktype["extensible"]
       
   485                         else:
       
   486                             self.Functions[blockname] = {"interface": interface,
       
   487                                                          "extensible": blocktype["extensible"]}
       
   488         
       
   489         self.Colourise(0, -1)
       
   490             
       
   491     def RefreshVariableTree(self):
       
   492         words = self.TagName.split("::")
       
   493         self.Variables = self.GenerateVariableTree([(variable["Name"], variable["Type"], variable["Tree"]) for variable in self.Controler.GetEditedElementInterfaceVars(self.TagName, self.Debug)])
       
   494         if self.Controler.GetEditedElementType(self.TagName, self.Debug)[1] == "function" or words[0] == "T" and self.TextSyntax == "IL":
       
   495             return_type = self.Controler.GetEditedElementInterfaceReturnType(self.TagName, self.Debug)
       
   496             if return_type is not None:
       
   497                 var_tree, var_dimension = self.Controler.GenerateVarTree(return_type, self.Debug)
       
   498                 self.Variables[words[-1].upper()] = self.GenerateVariableTree(var_tree)
       
   499             else:
       
   500                 self.Variables[words[-1].upper()] = {}
       
   501     
       
   502     def GenerateVariableTree(self, list):
       
   503         tree = {}
       
   504         for var_name, var_type, (var_tree, var_dimension) in list:
       
   505             tree[var_name.upper()] = self.GenerateVariableTree(var_tree)
       
   506         return tree
       
   507     
       
   508     def IsValidVariable(self, name, context):
       
   509         return context is not None and context.get(name, None) is not None
       
   510 
       
   511     def IsCallParameter(self, name, call):
       
   512         if call is not None:
       
   513             return (call["interface"].get(name.upper(), None) is not None or 
       
   514                     call["extensible"] and EXTENSIBLE_PARAMETER.match(name.upper()) is not None)
       
   515         return False
       
   516     
       
   517     def RefreshLineFolding(self, line_number):
       
   518         if self.TextSyntax in ["ST", "ALL"]:
       
   519             level = wx.stc.STC_FOLDLEVELBASE + self.Editor.GetLineIndentation(line_number)
       
   520             line = self.Editor.GetLine(line_number).strip()
       
   521             if line == "":
       
   522                 if line_number > 0:
       
   523                     if LineStartswith(self.Editor.GetLine(line_number - 1).strip(), self.BlockEndKeywords):
       
   524                         level = self.Editor.GetFoldLevel(self.Editor.GetFoldParent(line_number - 1)) & wx.stc.STC_FOLDLEVELNUMBERMASK
       
   525                     else:
       
   526                         level = self.Editor.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK
       
   527                 if level != wx.stc.STC_FOLDLEVELBASE:
       
   528                     level |=  wx.stc.STC_FOLDLEVELWHITEFLAG 
       
   529             elif LineStartswith(line, self.BlockStartKeywords):
       
   530                 level |= wx.stc.STC_FOLDLEVELHEADERFLAG
       
   531             elif LineStartswith(line, self.BlockEndKeywords):
       
   532                 if LineStartswith(self.Editor.GetLine(line_number - 1).strip(), self.BlockEndKeywords):
       
   533                     level = self.Editor.GetFoldLevel(self.Editor.GetFoldParent(line_number - 1)) & wx.stc.STC_FOLDLEVELNUMBERMASK
       
   534                 else:
       
   535                     level = self.Editor.GetFoldLevel(line_number - 1) & wx.stc.STC_FOLDLEVELNUMBERMASK
       
   536             self.Editor.SetFoldLevel(line_number, level)
       
   537     
       
   538     def OnStyleNeeded(self, event):
       
   539         self.TextChanged = True
       
   540         line_number = self.Editor.LineFromPosition(self.Editor.GetEndStyled())
       
   541         if line_number == 0:
       
   542             start_pos = last_styled_pos = 0
       
   543         else:
       
   544             start_pos = last_styled_pos = self.Editor.GetLineEndPosition(line_number - 1) + 1
       
   545         self.RefreshLineFolding(line_number)
       
   546         end_pos = event.GetPosition()
       
   547         self.StartStyling(start_pos, 0xff)
       
   548         
       
   549         current_context = self.Variables
       
   550         current_call = None
       
   551         
       
   552         current_pos = last_styled_pos
       
   553         state = SPACE
       
   554         line = ""
       
   555         word = ""
       
   556         while current_pos < end_pos:
       
   557             char = chr(self.Editor.GetCharAt(current_pos)).upper()
       
   558             line += char
       
   559             if char == NEWLINE:
       
   560                 self.ContextStack = []
       
   561                 current_context = self.Variables
       
   562                 if state == COMMENT:
       
   563                     self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_COMMENT)
       
   564                 elif state == NUMBER:
       
   565                     self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
       
   566                 elif state == WORD:
       
   567                     if word in self.Keywords or word in self.TypeNames:
       
   568                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD)
       
   569                     elif self.IsValidVariable(word, current_context):
       
   570                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE)
       
   571                     elif self.IsCallParameter(word, current_call):
       
   572                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_PARAMETER)
       
   573                     elif word in self.Functions:
       
   574                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION)
       
   575                     elif self.TextSyntax == "IL" and word in self.Jumps:
       
   576                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP)
       
   577                     elif word in self.EnumeratedValues:
       
   578                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
       
   579                     else:
       
   580                         self.SetStyling(current_pos - last_styled_pos, 31)
       
   581                         if word not in ["]", ")"] and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos):
       
   582                             self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK)
       
   583                             self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK)
       
   584                             self.StartStyling(current_pos, 0xff)
       
   585                 else:
       
   586                     self.SetStyling(current_pos - last_styled_pos, 31)
       
   587                 last_styled_pos = current_pos
       
   588                 state = SPACE
       
   589                 line = ""
       
   590                 line_number += 1
       
   591                 self.RefreshLineFolding(line_number)
       
   592             elif line.endswith("(*") and state != COMMENT:
       
   593                 self.SetStyling(current_pos - last_styled_pos - 1, 31)
       
   594                 last_styled_pos = current_pos
       
   595                 if state == WORD:
       
   596                     current_context = self.Variables
       
   597                 state = COMMENT
       
   598             elif line.endswith("{") and state != PRAGMA:
       
   599                 self.SetStyling(current_pos - last_styled_pos - 1, 31)
       
   600                 last_styled_pos = current_pos
       
   601                 if state == WORD:
       
   602                     current_context = self.Variables
       
   603                 state = PRAGMA
       
   604             elif state == COMMENT:
       
   605                 if line.endswith("*)"):
       
   606                     self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT)
       
   607                     last_styled_pos = current_pos + 1
       
   608                     state = SPACE
       
   609             elif state == PRAGMA:
       
   610                 if line.endswith("}"):
       
   611                     self.SetStyling(current_pos - last_styled_pos + 2, 31)
       
   612                     last_styled_pos = current_pos + 1
       
   613                     state = SPACE
       
   614             elif (line.endswith("'") or line.endswith('"')) and state not in [STRING, WSTRING]:
       
   615                 self.SetStyling(current_pos - last_styled_pos, 31)
       
   616                 last_styled_pos = current_pos
       
   617                 if state == WORD:
       
   618                     current_context = self.Variables
       
   619                 if line.endswith("'"):
       
   620                     state = STRING
       
   621                 else:
       
   622                     state = WSTRING
       
   623             elif state == STRING:
       
   624                 if line.endswith("'") and not line.endswith("$'"):
       
   625                     self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_STRING)
       
   626                     last_styled_pos = current_pos + 1
       
   627                     state = SPACE
       
   628             elif state == WSTRING:
       
   629                 if line.endswith('"') and not line.endswith('$"'):
       
   630                     self.SetStyling(current_pos - last_styled_pos + 1, STC_PLC_STRING)
       
   631                     last_styled_pos = current_pos + 1
       
   632                     state = SPACE
       
   633             elif char in LETTERS:
       
   634                 if state == NUMBER:
       
   635                     word = "#"
       
   636                     state = WORD
       
   637                 elif state == SPACE:
       
   638                     self.SetStyling(current_pos - last_styled_pos, 31)
       
   639                     word = char
       
   640                     last_styled_pos = current_pos
       
   641                     state = WORD
       
   642                 else:
       
   643                     word += char
       
   644             elif char in NUMBERS or char == '.' and state != WORD:
       
   645                 if state == SPACE:
       
   646                     self.SetStyling(current_pos - last_styled_pos, 31)
       
   647                     last_styled_pos = current_pos
       
   648                     state = NUMBER
       
   649                 elif state == WORD and char != '.':
       
   650                     word += char
       
   651             elif char == '(' and state == SPACE:
       
   652                 self.CallStack.append(current_call)
       
   653                 current_call = None
       
   654             else:
       
   655                 if state == WORD:
       
   656                     if word in self.Keywords or word in self.TypeNames:
       
   657                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD)
       
   658                     elif self.IsValidVariable(word, current_context):
       
   659                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE)
       
   660                     elif self.IsCallParameter(word, current_call):
       
   661                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_PARAMETER)
       
   662                     elif word in self.Functions:
       
   663                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION)    
       
   664                     elif self.TextSyntax == "IL" and word in self.Jumps:
       
   665                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP)
       
   666                     elif word in self.EnumeratedValues:
       
   667                         self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
       
   668                     else:
       
   669                         self.SetStyling(current_pos - last_styled_pos, 31)
       
   670                         if word not in ["]", ")"] and (self.GetCurrentPos() < last_styled_pos or self.GetCurrentPos() > current_pos):
       
   671                             self.StartStyling(last_styled_pos, wx.stc.STC_INDICS_MASK)
       
   672                             self.SetStyling(current_pos - last_styled_pos, wx.stc.STC_INDIC0_MASK)
       
   673                             self.StartStyling(current_pos, 0xff)
       
   674                     if char == '.':
       
   675                         if word != "]":
       
   676                             if current_context is not None:
       
   677                                 current_context = current_context.get(word, None)
       
   678                             else:
       
   679                                 current_context = None
       
   680                     elif char == '(':
       
   681                         self.CallStack.append(current_call)
       
   682                         current_call = self.Functions.get(word, None)
       
   683                         if current_call is None and self.IsValidVariable(word, current_context):
       
   684                             current_call = {"interface": current_context.get(word, {}),
       
   685                                             "extensible": False}
       
   686                         current_context = self.Variables
       
   687                     else:
       
   688                         if char == '[':
       
   689                             self.ContextStack.append(current_context.get(word, None))
       
   690                         current_context = self.Variables
       
   691                     
       
   692                     word = ""
       
   693                     last_styled_pos = current_pos
       
   694                     state = SPACE
       
   695                 elif state == NUMBER:
       
   696                     self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
       
   697                     last_styled_pos = current_pos
       
   698                     state = SPACE
       
   699                 if char == ']':
       
   700                     if len(self.ContextStack) > 0:
       
   701                         current_context = self.ContextStack.pop()
       
   702                     else:
       
   703                         current_context = self.Variables
       
   704                     word = char
       
   705                     state = WORD
       
   706                 elif char == ')':
       
   707                     current_context = self.Variables
       
   708                     if len(self.CallStack) > 0:
       
   709                         current_call = self.CallStack.pop()
       
   710                     else:
       
   711                         current_call = None
       
   712                     word = char
       
   713                     state = WORD
       
   714             current_pos += 1
       
   715         if state == COMMENT:
       
   716             self.SetStyling(current_pos - last_styled_pos + 2, STC_PLC_COMMENT)
       
   717         elif state == NUMBER:
       
   718             self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
       
   719         elif state == WORD:
       
   720             if word in self.Keywords or word in self.TypeNames:
       
   721                 self.SetStyling(current_pos - last_styled_pos, STC_PLC_WORD)
       
   722             elif self.IsValidVariable(word, current_context):
       
   723                 self.SetStyling(current_pos - last_styled_pos, STC_PLC_VARIABLE)
       
   724             elif self.IsCallParameter(word, current_call):
       
   725                 self.SetStyling(current_pos - last_styled_pos, STC_PLC_PARAMETER)
       
   726             elif self.TextSyntax == "IL" and word in self.Functions:
       
   727                 self.SetStyling(current_pos - last_styled_pos, STC_PLC_FUNCTION)
       
   728             elif word in self.Jumps:
       
   729                 self.SetStyling(current_pos - last_styled_pos, STC_PLC_JUMP)
       
   730             elif word in self.EnumeratedValues:
       
   731                 self.SetStyling(current_pos - last_styled_pos, STC_PLC_NUMBER)
       
   732             else:
       
   733                 self.SetStyling(current_pos - last_styled_pos, 31)
       
   734         else:
       
   735             self.SetStyling(current_pos - start_pos, 31)
       
   736         self.ShowHighlights(start_pos, end_pos)
       
   737         event.Skip()
       
   738     
       
   739     def OnMarginClick(self, event):
       
   740         if event.GetMargin() == 2:
       
   741             line = self.Editor.LineFromPosition(event.GetPosition())
       
   742             if self.Editor.GetFoldLevel(line) & wx.stc.STC_FOLDLEVELHEADERFLAG:
       
   743                 self.Editor.ToggleFold(line)
       
   744         event.Skip()
       
   745         
       
   746     def Cut(self):
       
   747         self.ResetBuffer()
       
   748         self.DisableEvents = True
       
   749         self.Editor.CmdKeyExecute(wx.stc.STC_CMD_CUT)
       
   750         self.DisableEvents = False
       
   751         self.RefreshModel()
       
   752         self.RefreshBuffer()
       
   753     
       
   754     def Copy(self):
       
   755         self.Editor.CmdKeyExecute(wx.stc.STC_CMD_COPY)
       
   756     
       
   757     def Paste(self):
       
   758         self.ResetBuffer()
       
   759         self.DisableEvents = True
       
   760         self.Editor.CmdKeyExecute(wx.stc.STC_CMD_PASTE)
       
   761         self.DisableEvents = False
       
   762         self.RefreshModel()
       
   763         self.RefreshBuffer()
       
   764     
       
   765     def Find(self, direction, search_params):
       
   766         if self.SearchParams != search_params:
       
   767             self.ClearHighlights(SEARCH_RESULT_HIGHLIGHT)
       
   768             
       
   769             self.SearchParams = search_params
       
   770             criteria = {
       
   771                 "raw_pattern": search_params["find_pattern"], 
       
   772                 "pattern": re.compile(search_params["find_pattern"]),
       
   773                 "case_sensitive": search_params["case_sensitive"],
       
   774                 "regular_expression": search_params["regular_expression"],
       
   775                 "filter": "all"}
       
   776             
       
   777             self.SearchResults = [
       
   778                 (infos[1:], start, end, SEARCH_RESULT_HIGHLIGHT)
       
   779                 for infos, start, end, text in 
       
   780                 self.Controler.SearchInPou(self.TagName, criteria, self.Debug)]
       
   781         
       
   782         if len(self.SearchResults) > 0:
       
   783             if self.CurrentFindHighlight is not None:
       
   784                 old_idx = self.SearchResults.index(self.CurrentFindHighlight)
       
   785                 if self.SearchParams["wrap"]:
       
   786                     idx = (old_idx + direction) % len(self.SearchResults)
       
   787                 else:
       
   788                     idx = max(0, min(old_idx + direction, len(self.SearchResults) - 1))
       
   789                 if idx != old_idx:
       
   790                     self.RemoveHighlight(*self.CurrentFindHighlight)
       
   791                     self.CurrentFindHighlight = self.SearchResults[idx]
       
   792                     self.AddHighlight(*self.CurrentFindHighlight)
       
   793             else:
       
   794                 self.CurrentFindHighlight = self.SearchResults[0]
       
   795                 self.AddHighlight(*self.CurrentFindHighlight)
       
   796             
       
   797         else:
       
   798             if self.CurrentFindHighlight is not None:
       
   799                 self.RemoveHighlight(*self.CurrentFindHighlight)
       
   800             self.CurrentFindHighlight = None
       
   801     
       
   802     def RefreshModel(self):
       
   803         self.RefreshJumpList()
       
   804         self.Controler.SetEditedElementText(self.TagName, self.GetText())
       
   805     
       
   806     def OnKeyDown(self, event):
       
   807         if self.Controler is not None:
       
   808         
       
   809             if self.Editor.CallTipActive():
       
   810                 self.Editor.CallTipCancel()
       
   811             key = event.GetKeyCode()
       
   812             key_handled = False
       
   813 
       
   814             line = self.Editor.GetCurrentLine()
       
   815             if line == 0:
       
   816                 start_pos = 0
       
   817             else:
       
   818                 start_pos = self.Editor.GetLineEndPosition(line - 1) + 1
       
   819             end_pos = self.GetCurrentPos()
       
   820             lineText = self.Editor.GetTextRange(start_pos, end_pos).replace("\t", " ")
       
   821             
       
   822             # Code completion
       
   823             if key == wx.WXK_SPACE and event.ControlDown():
       
   824                 
       
   825                 words = lineText.split(" ")
       
   826                 words = [word for i, word in enumerate(words) if word != '' or i == len(words) - 1]
       
   827                             
       
   828                 kw = []
       
   829                 
       
   830                 if self.TextSyntax == "IL":
       
   831                     if len(words) == 1:
       
   832                         kw = self.Keywords
       
   833                     elif len(words) == 2:
       
   834                         if words[0].upper() in ["CAL", "CALC", "CALNC"]:
       
   835                             kw = self.Functions
       
   836                         elif words[0].upper() in ["JMP", "JMPC", "JMPNC"]:
       
   837                             kw = self.Jumps
       
   838                         else:
       
   839                             kw = self.Variables.keys()
       
   840                 else:
       
   841                     kw = self.Keywords + self.Variables.keys() + self.Functions
       
   842                 if len(kw) > 0:
       
   843                     if len(words[-1]) > 0:
       
   844                         kw = [keyword for keyword in kw if keyword.startswith(words[-1])]
       
   845                     kw.sort()
       
   846                     self.Editor.AutoCompSetIgnoreCase(True)
       
   847                     self.Editor.AutoCompShow(len(words[-1]), " ".join(kw))
       
   848                 key_handled = True
       
   849             elif key == wx.WXK_RETURN or key == wx.WXK_NUMPAD_ENTER:
       
   850                 if self.TextSyntax in ["ST", "ALL"]:
       
   851                     indent = self.Editor.GetLineIndentation(line)
       
   852                     if LineStartswith(lineText.strip(), self.BlockStartKeywords):
       
   853                         indent = (indent / 2 + 1) * 2
       
   854                     self.Editor.AddText("\n" + " " * indent)
       
   855                     key_handled = True
       
   856             elif key == wx.WXK_BACK:
       
   857                 if self.TextSyntax in ["ST", "ALL"]:
       
   858                     indent = self.Editor.GetLineIndentation(line)
       
   859                     if lineText.strip() == "" and indent > 0:
       
   860                         self.Editor.DelLineLeft()
       
   861                         self.Editor.AddText(" " * ((max(0, indent - 1) / 2) * 2))
       
   862                         key_handled = True
       
   863             if not key_handled:
       
   864                 event.Skip()
       
   865 
       
   866     def OnKillFocus(self, event):
       
   867         self.Editor.AutoCompCancel()
       
   868         event.Skip()
       
   869 
       
   870 #-------------------------------------------------------------------------------
       
   871 #                        Highlights showing functions
       
   872 #-------------------------------------------------------------------------------
       
   873 
       
   874     def OnRefreshHighlightsTimer(self, event):
       
   875         self.RefreshView()
       
   876         event.Skip()
       
   877 
       
   878     def ClearHighlights(self, highlight_type=None):
       
   879         EditorPanel.ClearHighlights(self, highlight_type)
       
   880         
       
   881         if highlight_type is None:
       
   882             self.Highlights = []
       
   883         else:
       
   884             highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None)
       
   885             if highlight_type is not None:
       
   886                 self.Highlights = [(infos, start, end, highlight) for (infos, start, end, highlight) in self.Highlights if highlight != highlight_type]
       
   887         self.RefreshView()
       
   888 
       
   889     def AddHighlight(self, infos, start, end, highlight_type):
       
   890         EditorPanel.AddHighlight(self, infos, start, end, highlight_type)
       
   891         
       
   892         highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None)
       
   893         if infos[0] == "body" and highlight_type is not None:
       
   894             self.Highlights.append((infos[1], start, end, highlight_type))
       
   895             self.Editor.GotoPos(self.Editor.PositionFromLine(start[0]) + start[1])
       
   896             self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)
       
   897 
       
   898     def RemoveHighlight(self, infos, start, end, highlight_type):
       
   899         EditorPanel.RemoveHighlight(self, infos, start, end, highlight_type)
       
   900         
       
   901         highlight_type = HIGHLIGHT_TYPES.get(highlight_type, None)
       
   902         if (infos[0] == "body" and highlight_type is not None and 
       
   903             (infos[1], start, end, highlight_type) in self.Highlights):
       
   904             self.Highlights.remove((infos[1], start, end, highlight_type))
       
   905             self.RefreshHighlightsTimer.Start(int(REFRESH_HIGHLIGHT_PERIOD * 1000), oneShot=True)
       
   906     
       
   907     def ShowHighlights(self, start_pos, end_pos):
       
   908         for indent, start, end, highlight_type in self.Highlights:
       
   909             if start[0] == 0:
       
   910                 highlight_start_pos = start[1] - indent
       
   911             else:
       
   912                 highlight_start_pos = self.Editor.GetLineEndPosition(start[0] - 1) + start[1] - indent + 1
       
   913             if end[0] == 0:
       
   914                 highlight_end_pos = end[1] - indent + 1
       
   915             else:
       
   916                 highlight_end_pos = self.Editor.GetLineEndPosition(end[0] - 1) + end[1] - indent + 2
       
   917             if highlight_start_pos < end_pos and highlight_end_pos > start_pos:
       
   918                 self.StartStyling(highlight_start_pos, 0xff)
       
   919                 self.SetStyling(highlight_end_pos - highlight_start_pos, highlight_type)
       
   920                 self.StartStyling(highlight_start_pos, 0x00)
       
   921                 self.SetStyling(len(self.Editor.GetText()) - highlight_end_pos, wx.stc.STC_STYLE_DEFAULT)
       
   922