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 #---------------------------------------------------------------------------- 
  23 from UICommon 
import CaseInsensitiveCompare
 
  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(): 
 121         if id == EXPAND_TEXT_ID
: 
 122             if self
.GetCtrl().GetViewFolding(): 
 123                 event
.Enable(self
.GetCtrl().CanLineExpand(self
.GetCtrl().GetCurrentLine())) 
 127         elif id == COLLAPSE_TEXT_ID
: 
 128             if self
.GetCtrl().GetViewFolding(): 
 129                 event
.Enable(self
.GetCtrl().CanLineCollapse(self
.GetCtrl().GetCurrentLine())) 
 133         elif (id == EXPAND_TOP_ID
 
 134         or id == COLLAPSE_TOP_ID
 
 135         or id == EXPAND_ALL_ID
 
 136         or id == COLLAPSE_ALL_ID
): 
 137             if self
.GetCtrl().GetViewFolding(): 
 138                 event
.Enable(self
.GetCtrl().GetTextLength() > 0) 
 142         elif (id == AUTO_COMPLETE_ID
 
 143         or id == CLEAN_WHITESPACE
 
 144         or id == INDENT_LINES_ID
 
 145         or id == DEDENT_LINES_ID
 
 146         or id == COMMENT_LINES_ID
 
 147         or id == UNCOMMENT_LINES_ID
): 
 148             event
.Enable(self
.GetCtrl().GetTextLength() > 0) 
 150         elif id == CHECK_CODE_ID
: 
 153         elif id == SET_INDENT_WIDTH_ID
: 
 156         elif id == FOLDING_ID
: 
 157             event
.Enable(self
.GetCtrl().GetViewFolding()) 
 159         elif id == USE_TABS_ID
: 
 161             event
.Check(self
.GetCtrl().GetUseTabs()) 
 164             return STCTextEditor
.TextView
.ProcessUpdateUIEvent(self
, event
) 
 167     #---------------------------------------------------------------------------- 
 168     # Methods for OutlineService 
 169     #---------------------------------------------------------------------------- 
 171     def OnChangeFilename(self
): 
 172         wx
.lib
.docview
.View
.OnChangeFilename(self
) 
 173         self
.LoadOutline(force
=True) 
 176     def ClearOutline(self
): 
 177         outlineService 
= wx
.GetApp().GetService(OutlineService
.OutlineService
) 
 178         if not outlineService
: 
 181         outlineView 
= outlineService
.GetView() 
 185         outlineView
.ClearTreeCtrl() 
 188     def LoadOutline(self
, force
=False): 
 189         outlineService 
= wx
.GetApp().GetService(OutlineService
.OutlineService
) 
 190         if not outlineService
: 
 192         outlineService
.LoadOutline(self
, force
=force
) 
 195     def DoLoadOutlineCallback(self
, force
=False): 
 196         outlineService 
= wx
.GetApp().GetService(OutlineService
.OutlineService
) 
 197         if not outlineService
: 
 200         outlineView 
= outlineService
.GetView() 
 204         treeCtrl 
= outlineView
.GetTreeCtrl() 
 208         view 
= treeCtrl
.GetCallbackView() 
 209         newCheckSum 
= self
.GenCheckSum() 
 211             if view 
and view 
is self
: 
 212                 if self
._checkSum 
== newCheckSum
: 
 214         self
._checkSum 
= newCheckSum
 
 216         treeCtrl
.DeleteAllItems() 
 218         document 
= self
.GetDocument() 
 222         filename 
= document
.GetFilename() 
 224             rootItem 
= treeCtrl
.AddRoot(os
.path
.basename(filename
)) 
 225             treeCtrl
.SetDoSelectCallback(rootItem
, self
, (0,0)) 
 229         text 
= self
.GetValue() 
 233         CLASS_PATTERN 
= 'class[ \t]+\w+.*?:' 
 234         DEF_PATTERN 
= 'def[ \t]+\w+\(.*?\)' 
 235         classPat 
= re
.compile(CLASS_PATTERN
, re
.M|re
.S
) 
 236         defPat
= re
.compile(DEF_PATTERN
, re
.M|re
.S
) 
 237         pattern 
= re
.compile('^[ \t]*((' + CLASS_PATTERN 
+ ')|('+ DEF_PATTERN 
+'.*?:)).*?$', re
.M|re
.S
) 
 239         iter = pattern
.finditer(text
) 
 240         indentStack 
= [(0, rootItem
)] 
 242             line 
= pattern
.string
[pattern
.start(0):pattern
.end(0)] 
 243             classLine 
= classPat
.search(line
) 
 245                 indent 
= classLine
.start(0) 
 246                 itemStr 
= classLine
.string
[classLine
.start(0):classLine
.end(0)-1]  # don't take the closing ':' 
 247                 itemStr 
= itemStr
.replace("\n", "").replace("\r", "").replace(",\\", ",").replace("  ", "")  # remove line continuations and spaces from outline view 
 249                 defLine 
= defPat
.search(line
) 
 251                     indent 
= defLine
.start(0) 
 252                     itemStr 
= defLine
.string
[defLine
.start(0):defLine
.end(0)] 
 253                     itemStr 
= itemStr
.replace("\n", "").replace("\r", "").replace(",\\", ",").replace("  ", "")  # remove line continuations and spaces from outline view 
 256                 parentItem 
= rootItem
 
 258                 lastItem 
= indentStack
.pop() 
 259                 while lastItem
[0] >= indent
: 
 260                     lastItem 
= indentStack
.pop() 
 261                 indentStack
.append(lastItem
) 
 262                 parentItem 
= lastItem
[1] 
 264             item 
= treeCtrl
.AppendItem(parentItem
, itemStr
) 
 265             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 
 266             indentStack
.append((indent
, item
)) 
 268         treeCtrl
.Expand(rootItem
) 
 273     def DoSelectCallback(self
, data
): 
 275             self
.EnsureVisibleEnforcePolicy(self
.LineFromPosition(data
[0])) 
 276             # wxBug: need to select in reverse order (end, start) to place cursor at begining of line, 
 277             #        otherwise, display is scrolled over to the right hard and is hard to view 
 278             self
.SetSelection(data
[1], data
[0]) 
 281 ##    def checksum(self, bytes):         
 282 ##        def rotate_right(c): 
 284 ##                return (c>>1)|0x8000 
 290 ##            ch = ord(ch) & 0xFF 
 291 ##            result = (rotate_right(result)+ch) & 0xFFFF 
 295     def GenCheckSum(self
): 
 296         """ Poor man's checksum.  We'll assume most changes will change the length of the file. 
 298         text 
= self
.GetValue() 
 305     #---------------------------------------------------------------------------- 
 307     #---------------------------------------------------------------------------- 
 309     def OnCheckCode(self
): 
 310         """ Need to overshadow this for each specific subclass """ 
 313                 code 
= self
.GetCtrl().GetText() 
 314                 codeObj 
= compile(code
, self
.GetDocument().GetFilename(), 'exec') 
 315                 self
._GetParentFrame
().SetStatusText(_("The file successfully compiled")) 
 316             except SyntaxError, (message
, (fileName
, line
, col
, text
)): 
 317                 pos 
= self
.GetCtrl().PositionFromLine(line 
- 1) + col 
- 1 
 318                 self
.GetCtrl().SetSelection(pos
, pos
) 
 319                 self
._GetParentFrame
().SetStatusText(_("Syntax Error: %s") % message
) 
 321                 self
._GetParentFrame
().SetStatusText("%s: %s" % (sys
.exc_info()[0], sys
.exc_info()[1])) 
 324     def OnAutoComplete(self
): 
 325         self
.GetCtrl().AutoCompCancel() 
 326         self
.GetCtrl().AutoCompSetAutoHide(0) 
 327         self
.GetCtrl().AutoCompSetChooseSingle(True) 
 328         self
.GetCtrl().AutoCompSetIgnoreCase(True) 
 329         context
, hint 
= self
.GetAutoCompleteHint() 
 330         replaceList
, replaceLen 
= self
.GetAutoCompleteKeywordList(context
, hint
) 
 331         if replaceList 
and len(replaceList
) != 0:  
 332             self
.GetCtrl().AutoCompShow(replaceLen
, replaceList
) 
 335     def GetAutoCompleteHint(self
): 
 336         """ Replace this method with Editor specific method """ 
 337         pos 
= self
.GetCtrl().GetCurrentPos() 
 340         if chr(self
.GetCtrl().GetCharAt(pos 
- 1)) == '.': 
 346         validLetters 
= string
.letters 
+ string
.digits 
+ '_.' 
 352             char 
= chr(self
.GetCtrl().GetCharAt(pos
)) 
 353             if char 
not in validLetters
: 
 359             lastDot 
= word
.rfind('.') 
 361                 context 
= word
[0:lastDot
] 
 362                 hint 
= word
[lastDot
+1:] 
 367     def GetAutoCompleteDefaultKeywords(self
): 
 368         """ Replace this method with Editor specific keywords """ 
 369         return ['Put', 'Editor Specific', 'Keywords', 'Here'] 
 372     def GetAutoCompleteKeywordList(self
, context
, hint
):             
 373         """ Replace this method with Editor specific keywords """ 
 374         kw 
= self
.GetAutoCompleteDefaultKeywords() 
 376         if hint 
and len(hint
): 
 377             lowerHint 
= hint
.lower() 
 378             filterkw 
= filter(lambda item
: item
.lower().startswith(lowerHint
), kw
)  # remove variables and methods that don't match hint 
 382             replaceLen 
= len(hint
) 
 386         kw
.sort(CaseInsensitiveCompare
) 
 387         return " ".join(kw
), replaceLen
 
 390     def OnCleanWhiteSpace(self
): 
 392         for lineNo 
in self
._GetSelectedLineNumbers
(): 
 393             lineText 
= string
.rstrip(self
.GetCtrl().GetLine(lineNo
)) 
 396             for char 
in lineText
: 
 398                     indent 
= indent 
+ self
.GetCtrl().GetIndent() 
 400                 elif char 
in string
.whitespace
: 
 405             if self
.GetCtrl().GetUseTabs(): 
 406                 indentText 
= (indent 
/ self
.GetCtrl().GetIndent()) * '\t' + (indent 
% self
.GetCtrl().GetIndent()) * ' ' 
 408                 indentText 
= indent 
* ' ' 
 409             lineText 
= indentText 
+ lineText
[lstrip
:] + '\n' 
 410             newText 
= newText 
+ lineText
 
 411         self
._ReplaceSelectedLines
(newText
) 
 414     def OnSetIndentWidth(self
): 
 415         dialog 
= wx
.TextEntryDialog(self
._GetParentFrame
(), _("Enter new indent width (2-10):"), _("Set Indent Width"), "%i" % self
.GetCtrl().GetIndent()) 
 416         dialog
.CenterOnParent() 
 417         if dialog
.ShowModal() == wx
.ID_OK
: 
 419                 indent 
= int(dialog
.GetValue()) 
 420                 if indent 
>= 2 and indent 
<= 10: 
 421                     self
.GetCtrl().SetIndent(indent
) 
 422                     self
.GetCtrl().SetTabWidth(indent
) 
 428     def GetIndentWidth(self
): 
 429         return self
.GetCtrl().GetIndent() 
 432     def OnCommentLines(self
): 
 434         for lineNo 
in self
._GetSelectedLineNumbers
(): 
 435             lineText 
= self
.GetCtrl().GetLine(lineNo
) 
 436             if (len(lineText
) > 1 and lineText
[0] == '#') or (len(lineText
) > 2 and lineText
[:2] == '##'): 
 437                 newText 
= newText 
+ lineText
 
 439                 newText 
= newText 
+ "##" + lineText
 
 440         self
._ReplaceSelectedLines
(newText
) 
 443     def OnUncommentLines(self
): 
 445         for lineNo 
in self
._GetSelectedLineNumbers
(): 
 446             lineText 
= self
.GetCtrl().GetLine(lineNo
) 
 447             if len(lineText
) >= 2 and lineText
[:2] == "##": 
 448                 lineText 
= lineText
[2:] 
 449             elif len(lineText
) >= 1 and lineText
[:1] == "#": 
 450                 lineText 
= lineText
[1:] 
 451             newText 
= newText 
+ lineText
 
 452         self
._ReplaceSelectedLines
(newText
) 
 455     def _GetSelectedLineNumbers(self
): 
 456         selStart
, selEnd 
= self
._GetPositionsBoundingSelectedLines
() 
 457         return range(self
.GetCtrl().LineFromPosition(selStart
), self
.GetCtrl().LineFromPosition(selEnd
)) 
 460     def _GetPositionsBoundingSelectedLines(self
): 
 461         startPos 
= self
.GetCtrl().GetCurrentPos() 
 462         endPos 
= self
.GetCtrl().GetAnchor() 
 463         if startPos 
> endPos
: 
 467         if endPos 
== self
.GetCtrl().PositionFromLine(self
.GetCtrl().LineFromPosition(endPos
)): 
 468             endPos 
= endPos 
- 1  # If it's at the very beginning of a line, use the line above it as the ending line 
 469         selStart 
= self
.GetCtrl().PositionFromLine(self
.GetCtrl().LineFromPosition(startPos
)) 
 470         selEnd 
= self
.GetCtrl().PositionFromLine(self
.GetCtrl().LineFromPosition(endPos
) + 1) 
 471         return selStart
, selEnd
 
 474     def _ReplaceSelectedLines(self
, text
): 
 477         selStart
, selEnd 
= self
._GetPositionsBoundingSelectedLines
() 
 478         self
.GetCtrl().SetSelection(selStart
, selEnd
) 
 479         self
.GetCtrl().ReplaceSelection(text
) 
 480         self
.GetCtrl().SetSelection(selStart 
+ len(text
), selStart
) 
 483     def OnUpdate(self
, sender 
= None, hint 
= None): 
 484         if wx
.lib
.docview
.View
.OnUpdate(self
, sender
, hint
): 
 487         if hint 
== "ViewStuff": 
 488             self
.GetCtrl().SetViewDefaults() 
 490             font
, color 
= self
.GetCtrl().GetFontAndColorFromConfig() 
 491             self
.GetCtrl().SetFont(font
) 
 492             self
.GetCtrl().SetFontColor(color
) 
 494             import DebuggerService
 
 495             dbg_service 
= wx
.GetApp().GetService(DebuggerService
.DebuggerService
) 
 497                 dbg_service
.SetCurrentBreakpointMarkers(self
) 
 500 class CodeService(STCTextEditor
.TextService
): 
 504         STCTextEditor
.TextService
.__init
__(self
) 
 507     def InstallControls(self
, frame
, menuBar 
= None, toolBar 
= None, statusBar 
= None, document 
= None): 
 508         # TODO NEED TO DO INSTANCEOF CHECK HERE FOR SDI 
 509         #if document and document.GetDocumentTemplate().GetDocumentType() != TextDocument: 
 511         if not document 
and wx
.GetApp().GetDocumentManager().GetFlags() & wx
.lib
.docview
.DOC_SDI
: 
 514         viewMenu 
= menuBar
.GetMenu(menuBar
.FindMenu(_("&View"))) 
 515         isWindows 
= (wx
.Platform 
== '__WXMSW__') 
 517         if not menuBar
.FindItemById(EXPAND_TEXT_ID
):  # check if below menu items have been already been installed 
 518             foldingMenu 
= wx
.Menu() 
 520                 foldingMenu
.Append(EXPAND_TEXT_ID
, _("&Expand\tNumpad-Plus"), _("Expands a collapsed block of text")) 
 522                 foldingMenu
.Append(EXPAND_TEXT_ID
, _("&Expand"), _("Expands a collapsed block of text")) 
 524             wx
.EVT_MENU(frame
, EXPAND_TEXT_ID
, frame
.ProcessEvent
) 
 525             wx
.EVT_UPDATE_UI(frame
, EXPAND_TEXT_ID
, frame
.ProcessUpdateUIEvent
) 
 528                 foldingMenu
.Append(COLLAPSE_TEXT_ID
, _("&Collapse\tNumpad+Minus"), _("Collapse a block of text")) 
 530                 foldingMenu
.Append(COLLAPSE_TEXT_ID
, _("&Collapse"), _("Collapse a block of text")) 
 531             wx
.EVT_MENU(frame
, COLLAPSE_TEXT_ID
, frame
.ProcessEvent
) 
 532             wx
.EVT_UPDATE_UI(frame
, COLLAPSE_TEXT_ID
, frame
.ProcessUpdateUIEvent
) 
 535                 foldingMenu
.Append(EXPAND_TOP_ID
, _("Expand &Top Level\tCtrl+Numpad+Plus"), _("Expands the top fold levels in the document")) 
 537                 foldingMenu
.Append(EXPAND_TOP_ID
, _("Expand &Top Level"), _("Expands the top fold levels in the document")) 
 538             wx
.EVT_MENU(frame
, EXPAND_TOP_ID
, frame
.ProcessEvent
) 
 539             wx
.EVT_UPDATE_UI(frame
, EXPAND_TOP_ID
, frame
.ProcessUpdateUIEvent
) 
 542                 foldingMenu
.Append(COLLAPSE_TOP_ID
, _("Collapse Top &Level\tCtrl+Numpad+Minus"), _("Collapses the top fold levels in the document")) 
 544                 foldingMenu
.Append(COLLAPSE_TOP_ID
, _("Collapse Top &Level"), _("Collapses the top fold levels in the document")) 
 545             wx
.EVT_MENU(frame
, COLLAPSE_TOP_ID
, frame
.ProcessEvent
) 
 546             wx
.EVT_UPDATE_UI(frame
, COLLAPSE_TOP_ID
, frame
.ProcessUpdateUIEvent
) 
 549                 foldingMenu
.Append(EXPAND_ALL_ID
, _("Expand &All\tShift+Numpad+Plus"), _("Expands all of the fold levels in the document")) 
 551                 foldingMenu
.Append(EXPAND_ALL_ID
, _("Expand &All"), _("Expands all of the fold levels in the document")) 
 552             wx
.EVT_MENU(frame
, EXPAND_ALL_ID
, frame
.ProcessEvent
) 
 553             wx
.EVT_UPDATE_UI(frame
, EXPAND_ALL_ID
, frame
.ProcessUpdateUIEvent
) 
 556                 foldingMenu
.Append(COLLAPSE_ALL_ID
, _("Colla&pse All\tShift+Numpad+Minus"), _("Collapses all of the fold levels in the document")) 
 558                 foldingMenu
.Append(COLLAPSE_ALL_ID
, _("Colla&pse All"), _("Collapses all of the fold levels in the document")) 
 559             wx
.EVT_MENU(frame
, COLLAPSE_ALL_ID
, frame
.ProcessEvent
) 
 560             wx
.EVT_UPDATE_UI(frame
, COLLAPSE_ALL_ID
, frame
.ProcessUpdateUIEvent
) 
 562             viewMenu
.AppendMenu(FOLDING_ID
, _("&Folding"), foldingMenu
) 
 563             wx
.EVT_UPDATE_UI(frame
, FOLDING_ID
, frame
.ProcessUpdateUIEvent
) 
 565         formatMenuIndex 
= menuBar
.FindMenu(_("&Format")) 
 566         if formatMenuIndex 
> -1: 
 567             formatMenu 
= menuBar
.GetMenu(formatMenuIndex
) 
 569             formatMenu 
= wx
.Menu() 
 570         if not menuBar
.FindItemById(CHECK_CODE_ID
):  # check if below menu items have been already been installed 
 571             formatMenu
.AppendSeparator() 
 572             formatMenu
.Append(CHECK_CODE_ID
, _("&Check Code"), _("Checks the document for syntax and indentation errors")) 
 573             wx
.EVT_MENU(frame
, CHECK_CODE_ID
, frame
.ProcessEvent
) 
 574             wx
.EVT_UPDATE_UI(frame
, CHECK_CODE_ID
, frame
.ProcessUpdateUIEvent
) 
 575             formatMenu
.Append(AUTO_COMPLETE_ID
, _("&Auto Complete\tCtrl+Space"), _("Provides suggestions on how to complete the current statement")) 
 576             wx
.EVT_MENU(frame
, AUTO_COMPLETE_ID
, frame
.ProcessEvent
) 
 577             wx
.EVT_UPDATE_UI(frame
, AUTO_COMPLETE_ID
, frame
.ProcessUpdateUIEvent
) 
 578             formatMenu
.Append(CLEAN_WHITESPACE
, _("Clean &Whitespace"), _("Converts leading spaces to tabs or vice versa per 'use tabs' and clears trailing spaces")) 
 579             wx
.EVT_MENU(frame
, CLEAN_WHITESPACE
, frame
.ProcessEvent
) 
 580             wx
.EVT_UPDATE_UI(frame
, CLEAN_WHITESPACE
, frame
.ProcessUpdateUIEvent
) 
 581             formatMenu
.AppendSeparator() 
 582             formatMenu
.Append(INDENT_LINES_ID
, _("&Indent Lines\tTab"), _("Indents the selected lines one indent width")) 
 583             wx
.EVT_MENU(frame
, INDENT_LINES_ID
, frame
.ProcessEvent
) 
 584             wx
.EVT_UPDATE_UI(frame
, INDENT_LINES_ID
, frame
.ProcessUpdateUIEvent
) 
 585             formatMenu
.Append(DEDENT_LINES_ID
, _("&Dedent Lines\tShift+Tab"), _("Dedents the selected lines one indent width")) 
 586             wx
.EVT_MENU(frame
, DEDENT_LINES_ID
, frame
.ProcessEvent
) 
 587             wx
.EVT_UPDATE_UI(frame
, DEDENT_LINES_ID
, frame
.ProcessUpdateUIEvent
) 
 588             formatMenu
.Append(COMMENT_LINES_ID
, _("Comment &Lines\tCtrl+Q"), _("Comments out the selected lines be prefixing each one with a comment indicator")) 
 589             wx
.EVT_MENU(frame
, COMMENT_LINES_ID
, frame
.ProcessEvent
) 
 590             wx
.EVT_UPDATE_UI(frame
, COMMENT_LINES_ID
, frame
.ProcessUpdateUIEvent
) 
 591             formatMenu
.Append(UNCOMMENT_LINES_ID
, _("&Uncomment Lines\tCtrl+Shift+Q"), _("Removes comment prefixes from each of the selected lines")) 
 592             wx
.EVT_MENU(frame
, UNCOMMENT_LINES_ID
, frame
.ProcessEvent
) 
 593             wx
.EVT_UPDATE_UI(frame
, UNCOMMENT_LINES_ID
, frame
.ProcessUpdateUIEvent
) 
 594             formatMenu
.AppendSeparator() 
 595             formatMenu
.AppendCheckItem(USE_TABS_ID
, _("Use &Tabs"), _("Toggles use of tabs or whitespaces for indents")) 
 596             wx
.EVT_MENU(frame
, USE_TABS_ID
, frame
.ProcessEvent
) 
 597             wx
.EVT_UPDATE_UI(frame
, USE_TABS_ID
, frame
.ProcessUpdateUIEvent
) 
 598             formatMenu
.Append(SET_INDENT_WIDTH_ID
, _("&Set Indent Width..."), _("Sets the indent width")) 
 599             wx
.EVT_MENU(frame
, SET_INDENT_WIDTH_ID
, frame
.ProcessEvent
) 
 600             wx
.EVT_UPDATE_UI(frame
, SET_INDENT_WIDTH_ID
, frame
.ProcessUpdateUIEvent
) 
 601         if formatMenuIndex 
== -1: 
 602             viewMenuIndex 
= menuBar
.FindMenu(_("&View")) 
 603             menuBar
.Insert(viewMenuIndex 
+ 1, formatMenu
, _("&Format")) 
 605 ##        accelTable = wx.AcceleratorTable([ 
 606 ##            (wx.ACCEL_NORMAL, wx.WXK_TAB, INDENT_LINES_ID), 
 607 ##            (wx.ACCEL_SHIFT, wx.WXK_TAB, DEDENT_LINES_ID), 
 608 ##            eval(_("wx.ACCEL_CTRL, ord('Q'), COMMENT_LINES_ID")), 
 609 ##            eval(_("wx.ACCEL_CTRL | wx.ACCEL_SHIFT, ord('Q'), UNCOMMENT_LINES_ID")) 
 611 ##        frame.SetAcceleratorTable(accelTable) 
 613     def ProcessUpdateUIEvent(self
, event
): 
 615         if (id == EXPAND_TEXT_ID
 
 616         or id == COLLAPSE_TEXT_ID
 
 617         or id == EXPAND_TOP_ID
 
 618         or id == COLLAPSE_TOP_ID
 
 619         or id == EXPAND_ALL_ID
 
 620         or id == COLLAPSE_ALL_ID
 
 621         or id == CHECK_CODE_ID
 
 622         or id == AUTO_COMPLETE_ID
 
 623         or id == CLEAN_WHITESPACE
 
 624         or id == SET_INDENT_WIDTH_ID
 
 626         or id == INDENT_LINES_ID
 
 627         or id == DEDENT_LINES_ID
 
 628         or id == COMMENT_LINES_ID
 
 629         or id == UNCOMMENT_LINES_ID
 
 630         or id == FOLDING_ID
): 
 634             return STCTextEditor
.TextService
.ProcessUpdateUIEvent(self
, event
) 
 637 class CodeCtrl(STCTextEditor
.TextCtrl
): 
 638     CURRENT_LINE_MARKER_NUM 
= 2 
 639     BREAKPOINT_MARKER_NUM 
= 1 
 640     CURRENT_LINE_MARKER_MASK 
= 0x4 
 641     BREAKPOINT_MARKER_MASK 
= 0x2 
 644     def __init__(self
, parent
, id=-1, style 
= wx
.NO_FULL_REPAINT_ON_RESIZE
, clearTab
=True): 
 645         STCTextEditor
.TextCtrl
.__init
__(self
, parent
, id, style
) 
 648         self
.Bind(wx
.EVT_RIGHT_UP
, self
.OnRightUp
) 
 649         self
.SetProperty("fold", "1") 
 651         # Setup a margin to hold fold markers 
 652         #self.SetFoldFlags(16)  ###  WHAT IS THIS VALUE?  WHAT ARE THE OTHER FLAGS?  DOES IT MATTER? 
 653         self
.SetMarginType(2, wx
.stc
.STC_MARGIN_SYMBOL
) 
 654         self
.SetMarginMask(2, wx
.stc
.STC_MASK_FOLDERS
) 
 655         self
.SetMarginSensitive(2, True) 
 657         self
.SetMarginSensitive(1, False) 
 658         self
.SetMarginMask(1, 0x4) 
 660         self
.SetMarginSensitive(0, True) 
 661         self
.SetMarginType(0, wx
.stc
.STC_MARGIN_SYMBOL
) 
 662         self
.SetMarginMask(0, 0x3) 
 663         self
.SetMarginWidth(0, 12) 
 665         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDEREND
,     wx
.stc
.STC_MARK_BOXPLUSCONNECTED
,  "white", "black") 
 666         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDEROPENMID
, wx
.stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black") 
 667         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDERMIDTAIL
, wx
.stc
.STC_MARK_TCORNER
,  "white", "black") 
 668         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDERTAIL
,    wx
.stc
.STC_MARK_LCORNER
,  "white", "black") 
 669         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDERSUB
,     wx
.stc
.STC_MARK_VLINE
,    "white", "black") 
 670         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDER
,        wx
.stc
.STC_MARK_BOXPLUS
,  "white", "black") 
 671         self
.MarkerDefine(wx
.stc
.STC_MARKNUM_FOLDEROPEN
,    wx
.stc
.STC_MARK_BOXMINUS
, "white", "black") 
 672         # Define the current line marker 
 673         self
.MarkerDefine(CodeCtrl
.CURRENT_LINE_MARKER_NUM
, wx
.stc
.STC_MARK_SHORTARROW
, wx
.BLACK
, (255,255,128)) 
 674         # Define the breakpoint marker 
 675         self
.MarkerDefine(CodeCtrl
.BREAKPOINT_MARKER_NUM
, wx
.stc
.STC_MARK_CIRCLE
, wx
.BLACK
, (255,0,0)) 
 677         if _WINDOWS 
and clearTab
:  # should test to see if menu item exists, if it does, add this workaround 
 678             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 
 680         wx
.stc
.EVT_STC_MARGINCLICK(self
, self
.GetId(), self
.OnMarginClick
) 
 681         wx
.EVT_KEY_DOWN(self
, self
.OnKeyPressed
) 
 682         if self
.GetMatchingBraces():  
 683             wx
.stc
.EVT_STC_UPDATEUI(self
, self
.GetId(), self
.OnUpdateUI
) 
 689     def OnRightUp(self
, event
): 
 690         #Hold onto the current line number, no way to get it later. 
 691         self
._rightClickPosition 
= self
.PositionFromPoint(event
.GetPosition()) 
 692         self
._rightClickLine 
= self
.LineFromPosition(self
._rightClickPosition
) 
 693         self
.PopupMenu(self
.CreatePopupMenu(), event
.GetPosition()) 
 694         self
._rightClickLine 
= -1 
 695         self
._rightClickPosition 
= -1 
 698     def CreatePopupMenu(self
): 
 699         TOGGLEBREAKPOINT_ID 
= wx
.NewId() 
 700         TOGGLEMARKER_ID 
= wx
.NewId() 
 701         SYNCTREE_ID 
= wx
.NewId() 
 705         self
.Bind(wx
.EVT_MENU
, self
.OnPopSyncOutline
, id=SYNCTREE_ID
) 
 706         item 
= wx
.MenuItem(menu
, SYNCTREE_ID
, _("Find in Outline View")) 
 707         menu
.AppendItem(item
) 
 708         menu
.AppendSeparator() 
 709         self
.Bind(wx
.EVT_MENU
, self
.OnPopToggleBP
, id=TOGGLEBREAKPOINT_ID
) 
 710         item 
= wx
.MenuItem(menu
, TOGGLEBREAKPOINT_ID
, _("Toggle Breakpoint")) 
 711         menu
.AppendItem(item
) 
 712         self
.Bind(wx
.EVT_MENU
, self
.OnPopToggleMarker
, id=TOGGLEMARKER_ID
) 
 713         item 
= wx
.MenuItem(menu
, TOGGLEMARKER_ID
, _("Toggle Bookmark")) 
 714         menu
.AppendItem(item
) 
 715         menu
.AppendSeparator() 
 717         itemIDs 
= [wx
.ID_UNDO
, wx
.ID_REDO
, None, 
 718                    wx
.ID_CUT
, wx
.ID_COPY
, wx
.ID_PASTE
, wx
.ID_CLEAR
, None, wx
.ID_SELECTALL
] 
 720         menuBar 
= wx
.GetApp().GetTopWindow().GetMenuBar() 
 721         for itemID 
in itemIDs
: 
 723                 menu
.AppendSeparator() 
 725                 item 
= menuBar
.FindItemById(itemID
) 
 727                     menu
.Append(itemID
, item
.GetLabel()) 
 728                     wx
.EVT_MENU(self
, itemID
, self
.DSProcessEvent
)  # wxHack: for customized right mouse menu doesn't work with new DynamicSashWindow 
 729                     wx
.EVT_UPDATE_UI(self
, itemID
, self
.DSProcessUpdateUIEvent
)  # wxHack: for customized right mouse menu doesn't work with new DynamicSashWindow 
 733     def OnPopToggleBP(self
, event
): 
 734         """ Toggle break point on right click line, not current line """ 
 735         import DebuggerService
 
 736         wx
.GetApp().GetService(DebuggerService
.DebuggerService
).OnToggleBreakpoint(event
, line
=self
._rightClickLine
) 
 739     def OnPopToggleMarker(self
, event
): 
 740         """ Toggle marker on right click line, not current line """ 
 741         wx
.GetApp().GetDocumentManager().GetCurrentView().MarkerToggle(lineNum 
= self
._rightClickLine
) 
 744     def OnPopSyncOutline(self
, event
): 
 745         wx
.GetApp().GetService(OutlineService
.OutlineService
).LoadOutline(wx
.GetApp().GetDocumentManager().GetCurrentView(), position
=self
._rightClickPosition
) 
 748     def HasSelection(self
): 
 749         return self
.GetSelectionStart() - self
.GetSelectionEnd() != 0   
 752     def ClearCurrentLineMarkers(self
): 
 753         self
.MarkerDeleteAll(CodeCtrl
.CURRENT_LINE_MARKER_NUM
) 
 756     def ClearCurrentBreakpoinMarkers(self
): 
 757         self
.MarkerDeleteAll(CodeCtrl
.BREAKPOINT_MARKER_NUM
) 
 760     def GetDefaultFont(self
): 
 761         if wx
.Platform 
== '__WXMSW__': 
 765         return wx
.Font(10, wx
.DEFAULT
, wx
.NORMAL
, wx
.NORMAL
, faceName 
= font
) 
 768     def GetMatchingBraces(self
): 
 769         """ Overwrite this method for language specific braces """ 
 773     def CanWordWrap(self
): 
 777     def SetFont(self
, font
): 
 781     def SetFontColor(self
, fontColor
): 
 782         self
._fontColor 
= fontColor
 
 785     def UpdateStyles(self
): 
 787         if not self
.GetFont(): 
 790         faces 
= { 'font' : self
.GetFont().GetFaceName(), 
 791                   'size' : self
.GetFont().GetPointSize(), 
 792                   'size2': self
.GetFont().GetPointSize() - 2, 
 793                   'color' : "%02x%02x%02x" % (self
.GetFontColor().Red(), self
.GetFontColor().Green(), self
.GetFontColor().Blue()) 
 796         # Global default styles for all languages 
 797         self
.StyleSetSpec(wx
.stc
.STC_STYLE_DEFAULT
,     "face:%(font)s,fore:#FFFFFF,size:%(size)d" % faces
) 
 798         self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,  "face:%(font)s,back:#C0C0C0,face:%(font)s,size:%(size2)d" % faces
) 
 799         self
.StyleSetSpec(wx
.stc
.STC_STYLE_CONTROLCHAR
, "face:%(font)s" % faces
) 
 800         self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,  "face:%(font)s,fore:#000000,back:#70FFFF,size:%(size)d" % faces
) 
 801         self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,    "face:%(font)s,fore:#000000,back:#FF0000,size:%(size)d" % faces
) 
 804     def OnKeyPressed(self
, event
): 
 805         if self
.CallTipActive(): 
 807         key 
= event
.KeyCode() 
 808         if False:  # key == wx.WXK_SPACE and event.ControlDown(): 
 809             pos 
= self
.GetCurrentPos() 
 811             if event
.ShiftDown(): 
 812                 self
.CallTipSetBackground("yellow") 
 813                 self
.CallTipShow(pos
, 'param1, param2') 
 817                 #for x in range(50000): 
 818                 #    lst.append('%05d' % x) 
 819                 #st = string.join(lst) 
 821                 #self.AutoCompShow(0, st) 
 823                 kw 
= keyword
.kwlist
[:] 
 826                 kw
.append("__init__") 
 829                 kw
.append("this_is_a_longer_value") 
 830                 kw
.append("this_is_a_much_much_much_much_much_much_much_longer_value") 
 832                 kw
.sort()  # Python sorts are case sensitive 
 833                 self
.AutoCompSetIgnoreCase(False)  # so this needs to match 
 835                 self
.AutoCompShow(0, string
.join(kw
)) 
 836         elif key 
== wx
.WXK_RETURN
: 
 839             STCTextEditor
.TextCtrl
.OnKeyPressed(self
, event
) 
 844         self
.EnsureCaretVisible() 
 845         # Need to do a default one for all languges 
 848     def OnMarginClick(self
, evt
): 
 849         # fold and unfold as needed 
 850         if evt
.GetMargin() == 2: 
 851             if evt
.GetShift() and evt
.GetControl(): 
 852                 lineCount 
= self
.GetLineCount() 
 855                 # find out if we are folding or unfolding 
 856                 for lineNum 
in range(lineCount
): 
 857                     if self
.GetFoldLevel(lineNum
) & wx
.stc
.STC_FOLDLEVELHEADERFLAG
: 
 858                         expanding 
= not self
.GetFoldExpanded(lineNum
) 
 861                 self
.ToggleFoldAll(expanding
) 
 863                 lineClicked 
= self
.LineFromPosition(evt
.GetPosition()) 
 864                 if self
.GetFoldLevel(lineClicked
) & wx
.stc
.STC_FOLDLEVELHEADERFLAG
: 
 866                         self
.SetFoldExpanded(lineClicked
, True) 
 867                         self
.Expand(lineClicked
, True, True, 1) 
 868                     elif evt
.GetControl(): 
 869                         if self
.GetFoldExpanded(lineClicked
): 
 870                             self
.SetFoldExpanded(lineClicked
, False) 
 871                             self
.Expand(lineClicked
, False, True, 0) 
 873                             self
.SetFoldExpanded(lineClicked
, True) 
 874                             self
.Expand(lineClicked
, True, True, 100) 
 876                         self
.ToggleFold(lineClicked
) 
 878         elif evt
.GetMargin() == 0: 
 879             #This is used to toggle breakpoints via the debugger service. 
 880             import DebuggerService
 
 881             db_service 
= wx
.GetApp().GetService(DebuggerService
.DebuggerService
) 
 883                 db_service
.OnToggleBreakpoint(evt
, line
=self
.LineFromPosition(evt
.GetPosition())) 
 886     def OnUpdateUI(self
, evt
): 
 887         braces 
= self
.GetMatchingBraces() 
 889         # check for matching braces 
 893         caretPos 
= self
.GetCurrentPos() 
 895             charBefore 
= self
.GetCharAt(caretPos 
- 1) 
 896             styleBefore 
= self
.GetStyleAt(caretPos 
- 1) 
 899         if charBefore 
and chr(charBefore
) in braces
: 
 900             braceAtCaret 
= caretPos 
- 1 
 904             charAfter 
= self
.GetCharAt(caretPos
) 
 905             styleAfter 
= self
.GetStyleAt(caretPos
) 
 906             if charAfter 
and chr(charAfter
) in braces
: 
 907                 braceAtCaret 
= caretPos
 
 909         if braceAtCaret 
>= 0: 
 910             braceOpposite 
= self
.BraceMatch(braceAtCaret
) 
 912         if braceAtCaret 
!= -1  and braceOpposite 
== -1: 
 913             self
.BraceBadLight(braceAtCaret
) 
 915             self
.BraceHighlight(braceAtCaret
, braceOpposite
) 
 920     def ToggleFoldAll(self
, expand 
= True, topLevelOnly 
= False): 
 922         lineCount 
= self
.GetLineCount() 
 924             if not topLevelOnly 
or (topLevelOnly 
and self
.GetFoldLevel(i
) & wx
.stc
.STC_FOLDLEVELNUMBERMASK  
== wx
.stc
.STC_FOLDLEVELBASE
): 
 925                 if (expand 
and self
.CanLineExpand(i
)) or (not expand 
and self
.CanLineCollapse(i
)): 
 930     def CanLineExpand(self
, line
): 
 931         return not self
.GetFoldExpanded(line
) 
 934     def CanLineCollapse(self
, line
): 
 935         return self
.GetFoldExpanded(line
) and self
.GetFoldLevel(line
) & wx
.stc
.STC_FOLDLEVELHEADERFLAG
 
 938     def Expand(self
, line
, doExpand
, force
=False, visLevels
=0, level
=-1): 
 939         lastChild 
= self
.GetLastChild(line
, level
) 
 941         while line 
<= lastChild
: 
 944                     self
.ShowLines(line
, line
) 
 946                     self
.HideLines(line
, line
) 
 949                     self
.ShowLines(line
, line
) 
 952                 level 
= self
.GetFoldLevel(line
) 
 954             if level 
& wx
.stc
.STC_FOLDLEVELHEADERFLAG
: 
 957                         self
.SetFoldExpanded(line
, True) 
 959                         self
.SetFoldExpanded(line
, False) 
 960                     line 
= self
.Expand(line
, doExpand
, force
, visLevels
-1) 
 963                     if doExpand 
and self
.GetFoldExpanded(line
): 
 964                         line 
= self
.Expand(line
, True, force
, visLevels
-1) 
 966                         line 
= self
.Expand(line
, False, force
, visLevels
-1)