1 #---------------------------------------------------------------------------- 
   3 # Purpose:      Abstract Code Editor for pydocview tbat uses the Styled Text Control 
   9 # Copyright:    (c) 2004-2005 ActiveGrid, Inc. 
  10 # License:      wxWindows License 
  11 #---------------------------------------------------------------------------- 
  22 import DebuggerService
 
  25 if wx
.Platform 
== '__WXMSW__': 
  31 EXPAND_TEXT_ID 
= wx
.NewId() 
  32 COLLAPSE_TEXT_ID 
= wx
.NewId() 
  33 EXPAND_TOP_ID 
= wx
.NewId() 
  34 COLLAPSE_TOP_ID 
= wx
.NewId() 
  35 EXPAND_ALL_ID 
= wx
.NewId() 
  36 COLLAPSE_ALL_ID 
= wx
.NewId() 
  37 CHECK_CODE_ID 
= wx
.NewId() 
  38 AUTO_COMPLETE_ID 
= wx
.NewId() 
  39 CLEAN_WHITESPACE 
= wx
.NewId() 
  40 COMMENT_LINES_ID 
= wx
.NewId() 
  41 UNCOMMENT_LINES_ID 
= wx
.NewId() 
  42 INDENT_LINES_ID 
= wx
.NewId() 
  43 DEDENT_LINES_ID 
= wx
.NewId() 
  44 USE_TABS_ID 
= wx
.NewId() 
  45 SET_INDENT_WIDTH_ID 
= wx
.NewId() 
  46 FOLDING_ID 
= wx
.NewId() 
  49 class CodeDocument(STCTextEditor
.TextDocument
): 
  53 class CodeView(STCTextEditor
.TextView
): 
  56     #---------------------------------------------------------------------------- 
  58     #---------------------------------------------------------------------------- 
  61     def GetCtrlClass(self
): 
  62         """ Used in split window to instantiate new instances """ 
  66     def ProcessEvent(self
, event
): 
  68         if id == EXPAND_TEXT_ID
: 
  69             self
.GetCtrl().ToggleFold(self
.GetCtrl().GetCurrentLine()) 
  71         elif id == COLLAPSE_TEXT_ID
: 
  72             self
.GetCtrl().ToggleFold(self
.GetCtrl().GetCurrentLine()) 
  74         elif id == EXPAND_TOP_ID
: 
  75             self
.GetCtrl().ToggleFoldAll(expand 
= True, topLevelOnly 
= True) 
  77         elif id == COLLAPSE_TOP_ID
: 
  78             self
.GetCtrl().ToggleFoldAll(expand 
= False, topLevelOnly 
= True) 
  80         elif id == EXPAND_ALL_ID
: 
  81             self
.GetCtrl().ToggleFoldAll(expand 
= True) 
  83         elif id == COLLAPSE_ALL_ID
: 
  84             self
.GetCtrl().ToggleFoldAll(expand 
= False) 
  86         elif id == CHECK_CODE_ID
: 
  89         elif id == AUTO_COMPLETE_ID
: 
  92         elif id == CLEAN_WHITESPACE
: 
  93             self
.OnCleanWhiteSpace() 
  95         elif id == SET_INDENT_WIDTH_ID
: 
  96             self
.OnSetIndentWidth() 
  98         elif id == USE_TABS_ID
: 
  99             self
.GetCtrl().SetUseTabs(not self
.GetCtrl().GetUseTabs()) 
 101         elif id == INDENT_LINES_ID
: 
 102             self
.GetCtrl().CmdKeyExecute(wx
.stc
.STC_CMD_TAB
) 
 104         elif id == DEDENT_LINES_ID
: 
 105             self
.GetCtrl().CmdKeyExecute(wx
.stc
.STC_CMD_BACKTAB
) 
 107         elif id == COMMENT_LINES_ID
: 
 108             self
.OnCommentLines() 
 110         elif id == UNCOMMENT_LINES_ID
: 
 111             self
.OnUncommentLines() 
 114             return STCTextEditor
.TextView
.ProcessEvent(self
, event
) 
 117     def ProcessUpdateUIEvent(self
, event
): 
 118         if not self
.GetCtrl(): 
 120         hasText 
= self
.GetCtrl().GetTextLength() > 0 
 122         if id == EXPAND_TEXT_ID
: 
 123             event
.Enable(self
.GetCtrl().CanLineExpand(self
.GetCtrl().GetCurrentLine())) 
 125         elif id == COLLAPSE_TEXT_ID
: 
 126             event
.Enable(self
.GetCtrl().CanLineCollapse(self
.GetCtrl().GetCurrentLine())) 
 128         elif id == EXPAND_TOP_ID
: 
 129             event
.Enable(hasText
) 
 131         elif id == COLLAPSE_TOP_ID
: 
 132             event
.Enable(hasText
) 
 134         elif id == EXPAND_ALL_ID
: 
 135             event
.Enable(hasText
) 
 137         elif id == COLLAPSE_ALL_ID
: 
 138             event
.Enable(hasText
) 
 140         elif id == CHECK_CODE_ID
: 
 143         elif id == AUTO_COMPLETE_ID
: 
 144             event
.Enable(hasText
) 
 146         elif id == CLEAN_WHITESPACE
: 
 147             event
.Enable(hasText
) 
 149         elif id == SET_INDENT_WIDTH_ID
: 
 152         elif id == USE_TABS_ID
: 
 154             event
.Check(self
.GetCtrl().GetUseTabs()) 
 156         elif id == INDENT_LINES_ID
: 
 157             event
.Enable(hasText
) 
 159         elif id == DEDENT_LINES_ID
: 
 160             event
.Enable(hasText
) 
 162         elif id == COMMENT_LINES_ID
: 
 163             event
.Enable(hasText
) 
 165         elif id == UNCOMMENT_LINES_ID
: 
 166             event
.Enable(hasText
) 
 168         elif id == FOLDING_ID
: 
 172             return STCTextEditor
.TextView
.ProcessUpdateUIEvent(self
, event
) 
 175     #---------------------------------------------------------------------------- 
 176     # Methods for OutlineService 
 177     #---------------------------------------------------------------------------- 
 179     def OnChangeFilename(self
): 
 180         wx
.lib
.docview
.View
.OnChangeFilename(self
) 
 181         self
.LoadOutline(force
=True) 
 184     def ClearOutline(self
): 
 185         outlineService 
= wx
.GetApp().GetService(OutlineService
.OutlineService
) 
 186         if not outlineService
: 
 189         outlineView 
= outlineService
.GetView() 
 193         outlineView
.ClearTreeCtrl() 
 196     def LoadOutline(self
, force
=False): 
 197         outlineService 
= wx
.GetApp().GetService(OutlineService
.OutlineService
) 
 198         if not outlineService
: 
 200         outlineService
.LoadOutline(self
, force
=force
) 
 203     def DoLoadOutlineCallback(self
, force
=False): 
 204         outlineService 
= wx
.GetApp().GetService(OutlineService
.OutlineService
) 
 205         if not outlineService
: 
 208         outlineView 
= outlineService
.GetView() 
 212         treeCtrl 
= outlineView
.GetTreeCtrl() 
 216         view 
= treeCtrl
.GetCallbackView() 
 217         newCheckSum 
= self
.GenCheckSum() 
 219             if view 
and view 
is self
: 
 220                 if self
._checkSum 
== newCheckSum
: 
 222         self
._checkSum 
= newCheckSum
 
 224         treeCtrl
.DeleteAllItems() 
 226         document 
= self
.GetDocument() 
 230         filename 
= document
.GetFilename() 
 232             rootItem 
= treeCtrl
.AddRoot(os
.path
.basename(filename
)) 
 233             treeCtrl
.SetDoSelectCallback(rootItem
, self
, None) 
 237         text 
= self
.GetValue() 
 241         CLASS_PATTERN 
= 'class[ \t]+\w+.*?:' 
 242         DEF_PATTERN 
= 'def[ \t]+\w+\(.*?\)' 
 243         classPat 
= re
.compile(CLASS_PATTERN
, re
.M|re
.S
) 
 244         defPat
= re
.compile(DEF_PATTERN
, re
.M|re
.S
) 
 245         pattern 
= re
.compile('^[ \t]*((' + CLASS_PATTERN 
+ ')|('+ DEF_PATTERN 
+'.*?:)).*?$', re
.M|re
.S
) 
 247         iter = pattern
.finditer(text
) 
 248         indentStack 
= [(0, rootItem
)] 
 250             line 
= pattern
.string
[pattern
.start(0):pattern
.end(0)] 
 251             classLine 
= classPat
.search(line
) 
 253                 indent 
= classLine
.start(0) 
 254                 itemStr 
= classLine
.string
[classLine
.start(0):classLine
.end(0)-1]  # don't take the closing ':' 
 256                 defLine 
= defPat
.search(line
) 
 258                     indent 
= defLine
.start(0) 
 259                     itemStr 
= defLine
.string
[defLine
.start(0):defLine
.end(0)] 
 262                 parentItem 
= rootItem
 
 264                 lastItem 
= indentStack
.pop() 
 265                 while lastItem
[0] >= indent
: 
 266                     lastItem 
= indentStack
.pop() 
 267                 indentStack
.append(lastItem
) 
 268                 parentItem 
= lastItem
[1] 
 270             item 
= treeCtrl
.AppendItem(parentItem
, itemStr
) 
 271             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 
 272             indentStack
.append((indent
, item
)) 
 274         treeCtrl
.Expand(rootItem
) 
 279     def DoSelectCallback(self
, data
): 
 281             self
.EnsureVisibleEnforcePolicy(self
.LineFromPosition(data
[0])) 
 282             # wxBug: need to select in reverse order (end, start) to place cursor at begining of line, 
 283             #        otherwise, display is scrolled over to the right hard and is hard to view 
 284             self
.SetSelection(data
[1], data
[0]) 
 287 ##    def checksum(self, bytes):         
 288 ##        def rotate_right(c): 
 290 ##                return (c>>1)|0x8000 
 296 ##            ch = ord(ch) & 0xFF 
 297 ##            result = (rotate_right(result)+ch) & 0xFFFF 
 301     def GenCheckSum(self
): 
 302         """ Poor man's checksum.  We'll assume most changes will change the length of the file. 
 304         text 
= self
.GetValue() 
 311     #---------------------------------------------------------------------------- 
 313     #---------------------------------------------------------------------------- 
 315     def OnCheckCode(self
): 
 316         """ Need to overshadow this for each specific subclass """ 
 319                 code 
= self
.GetCtrl().GetText() 
 320                 codeObj 
= compile(code
, self
.GetDocument().GetFilename(), 'exec') 
 321                 self
._GetParentFrame
().SetStatusText(_("The file successfully compiled")) 
 322             except SyntaxError, (message
, (fileName
, line
, col
, text
)): 
 323                 pos 
= self
.GetCtrl().PositionFromLine(line 
- 1) + col 
- 1 
 324                 self
.GetCtrl().SetSelection(pos
, pos
) 
 325                 self
._GetParentFrame
().SetStatusText(_("Syntax Error: %s") % message
) 
 327                 self
._GetParentFrame
().SetStatusText(sys
.exc_info()[0]) 
 330     def OnAutoComplete(self
): 
 331         self
.GetCtrl().AutoCompCancel() 
 332         self
.GetCtrl().AutoCompSetAutoHide(0) 
 333         self
.GetCtrl().AutoCompSetChooseSingle(True) 
 334         self
.GetCtrl().AutoCompSetIgnoreCase(True) 
 335         context
, hint 
= self
.GetAutoCompleteHint() 
 336         replaceList
, replaceLen 
= self
.GetAutoCompleteKeywordList(context
, hint
) 
 337         if replaceList 
and len(replaceList
) != 0:  
 338             self
.GetCtrl().AutoCompShow(replaceLen
, replaceList
) 
 341     def GetAutoCompleteHint(self
): 
 342         """ Replace this method with Editor specific method """ 
 343         pos 
= self
.GetCtrl().GetCurrentPos() 
 346         if chr(self
.GetCtrl().GetCharAt(pos 
- 1)) == '.': 
 352         validLetters 
= string
.letters 
+ string
.digits 
+ '_.' 
 358             char 
= chr(self
.GetCtrl().GetCharAt(pos
)) 
 359             if char 
not in validLetters
: 
 365             lastDot 
= word
.rfind('.') 
 367                 context 
= word
[0:lastDot
] 
 368                 hint 
= word
[lastDot
+1:] 
 373     def GetAutoCompleteDefaultKeywords(self
): 
 374         """ Replace this method with Editor specific keywords """ 
 375         return ['Put', 'Editor Specific', 'Keywords', 'Here'] 
 378     def CaseInsensitiveCompare(self
, s1
, s2
): 
 379         """ GetAutoCompleteKeywordList() method used to show keywords in case insensitive order """ 
 390     def GetAutoCompleteKeywordList(self
, context
, hint
):             
 391         """ Replace this method with Editor specific keywords """ 
 392         kw 
= self
.GetAutoCompleteDefaultKeywords() 
 394         if hint 
and len(hint
): 
 395             lowerHint 
= hint
.lower() 
 396             filterkw 
= filter(lambda item
: item
.lower().startswith(lowerHint
), kw
)  # remove variables and methods that don't match hint 
 400             replaceLen 
= len(hint
) 
 404         kw
.sort(self
.CaseInsensitiveCompare
) 
 405         return " ".join(kw
), replaceLen
 
 408     def OnCleanWhiteSpace(self
): 
 410         for lineNo 
in self
._GetSelectedLineNumbers
(): 
 411             lineText 
= string
.rstrip(self
.GetCtrl().GetLine(lineNo
)) 
 414             for char 
in lineText
: 
 416                     indent 
= indent 
+ self
.GetCtrl().GetIndent() 
 418                 elif char 
in string
.whitespace
: 
 423             if self
.GetCtrl().GetUseTabs(): 
 424                 indentText 
= (indent 
/ self
.GetCtrl().GetIndent()) * '\t' + (indent 
% self
.GetCtrl().GetIndent()) * ' ' 
 426                 indentText 
= indent 
* ' ' 
 427             lineText 
= indentText 
+ lineText
[lstrip
:] + '\n' 
 428             newText 
= newText 
+ lineText
 
 429         self
._ReplaceSelectedLines
(newText
) 
 432     def OnSetIndentWidth(self
): 
 433         dialog 
= wx
.TextEntryDialog(self
._GetParentFrame
(), _("Enter new indent width (2-10):"), _("Set Indent Width"), "%i" % self
.GetCtrl().GetIndent()) 
 434         if dialog
.ShowModal() == wx
.ID_OK
: 
 436                 indent 
= int(dialog
.GetValue()) 
 437                 if indent 
>= 2 and indent 
<= 10: 
 438                     self
.GetCtrl().SetIndent(indent
) 
 439                     self
.GetCtrl().SetTabWidth(indent
) 
 445     def GetIndentWidth(self
): 
 446         return self
.GetCtrl().GetIndent() 
 449     def OnCommentLines(self
): 
 451         for lineNo 
in self
._GetSelectedLineNumbers
(): 
 452             lineText 
= self
.GetCtrl().GetLine(lineNo
) 
 453             if (len(lineText
) > 1 and lineText
[0] == '#') or (len(lineText
) > 2 and lineText
[:2] == '##'): 
 454                 newText 
= newText 
+ lineText
 
 456                 newText 
= newText 
+ "##" + lineText
 
 457         self
._ReplaceSelectedLines
(newText
) 
 460     def OnUncommentLines(self
): 
 462         for lineNo 
in self
._GetSelectedLineNumbers
(): 
 463             lineText 
= self
.GetCtrl().GetLine(lineNo
) 
 464             if len(lineText
) >= 2 and lineText
[:2] == "##": 
 465                 lineText 
= lineText
[2:] 
 466             elif len(lineText
) >= 1 and lineText
[:1] == "#": 
 467                 lineText 
= lineText
[1:] 
 468             newText 
= newText 
+ lineText
 
 469         self
._ReplaceSelectedLines
(newText
) 
 472     def _GetSelectedLineNumbers(self
): 
 473         selStart
, selEnd 
= self
._GetPositionsBoundingSelectedLines
() 
 474         return range(self
.GetCtrl().LineFromPosition(selStart
), self
.GetCtrl().LineFromPosition(selEnd
)) 
 477     def _GetPositionsBoundingSelectedLines(self
): 
 478         startPos 
= self
.GetCtrl().GetCurrentPos() 
 479         endPos 
= self
.GetCtrl().GetAnchor() 
 480         if startPos 
> endPos
: 
 484         if endPos 
== self
.GetCtrl().PositionFromLine(self
.GetCtrl().LineFromPosition(endPos
)): 
 485             endPos 
= endPos 
- 1  # If it's at the very beginning of a line, use the line above it as the ending line 
 486         selStart 
= self
.GetCtrl().PositionFromLine(self
.GetCtrl().LineFromPosition(startPos
)) 
 487         selEnd 
= self
.GetCtrl().PositionFromLine(self
.GetCtrl().LineFromPosition(endPos
) + 1) 
 488         return selStart
, selEnd
 
 491     def _ReplaceSelectedLines(self
, text
): 
 494         selStart
, selEnd 
= self
._GetPositionsBoundingSelectedLines
() 
 495         self
.GetCtrl().SetSelection(selStart
, selEnd
) 
 496         self
.GetCtrl().ReplaceSelection(text
) 
 497         self
.GetCtrl().SetSelection(selStart 
+ len(text
), selStart
) 
 500     def OnUpdate(self
, sender 
= None, hint 
= None): 
 501         if hint 
== "ViewStuff": 
 502             self
.GetCtrl().SetViewDefaults() 
 504             font
, color 
= self
.GetFontAndColorFromConfig() 
 505             self
.GetCtrl().SetFont(font
) 
 506             self
.GetCtrl().SetFontColor(color
) 
 508             dbg_service 
= wx
.GetApp().GetService(DebuggerService
.DebuggerService
) 
 510                 dbg_service
.SetCurrentBreakpointMarkers(self
) 
 513 class CodeService(STCTextEditor
.TextService
): 
 517         STCTextEditor
.TextService
.__init
__(self
) 
 520     def InstallControls(self
, frame
, menuBar 
= None, toolBar 
= None, statusBar 
= None, document 
= None): 
 521         # TODO NEED TO DO INSTANCEOF CHECK HERE FOR SDI 
 522         #if document and document.GetDocumentTemplate().GetDocumentType() != TextDocument: 
 524         if not document 
and wx
.GetApp().GetDocumentManager().GetFlags() & wx
.lib
.docview
.DOC_SDI
: 
 527         viewMenu 
= menuBar
.GetMenu(menuBar
.FindMenu(_("&View"))) 
 528         isWindows 
= (wx
.Platform 
== '__WXMSW__') 
 530         if not menuBar
.FindItemById(EXPAND_TEXT_ID
):  # check if below menu items have been already been installed 
 531             foldingMenu 
= wx
.Menu() 
 533                 foldingMenu
.Append(EXPAND_TEXT_ID
, _("&Expand\tNumpad-Plus"), _("Expands a collapsed block of text")) 
 535                 foldingMenu
.Append(EXPAND_TEXT_ID
, _("&Expand"), _("Expands a collapsed block of text")) 
 537             wx
.EVT_MENU(frame
, EXPAND_TEXT_ID
, frame
.ProcessEvent
) 
 538             wx
.EVT_UPDATE_UI(frame
, EXPAND_TEXT_ID
, frame
.ProcessUpdateUIEvent
) 
 541                 foldingMenu
.Append(COLLAPSE_TEXT_ID
, _("&Collapse\tNumpad+Minus"), _("Collapse a block of text")) 
 543                 foldingMenu
.Append(COLLAPSE_TEXT_ID
, _("&Collapse"), _("Collapse a block of text")) 
 544             wx
.EVT_MENU(frame
, COLLAPSE_TEXT_ID
, frame
.ProcessEvent
) 
 545             wx
.EVT_UPDATE_UI(frame
, COLLAPSE_TEXT_ID
, frame
.ProcessUpdateUIEvent
) 
 548                 foldingMenu
.Append(EXPAND_TOP_ID
, _("Expand &Top Level\tCtrl+Numpad+Plus"), _("Expands the top fold levels in the document")) 
 550                 foldingMenu
.Append(EXPAND_TOP_ID
, _("Expand &Top Level"), _("Expands the top fold levels in the document")) 
 551             wx
.EVT_MENU(frame
, EXPAND_TOP_ID
, frame
.ProcessEvent
) 
 552             wx
.EVT_UPDATE_UI(frame
, EXPAND_TOP_ID
, frame
.ProcessUpdateUIEvent
) 
 555                 foldingMenu
.Append(COLLAPSE_TOP_ID
, _("Collapse Top &Level\tCtrl+Numpad+Minus"), _("Collapses the top fold levels in the document")) 
 557                 foldingMenu
.Append(COLLAPSE_TOP_ID
, _("Collapse Top &Level"), _("Collapses the top fold levels in the document")) 
 558             wx
.EVT_MENU(frame
, COLLAPSE_TOP_ID
, frame
.ProcessEvent
) 
 559             wx
.EVT_UPDATE_UI(frame
, COLLAPSE_TOP_ID
, frame
.ProcessUpdateUIEvent
) 
 562                 foldingMenu
.Append(EXPAND_ALL_ID
, _("Expand &All\tShift+Numpad+Plus"), _("Expands all of the fold levels in the document")) 
 564                 foldingMenu
.Append(EXPAND_ALL_ID
, _("Expand &All"), _("Expands all of the fold levels in the document")) 
 565             wx
.EVT_MENU(frame
, EXPAND_ALL_ID
, frame
.ProcessEvent
) 
 566             wx
.EVT_UPDATE_UI(frame
, EXPAND_ALL_ID
, frame
.ProcessUpdateUIEvent
) 
 569                 foldingMenu
.Append(COLLAPSE_ALL_ID
, _("Colla&pse All\tShift+Numpad+Minus"), _("Collapses all of the fold levels in the document")) 
 571                 foldingMenu
.Append(COLLAPSE_ALL_ID
, _("Colla&pse All"), _("Collapses all of the fold levels in the document")) 
 572             wx
.EVT_MENU(frame
, COLLAPSE_ALL_ID
, frame
.ProcessEvent
) 
 573             wx
.EVT_UPDATE_UI(frame
, COLLAPSE_ALL_ID
, frame
.ProcessUpdateUIEvent
) 
 575             viewMenu
.AppendMenu(FOLDING_ID
, _("&Folding"), foldingMenu
) 
 576             wx
.EVT_UPDATE_UI(frame
, FOLDING_ID
, frame
.ProcessUpdateUIEvent
) 
 578         formatMenuIndex 
= menuBar
.FindMenu(_("&Format")) 
 579         if formatMenuIndex 
> -1: 
 580             formatMenu 
= menuBar
.GetMenu(formatMenuIndex
) 
 582             formatMenu 
= wx
.Menu() 
 583         if not menuBar
.FindItemById(CHECK_CODE_ID
):  # check if below menu items have been already been installed 
 584             formatMenu
.AppendSeparator() 
 585             formatMenu
.Append(CHECK_CODE_ID
, _("&Check Code"), _("Checks the document for syntax and indentation errors")) 
 586             wx
.EVT_MENU(frame
, CHECK_CODE_ID
, frame
.ProcessEvent
) 
 587             wx
.EVT_UPDATE_UI(frame
, CHECK_CODE_ID
, frame
.ProcessUpdateUIEvent
) 
 588             formatMenu
.Append(AUTO_COMPLETE_ID
, _("&Auto Complete\tCtrl+Space"), _("Provides suggestions on how to complete the current statement")) 
 589             wx
.EVT_MENU(frame
, AUTO_COMPLETE_ID
, frame
.ProcessEvent
) 
 590             wx
.EVT_UPDATE_UI(frame
, AUTO_COMPLETE_ID
, frame
.ProcessUpdateUIEvent
) 
 591             formatMenu
.Append(CLEAN_WHITESPACE
, _("Clean &Whitespace"), _("Converts leading spaces to tabs or vice versa per 'use tabs' and clears trailing spaces")) 
 592             wx
.EVT_MENU(frame
, CLEAN_WHITESPACE
, frame
.ProcessEvent
) 
 593             wx
.EVT_UPDATE_UI(frame
, CLEAN_WHITESPACE
, frame
.ProcessUpdateUIEvent
) 
 594             formatMenu
.AppendSeparator() 
 595             formatMenu
.Append(INDENT_LINES_ID
, _("&Indent Lines\tTab"), _("Indents the selected lines one indent width")) 
 596             wx
.EVT_MENU(frame
, INDENT_LINES_ID
, frame
.ProcessEvent
) 
 597             wx
.EVT_UPDATE_UI(frame
, INDENT_LINES_ID
, frame
.ProcessUpdateUIEvent
) 
 598             formatMenu
.Append(DEDENT_LINES_ID
, _("&Dedent Lines\tShift+Tab"), _("Dedents the selected lines one indent width")) 
 599             wx
.EVT_MENU(frame
, DEDENT_LINES_ID
, frame
.ProcessEvent
) 
 600             wx
.EVT_UPDATE_UI(frame
, DEDENT_LINES_ID
, frame
.ProcessUpdateUIEvent
) 
 601             formatMenu
.Append(COMMENT_LINES_ID
, _("Comment &Lines\tCtrl+Q"), _("Comments out the selected lines be prefixing each one with a comment indicator")) 
 602             wx
.EVT_MENU(frame
, COMMENT_LINES_ID
, frame
.ProcessEvent
) 
 603             wx
.EVT_UPDATE_UI(frame
, COMMENT_LINES_ID
, frame
.ProcessUpdateUIEvent
) 
 604             formatMenu
.Append(UNCOMMENT_LINES_ID
, _("&Uncomment Lines\tCtrl+Shift+Q"), _("Removes comment prefixes from each of the selected lines")) 
 605             wx
.EVT_MENU(frame
, UNCOMMENT_LINES_ID
, frame
.ProcessEvent
) 
 606             wx
.EVT_UPDATE_UI(frame
, UNCOMMENT_LINES_ID
, frame
.ProcessUpdateUIEvent
) 
 607             formatMenu
.AppendSeparator() 
 608             formatMenu
.AppendCheckItem(USE_TABS_ID
, _("Use &Tabs"), _("Toggles use of tabs or whitespaces for indents")) 
 609             wx
.EVT_MENU(frame
, USE_TABS_ID
, frame
.ProcessEvent
) 
 610             wx
.EVT_UPDATE_UI(frame
, USE_TABS_ID
, frame
.ProcessUpdateUIEvent
) 
 611             formatMenu
.Append(SET_INDENT_WIDTH_ID
, _("&Set Indent Width..."), _("Sets the indent width")) 
 612             wx
.EVT_MENU(frame
, SET_INDENT_WIDTH_ID
, frame
.ProcessEvent
) 
 613             wx
.EVT_UPDATE_UI(frame
, SET_INDENT_WIDTH_ID
, frame
.ProcessUpdateUIEvent
) 
 614         if formatMenuIndex 
== -1: 
 615             viewMenuIndex 
= menuBar
.FindMenu(_("&View")) 
 616             menuBar
.Insert(viewMenuIndex 
+ 1, formatMenu
, _("&Format")) 
 618 ##        accelTable = wx.AcceleratorTable([ 
 619 ##            (wx.ACCEL_NORMAL, wx.WXK_TAB, INDENT_LINES_ID), 
 620 ##            (wx.ACCEL_SHIFT, wx.WXK_TAB, DEDENT_LINES_ID), 
 621 ##            eval(_("wx.ACCEL_CTRL, ord('Q'), COMMENT_LINES_ID")), 
 622 ##            eval(_("wx.ACCEL_CTRL | wx.ACCEL_SHIFT, ord('Q'), UNCOMMENT_LINES_ID")) 
 624 ##        frame.SetAcceleratorTable(accelTable) 
 626     def ProcessUpdateUIEvent(self
, event
): 
 628         if id == EXPAND_TEXT_ID
: 
 631         elif id == COLLAPSE_TEXT_ID
: 
 634         elif id == EXPAND_TOP_ID
: 
 637         elif id == COLLAPSE_TOP_ID
: 
 640         elif id == EXPAND_ALL_ID
: 
 643         elif id == COLLAPSE_ALL_ID
: 
 646         elif id == CHECK_CODE_ID
: 
 649         elif id == AUTO_COMPLETE_ID
: 
 652         elif id == CLEAN_WHITESPACE
: 
 655         elif id == SET_INDENT_WIDTH_ID
: 
 658         elif id == USE_TABS_ID
: 
 661         elif id == INDENT_LINES_ID
: 
 664         elif id == DEDENT_LINES_ID
: 
 667         elif id == COMMENT_LINES_ID
: 
 670         elif id == UNCOMMENT_LINES_ID
: 
 673         elif id == FOLDING_ID
: 
 677             return STCTextEditor
.TextService
.ProcessUpdateUIEvent(self
, event
) 
 680 class CodeCtrl(STCTextEditor
.TextCtrl
): 
 681     CURRENT_LINE_MARKER_NUM 
= 2 
 682     BREAKPOINT_MARKER_NUM 
= 1 
 683     CURRENT_LINE_MARKER_MASK 
= 0x4 
 684     BREAKPOINT_MARKER_MASK 
= 0x2 
 687     def __init__(self
, parent
, ID 
= -1, style 
= wx
.NO_FULL_REPAINT_ON_RESIZE
): 
 690         STCTextEditor
.TextCtrl
.__init
__(self
, parent
, ID
, style
) 
 693         self
.Bind(wx
.EVT_RIGHT_UP
, self
.OnRightUp
) 
 694         self
.SetProperty("fold", "1") 
 696         # Setup a margin to hold fold markers 
 697         #self.SetFoldFlags(16)  ###  WHAT IS THIS VALUE?  WHAT ARE THE OTHER FLAGS?  DOES IT MATTER? 
 698         self
.SetMarginType(2, wx
.stc
.STC_MARGIN_SYMBOL
) 
 699         self
.SetMarginMask(2, wx
.stc
.STC_MASK_FOLDERS
) 
 700         self
.SetMarginSensitive(2, True) 
 701         self
.SetMarginWidth(2, 12) 
 703         self
.SetMarginSensitive(1, False) 
 704         self
.SetMarginMask(1, 0x4) 
 706         self
.SetMarginSensitive(0, True) 
 707         self
.SetMarginType(0, wx
.stc
.STC_MARGIN_SYMBOL
) 
 708         self
.SetMarginMask(0, 0x3) 
 709         self
.SetMarginWidth(0, 12) 
 711         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDEREND
,     wx
.stc
.STC_MARK_BOXPLUSCONNECTED
,  "white", "black") 
 712         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDEROPENMID
, wx
.stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black") 
 713         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDERMIDTAIL
, wx
.stc
.STC_MARK_TCORNER
,  "white", "black") 
 714         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDERTAIL
,    wx
.stc
.STC_MARK_LCORNER
,  "white", "black") 
 715         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDERSUB
,     wx
.stc
.STC_MARK_VLINE
,    "white", "black") 
 716         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDER
,        wx
.stc
.STC_MARK_BOXPLUS
,  "white", "black") 
 717         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDEROPEN
,    wx
.stc
.STC_MARK_BOXMINUS
, "white", "black") 
 718         # Define the current line marker 
 719         self
.MarkerDefine(CodeCtrl
.CURRENT_LINE_MARKER_NUM
, wx
.stc
.STC_MARK_SHORTARROW
, wx
.BLACK
, (255,255,128)) 
 720         # Define the breakpoint marker 
 721         self
.MarkerDefine(CodeCtrl
.BREAKPOINT_MARKER_NUM
, wx
.stc
.STC_MARK_CIRCLE
, wx
.BLACK
, (255,0,0)) 
 723         if _WINDOWS
:  # should test to see if menu item exists, if it does, add this workaround 
 724             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 
 726         wx
.stc
.EVT_STC_MARGINCLICK(self
, ID
, self
.OnMarginClick
) 
 727         wx
.EVT_KEY_DOWN(self
, self
.OnKeyPressed
) 
 728         if self
.GetMatchingBraces():  
 729             wx
.stc
.EVT_STC_UPDATEUI(self
, ID
, self
.OnUpdateUI
) 
 735     def OnRightUp(self
, event
): 
 736         #Hold onto the current line number, no way to get it later. 
 737         self
._rightClickPosition 
= self
.PositionFromPoint(event
.GetPosition()) 
 738         self
._rightClickLine 
= self
.LineFromPosition(self
._rightClickPosition
) 
 739         self
.PopupMenu(self
.CreatePopupMenu(), event
.GetPosition()) 
 740         self
._rightClickLine 
= -1 
 741         self
._rightClickPosition 
= -1 
 744     def CreatePopupMenu(self
): 
 745         TOGGLEBREAKPOINT_ID 
= wx
.NewId() 
 746         TOGGLEMARKER_ID 
= wx
.NewId() 
 747         SYNCTREE_ID 
= wx
.NewId() 
 751         self
.Bind(wx
.EVT_MENU
, self
.OnPopSyncOutline
, id=SYNCTREE_ID
) 
 752         item 
= wx
.MenuItem(menu
, SYNCTREE_ID
, _("Find in Outline View")) 
 753         menu
.AppendItem(item
) 
 754         menu
.AppendSeparator() 
 755         self
.Bind(wx
.EVT_MENU
, self
.OnPopToggleBP
, id=TOGGLEBREAKPOINT_ID
) 
 756         item 
= wx
.MenuItem(menu
, TOGGLEBREAKPOINT_ID
, _("Toggle Breakpoint")) 
 757         menu
.AppendItem(item
) 
 758         self
.Bind(wx
.EVT_MENU
, self
.OnPopToggleMarker
, id=TOGGLEMARKER_ID
) 
 759         item 
= wx
.MenuItem(menu
, TOGGLEMARKER_ID
, _("Toggle Marker")) 
 760         menu
.AppendItem(item
) 
 761         menu
.AppendSeparator() 
 763         itemIDs 
= [wx
.ID_UNDO
, wx
.ID_REDO
, None, 
 764                    wx
.ID_CUT
, wx
.ID_COPY
, wx
.ID_PASTE
, wx
.ID_CLEAR
, None, wx
.ID_SELECTALL
] 
 766         menuBar 
= wx
.GetApp().GetTopWindow().GetMenuBar() 
 767         for itemID 
in itemIDs
: 
 769                 menu
.AppendSeparator() 
 771                 item 
= menuBar
.FindItemById(itemID
) 
 773                     menu
.Append(itemID
, item
.GetLabel()) 
 778     def OnPopToggleBP(self
, event
): 
 779         """ Toggle break point on right click line, not current line """ 
 780         wx
.GetApp().GetService(DebuggerService
.DebuggerService
).OnToggleBreakpoint(event
, line
=self
._rightClickLine
) 
 783     def OnPopToggleMarker(self
, event
): 
 784         """ Toggle marker on right click line, not current line """ 
 785         wx
.GetApp().GetDocumentManager().GetCurrentView().MarkerToggle(lineNum 
= self
._rightClickLine
) 
 788     def OnPopSyncOutline(self
, event
): 
 789         wx
.GetApp().GetService(OutlineService
.OutlineService
).LoadOutline(wx
.GetApp().GetDocumentManager().GetCurrentView(), position
=self
._rightClickPosition
) 
 792     def HasSelection(self
): 
 793         return self
.GetSelectionStart() - self
.GetSelectionEnd() != 0   
 796     def ClearCurrentLineMarkers(self
): 
 797         self
.MarkerDeleteAll(CodeCtrl
.CURRENT_LINE_MARKER_NUM
) 
 800     def ClearCurrentBreakpoinMarkers(self
): 
 801         self
.MarkerDeleteAll(CodeCtrl
.BREAKPOINT_MARKER_NUM
) 
 804     def GetDefaultFont(self
): 
 805         if wx
.Platform 
== '__WXMSW__': 
 809         return wx
.Font(10, wx
.DEFAULT
, wx
.NORMAL
, wx
.NORMAL
, faceName 
= font
) 
 812     def GetMatchingBraces(self
): 
 813         """ Overwrite this method for language specific braces """ 
 817     def CanWordWrap(self
): 
 821     def SetFont(self
, font
): 
 825     def SetFontColor(self
, fontColor
): 
 826         self
._fontColor 
= fontColor
 
 829     def UpdateStyles(self
): 
 831         if not self
.GetFont(): 
 834         faces 
= { 'font' : self
.GetFont().GetFaceName(), 
 835                   'size' : self
.GetFont().GetPointSize(), 
 836                   'size2': self
.GetFont().GetPointSize() - 2, 
 837                   'color' : "%02x%02x%02x" % (self
.GetFontColor().Red(), self
.GetFontColor().Green(), self
.GetFontColor().Blue()) 
 840         # Global default styles for all languages 
 841         self
.StyleSetSpec(wx
.stc
.STC_STYLE_DEFAULT
,     "face:%(font)s,fore:#FFFFFF,size:%(size)d" % faces
) 
 842         self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,  "face:%(font)s,back:#C0C0C0,face:%(font)s,size:%(size2)d" % faces
) 
 843         self
.StyleSetSpec(wx
.stc
.STC_STYLE_CONTROLCHAR
, "face:%(font)s" % faces
) 
 844         self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,  "face:%(font)s,fore:#000000,back:#70FFFF,size:%(size)d" % faces
) 
 845         self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,    "face:%(font)s,fore:#000000,back:#FF0000,size:%(size)d" % faces
) 
 848     def OnKeyPressed(self
, event
): 
 849         if self
.CallTipActive(): 
 851         key 
= event
.KeyCode() 
 852         if False:  # key == wx.WXK_SPACE and event.ControlDown(): 
 853             pos 
= self
.GetCurrentPos() 
 855             if event
.ShiftDown(): 
 856                 self
.CallTipSetBackground("yellow") 
 857                 self
.CallTipShow(pos
, 'param1, param2') 
 861                 #for x in range(50000): 
 862                 #    lst.append('%05d' % x) 
 863                 #st = string.join(lst) 
 865                 #self.AutoCompShow(0, st) 
 867                 kw 
= keyword
.kwlist
[:] 
 870                 kw
.append("__init__") 
 873                 kw
.append("this_is_a_longer_value") 
 874                 kw
.append("this_is_a_much_much_much_much_much_much_much_longer_value") 
 876                 kw
.sort()  # Python sorts are case sensitive 
 877                 self
.AutoCompSetIgnoreCase(False)  # so this needs to match 
 879                 self
.AutoCompShow(0, string
.join(kw
)) 
 880         elif key 
== wx
.WXK_RETURN
: 
 883             STCTextEditor
.TextCtrl
.OnKeyPressed(self
, event
) 
 888         # Need to do a default one for all languges 
 891     def OnMarginClick(self
, evt
): 
 892         # fold and unfold as needed 
 893         if evt
.GetMargin() == 2: 
 894             if evt
.GetShift() and evt
.GetControl(): 
 895                 lineCount 
= self
.GetLineCount() 
 898                 # find out if we are folding or unfolding 
 899                 for lineNum 
in range(lineCount
): 
 900                     if self
.GetFoldLevel(lineNum
) & wx
.stc
.STC_FOLDLEVELHEADERFLAG
: 
 901                         expanding 
= not self
.GetFoldExpanded(lineNum
) 
 904                 self
.ToggleFoldAll(expanding
) 
 906                 lineClicked 
= self
.LineFromPosition(evt
.GetPosition()) 
 907                 if self
.GetFoldLevel(lineClicked
) & wx
.stc
.STC_FOLDLEVELHEADERFLAG
: 
 909                         self
.SetFoldExpanded(lineClicked
, True) 
 910                         self
.Expand(lineClicked
, True, True, 1) 
 911                     elif evt
.GetControl(): 
 912                         if self
.GetFoldExpanded(lineClicked
): 
 913                             self
.SetFoldExpanded(lineClicked
, False) 
 914                             self
.Expand(lineClicked
, False, True, 0) 
 916                             self
.SetFoldExpanded(lineClicked
, True) 
 917                             self
.Expand(lineClicked
, True, True, 100) 
 919                         self
.ToggleFold(lineClicked
) 
 921         elif evt
.GetMargin() == 0: 
 922             #This is used to toggle breakpoints via the debugger service. 
 923             db_service 
= wx
.GetApp().GetService(DebuggerService
.DebuggerService
) 
 925                 db_service
.OnToggleBreakpoint(evt
, line
=self
.LineFromPosition(evt
.GetPosition())) 
 928     def OnUpdateUI(self
, evt
): 
 929         braces 
= self
.GetMatchingBraces() 
 931         # check for matching braces 
 935         caretPos 
= self
.GetCurrentPos() 
 937             charBefore 
= self
.GetCharAt(caretPos 
- 1) 
 938             styleBefore 
= self
.GetStyleAt(caretPos 
- 1) 
 941         if charBefore 
and chr(charBefore
) in braces
: 
 942             braceAtCaret 
= caretPos 
- 1 
 946             charAfter 
= self
.GetCharAt(caretPos
) 
 947             styleAfter 
= self
.GetStyleAt(caretPos
) 
 948             if charAfter 
and chr(charAfter
) in braces
: 
 949                 braceAtCaret 
= caretPos
 
 951         if braceAtCaret 
>= 0: 
 952             braceOpposite 
= self
.BraceMatch(braceAtCaret
) 
 954         if braceAtCaret 
!= -1  and braceOpposite 
== -1: 
 955             self
.BraceBadLight(braceAtCaret
) 
 957             self
.BraceHighlight(braceAtCaret
, braceOpposite
) 
 962     def ToggleFoldAll(self
, expand 
= True, topLevelOnly 
= False): 
 964         lineCount 
= self
.GetLineCount() 
 966             if not topLevelOnly 
or (topLevelOnly 
and self
.GetFoldLevel(i
) & wx
.stc
.STC_FOLDLEVELNUMBERMASK  
== wx
.stc
.STC_FOLDLEVELBASE
): 
 967                 if (expand 
and self
.CanLineExpand(i
)) or (not expand 
and self
.CanLineCollapse(i
)): 
 972     def CanLineExpand(self
, line
): 
 973         return not self
.GetFoldExpanded(line
) 
 976     def CanLineCollapse(self
, line
): 
 977         return self
.GetFoldExpanded(line
) and self
.GetFoldLevel(line
) & wx
.stc
.STC_FOLDLEVELHEADERFLAG
 
 980     def Expand(self
, line
, doExpand
, force
=False, visLevels
=0, level
=-1): 
 981         lastChild 
= self
.GetLastChild(line
, level
) 
 983         while line 
<= lastChild
: 
 986                     self
.ShowLines(line
, line
) 
 988                     self
.HideLines(line
, line
) 
 991                     self
.ShowLines(line
, line
) 
 994                 level 
= self
.GetFoldLevel(line
) 
 996             if level 
& wx
.stc
.STC_FOLDLEVELHEADERFLAG
: 
 999                         self
.SetFoldExpanded(line
, True) 
1001                         self
.SetFoldExpanded(line
, False) 
1002                     line 
= self
.Expand(line
, doExpand
, force
, visLevels
-1) 
1005                     if doExpand 
and self
.GetFoldExpanded(line
): 
1006                         line 
= self
.Expand(line
, True, force
, visLevels
-1) 
1008                         line 
= self
.Expand(line
, False, force
, visLevels
-1)