TextViewer.py
changeset 64 dd6f693e46a1
parent 58 39cd981ff242
child 68 66308e07402c
equal deleted inserted replaced
63:04a02b4b2a57 64:dd6f693e46a1
    20 #
    20 #
    21 #You should have received a copy of the GNU General Public
    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
    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
    23 #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    24 
    24 
    25 from wxPython.wx import *
       
    26 from wxPython.stc import * 
       
    27 import wx
    25 import wx
       
    26 import wx.stc
    28 from types import *
    27 from types import *
    29 
    28 
    30 import re
    29 import re
    31 
    30 
    32 #-------------------------------------------------------------------------------
    31 #-------------------------------------------------------------------------------
    39 LETTERS = ['_']
    38 LETTERS = ['_']
    40 for i in xrange(26):
    39 for i in xrange(26):
    41     LETTERS.append(chr(ord('a') + i))
    40     LETTERS.append(chr(ord('a') + i))
    42     LETTERS.append(chr(ord('A') + i))
    41     LETTERS.append(chr(ord('A') + i))
    43 
    42 
    44 [wxSTC_PLC_WORD, wxSTC_PLC_COMMENT, wxSTC_PLC_NUMBER, wxSTC_PLC_VARIABLE, 
    43 [STC_PLC_WORD, STC_PLC_COMMENT, STC_PLC_NUMBER, STC_PLC_VARIABLE, 
    45  wxSTC_PLC_FUNCTION, wxSTC_PLC_JUMP] = range(6)
    44  STC_PLC_FUNCTION, STC_PLC_JUMP] = range(6)
    46 [SPACE, WORD, NUMBER, COMMENT] = range(4)
    45 [SPACE, WORD, NUMBER, COMMENT] = range(4)
    47 
    46 
    48 [wxID_TEXTVIEWER,
    47 [ID_TEXTVIEWER,
    49 ] = [wx.NewId() for _init_ctrls in range(1)]
    48 ] = [wx.NewId() for _init_ctrls in range(1)]
    50 
    49 
    51 if wx.Platform == '__WXMSW__':
    50 if wx.Platform == '__WXMSW__':
    52     faces = { 'times': 'Times New Roman',
    51     faces = { 'times': 'Times New Roman',
    53               'mono' : 'Courier New',
    52               'mono' : 'Courier New',
    88         else:
    87         else:
    89             return i + 1
    88             return i + 1
    90     else:
    89     else:
    91         return None
    90         return None
    92 
    91 
    93 class TextViewer(wxStyledTextCtrl):
    92 class TextViewer(wx.stc.StyledTextCtrl):
    94     
    93     
    95     def __init__(self, parent, window, controler):
    94     def __init__(self, parent, window, controler):
    96         wxStyledTextCtrl.__init__(self, parent, wxID_TEXTVIEWER, style=0)
    95         wx.stc.StyledTextCtrl.__init__(self, parent, ID_TEXTVIEWER, style=0)
    97         
    96         
    98         self.CmdKeyAssign(ord('+'), wxSTC_SCMOD_CTRL, wxSTC_CMD_ZOOMIN)
    97         self.CmdKeyAssign(ord('+'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMIN)
    99         self.CmdKeyAssign(ord('-'), wxSTC_SCMOD_CTRL, wxSTC_CMD_ZOOMOUT)
    98         self.CmdKeyAssign(ord('-'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMOUT)
   100         
    99         
   101         self.SetViewWhiteSpace(False)
   100         self.SetViewWhiteSpace(False)
   102         
   101         
   103         self.SetLexer(wxSTC_LEX_CONTAINER)
   102         self.SetLexer(wx.stc.STC_LEX_CONTAINER)
   104         
   103         
   105         # Global default styles for all languages
   104         # Global default styles for all languages
   106         self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
   105         self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % faces)
   107         self.StyleClearAll()  # Reset all to be like the default
   106         self.StyleClearAll()  # Reset all to be like the default
   108         
   107         
   109         self.StyleSetSpec(wxSTC_STYLE_LINENUMBER,  "back:#C0C0C0,size:%(size)d" % faces)
   108         self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,  "back:#C0C0C0,size:%(size)d" % faces)
   110         self.SetSelBackground(1, "#E0E0E0")
   109         self.SetSelBackground(1, "#E0E0E0")
   111         
   110         
   112         # Highlighting styles
   111         # Highlighting styles
   113         self.StyleSetSpec(wxSTC_PLC_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
   112         self.StyleSetSpec(STC_PLC_WORD, "fore:#00007F,bold,size:%(size)d" % faces)
   114         self.StyleSetSpec(wxSTC_PLC_VARIABLE, "fore:#7F0000,size:%(size)d" % faces)
   113         self.StyleSetSpec(STC_PLC_VARIABLE, "fore:#7F0000,size:%(size)d" % faces)
   115         self.StyleSetSpec(wxSTC_PLC_FUNCTION, "fore:#7F7F00,size:%(size)d" % faces)
   114         self.StyleSetSpec(STC_PLC_FUNCTION, "fore:#7F7F00,size:%(size)d" % faces)
   116         self.StyleSetSpec(wxSTC_PLC_COMMENT, "fore:#7F7F7F,size:%(size)d" % faces)
   115         self.StyleSetSpec(STC_PLC_COMMENT, "fore:#7F7F7F,size:%(size)d" % faces)
   117         self.StyleSetSpec(wxSTC_PLC_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
   116         self.StyleSetSpec(STC_PLC_NUMBER, "fore:#007F7F,size:%(size)d" % faces)
   118         self.StyleSetSpec(wxSTC_PLC_JUMP, "fore:#007F00,size:%(size)d" % faces)
   117         self.StyleSetSpec(STC_PLC_JUMP, "fore:#007F00,size:%(size)d" % faces)
   119         
   118         
   120         # Indicators styles
   119         # Indicators styles
   121         self.IndicatorSetStyle(0, wxSTC_INDIC_SQUIGGLE)
   120         self.IndicatorSetStyle(0, wx.stc.STC_INDIC_SQUIGGLE)
   122         self.IndicatorSetForeground(0, wxRED)
   121         self.IndicatorSetForeground(0, wx.RED)
   123         
   122         
   124         # Line numbers in the margin
   123         # Line numbers in the margin
   125         self.SetMarginType(1, wxSTC_MARGIN_NUMBER)
   124         self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER)
   126         self.SetMarginWidth(1, 50)
   125         self.SetMarginWidth(1, 50)
   127         
   126         
   128         # Indentation size
   127         # Indentation size
   129         self.SetTabWidth(2)
   128         self.SetTabWidth(2)
   130         self.SetUseTabs(0)
   129         self.SetUseTabs(0)
   139         self.CurrentAction = None
   138         self.CurrentAction = None
   140         
   139         
   141         self.Parent = window
   140         self.Parent = window
   142         self.Controler = controler
   141         self.Controler = controler
   143 
   142 
   144         self.SetModEventMask(wxSTC_MOD_BEFOREINSERT|wxSTC_MOD_BEFOREDELETE)
   143         self.SetModEventMask(wx.stc.STC_MOD_BEFOREINSERT|wx.stc.STC_MOD_BEFOREDELETE)
   145 
   144 
   146         EVT_KEY_DOWN(self, self.OnKeyDown)
   145         self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
   147         EVT_STC_STYLENEEDED(self, wxID_TEXTVIEWER, self.OnStyleNeeded)
   146         self.Bind(wx.stc.EVT_STC_STYLENEEDED, self.OnStyleNeeded, id=ID_TEXTVIEWER)
   148         EVT_STC_DO_DROP(self, wxID_TEXTVIEWER, self.OnDoDrop)
   147         self.Bind(wx.stc.EVT_STC_DO_DROP, self.OnDoDrop, id=ID_TEXTVIEWER)
   149         EVT_KILL_FOCUS(self, self.OnKillFocus)
   148         self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
   150         EVT_STC_MODIFIED(self, wxID_TEXTVIEWER, self.OnModification)
   149         self.Bind(wx.stc.EVT_STC_MODIFIED, self.OnModification, id=ID_TEXTVIEWER)
   151     
   150     
   152     def OnModification(self, event):
   151     def OnModification(self, event):
   153         if not self.DisableEvents:
   152         if not self.DisableEvents:
   154             mod_type = event.GetModificationType()
   153             mod_type = event.GetModificationType()
   155             if not (mod_type&wxSTC_PERFORMED_UNDO or mod_type&wxSTC_PERFORMED_REDO):
   154             if not (mod_type&wx.stc.STC_PERFORMED_UNDO or mod_type&wx.stc.STC_PERFORMED_REDO):
   156                 if mod_type&wxSTC_MOD_BEFOREINSERT:
   155                 if mod_type&wx.stc.STC_MOD_BEFOREINSERT:
   157                     if self.CurrentAction == None:
   156                     if self.CurrentAction == None:
   158                         self.StartBuffering()
   157                         self.StartBuffering()
   159                     elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1:
   158                     elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1:
   160                         self.Controler.EndBuffering()
   159                         self.Controler.EndBuffering()
   161                         self.StartBuffering()
   160                         self.StartBuffering()
   162                     self.CurrentAction = ("Add", event.GetPosition())
   161                     self.CurrentAction = ("Add", event.GetPosition())
   163                 elif mod_type&wxSTC_MOD_BEFOREDELETE:
   162                 elif mod_type&wx.stc.STC_MOD_BEFOREDELETE:
   164                     if self.CurrentAction == None:
   163                     if self.CurrentAction == None:
   165                         self.StartBuffering()
   164                         self.StartBuffering()
   166                     elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1:
   165                     elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1:
   167                         self.Controler.EndBuffering()
   166                         self.Controler.EndBuffering()
   168                         self.StartBuffering()
   167                         self.StartBuffering()
   254         while i < end_pos:
   253         while i < end_pos:
   255             char = chr(self.GetCharAt(i)).upper()
   254             char = chr(self.GetCharAt(i)).upper()
   256             line += char
   255             line += char
   257             if char == NEWLINE:
   256             if char == NEWLINE:
   258                 if state == COMMENT:
   257                 if state == COMMENT:
   259                     self.SetStyling(i - start_pos + 1, wxSTC_PLC_COMMENT)
   258                     self.SetStyling(i - start_pos + 1, STC_PLC_COMMENT)
   260                 elif state == NUMBER:
   259                 elif state == NUMBER:
   261                     self.SetStyling(i - start_pos, wxSTC_PLC_NUMBER)
   260                     self.SetStyling(i - start_pos, STC_PLC_NUMBER)
   262                 elif state == WORD:
   261                 elif state == WORD:
   263                     if word in self.Keywords:
   262                     if word in self.Keywords:
   264                         self.SetStyling(i - start_pos, wxSTC_PLC_WORD)
   263                         self.SetStyling(i - start_pos, STC_PLC_WORD)
   265                     elif word in self.Variables:
   264                     elif word in self.Variables:
   266                         self.SetStyling(i - start_pos, wxSTC_PLC_VARIABLE)
   265                         self.SetStyling(i - start_pos, STC_PLC_VARIABLE)
   267                     elif word in self.Functions:
   266                     elif word in self.Functions:
   268                         self.SetStyling(i - start_pos, wxSTC_PLC_FUNCTION)
   267                         self.SetStyling(i - start_pos, STC_PLC_FUNCTION)
   269                     elif word in self.Jumps:
   268                     elif word in self.Jumps:
   270                         self.SetStyling(i - start_pos, wxSTC_PLC_JUMP)
   269                         self.SetStyling(i - start_pos, STC_PLC_JUMP)
   271                     else:
   270                     else:
   272                         self.SetStyling(i - start_pos, 31)
   271                         self.SetStyling(i - start_pos, 31)
   273                         if self.GetCurrentPos() < start_pos or self.GetCurrentPos() > i:
   272                         if self.GetCurrentPos() < start_pos or self.GetCurrentPos() > i:
   274                             self.StartStyling(start_pos, wxSTC_INDICS_MASK)
   273                             self.StartStyling(start_pos, wx.stc.STC_INDICS_MASK)
   275                             self.SetStyling(i - start_pos, wxSTC_INDIC0_MASK)
   274                             self.SetStyling(i - start_pos, wx.stc.STC_INDIC0_MASK)
   276                             self.StartStyling(i, 0xff)    
   275                             self.StartStyling(i, 0xff)    
   277                 else:
   276                 else:
   278                     self.SetStyling(i - start_pos, 31)
   277                     self.SetStyling(i - start_pos, 31)
   279                 start_pos = i
   278                 start_pos = i
   280                 state = SPACE
   279                 state = SPACE
   283                 self.SetStyling(i - start_pos - 1, 31)
   282                 self.SetStyling(i - start_pos - 1, 31)
   284                 start_pos = i
   283                 start_pos = i
   285                 state = COMMENT
   284                 state = COMMENT
   286             elif state == COMMENT:
   285             elif state == COMMENT:
   287                 if line.endswith("*)"):
   286                 if line.endswith("*)"):
   288                     self.SetStyling(i - start_pos + 2, wxSTC_PLC_COMMENT)
   287                     self.SetStyling(i - start_pos + 2, STC_PLC_COMMENT)
   289                     start_pos = i + 1
   288                     start_pos = i + 1
   290                     state = SPACE
   289                     state = SPACE
   291             elif char in LETTERS:
   290             elif char in LETTERS:
   292                 if state == NUMBER:
   291                 if state == NUMBER:
   293                     word = "#"
   292                     word = "#"
   307                 if state == WORD and char != '.':
   306                 if state == WORD and char != '.':
   308                     word += char
   307                     word += char
   309             else:
   308             else:
   310                 if state == WORD:
   309                 if state == WORD:
   311                     if word in self.Keywords:
   310                     if word in self.Keywords:
   312                         self.SetStyling(i - start_pos, wxSTC_PLC_WORD)
   311                         self.SetStyling(i - start_pos, STC_PLC_WORD)
   313                     elif word in self.Variables:
   312                     elif word in self.Variables:
   314                         self.SetStyling(i - start_pos, wxSTC_PLC_VARIABLE)
   313                         self.SetStyling(i - start_pos, STC_PLC_VARIABLE)
   315                     elif word in self.Functions:
   314                     elif word in self.Functions:
   316                         self.SetStyling(i - start_pos, wxSTC_PLC_FUNCTION)
   315                         self.SetStyling(i - start_pos, STC_PLC_FUNCTION)
   317                     elif word in self.Jumps:
   316                     elif word in self.Jumps:
   318                         self.SetStyling(i - start_pos, wxSTC_PLC_JUMP)
   317                         self.SetStyling(i - start_pos, STC_PLC_JUMP)
   319                     else:
   318                     else:
   320                         self.SetStyling(i - start_pos, 31)
   319                         self.SetStyling(i - start_pos, 31)
   321                         if self.GetCurrentPos() < start_pos or self.GetCurrentPos() > i:
   320                         if self.GetCurrentPos() < start_pos or self.GetCurrentPos() > i:
   322                             self.StartStyling(start_pos, wxSTC_INDICS_MASK)
   321                             self.StartStyling(start_pos, wx.stc.STC_INDICS_MASK)
   323                             self.SetStyling(i - start_pos, wxSTC_INDIC0_MASK)
   322                             self.SetStyling(i - start_pos, wx.stc.STC_INDIC0_MASK)
   324                             self.StartStyling(i, 0xff)
   323                             self.StartStyling(i, 0xff)
   325                     word = ""
   324                     word = ""
   326                     start_pos = i
   325                     start_pos = i
   327                     state = SPACE
   326                     state = SPACE
   328                 elif state == NUMBER:
   327                 elif state == NUMBER:
   329                     self.SetStyling(i - start_pos, wxSTC_PLC_NUMBER)
   328                     self.SetStyling(i - start_pos, STC_PLC_NUMBER)
   330                     start_pos = i
   329                     start_pos = i
   331                     state = SPACE
   330                     state = SPACE
   332             i += 1
   331             i += 1
   333         if state == COMMENT:
   332         if state == COMMENT:
   334             self.SetStyling(i - start_pos + 2, wxSTC_PLC_COMMENT)
   333             self.SetStyling(i - start_pos + 2, STC_PLC_COMMENT)
   335         elif state == NUMBER:
   334         elif state == NUMBER:
   336             self.SetStyling(i - start_pos, wxSTC_PLC_NUMBER)
   335             self.SetStyling(i - start_pos, STC_PLC_NUMBER)
   337         elif state == WORD:
   336         elif state == WORD:
   338             if word in self.Keywords:
   337             if word in self.Keywords:
   339                 self.SetStyling(i - start_pos, wxSTC_PLC_WORD)
   338                 self.SetStyling(i - start_pos, STC_PLC_WORD)
   340             elif word in self.Variables:
   339             elif word in self.Variables:
   341                 self.SetStyling(i - start_pos, wxSTC_PLC_VARIABLE)
   340                 self.SetStyling(i - start_pos, STC_PLC_VARIABLE)
   342             elif word in self.Functions:
   341             elif word in self.Functions:
   343                 self.SetStyling(i - start_pos, wxSTC_PLC_FUNCTION)
   342                 self.SetStyling(i - start_pos, STC_PLC_FUNCTION)
   344             elif word in self.Jumps:
   343             elif word in self.Jumps:
   345                 self.SetStyling(i - start_pos, wxSTC_PLC_JUMP)
   344                 self.SetStyling(i - start_pos, STC_PLC_JUMP)
   346             else:
   345             else:
   347                 self.SetStyling(i - start_pos, 31)
   346                 self.SetStyling(i - start_pos, 31)
   348         else:
   347         else:
   349             self.SetStyling(i - start_pos, 31)
   348             self.SetStyling(i - start_pos, 31)
   350         event.Skip()
   349         event.Skip()
   351     
   350     
   352     def Cut(self):
   351     def Cut(self):
   353         self.ResetBuffer()
   352         self.ResetBuffer()
   354         self.CmdKeyExecute(wxSTC_CMD_CUT)
   353         self.CmdKeyExecute(wx.stc.STC_CMD_CUT)
   355         self.RefreshBuffer()
   354         self.RefreshBuffer()
   356     
   355     
   357     def Copy(self):
   356     def Copy(self):
   358         self.CmdKeyExecute(wxSTC_CMD_COPY)
   357         self.CmdKeyExecute(wx.stc.STC_CMD_COPY)
   359     
   358     
   360     def Paste(self):
   359     def Paste(self):
   361         self.ResetBuffer()
   360         self.ResetBuffer()
   362         self.CmdKeyExecute(wxSTC_CMD_PASTE)
   361         self.CmdKeyExecute(wx.stc.STC_CMD_PASTE)
   363         self.RefreshBuffer()
   362         self.RefreshBuffer()
   364     
   363     
   365     def RefreshModel(self):
   364     def RefreshModel(self):
   366         if self.TextChanged:
   365         if self.TextChanged:
   367             self.RefreshJumpList()
   366             self.RefreshJumpList()
   371         if self.CallTipActive():
   370         if self.CallTipActive():
   372             self.CallTipCancel()
   371             self.CallTipCancel()
   373         key = event.KeyCode()
   372         key = event.KeyCode()
   374 
   373 
   375         # Code completion
   374         # Code completion
   376         if key == WXK_SPACE and event.ControlDown():
   375         if key == wx.WXK_SPACE and event.ControlDown():
   377             
   376             
   378             line = self.GetCurrentLine()
   377             line = self.GetCurrentLine()
   379             if line == 0:
   378             if line == 0:
   380                 start_pos = 0
   379                 start_pos = 0
   381             else:
   380             else:
   404                 kw.sort()
   403                 kw.sort()
   405                 self.AutoCompSetIgnoreCase(True)
   404                 self.AutoCompSetIgnoreCase(True)
   406                 self.AutoCompShow(len(words[-1]), " ".join(kw))
   405                 self.AutoCompShow(len(words[-1]), " ".join(kw))
   407         else:
   406         else:
   408             self.TextChanged = False
   407             self.TextChanged = False
   409             wxCallAfter(self.RefreshModel)
   408             wx.CallAfter(self.RefreshModel)
   410             event.Skip()
   409             event.Skip()
   411 
   410 
   412     def OnKillFocus(self, event):
   411     def OnKillFocus(self, event):
   413         self.AutoCompCancel()
   412         self.AutoCompCancel()
   414         event.Skip()
   413         event.Skip()