New Features: In Tab-View mode, Ctrl-number will take the user to
    the numbered tab view.  Modified files now show an '*' astrisk in
    the view title.  Debugger framework can now support PHP debugging.
    Not important for python development, but at least that means the
    debugger framework is more generalized.
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@38852 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
		
	
		
			
				
	
	
		
			973 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			973 lines
		
	
	
		
			38 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
#----------------------------------------------------------------------------
 | 
						|
# Name:         CodeEditor.py
 | 
						|
# Purpose:      Abstract Code Editor for pydocview tbat uses the Styled Text Control
 | 
						|
#
 | 
						|
# Author:       Peter Yared
 | 
						|
#
 | 
						|
# Created:      8/10/03
 | 
						|
# CVS-ID:       $Id$
 | 
						|
# Copyright:    (c) 2004-2005 ActiveGrid, Inc.
 | 
						|
# License:      wxWindows License
 | 
						|
#----------------------------------------------------------------------------
 | 
						|
 | 
						|
 | 
						|
import STCTextEditor
 | 
						|
import wx
 | 
						|
import wx.lib.docview
 | 
						|
import OutlineService
 | 
						|
import os
 | 
						|
import re
 | 
						|
import string
 | 
						|
import sys
 | 
						|
import MarkerService
 | 
						|
from UICommon import CaseInsensitiveCompare
 | 
						|
_ = wx.GetTranslation
 | 
						|
if wx.Platform == '__WXMSW__':
 | 
						|
    _WINDOWS = True
 | 
						|
else:
 | 
						|
    _WINDOWS = False
 | 
						|
 | 
						|
 | 
						|
EXPAND_TEXT_ID = wx.NewId()
 | 
						|
COLLAPSE_TEXT_ID = wx.NewId()
 | 
						|
EXPAND_TOP_ID = wx.NewId()
 | 
						|
COLLAPSE_TOP_ID = wx.NewId()
 | 
						|
EXPAND_ALL_ID = wx.NewId()
 | 
						|
COLLAPSE_ALL_ID = wx.NewId()
 | 
						|
CHECK_CODE_ID = wx.NewId()
 | 
						|
AUTO_COMPLETE_ID = wx.NewId()
 | 
						|
CLEAN_WHITESPACE = wx.NewId()
 | 
						|
COMMENT_LINES_ID = wx.NewId()
 | 
						|
UNCOMMENT_LINES_ID = wx.NewId()
 | 
						|
INDENT_LINES_ID = wx.NewId()
 | 
						|
DEDENT_LINES_ID = wx.NewId()
 | 
						|
USE_TABS_ID = wx.NewId()
 | 
						|
SET_INDENT_WIDTH_ID = wx.NewId()
 | 
						|
FOLDING_ID = wx.NewId()
 | 
						|
 | 
						|
 | 
						|
class CodeDocument(STCTextEditor.TextDocument):
 | 
						|
    pass    
 | 
						|
 | 
						|
 | 
						|
class CodeView(STCTextEditor.TextView):
 | 
						|
 | 
						|
 | 
						|
    #----------------------------------------------------------------------------
 | 
						|
    # Overridden methods
 | 
						|
    #----------------------------------------------------------------------------
 | 
						|
 | 
						|
 | 
						|
    def GetCtrlClass(self):
 | 
						|
        """ Used in split window to instantiate new instances """
 | 
						|
        return CodeCtrl
 | 
						|
 | 
						|
 | 
						|
    def ProcessEvent(self, event):
 | 
						|
        id = event.GetId()
 | 
						|
        if id == EXPAND_TEXT_ID:
 | 
						|
            self.GetCtrl().ToggleFold(self.GetCtrl().GetCurrentLine())
 | 
						|
            return True
 | 
						|
        elif id == COLLAPSE_TEXT_ID:
 | 
						|
            self.GetCtrl().ToggleFold(self.GetCtrl().GetCurrentLine())
 | 
						|
            return True
 | 
						|
        elif id == EXPAND_TOP_ID:
 | 
						|
            self.GetCtrl().ToggleFoldAll(expand = True, topLevelOnly = True)
 | 
						|
            return True
 | 
						|
        elif id == COLLAPSE_TOP_ID:
 | 
						|
            self.GetCtrl().ToggleFoldAll(expand = False, topLevelOnly = True)
 | 
						|
            return True
 | 
						|
        elif id == EXPAND_ALL_ID:
 | 
						|
            self.GetCtrl().ToggleFoldAll(expand = True)
 | 
						|
            return True
 | 
						|
        elif id == COLLAPSE_ALL_ID:
 | 
						|
            self.GetCtrl().ToggleFoldAll(expand = False)
 | 
						|
            return True
 | 
						|
        elif id == CHECK_CODE_ID:
 | 
						|
            self.OnCheckCode()
 | 
						|
            return True
 | 
						|
        elif id == AUTO_COMPLETE_ID:
 | 
						|
            self.OnAutoComplete()
 | 
						|
            return True
 | 
						|
        elif id == CLEAN_WHITESPACE:
 | 
						|
            self.OnCleanWhiteSpace()
 | 
						|
            return True
 | 
						|
        elif id == SET_INDENT_WIDTH_ID:
 | 
						|
            self.OnSetIndentWidth()
 | 
						|
            return True
 | 
						|
        elif id == USE_TABS_ID:
 | 
						|
            self.GetCtrl().SetUseTabs(not self.GetCtrl().GetUseTabs())
 | 
						|
            return True
 | 
						|
        elif id == INDENT_LINES_ID:
 | 
						|
            self.GetCtrl().CmdKeyExecute(wx.stc.STC_CMD_TAB)
 | 
						|
            return True
 | 
						|
        elif id == DEDENT_LINES_ID:
 | 
						|
            self.GetCtrl().CmdKeyExecute(wx.stc.STC_CMD_BACKTAB)
 | 
						|
            return True
 | 
						|
        elif id == COMMENT_LINES_ID:
 | 
						|
            self.OnCommentLines()
 | 
						|
            return True
 | 
						|
        elif id == UNCOMMENT_LINES_ID:
 | 
						|
            self.OnUncommentLines()
 | 
						|
            return True
 | 
						|
        else:
 | 
						|
            return STCTextEditor.TextView.ProcessEvent(self, event)
 | 
						|
 | 
						|
 | 
						|
    def ProcessUpdateUIEvent(self, event):
 | 
						|
        if not self.GetCtrl():
 | 
						|
            return False
 | 
						|
        id = event.GetId()
 | 
						|
        if id == EXPAND_TEXT_ID:
 | 
						|
            if self.GetCtrl().GetViewFolding():
 | 
						|
                event.Enable(self.GetCtrl().CanLineExpand(self.GetCtrl().GetCurrentLine()))
 | 
						|
            else:
 | 
						|
                event.Enable(False)
 | 
						|
            return True
 | 
						|
        elif id == COLLAPSE_TEXT_ID:
 | 
						|
            if self.GetCtrl().GetViewFolding():
 | 
						|
                event.Enable(self.GetCtrl().CanLineCollapse(self.GetCtrl().GetCurrentLine()))
 | 
						|
            else:
 | 
						|
                event.Enable(False)
 | 
						|
            return True
 | 
						|
        elif (id == EXPAND_TOP_ID
 | 
						|
        or id == COLLAPSE_TOP_ID
 | 
						|
        or id == EXPAND_ALL_ID
 | 
						|
        or id == COLLAPSE_ALL_ID):
 | 
						|
            if self.GetCtrl().GetViewFolding():
 | 
						|
                event.Enable(self.GetCtrl().GetTextLength() > 0)
 | 
						|
            else:
 | 
						|
                event.Enable(False)
 | 
						|
            return True            
 | 
						|
        elif (id == AUTO_COMPLETE_ID
 | 
						|
        or id == CLEAN_WHITESPACE
 | 
						|
        or id == INDENT_LINES_ID
 | 
						|
        or id == DEDENT_LINES_ID
 | 
						|
        or id == COMMENT_LINES_ID
 | 
						|
        or id == UNCOMMENT_LINES_ID):
 | 
						|
            event.Enable(self.GetCtrl().GetTextLength() > 0)
 | 
						|
            return True
 | 
						|
        elif id == CHECK_CODE_ID:
 | 
						|
            event.Enable(False)
 | 
						|
            return True
 | 
						|
        elif id == SET_INDENT_WIDTH_ID:
 | 
						|
            event.Enable(True)
 | 
						|
            return True
 | 
						|
        elif id == FOLDING_ID:
 | 
						|
            event.Enable(self.GetCtrl().GetViewFolding())
 | 
						|
            return True
 | 
						|
        elif id == USE_TABS_ID:
 | 
						|
            event.Enable(True)
 | 
						|
            event.Check(self.GetCtrl().GetUseTabs())
 | 
						|
            return True
 | 
						|
        else:
 | 
						|
            return STCTextEditor.TextView.ProcessUpdateUIEvent(self, event)
 | 
						|
 | 
						|
 | 
						|
    #----------------------------------------------------------------------------
 | 
						|
    # Methods for OutlineService
 | 
						|
    #----------------------------------------------------------------------------
 | 
						|
 | 
						|
    def OnChangeFilename(self):
 | 
						|
        wx.lib.docview.View.OnChangeFilename(self)
 | 
						|
        self.LoadOutline(force=True)
 | 
						|
        
 | 
						|
 | 
						|
    def ClearOutline(self):
 | 
						|
        outlineService = wx.GetApp().GetService(OutlineService.OutlineService)
 | 
						|
        if not outlineService:
 | 
						|
            return
 | 
						|
 | 
						|
        outlineView = outlineService.GetView()
 | 
						|
        if not outlineView:
 | 
						|
            return
 | 
						|
 | 
						|
        outlineView.ClearTreeCtrl()
 | 
						|
 | 
						|
 | 
						|
    def LoadOutline(self, force=False):
 | 
						|
        outlineService = wx.GetApp().GetService(OutlineService.OutlineService)
 | 
						|
        if not outlineService:
 | 
						|
            return
 | 
						|
        outlineService.LoadOutline(self, force=force)
 | 
						|
 | 
						|
 | 
						|
    def DoLoadOutlineCallback(self, force=False):
 | 
						|
        outlineService = wx.GetApp().GetService(OutlineService.OutlineService)
 | 
						|
        if not outlineService:
 | 
						|
            return False
 | 
						|
 | 
						|
        outlineView = outlineService.GetView()
 | 
						|
        if not outlineView:
 | 
						|
            return False
 | 
						|
 | 
						|
        treeCtrl = outlineView.GetTreeCtrl()
 | 
						|
        if not treeCtrl:
 | 
						|
            return False
 | 
						|
 | 
						|
        view = treeCtrl.GetCallbackView()
 | 
						|
        newCheckSum = self.GenCheckSum()
 | 
						|
        if not force:
 | 
						|
            if view and view is self:
 | 
						|
                if self._checkSum == newCheckSum:
 | 
						|
                    return False
 | 
						|
        self._checkSum = newCheckSum
 | 
						|
 | 
						|
        treeCtrl.DeleteAllItems()
 | 
						|
 | 
						|
        document = self.GetDocument()
 | 
						|
        if not document:
 | 
						|
            return True
 | 
						|
 | 
						|
        filename = document.GetFilename()
 | 
						|
        if filename:
 | 
						|
            rootItem = treeCtrl.AddRoot(os.path.basename(filename))
 | 
						|
            treeCtrl.SetDoSelectCallback(rootItem, self, (0,0))
 | 
						|
        else:
 | 
						|
            return True
 | 
						|
 | 
						|
        text = self.GetValue()
 | 
						|
        if not text:
 | 
						|
            return True
 | 
						|
 | 
						|
        CLASS_PATTERN = 'class[ \t]+\w+.*?:'
 | 
						|
        DEF_PATTERN = 'def[ \t]+\w+\(.*?\)'
 | 
						|
        classPat = re.compile(CLASS_PATTERN, re.M|re.S)
 | 
						|
        defPat= re.compile(DEF_PATTERN, re.M|re.S)
 | 
						|
        pattern = re.compile('^[ \t]*((' + CLASS_PATTERN + ')|('+ DEF_PATTERN +'.*?:)).*?$', re.M|re.S)
 | 
						|
 | 
						|
        iter = pattern.finditer(text)
 | 
						|
        indentStack = [(0, rootItem)]
 | 
						|
        for pattern in iter:
 | 
						|
            line = pattern.string[pattern.start(0):pattern.end(0)]
 | 
						|
            classLine = classPat.search(line)
 | 
						|
            if classLine:
 | 
						|
                indent = classLine.start(0)
 | 
						|
                itemStr = classLine.string[classLine.start(0):classLine.end(0)-1]  # don't take the closing ':'
 | 
						|
                itemStr = itemStr.replace("\n", "").replace("\r", "").replace(",\\", ",").replace("  ", "")  # remove line continuations and spaces from outline view
 | 
						|
            else:
 | 
						|
                defLine = defPat.search(line)
 | 
						|
                if defLine:
 | 
						|
                    indent = defLine.start(0)
 | 
						|
                    itemStr = defLine.string[defLine.start(0):defLine.end(0)]
 | 
						|
                    itemStr = itemStr.replace("\n", "").replace("\r", "").replace(",\\", ",").replace("  ", "")  # remove line continuations and spaces from outline view
 | 
						|
 | 
						|
            if indent == 0:
 | 
						|
                parentItem = rootItem
 | 
						|
            else:
 | 
						|
                lastItem = indentStack.pop()
 | 
						|
                while lastItem[0] >= indent:
 | 
						|
                    lastItem = indentStack.pop()
 | 
						|
                indentStack.append(lastItem)
 | 
						|
                parentItem = lastItem[1]
 | 
						|
 | 
						|
            item = treeCtrl.AppendItem(parentItem, itemStr)
 | 
						|
            treeCtrl.SetDoSelectCallback(item, self, (pattern.end(0), pattern.start(0) + indent))  # select in reverse order because we want the cursor to be at the start of the line so it wouldn't scroll to the right
 | 
						|
            indentStack.append((indent, item))
 | 
						|
 | 
						|
        treeCtrl.Expand(rootItem)
 | 
						|
 | 
						|
        return True
 | 
						|
 | 
						|
 | 
						|
    def DoSelectCallback(self, data):
 | 
						|
        if data:
 | 
						|
            self.EnsureVisibleEnforcePolicy(self.LineFromPosition(data[0]))
 | 
						|
            # wxBug: need to select in reverse order (end, start) to place cursor at begining of line,
 | 
						|
            #        otherwise, display is scrolled over to the right hard and is hard to view
 | 
						|
            self.SetSelection(data[1], data[0])
 | 
						|
 | 
						|
 | 
						|
##    def checksum(self, bytes):        
 | 
						|
##        def rotate_right(c):
 | 
						|
##            if c&1:
 | 
						|
##                return (c>>1)|0x8000
 | 
						|
##            else:
 | 
						|
##                return c>>1
 | 
						|
##                
 | 
						|
##        result = 0
 | 
						|
##        for ch in bytes:
 | 
						|
##            ch = ord(ch) & 0xFF
 | 
						|
##            result = (rotate_right(result)+ch) & 0xFFFF
 | 
						|
##        return result
 | 
						|
##
 | 
						|
 | 
						|
    def GenCheckSum(self):
 | 
						|
        """ Poor man's checksum.  We'll assume most changes will change the length of the file.
 | 
						|
        """
 | 
						|
        text = self.GetValue()
 | 
						|
        if text:
 | 
						|
            return len(text)
 | 
						|
        else:
 | 
						|
            return 0
 | 
						|
 | 
						|
 | 
						|
    #----------------------------------------------------------------------------
 | 
						|
    # Format methods
 | 
						|
    #----------------------------------------------------------------------------
 | 
						|
 | 
						|
    def OnCheckCode(self):
 | 
						|
        """ Need to overshadow this for each specific subclass """
 | 
						|
        if 0:
 | 
						|
            try:
 | 
						|
                code = self.GetCtrl().GetText()
 | 
						|
                codeObj = compile(code, self.GetDocument().GetFilename(), 'exec')
 | 
						|
                self._GetParentFrame().SetStatusText(_("The file successfully compiled"))
 | 
						|
            except SyntaxError, (message, (fileName, line, col, text)):
 | 
						|
                pos = self.GetCtrl().PositionFromLine(line - 1) + col - 1
 | 
						|
                self.GetCtrl().SetSelection(pos, pos)
 | 
						|
                self._GetParentFrame().SetStatusText(_("Syntax Error: %s") % message)
 | 
						|
            except:
 | 
						|
                self._GetParentFrame().SetStatusText("%s: %s" % (sys.exc_info()[0], sys.exc_info()[1]))
 | 
						|
 | 
						|
 | 
						|
    def OnAutoComplete(self):
 | 
						|
        self.GetCtrl().AutoCompCancel()
 | 
						|
        self.GetCtrl().AutoCompSetAutoHide(0)
 | 
						|
        self.GetCtrl().AutoCompSetChooseSingle(True)
 | 
						|
        self.GetCtrl().AutoCompSetIgnoreCase(True)
 | 
						|
        context, hint = self.GetAutoCompleteHint()
 | 
						|
        replaceList, replaceLen = self.GetAutoCompleteKeywordList(context, hint)
 | 
						|
        if replaceList and len(replaceList) != 0: 
 | 
						|
            self.GetCtrl().AutoCompShow(replaceLen, replaceList)
 | 
						|
 | 
						|
 | 
						|
    def GetAutoCompleteHint(self):
 | 
						|
        """ Replace this method with Editor specific method """
 | 
						|
        pos = self.GetCtrl().GetCurrentPos()
 | 
						|
        if pos == 0:
 | 
						|
            return None, None
 | 
						|
        if chr(self.GetCtrl().GetCharAt(pos - 1)) == '.':
 | 
						|
            pos = pos - 1
 | 
						|
            hint = None
 | 
						|
        else:
 | 
						|
            hint = ''
 | 
						|
            
 | 
						|
        validLetters = string.letters + string.digits + '_.'
 | 
						|
        word = ''
 | 
						|
        while (True):
 | 
						|
            pos = pos - 1
 | 
						|
            if pos < 0:
 | 
						|
                break
 | 
						|
            char = chr(self.GetCtrl().GetCharAt(pos))
 | 
						|
            if char not in validLetters:
 | 
						|
                break
 | 
						|
            word = char + word
 | 
						|
            
 | 
						|
        context = word
 | 
						|
        if hint is not None:            
 | 
						|
            lastDot = word.rfind('.')
 | 
						|
            if lastDot != -1:
 | 
						|
                context = word[0:lastDot]
 | 
						|
                hint = word[lastDot+1:]
 | 
						|
                    
 | 
						|
        return context, hint
 | 
						|
        
 | 
						|
 | 
						|
    def GetAutoCompleteDefaultKeywords(self):
 | 
						|
        """ Replace this method with Editor specific keywords """
 | 
						|
        return ['Put', 'Editor Specific', 'Keywords', 'Here']
 | 
						|
 | 
						|
 | 
						|
    def GetAutoCompleteKeywordList(self, context, hint):            
 | 
						|
        """ Replace this method with Editor specific keywords """
 | 
						|
        kw = self.GetAutoCompleteDefaultKeywords()
 | 
						|
        
 | 
						|
        if hint and len(hint):
 | 
						|
            lowerHint = hint.lower()
 | 
						|
            filterkw = filter(lambda item: item.lower().startswith(lowerHint), kw)  # remove variables and methods that don't match hint
 | 
						|
            kw = filterkw
 | 
						|
 | 
						|
        if hint:
 | 
						|
            replaceLen = len(hint)
 | 
						|
        else:
 | 
						|
            replaceLen = 0
 | 
						|
            
 | 
						|
        kw.sort(CaseInsensitiveCompare)
 | 
						|
        return " ".join(kw), replaceLen
 | 
						|
        
 | 
						|
 | 
						|
    def OnCleanWhiteSpace(self):
 | 
						|
        newText = ""
 | 
						|
        for lineNo in self._GetSelectedLineNumbers():
 | 
						|
            lineText = string.rstrip(self.GetCtrl().GetLine(lineNo))
 | 
						|
            indent = 0
 | 
						|
            lstrip = 0
 | 
						|
            for char in lineText:
 | 
						|
                if char == '\t':
 | 
						|
                    indent = indent + self.GetCtrl().GetIndent()
 | 
						|
                    lstrip = lstrip + 1
 | 
						|
                elif char in string.whitespace:
 | 
						|
                    indent = indent + 1
 | 
						|
                    lstrip = lstrip + 1
 | 
						|
                else:
 | 
						|
                    break
 | 
						|
            if self.GetCtrl().GetUseTabs():
 | 
						|
                indentText = (indent / self.GetCtrl().GetIndent()) * '\t' + (indent % self.GetCtrl().GetIndent()) * ' '
 | 
						|
            else:
 | 
						|
                indentText = indent * ' '
 | 
						|
            lineText = indentText + lineText[lstrip:] + '\n'
 | 
						|
            newText = newText + lineText
 | 
						|
        self._ReplaceSelectedLines(newText)
 | 
						|
 | 
						|
 | 
						|
    def OnSetIndentWidth(self):
 | 
						|
        dialog = wx.TextEntryDialog(self._GetParentFrame(), _("Enter new indent width (2-10):"), _("Set Indent Width"), "%i" % self.GetCtrl().GetIndent())
 | 
						|
        dialog.CenterOnParent()
 | 
						|
        if dialog.ShowModal() == wx.ID_OK:
 | 
						|
            try:
 | 
						|
                indent = int(dialog.GetValue())
 | 
						|
                if indent >= 2 and indent <= 10:
 | 
						|
                    self.GetCtrl().SetIndent(indent)
 | 
						|
                    self.GetCtrl().SetTabWidth(indent)
 | 
						|
            except:
 | 
						|
                pass
 | 
						|
        dialog.Destroy()
 | 
						|
 | 
						|
 | 
						|
    def GetIndentWidth(self):
 | 
						|
        return self.GetCtrl().GetIndent()
 | 
						|
                
 | 
						|
 | 
						|
    def OnCommentLines(self):
 | 
						|
        newText = ""
 | 
						|
        for lineNo in self._GetSelectedLineNumbers():
 | 
						|
            lineText = self.GetCtrl().GetLine(lineNo)
 | 
						|
            if (len(lineText) > 1 and lineText[0] == '#') or (len(lineText) > 2 and lineText[:2] == '##'):
 | 
						|
                newText = newText + lineText
 | 
						|
            else:
 | 
						|
                newText = newText + "##" + lineText
 | 
						|
        self._ReplaceSelectedLines(newText)
 | 
						|
 | 
						|
 | 
						|
    def OnUncommentLines(self):
 | 
						|
        newText = ""
 | 
						|
        for lineNo in self._GetSelectedLineNumbers():
 | 
						|
            lineText = self.GetCtrl().GetLine(lineNo)
 | 
						|
            if len(lineText) >= 2 and lineText[:2] == "##":
 | 
						|
                lineText = lineText[2:]
 | 
						|
            elif len(lineText) >= 1 and lineText[:1] == "#":
 | 
						|
                lineText = lineText[1:]
 | 
						|
            newText = newText + lineText
 | 
						|
        self._ReplaceSelectedLines(newText)
 | 
						|
 | 
						|
 | 
						|
    def _GetSelectedLineNumbers(self):
 | 
						|
        selStart, selEnd = self._GetPositionsBoundingSelectedLines()
 | 
						|
        return range(self.GetCtrl().LineFromPosition(selStart), self.GetCtrl().LineFromPosition(selEnd))
 | 
						|
 | 
						|
 | 
						|
    def _GetPositionsBoundingSelectedLines(self):
 | 
						|
        startPos = self.GetCtrl().GetCurrentPos()
 | 
						|
        endPos = self.GetCtrl().GetAnchor()
 | 
						|
        if startPos > endPos:
 | 
						|
            temp = endPos
 | 
						|
            endPos = startPos
 | 
						|
            startPos = temp
 | 
						|
        if endPos == self.GetCtrl().PositionFromLine(self.GetCtrl().LineFromPosition(endPos)):
 | 
						|
            endPos = endPos - 1  # If it's at the very beginning of a line, use the line above it as the ending line
 | 
						|
        selStart = self.GetCtrl().PositionFromLine(self.GetCtrl().LineFromPosition(startPos))
 | 
						|
        selEnd = self.GetCtrl().PositionFromLine(self.GetCtrl().LineFromPosition(endPos) + 1)
 | 
						|
        return selStart, selEnd
 | 
						|
 | 
						|
 | 
						|
    def _ReplaceSelectedLines(self, text):
 | 
						|
        if len(text) == 0:
 | 
						|
            return
 | 
						|
        selStart, selEnd = self._GetPositionsBoundingSelectedLines()
 | 
						|
        self.GetCtrl().SetSelection(selStart, selEnd)
 | 
						|
        self.GetCtrl().ReplaceSelection(text)
 | 
						|
        self.GetCtrl().SetSelection(selStart + len(text), selStart)
 | 
						|
 | 
						|
 | 
						|
    def OnUpdate(self, sender = None, hint = None):
 | 
						|
        if wx.lib.docview.View.OnUpdate(self, sender, hint):
 | 
						|
            return
 | 
						|
 | 
						|
        if hint == "ViewStuff":
 | 
						|
            self.GetCtrl().SetViewDefaults()
 | 
						|
        elif hint == "Font":
 | 
						|
            font, color = self.GetCtrl().GetFontAndColorFromConfig()
 | 
						|
            self.GetCtrl().SetFont(font)
 | 
						|
            self.GetCtrl().SetFontColor(color)
 | 
						|
        else:
 | 
						|
            import DebuggerService
 | 
						|
            dbg_service = wx.GetApp().GetService(DebuggerService.DebuggerService)
 | 
						|
            if dbg_service:
 | 
						|
                dbg_service.SetCurrentBreakpointMarkers(self)
 | 
						|
 | 
						|
 | 
						|
class CodeService(STCTextEditor.TextService):
 | 
						|
 | 
						|
 | 
						|
    def __init__(self):
 | 
						|
        STCTextEditor.TextService.__init__(self)
 | 
						|
 | 
						|
 | 
						|
    def InstallControls(self, frame, menuBar = None, toolBar = None, statusBar = None, document = None):
 | 
						|
        # TODO NEED TO DO INSTANCEOF CHECK HERE FOR SDI
 | 
						|
        #if document and document.GetDocumentTemplate().GetDocumentType() != TextDocument:
 | 
						|
        #    return
 | 
						|
        if not document and wx.GetApp().GetDocumentManager().GetFlags() & wx.lib.docview.DOC_SDI:
 | 
						|
            return
 | 
						|
 | 
						|
        viewMenu = menuBar.GetMenu(menuBar.FindMenu(_("&View")))
 | 
						|
        isWindows = (wx.Platform == '__WXMSW__')
 | 
						|
 | 
						|
        if not menuBar.FindItemById(EXPAND_TEXT_ID):  # check if below menu items have been already been installed
 | 
						|
            foldingMenu = wx.Menu()
 | 
						|
            if isWindows:
 | 
						|
                foldingMenu.Append(EXPAND_TEXT_ID, _("&Expand\tNumpad-Plus"), _("Expands a collapsed block of text"))
 | 
						|
            else:
 | 
						|
                foldingMenu.Append(EXPAND_TEXT_ID, _("&Expand"), _("Expands a collapsed block of text"))
 | 
						|
 | 
						|
            wx.EVT_MENU(frame, EXPAND_TEXT_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, EXPAND_TEXT_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            
 | 
						|
            if isWindows:
 | 
						|
                foldingMenu.Append(COLLAPSE_TEXT_ID, _("&Collapse\tNumpad+Minus"), _("Collapse a block of text"))
 | 
						|
            else:
 | 
						|
                foldingMenu.Append(COLLAPSE_TEXT_ID, _("&Collapse"), _("Collapse a block of text"))
 | 
						|
            wx.EVT_MENU(frame, COLLAPSE_TEXT_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, COLLAPSE_TEXT_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            
 | 
						|
            if isWindows:
 | 
						|
                foldingMenu.Append(EXPAND_TOP_ID, _("Expand &Top Level\tCtrl+Numpad+Plus"), _("Expands the top fold levels in the document"))
 | 
						|
            else:
 | 
						|
                foldingMenu.Append(EXPAND_TOP_ID, _("Expand &Top Level"), _("Expands the top fold levels in the document"))
 | 
						|
            wx.EVT_MENU(frame, EXPAND_TOP_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, EXPAND_TOP_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            
 | 
						|
            if isWindows:
 | 
						|
                foldingMenu.Append(COLLAPSE_TOP_ID, _("Collapse Top &Level\tCtrl+Numpad+Minus"), _("Collapses the top fold levels in the document"))
 | 
						|
            else:
 | 
						|
                foldingMenu.Append(COLLAPSE_TOP_ID, _("Collapse Top &Level"), _("Collapses the top fold levels in the document"))
 | 
						|
            wx.EVT_MENU(frame, COLLAPSE_TOP_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, COLLAPSE_TOP_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            
 | 
						|
            if isWindows:
 | 
						|
                foldingMenu.Append(EXPAND_ALL_ID, _("Expand &All\tShift+Numpad+Plus"), _("Expands all of the fold levels in the document"))
 | 
						|
            else:
 | 
						|
                foldingMenu.Append(EXPAND_ALL_ID, _("Expand &All"), _("Expands all of the fold levels in the document"))
 | 
						|
            wx.EVT_MENU(frame, EXPAND_ALL_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, EXPAND_ALL_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            
 | 
						|
            if isWindows:
 | 
						|
                foldingMenu.Append(COLLAPSE_ALL_ID, _("Colla&pse All\tShift+Numpad+Minus"), _("Collapses all of the fold levels in the document"))
 | 
						|
            else:
 | 
						|
                foldingMenu.Append(COLLAPSE_ALL_ID, _("Colla&pse All"), _("Collapses all of the fold levels in the document"))
 | 
						|
            wx.EVT_MENU(frame, COLLAPSE_ALL_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, COLLAPSE_ALL_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            
 | 
						|
            viewMenu.AppendMenu(FOLDING_ID, _("&Folding"), foldingMenu)
 | 
						|
            wx.EVT_UPDATE_UI(frame, FOLDING_ID, frame.ProcessUpdateUIEvent)
 | 
						|
 | 
						|
        formatMenuIndex = menuBar.FindMenu(_("&Format"))
 | 
						|
        if formatMenuIndex > -1:
 | 
						|
            formatMenu = menuBar.GetMenu(formatMenuIndex)
 | 
						|
        else:
 | 
						|
            formatMenu = wx.Menu()
 | 
						|
        if not menuBar.FindItemById(CHECK_CODE_ID):  # check if below menu items have been already been installed
 | 
						|
            formatMenu.AppendSeparator()
 | 
						|
            formatMenu.Append(CHECK_CODE_ID, _("&Check Code"), _("Checks the document for syntax and indentation errors"))
 | 
						|
            wx.EVT_MENU(frame, CHECK_CODE_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, CHECK_CODE_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            formatMenu.Append(AUTO_COMPLETE_ID, _("&Auto Complete\tCtrl+Space"), _("Provides suggestions on how to complete the current statement"))
 | 
						|
            wx.EVT_MENU(frame, AUTO_COMPLETE_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, AUTO_COMPLETE_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            formatMenu.Append(CLEAN_WHITESPACE, _("Clean &Whitespace"), _("Converts leading spaces to tabs or vice versa per 'use tabs' and clears trailing spaces"))
 | 
						|
            wx.EVT_MENU(frame, CLEAN_WHITESPACE, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, CLEAN_WHITESPACE, frame.ProcessUpdateUIEvent)
 | 
						|
            formatMenu.AppendSeparator()
 | 
						|
            formatMenu.Append(INDENT_LINES_ID, _("&Indent Lines\tTab"), _("Indents the selected lines one indent width"))
 | 
						|
            wx.EVT_MENU(frame, INDENT_LINES_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, INDENT_LINES_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            formatMenu.Append(DEDENT_LINES_ID, _("&Dedent Lines\tShift+Tab"), _("Dedents the selected lines one indent width"))
 | 
						|
            wx.EVT_MENU(frame, DEDENT_LINES_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, DEDENT_LINES_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            formatMenu.Append(COMMENT_LINES_ID, _("Comment &Lines\tCtrl+Q"), _("Comments out the selected lines be prefixing each one with a comment indicator"))
 | 
						|
            wx.EVT_MENU(frame, COMMENT_LINES_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, COMMENT_LINES_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            formatMenu.Append(UNCOMMENT_LINES_ID, _("&Uncomment Lines\tCtrl+Shift+Q"), _("Removes comment prefixes from each of the selected lines"))
 | 
						|
            wx.EVT_MENU(frame, UNCOMMENT_LINES_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, UNCOMMENT_LINES_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            formatMenu.AppendSeparator()
 | 
						|
            formatMenu.AppendCheckItem(USE_TABS_ID, _("Use &Tabs"), _("Toggles use of tabs or whitespaces for indents"))
 | 
						|
            wx.EVT_MENU(frame, USE_TABS_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, USE_TABS_ID, frame.ProcessUpdateUIEvent)
 | 
						|
            formatMenu.Append(SET_INDENT_WIDTH_ID, _("&Set Indent Width..."), _("Sets the indent width"))
 | 
						|
            wx.EVT_MENU(frame, SET_INDENT_WIDTH_ID, frame.ProcessEvent)
 | 
						|
            wx.EVT_UPDATE_UI(frame, SET_INDENT_WIDTH_ID, frame.ProcessUpdateUIEvent)
 | 
						|
        if formatMenuIndex == -1:
 | 
						|
            viewMenuIndex = menuBar.FindMenu(_("&View"))
 | 
						|
            menuBar.Insert(viewMenuIndex + 1, formatMenu, _("&Format"))
 | 
						|
 | 
						|
##        accelTable = wx.AcceleratorTable([
 | 
						|
##            (wx.ACCEL_NORMAL, wx.WXK_TAB, INDENT_LINES_ID),
 | 
						|
##            (wx.ACCEL_SHIFT, wx.WXK_TAB, DEDENT_LINES_ID),
 | 
						|
##            eval(_("wx.ACCEL_CTRL, ord('Q'), COMMENT_LINES_ID")),
 | 
						|
##            eval(_("wx.ACCEL_CTRL | wx.ACCEL_SHIFT, ord('Q'), UNCOMMENT_LINES_ID"))
 | 
						|
##            ])
 | 
						|
##        frame.SetAcceleratorTable(accelTable)
 | 
						|
 | 
						|
    def ProcessUpdateUIEvent(self, event):
 | 
						|
        id = event.GetId()
 | 
						|
        if (id == EXPAND_TEXT_ID
 | 
						|
        or id == COLLAPSE_TEXT_ID
 | 
						|
        or id == EXPAND_TOP_ID
 | 
						|
        or id == COLLAPSE_TOP_ID
 | 
						|
        or id == EXPAND_ALL_ID
 | 
						|
        or id == COLLAPSE_ALL_ID
 | 
						|
        or id == CHECK_CODE_ID
 | 
						|
        or id == AUTO_COMPLETE_ID
 | 
						|
        or id == CLEAN_WHITESPACE
 | 
						|
        or id == SET_INDENT_WIDTH_ID
 | 
						|
        or id == USE_TABS_ID
 | 
						|
        or id == INDENT_LINES_ID
 | 
						|
        or id == DEDENT_LINES_ID
 | 
						|
        or id == COMMENT_LINES_ID
 | 
						|
        or id == UNCOMMENT_LINES_ID
 | 
						|
        or id == FOLDING_ID):
 | 
						|
            event.Enable(False)
 | 
						|
            return True
 | 
						|
        else:
 | 
						|
            return STCTextEditor.TextService.ProcessUpdateUIEvent(self, event)
 | 
						|
 | 
						|
 | 
						|
class CodeCtrl(STCTextEditor.TextCtrl):
 | 
						|
    CURRENT_LINE_MARKER_NUM = 2
 | 
						|
    BREAKPOINT_MARKER_NUM = 1
 | 
						|
    CURRENT_LINE_MARKER_MASK = 0x4
 | 
						|
    BREAKPOINT_MARKER_MASK = 0x2
 | 
						|
    
 | 
						|
            
 | 
						|
    def __init__(self, parent, id=-1, style = wx.NO_FULL_REPAINT_ON_RESIZE, clearTab=True):
 | 
						|
        STCTextEditor.TextCtrl.__init__(self, parent, id, style)
 | 
						|
        
 | 
						|
        self.UsePopUp(False)
 | 
						|
        self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
 | 
						|
        self.SetProperty("fold", "1")
 | 
						|
 | 
						|
        # Setup a margin to hold fold markers
 | 
						|
        #self.SetFoldFlags(16)  ###  WHAT IS THIS VALUE?  WHAT ARE THE OTHER FLAGS?  DOES IT MATTER?
 | 
						|
        self.SetMarginType(2, wx.stc.STC_MARGIN_SYMBOL)
 | 
						|
        self.SetMarginMask(2, wx.stc.STC_MASK_FOLDERS)
 | 
						|
        self.SetMarginSensitive(2, True)
 | 
						|
        
 | 
						|
        self.SetMarginSensitive(1, False)
 | 
						|
        self.SetMarginMask(1, 0x4)
 | 
						|
        
 | 
						|
        self.SetMarginSensitive(0, True)
 | 
						|
        self.SetMarginType(0, wx.stc.STC_MARGIN_SYMBOL)
 | 
						|
        self.SetMarginMask(0, 0x3)
 | 
						|
        self.SetMarginWidth(0, 12)
 | 
						|
 | 
						|
        self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEREND,     wx.stc.STC_MARK_BOXPLUSCONNECTED,  "white", "black")
 | 
						|
        self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPENMID, wx.stc.STC_MARK_BOXMINUSCONNECTED, "white", "black")
 | 
						|
        self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERMIDTAIL, wx.stc.STC_MARK_TCORNER,  "white", "black")
 | 
						|
        self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERTAIL,    wx.stc.STC_MARK_LCORNER,  "white", "black")
 | 
						|
        self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERSUB,     wx.stc.STC_MARK_VLINE,    "white", "black")
 | 
						|
        self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDER,        wx.stc.STC_MARK_BOXPLUS,  "white", "black")
 | 
						|
        self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPEN,    wx.stc.STC_MARK_BOXMINUS, "white", "black")
 | 
						|
        # Define the current line marker
 | 
						|
        self.MarkerDefine(CodeCtrl.CURRENT_LINE_MARKER_NUM, wx.stc.STC_MARK_SHORTARROW, wx.BLACK, (255,255,128))
 | 
						|
        # Define the breakpoint marker
 | 
						|
        self.MarkerDefine(CodeCtrl.BREAKPOINT_MARKER_NUM, wx.stc.STC_MARK_CIRCLE, wx.BLACK, (255,0,0))
 | 
						|
        
 | 
						|
        if _WINDOWS and clearTab:  # should test to see if menu item exists, if it does, add this workaround
 | 
						|
            self.CmdKeyClear(wx.stc.STC_KEY_TAB, 0)  # menu item "Indent Lines" from CodeService.InstallControls() generates another INDENT_LINES_ID event, so we'll explicitly disable the tab processing in the editor
 | 
						|
 | 
						|
        wx.stc.EVT_STC_MARGINCLICK(self, self.GetId(), self.OnMarginClick)
 | 
						|
        wx.EVT_KEY_DOWN(self, self.OnKeyPressed)
 | 
						|
        if self.GetMatchingBraces(): 
 | 
						|
            wx.stc.EVT_STC_UPDATEUI(self, self.GetId(), self.OnUpdateUI)
 | 
						|
 | 
						|
        self.StyleClearAll()
 | 
						|
        self.UpdateStyles()
 | 
						|
        
 | 
						|
 | 
						|
    def OnRightUp(self, event):
 | 
						|
        #Hold onto the current line number, no way to get it later.
 | 
						|
        self._rightClickPosition = self.PositionFromPoint(event.GetPosition())
 | 
						|
        self._rightClickLine = self.LineFromPosition(self._rightClickPosition)
 | 
						|
        self.PopupMenu(self.CreatePopupMenu(), event.GetPosition())
 | 
						|
        self._rightClickLine = -1
 | 
						|
        self._rightClickPosition = -1
 | 
						|
        
 | 
						|
 | 
						|
    def CreatePopupMenu(self):
 | 
						|
        TOGGLEBREAKPOINT_ID = wx.NewId()
 | 
						|
        TOGGLEMARKER_ID = wx.NewId()
 | 
						|
        SYNCTREE_ID = wx.NewId()
 | 
						|
        
 | 
						|
        menu = wx.Menu()
 | 
						|
        
 | 
						|
        self.Bind(wx.EVT_MENU, self.OnPopSyncOutline, id=SYNCTREE_ID)
 | 
						|
        item = wx.MenuItem(menu, SYNCTREE_ID, _("Find in Outline View"))
 | 
						|
        menu.AppendItem(item)
 | 
						|
        menu.AppendSeparator()
 | 
						|
        self.Bind(wx.EVT_MENU, self.OnPopToggleBP, id=TOGGLEBREAKPOINT_ID)
 | 
						|
        item = wx.MenuItem(menu, TOGGLEBREAKPOINT_ID, _("Toggle Breakpoint"))
 | 
						|
        menu.AppendItem(item)
 | 
						|
        self.Bind(wx.EVT_MENU, self.OnPopToggleMarker, id=TOGGLEMARKER_ID)
 | 
						|
        item = wx.MenuItem(menu, TOGGLEMARKER_ID, _("Toggle Bookmark"))
 | 
						|
        menu.AppendItem(item)
 | 
						|
        menu.AppendSeparator()
 | 
						|
                
 | 
						|
        itemIDs = [wx.ID_UNDO, wx.ID_REDO, None,
 | 
						|
                   wx.ID_CUT, wx.ID_COPY, wx.ID_PASTE, wx.ID_CLEAR, None, wx.ID_SELECTALL]
 | 
						|
 | 
						|
        menuBar = wx.GetApp().GetTopWindow().GetMenuBar()
 | 
						|
        for itemID in itemIDs:
 | 
						|
            if not itemID:
 | 
						|
                menu.AppendSeparator()
 | 
						|
            else:
 | 
						|
                item = menuBar.FindItemById(itemID)
 | 
						|
                if item:
 | 
						|
                    menu.Append(itemID, item.GetLabel())
 | 
						|
                    wx.EVT_MENU(self, itemID, self.DSProcessEvent)  # wxHack: for customized right mouse menu doesn't work with new DynamicSashWindow
 | 
						|
                    wx.EVT_UPDATE_UI(self, itemID, self.DSProcessUpdateUIEvent)  # wxHack: for customized right mouse menu doesn't work with new DynamicSashWindow
 | 
						|
        return menu
 | 
						|
                
 | 
						|
 | 
						|
    def OnPopToggleBP(self, event):
 | 
						|
        """ Toggle break point on right click line, not current line """
 | 
						|
        import DebuggerService
 | 
						|
        wx.GetApp().GetService(DebuggerService.DebuggerService).OnToggleBreakpoint(event, line=self._rightClickLine)
 | 
						|
      
 | 
						|
  
 | 
						|
    def OnPopToggleMarker(self, event):
 | 
						|
        """ Toggle marker on right click line, not current line """
 | 
						|
        wx.GetApp().GetDocumentManager().GetCurrentView().MarkerToggle(lineNum = self._rightClickLine)
 | 
						|
 | 
						|
 | 
						|
    def OnPopSyncOutline(self, event):
 | 
						|
        wx.GetApp().GetService(OutlineService.OutlineService).LoadOutline(wx.GetApp().GetDocumentManager().GetCurrentView(), position=self._rightClickPosition)
 | 
						|
          
 | 
						|
 | 
						|
    def HasSelection(self):
 | 
						|
        return self.GetSelectionStart() - self.GetSelectionEnd() != 0  
 | 
						|
 | 
						|
 | 
						|
    def ClearCurrentLineMarkers(self):
 | 
						|
        self.MarkerDeleteAll(CodeCtrl.CURRENT_LINE_MARKER_NUM)
 | 
						|
        
 | 
						|
 | 
						|
    def ClearCurrentBreakpoinMarkers(self):
 | 
						|
        self.MarkerDeleteAll(CodeCtrl.BREAKPOINT_MARKER_NUM)
 | 
						|
 | 
						|
 | 
						|
    def GetDefaultFont(self):
 | 
						|
        if wx.Platform == '__WXMSW__':
 | 
						|
            font = "Courier New"
 | 
						|
        else:
 | 
						|
            font = "Courier"
 | 
						|
        return wx.Font(10, wx.DEFAULT, wx.NORMAL, wx.NORMAL, faceName = font)
 | 
						|
 | 
						|
 | 
						|
    def GetMatchingBraces(self):
 | 
						|
        """ Overwrite this method for language specific braces """
 | 
						|
        return "[]{}()"
 | 
						|
 | 
						|
 | 
						|
    def CanWordWrap(self):
 | 
						|
        return False
 | 
						|
        
 | 
						|
 | 
						|
    def SetFont(self, font):
 | 
						|
        self._font = font
 | 
						|
 | 
						|
 | 
						|
    def SetFontColor(self, fontColor):
 | 
						|
        self._fontColor = fontColor
 | 
						|
 | 
						|
 | 
						|
    def UpdateStyles(self):
 | 
						|
 | 
						|
        if not self.GetFont():
 | 
						|
            return
 | 
						|
 | 
						|
        faces = { 'font' : self.GetFont().GetFaceName(),
 | 
						|
                  'size' : self.GetFont().GetPointSize(),
 | 
						|
                  'size2': self.GetFont().GetPointSize() - 2,
 | 
						|
                  'color' : "%02x%02x%02x" % (self.GetFontColor().Red(), self.GetFontColor().Green(), self.GetFontColor().Blue())
 | 
						|
                  }
 | 
						|
 | 
						|
        # Global default styles for all languages
 | 
						|
        self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT,     "face:%(font)s,fore:#FFFFFF,size:%(size)d" % faces)
 | 
						|
        self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,  "face:%(font)s,back:#C0C0C0,face:%(font)s,size:%(size2)d" % faces)
 | 
						|
        self.StyleSetSpec(wx.stc.STC_STYLE_CONTROLCHAR, "face:%(font)s" % faces)
 | 
						|
        self.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,  "face:%(font)s,fore:#000000,back:#70FFFF,size:%(size)d" % faces)
 | 
						|
        self.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,    "face:%(font)s,fore:#000000,back:#FF0000,size:%(size)d" % faces)
 | 
						|
 | 
						|
 | 
						|
    def OnKeyPressed(self, event):
 | 
						|
        if self.CallTipActive():
 | 
						|
            self.CallTipCancel()
 | 
						|
        key = event.KeyCode()
 | 
						|
        if False:  # key == wx.WXK_SPACE and event.ControlDown():
 | 
						|
            pos = self.GetCurrentPos()
 | 
						|
            # Tips
 | 
						|
            if event.ShiftDown():
 | 
						|
                self.CallTipSetBackground("yellow")
 | 
						|
                self.CallTipShow(pos, 'param1, param2')
 | 
						|
            # Code completion
 | 
						|
            else:
 | 
						|
                #lst = []
 | 
						|
                #for x in range(50000):
 | 
						|
                #    lst.append('%05d' % x)
 | 
						|
                #st = string.join(lst)
 | 
						|
                #print len(st)
 | 
						|
                #self.AutoCompShow(0, st)
 | 
						|
 | 
						|
                kw = keyword.kwlist[:]
 | 
						|
                kw.append("zzzzzz")
 | 
						|
                kw.append("aaaaa")
 | 
						|
                kw.append("__init__")
 | 
						|
                kw.append("zzaaaaa")
 | 
						|
                kw.append("zzbaaaa")
 | 
						|
                kw.append("this_is_a_longer_value")
 | 
						|
                kw.append("this_is_a_much_much_much_much_much_much_much_longer_value")
 | 
						|
 | 
						|
                kw.sort()  # Python sorts are case sensitive
 | 
						|
                self.AutoCompSetIgnoreCase(False)  # so this needs to match
 | 
						|
 | 
						|
                self.AutoCompShow(0, string.join(kw))
 | 
						|
        elif key == wx.WXK_RETURN:
 | 
						|
            self.DoIndent()
 | 
						|
        else:
 | 
						|
            STCTextEditor.TextCtrl.OnKeyPressed(self, event)
 | 
						|
 | 
						|
 | 
						|
    def DoIndent(self):
 | 
						|
        self.AddText('\n')
 | 
						|
        self.EnsureCaretVisible()
 | 
						|
        # Need to do a default one for all languges
 | 
						|
 | 
						|
 | 
						|
    def OnMarginClick(self, evt):
 | 
						|
        # fold and unfold as needed
 | 
						|
        if evt.GetMargin() == 2:
 | 
						|
            if evt.GetShift() and evt.GetControl():
 | 
						|
                lineCount = self.GetLineCount()
 | 
						|
                expanding = True
 | 
						|
 | 
						|
                # find out if we are folding or unfolding
 | 
						|
                for lineNum in range(lineCount):
 | 
						|
                    if self.GetFoldLevel(lineNum) & wx.stc.STC_FOLDLEVELHEADERFLAG:
 | 
						|
                        expanding = not self.GetFoldExpanded(lineNum)
 | 
						|
                        break;
 | 
						|
 | 
						|
                self.ToggleFoldAll(expanding)
 | 
						|
            else:
 | 
						|
                lineClicked = self.LineFromPosition(evt.GetPosition())
 | 
						|
                if self.GetFoldLevel(lineClicked) & wx.stc.STC_FOLDLEVELHEADERFLAG:
 | 
						|
                    if evt.GetShift():
 | 
						|
                        self.SetFoldExpanded(lineClicked, True)
 | 
						|
                        self.Expand(lineClicked, True, True, 1)
 | 
						|
                    elif evt.GetControl():
 | 
						|
                        if self.GetFoldExpanded(lineClicked):
 | 
						|
                            self.SetFoldExpanded(lineClicked, False)
 | 
						|
                            self.Expand(lineClicked, False, True, 0)
 | 
						|
                        else:
 | 
						|
                            self.SetFoldExpanded(lineClicked, True)
 | 
						|
                            self.Expand(lineClicked, True, True, 100)
 | 
						|
                    else:
 | 
						|
                        self.ToggleFold(lineClicked)
 | 
						|
 | 
						|
        elif evt.GetMargin() == 0:
 | 
						|
            #This is used to toggle breakpoints via the debugger service.
 | 
						|
            import DebuggerService
 | 
						|
            db_service = wx.GetApp().GetService(DebuggerService.DebuggerService)
 | 
						|
            if db_service:
 | 
						|
                db_service.OnToggleBreakpoint(evt, line=self.LineFromPosition(evt.GetPosition()))
 | 
						|
            
 | 
						|
 | 
						|
    def OnUpdateUI(self, evt):
 | 
						|
        braces = self.GetMatchingBraces()
 | 
						|
        
 | 
						|
        # check for matching braces
 | 
						|
        braceAtCaret = -1
 | 
						|
        braceOpposite = -1
 | 
						|
        charBefore = None
 | 
						|
        caretPos = self.GetCurrentPos()
 | 
						|
        if caretPos > 0:
 | 
						|
            charBefore = self.GetCharAt(caretPos - 1)
 | 
						|
            styleBefore = self.GetStyleAt(caretPos - 1)
 | 
						|
 | 
						|
        # check before
 | 
						|
        if charBefore and chr(charBefore) in braces:
 | 
						|
            braceAtCaret = caretPos - 1
 | 
						|
 | 
						|
        # check after
 | 
						|
        if braceAtCaret < 0:
 | 
						|
            charAfter = self.GetCharAt(caretPos)
 | 
						|
            styleAfter = self.GetStyleAt(caretPos)
 | 
						|
            if charAfter and chr(charAfter) in braces:
 | 
						|
                braceAtCaret = caretPos
 | 
						|
 | 
						|
        if braceAtCaret >= 0:
 | 
						|
            braceOpposite = self.BraceMatch(braceAtCaret)
 | 
						|
 | 
						|
        if braceAtCaret != -1  and braceOpposite == -1:
 | 
						|
            self.BraceBadLight(braceAtCaret)
 | 
						|
        else:
 | 
						|
            self.BraceHighlight(braceAtCaret, braceOpposite)
 | 
						|
 | 
						|
        evt.Skip()
 | 
						|
 | 
						|
 | 
						|
    def ToggleFoldAll(self, expand = True, topLevelOnly = False):
 | 
						|
        i = 0
 | 
						|
        lineCount = self.GetLineCount()
 | 
						|
        while i < lineCount:
 | 
						|
            if not topLevelOnly or (topLevelOnly and self.GetFoldLevel(i) & wx.stc.STC_FOLDLEVELNUMBERMASK  == wx.stc.STC_FOLDLEVELBASE):
 | 
						|
                if (expand and self.CanLineExpand(i)) or (not expand and self.CanLineCollapse(i)):
 | 
						|
                    self.ToggleFold(i)
 | 
						|
            i = i + 1
 | 
						|
 | 
						|
 | 
						|
    def CanLineExpand(self, line):
 | 
						|
        return not self.GetFoldExpanded(line)
 | 
						|
 | 
						|
 | 
						|
    def CanLineCollapse(self, line):
 | 
						|
        return self.GetFoldExpanded(line) and self.GetFoldLevel(line) & wx.stc.STC_FOLDLEVELHEADERFLAG
 | 
						|
 | 
						|
 | 
						|
    def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
 | 
						|
        lastChild = self.GetLastChild(line, level)
 | 
						|
        line = line + 1
 | 
						|
        while line <= lastChild:
 | 
						|
            if force:
 | 
						|
                if visLevels > 0:
 | 
						|
                    self.ShowLines(line, line)
 | 
						|
                else:
 | 
						|
                    self.HideLines(line, line)
 | 
						|
            else:
 | 
						|
                if doExpand:
 | 
						|
                    self.ShowLines(line, line)
 | 
						|
 | 
						|
            if level == -1:
 | 
						|
                level = self.GetFoldLevel(line)
 | 
						|
 | 
						|
            if level & wx.stc.STC_FOLDLEVELHEADERFLAG:
 | 
						|
                if force:
 | 
						|
                    if visLevels > 1:
 | 
						|
                        self.SetFoldExpanded(line, True)
 | 
						|
                    else:
 | 
						|
                        self.SetFoldExpanded(line, False)
 | 
						|
                    line = self.Expand(line, doExpand, force, visLevels-1)
 | 
						|
 | 
						|
                else:
 | 
						|
                    if doExpand and self.GetFoldExpanded(line):
 | 
						|
                        line = self.Expand(line, True, force, visLevels-1)
 | 
						|
                    else:
 | 
						|
                        line = self.Expand(line, False, force, visLevels-1)
 | 
						|
            else:
 | 
						|
                line = line + 1;
 | 
						|
 | 
						|
        return line
 | 
						|
 | 
						|
 |