TextViewer.py
changeset 56 7187e1c00975
parent 53 4988262d03e3
child 58 39cd981ff242
--- a/TextViewer.py	Wed Jul 25 10:06:29 2007 +0200
+++ b/TextViewer.py	Thu Jul 26 17:23:21 2007 +0200
@@ -25,6 +25,7 @@
 from wxPython.wx import *
 from wxPython.stc import * 
 import wx
+from types import *
 
 import re
 
@@ -68,6 +69,27 @@
 IDENTIFIER_MODEL = re.compile(re_texts["identifier"])
 LABEL_MODEL = re.compile("[ \t\n]%(identifier)s:[ \t\n]"%re_texts)
 
+def GetCursorPos(old, new):
+    old_length = len(old)
+    new_length = len(new)
+    common_length = min(old_length, new_length)
+    i = 0
+    for i in xrange(common_length):
+        if old[i] != new[i]:
+            break
+    if old_length < new_length:
+        if common_length > 0 and old[i] != new[i]:
+            return i + new_length - old_length
+        else:
+            return i + new_length - old_length + 1
+    elif old_length > new_length or i < min(old_length, new_length) - 1:
+        if common_length > 0 and old[i] != new[i]:
+            return i
+        else:
+            return i + 1
+    else:
+        return None
+
 class TextViewer(wxStyledTextCtrl):
     
     def __init__(self, parent, window, controler):
@@ -112,14 +134,40 @@
         self.Functions = []
         self.Jumps = []
         self.TextChanged = False
+        self.DisableEvents = True
         self.TextSyntax = "ST"
-        
+        self.CurrentAction = None
+        
+        self.Parent = window
         self.Controler = controler
 
+        self.SetModEventMask(wxSTC_MOD_BEFOREINSERT|wxSTC_MOD_BEFOREDELETE)
+
         EVT_KEY_DOWN(self, self.OnKeyDown)
         EVT_STC_STYLENEEDED(self, wxID_TEXTVIEWER, self.OnStyleNeeded)
         EVT_STC_DO_DROP(self, wxID_TEXTVIEWER, self.OnDoDrop)
         EVT_KILL_FOCUS(self, self.OnKillFocus)
+        EVT_STC_MODIFIED(self, wxID_TEXTVIEWER, self.OnModification)
+    
+    def OnModification(self, event):
+        if not self.DisableEvents:
+            mod_type = event.GetModificationType()
+            if not (mod_type&wxSTC_PERFORMED_UNDO or mod_type&wxSTC_PERFORMED_REDO):
+                if mod_type&wxSTC_MOD_BEFOREINSERT:
+                    if self.CurrentAction == None:
+                        self.StartBuffering()
+                    elif self.CurrentAction[0] != "Add" or self.CurrentAction[1] != event.GetPosition() - 1:
+                        self.Controler.EndBuffering()
+                        self.StartBuffering()
+                    self.CurrentAction = ("Add", event.GetPosition())
+                elif mod_type&wxSTC_MOD_BEFOREDELETE:
+                    if self.CurrentAction == None:
+                        self.StartBuffering()
+                    elif self.CurrentAction[0] != "Delete" or self.CurrentAction[1] != event.GetPosition() + 1:
+                        self.Controler.EndBuffering()
+                        self.StartBuffering()
+                    self.CurrentAction = ("Delete", event.GetPosition())
+        event.Skip()
     
     def OnDoDrop(self, event):
         try:
@@ -156,10 +204,39 @@
         self.Jumps = [jump.upper() for jump in LABEL_MODEL.findall(self.GetText())]
         self.Colourise(0, -1)
     
+    # Buffer the last model state
+    def RefreshBuffer(self):
+        self.Controler.BufferProject()
+        self.Parent.RefreshTitle()
+        self.Parent.RefreshEditMenu()
+    
+    def StartBuffering(self):
+        self.Controler.StartBuffering()
+        self.Parent.RefreshTitle()
+        self.Parent.RefreshEditMenu()
+    
+    def ResetBuffer(self):
+        if self.CurrentAction != None:
+            self.Controler.EndBuffering()
+            self.CurrentAction = None
+    
     def RefreshView(self):
-        self.SetText(self.Controler.GetCurrentElementEditingText())
+        self.ResetBuffer()
+        self.DisableEvents = True
+        old_cursor_pos = self.GetCurrentPos()
+        old_text = self.GetText()
+        new_text = self.Controler.GetCurrentElementEditingText()
+        self.SetText(new_text)
+        new_cursor_pos = GetCursorPos(old_text, new_text)
+        if new_cursor_pos != None:
+            self.SetSelection(new_cursor_pos, new_cursor_pos)
+            self.EnsureCaretVisible()
+        else:
+            self.SetSelection(old_cursor_pos, old_cursor_pos)
         self.RefreshJumpList()
-    
+        self.EmptyUndoBuffer()
+        self.DisableEvents = False
+        
     def OnStyleNeeded(self, event):
         self.TextChanged = True
         line = self.LineFromPosition(self.GetEndStyled())
@@ -273,13 +350,17 @@
         event.Skip()
     
     def Cut(self):
+        self.ResetBuffer()
         self.CmdKeyExecute(wxSTC_CMD_CUT)
-        
+        self.RefreshBuffer()
+    
     def Copy(self):
         self.CmdKeyExecute(wxSTC_CMD_COPY)
     
     def Paste(self):
+        self.ResetBuffer()
         self.CmdKeyExecute(wxSTC_CMD_PASTE)
+        self.RefreshBuffer()
     
     def RefreshModel(self):
         if self.TextChanged: