1 #----------------------------------------------------------------------------
2 # Name: PythonEditor.py
3 # Purpose: PythonEditor for wx.lib.pydocview tbat uses the Styled Text Control
9 # Copyright: (c) 2004-2005 ActiveGrid, Inc.
10 # License: wxWindows License
11 #----------------------------------------------------------------------------
16 import wx
.lib
.pydocview
18 import keyword
# So it knows what to hilite
19 import wx
.py
# For the Python interpreter
20 import wx
.stc
# For the Python interpreter
21 import cStringIO
# For indent
24 import keyword
# for GetAutoCompleteKeywordList
25 import sys
# for GetAutoCompleteKeywordList
26 import MessageService
# for OnCheckCode
29 import checker
# for pychecker
30 _CHECKER_INSTALLED
= True
32 _CHECKER_INSTALLED
= False
33 import os
.path
# for pychecker
36 if wx
.Platform
== '__WXMSW__':
42 VIEW_PYTHON_INTERPRETER_ID
= wx
.NewId()
45 class PythonDocument(CodeEditor
.CodeDocument
):
49 class PythonView(CodeEditor
.CodeView
):
52 def ProcessUpdateUIEvent(self
, event
):
53 if not self
.GetCtrl():
57 if id == CodeEditor
.CHECK_CODE_ID
:
58 hasText
= self
.GetCtrl().GetTextLength() > 0
62 return CodeEditor
.CodeView
.ProcessUpdateUIEvent(self
, event
)
65 def GetCtrlClass(self
):
66 """ Used in split window to instantiate new instances """
70 def OnActivateView(self
, activate
, activeView
, deactiveView
):
71 STCTextEditor
.TextView
.OnActivateView(self
, activate
, activeView
, deactiveView
)
73 wx
.CallAfter(self
.LoadOutline
) # need CallAfter because document isn't loaded yet
76 def OnClose(self
, deleteWindow
= True):
77 status
= STCTextEditor
.TextView
.OnClose(self
, deleteWindow
)
78 wx
.CallAfter(self
.ClearOutline
) # need CallAfter because when closing the document, it is Activated and then Close, so need to match OnActivateView's CallAfter
82 def GetAutoCompleteKeywordList(self
, context
, hint
):
85 if context
and len(context
):
86 obj
= eval(context
, globals(), locals())
88 if not hint
or len(hint
) == 0: # context isn't valid, maybe it was the hint
92 kw
= keyword
.kwlist
[:]
95 kw
= filter(lambda item
: item
[0] != '_', symTbl
) # remove local variables and methods
97 if hint
and len(hint
):
98 lowerHint
= hint
.lower()
99 filterkw
= filter(lambda item
: item
.lower().startswith(lowerHint
), kw
) # remove variables and methods that don't match hint
102 kw
.sort(self
.CaseInsensitiveCompare
)
105 replaceLen
= len(hint
)
109 return " ".join(kw
), replaceLen
112 def OnCheckCode(self
):
113 if not _CHECKER_INSTALLED
:
114 wx
.MessageBox(_("pychecker not found. Please install pychecker."), _("Check Code"))
117 filename
= os
.path
.basename(self
.GetDocument().GetFilename())
119 # pychecker only works on files, doesn't take a stream or string input
120 if self
.GetDocument().IsModified():
121 dlg
= wx
.MessageDialog(self
.GetFrame(), _("'%s' has been modfied and must be saved first. Save file and check code?") % filename
, _("Check Code"))
122 val
= dlg
.ShowModal()
125 self
.GetDocument().Save()
129 messageService
= wx
.GetApp().GetService(MessageService
.MessageService
)
130 messageService
.ShowWindow()
131 view
= messageService
.GetView()
136 view
.SetCallback(self
.OnJumpToFoundLine
)
138 # Set cursor to Wait cursor
139 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_WAIT
))
141 # This takes a while for involved code
142 checker
.checkSyntax(self
.GetDocument().GetFilename(), view
)
144 # Set cursor to Default cursor
145 wx
.GetApp().GetTopWindow().SetCursor(wx
.StockCursor(wx
.CURSOR_DEFAULT
))
148 def OnJumpToFoundLine(self
, event
):
149 messageService
= wx
.GetApp().GetService(MessageService
.MessageService
)
150 lineText
, pos
= messageService
.GetView().GetCurrLine()
152 lineEnd
= lineText
.find(".py:")
156 lineStart
= lineEnd
+ len(".py:")
157 lineEnd
= lineText
.find(":", lineStart
)
158 lineNum
= int(lineText
[lineStart
:lineEnd
])
160 filename
= lineText
[0:lineStart
- 1]
163 openDocs
= wx
.GetApp().GetDocumentManager().GetDocuments()
164 for openDoc
in openDocs
:
165 if openDoc
.GetFilename() == filename
:
166 foundView
= openDoc
.GetFirstView()
170 doc
= wx
.GetApp().GetDocumentManager().CreateDocument(filename
, wx
.lib
.docview
.DOC_SILENT
)
171 foundView
= doc
.GetFirstView()
174 foundView
.GetFrame().SetFocus()
176 foundView
.GotoLine(lineNum
)
177 startPos
= foundView
.PositionFromLine(lineNum
)
178 endPos
= foundView
.GetLineEndPosition(lineNum
)
179 # wxBug: Need to select in reverse order, (end, start) to put cursor at head of line so positioning is correct
180 # Also, if we use the correct positioning order (start, end), somehow, when we open a edit window for the first
181 # time, we don't see the selection, it is scrolled off screen
182 foundView
.SetSelection(endPos
, startPos
)
183 wx
.GetApp().GetService(OutlineService
.OutlineService
).LoadOutline(foundView
, position
=startPos
)
187 class PythonInterpreterView(wx
.lib
.docview
.View
):
190 def OnCreate(self
, doc
, flags
):
191 frame
= wx
.GetApp().CreateDocumentFrame(self
, doc
, flags
)
192 sizer
= wx
.BoxSizer()
193 self
._pyCrust
= wx
.py
.crust
.Crust(frame
)
194 sizer
.Add(self
._pyCrust
, 1, wx
.EXPAND
, 0)
195 frame
.SetSizer(sizer
)
202 def ProcessEvent(self
, event
):
203 if not hasattr(self
, "_pyCrust") or not self
._pyCrust
:
204 return wx
.lib
.docview
.View
.ProcessEvent(self
, event
)
205 stcControl
= wx
.Window_FindFocus()
206 if not isinstance(stcControl
, wx
.stc
.StyledTextCtrl
):
207 return wx
.lib
.docview
.View
.ProcessEvent(self
, event
)
212 elif id == wx
.ID_REDO
:
215 elif id == wx
.ID_CUT
:
218 elif id == wx
.ID_COPY
:
221 elif id == wx
.ID_PASTE
:
224 elif id == wx
.ID_CLEAR
:
227 elif id == wx
.ID_SELECTALL
:
228 stcControl
.SetSelection(0, -1)
231 return wx
.lib
.docview
.View
.ProcessEvent(self
, event
)
234 def ProcessUpdateUIEvent(self
, event
):
235 if not hasattr(self
, "_pyCrust") or not self
._pyCrust
:
236 return wx
.lib
.docview
.View
.ProcessUpdateUIEvent(self
, event
)
237 stcControl
= wx
.Window_FindFocus()
238 if not isinstance(stcControl
, wx
.stc
.StyledTextCtrl
):
239 return wx
.lib
.docview
.View
.ProcessUpdateUIEvent(self
, event
)
242 event
.Enable(stcControl
.CanUndo())
244 elif id == wx
.ID_REDO
:
245 event
.Enable(stcControl
.CanRedo())
247 elif id == wx
.ID_CUT
:
248 event
.Enable(stcControl
.CanCut())
250 elif id == wx
.ID_COPY
:
251 event
.Enable(stcControl
.CanCopy())
253 elif id == wx
.ID_PASTE
:
254 event
.Enable(stcControl
.CanPaste())
256 elif id == wx
.ID_CLEAR
:
257 event
.Enable(True) # wxBug: should be stcControl.CanCut()) but disabling clear item means del key doesn't work in control as expected
259 elif id == wx
.ID_SELECTALL
:
260 event
.Enable(stcControl
.GetTextLength() > 0)
263 return wx
.lib
.docview
.View
.ProcessUpdateUIEvent(self
, event
)
266 def OnClose(self
, deleteWindow
=True):
267 if deleteWindow
and self
.GetFrame():
268 self
.GetFrame().Destroy()
272 class PythonService(CodeEditor
.CodeService
):
276 CodeEditor
.CodeService
.__init
__(self
)
279 def InstallControls(self
, frame
, menuBar
= None, toolBar
= None, statusBar
= None, document
= None):
280 CodeEditor
.CodeService
.InstallControls(self
, frame
, menuBar
, toolBar
, statusBar
, document
)
282 if document
and document
.GetDocumentTemplate().GetDocumentType() != PythonDocument
:
284 if not document
and wx
.GetApp().GetDocumentManager().GetFlags() & wx
.lib
.docview
.DOC_SDI
:
287 viewMenu
= menuBar
.GetMenu(menuBar
.FindMenu(_("&View")))
289 viewStatusBarItemPos
= self
.GetMenuItemPos(viewMenu
, wx
.lib
.pydocview
.VIEW_STATUSBAR_ID
)
290 viewMenu
.InsertCheckItem(viewStatusBarItemPos
+ 1, VIEW_PYTHON_INTERPRETER_ID
, _("Python &Interpreter"), _("Shows or hides the Python interactive window"))
291 wx
.EVT_MENU(frame
, VIEW_PYTHON_INTERPRETER_ID
, frame
.ProcessEvent
)
292 wx
.EVT_UPDATE_UI(frame
, VIEW_PYTHON_INTERPRETER_ID
, frame
.ProcessUpdateUIEvent
)
295 def ProcessEvent(self
, event
):
297 if id == VIEW_PYTHON_INTERPRETER_ID
:
298 self
.OnViewPythonInterpreter(event
)
301 return CodeEditor
.CodeService
.ProcessEvent(self
, event
)
304 def ProcessUpdateUIEvent(self
, event
):
306 if id == VIEW_PYTHON_INTERPRETER_ID
:
308 docManager
= wx
.GetApp().GetDocumentManager()
310 for doc
in docManager
.GetDocuments():
311 if isinstance(doc
.GetFirstView(), PythonInterpreterView
):
316 return CodeEditor
.CodeService
.ProcessUpdateUIEvent(self
, event
)
319 def OnViewPythonInterpreter(self
, event
):
320 for doc
in wx
.GetApp().GetDocumentManager().GetDocuments():
321 if isinstance(doc
.GetFirstView(), PythonInterpreterView
):
322 doc
.GetFirstView().GetDocument().DeleteAllViews()
325 docManager
= self
.GetDocumentManager()
326 template
= wx
.lib
.docview
.DocTemplate(docManager
,
327 _("Python Interpreter"),
331 _("Python Interpreter Document"),
332 _("Python Interpreter View"),
333 wx
.lib
.docview
.Document
,
334 PythonInterpreterView
,
335 flags
= wx
.lib
.docview
.TEMPLATE_INVISIBLE
)
336 newDoc
= template
.CreateDocument('', wx
.lib
.docview
.DOC_SILENT
)
338 newDoc
.SetDocumentName(template
.GetDocumentName())
339 newDoc
.SetDocumentTemplate(template
)
340 newDoc
.OnNewDocument()
341 newDoc
.SetWriteable(False)
342 newDoc
.GetFirstView().GetFrame().SetTitle(_("Python Interpreter"))
345 class PythonCtrl(CodeEditor
.CodeCtrl
):
348 def __init__(self
, parent
, ID
= -1, style
= wx
.NO_FULL_REPAINT_ON_RESIZE
):
349 CodeEditor
.CodeCtrl
.__init
__(self
, parent
, ID
, style
)
350 self
.SetProperty("tab.timmy.whinge.level", "1")
351 self
.SetProperty("fold.comment.python", "1")
352 self
.SetProperty("fold.quotes.python", "1")
353 self
.SetLexer(wx
.stc
.STC_LEX_PYTHON
)
354 self
.SetKeyWords(0, string
.join(keyword
.kwlist
))
357 def SetViewDefaults(self
):
358 CodeEditor
.CodeCtrl
.SetViewDefaults(self
, configPrefix
= "Python", hasWordWrap
= False, hasTabs
= True)
361 def GetFontAndColorFromConfig(self
):
362 return CodeEditor
.CodeCtrl
.GetFontAndColorFromConfig(self
, configPrefix
= "Python")
365 def UpdateStyles(self
):
366 CodeEditor
.CodeCtrl
.UpdateStyles(self
)
368 if not self
.GetFont():
371 faces
= { 'font' : self
.GetFont().GetFaceName(),
372 'size' : self
.GetFont().GetPointSize(),
373 'size2': self
.GetFont().GetPointSize() - 2,
374 'color' : "%02x%02x%02x" % (self
.GetFontColor().Red(), self
.GetFontColor().Green(), self
.GetFontColor().Blue())
379 self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, "face:%(font)s,fore:#000000,face:%(font)s,size:%(size)d" % faces
)
381 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
, "face:%(font)s,fore:#007F00,italic,face:%(font)s,size:%(size)d" % faces
)
383 self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, "face:%(font)s,fore:#007F7F,size:%(size)d" % faces
)
385 self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, "face:%(font)s,fore:#7F007F,face:%(font)s,size:%(size)d" % faces
)
386 # Single quoted string
387 self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, "face:%(font)s,fore:#7F007F,face:%(font)s,size:%(size)d" % faces
)
389 self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, "face:%(font)s,fore:#00007F,bold,size:%(size)d" % faces
)
391 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, "face:%(font)s,fore:#7F0000,size:%(size)d" % faces
)
392 # Triple double quotes
393 self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, "face:%(font)s,fore:#7F0000,size:%(size)d" % faces
)
394 # Class name definition
395 self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, "face:%(font)s,fore:#0000FF,bold,size:%(size)d" % faces
)
396 # Function or method name definition
397 self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, "face:%(font)s,fore:#007F7F,bold,size:%(size)d" % faces
)
399 self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, "face:%(font)s,size:%(size)d" % faces
)
401 self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, "face:%(font)s,fore:#%(color)s,face:%(font)s,size:%(size)d" % faces
)
403 self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, "face:%(font)s,fore:#7F7F7F,size:%(size)d" % faces
)
404 # End of line where string is not closed
405 self
.StyleSetSpec(wx
.stc
.STC_P_STRINGEOL
, "face:%(font)s,fore:#000000,face:%(font)s,back:#E0C0E0,eol,size:%(size)d" % faces
)
408 def OnUpdateUI(self
, evt
):
409 braces
= self
.GetMatchingBraces()
411 # check for matching braces
415 caretPos
= self
.GetCurrentPos()
417 charBefore
= self
.GetCharAt(caretPos
- 1)
418 styleBefore
= self
.GetStyleAt(caretPos
- 1)
421 if charBefore
and chr(charBefore
) in braces
and styleBefore
== wx
.stc
.STC_P_OPERATOR
:
422 braceAtCaret
= caretPos
- 1
426 charAfter
= self
.GetCharAt(caretPos
)
427 styleAfter
= self
.GetStyleAt(caretPos
)
428 if charAfter
and chr(charAfter
) in braces
and styleAfter
== wx
.stc
.STC_P_OPERATOR
:
429 braceAtCaret
= caretPos
431 if braceAtCaret
>= 0:
432 braceOpposite
= self
.BraceMatch(braceAtCaret
)
434 if braceAtCaret
!= -1 and braceOpposite
== -1:
435 self
.BraceBadLight(braceAtCaret
)
437 self
.BraceHighlight(braceAtCaret
, braceOpposite
)
443 (text
, caretPos
) = self
.GetCurLine()
445 self
._tokenizerChars
= {} # This is really too much, need to find something more like a C array
446 for i
in range(len(text
)):
447 self
._tokenizerChars
[i
] = 0
449 ctext
= cStringIO
.StringIO(text
)
451 tokenize
.tokenize(ctext
.readline
, self
)
455 # Left in for debugging purposes:
456 #for i in range(len(text)):
457 # print i, text[i], self._tokenizerChars[i]
459 if caretPos
== 0 or len(string
.strip(text
)) == 0: # At beginning of line or within an empty line
462 doExtraIndent
= False
468 startSquareBracketCount
= 0
469 endSquareBracketCount
= 0
470 startCurlyBracketCount
= 0
471 endCurlyBracketCount
= 0
474 for i
in range(caretPos
- 1, -1, -1): # Go through each character before the caret
475 if i
>= len(text
): # Sometimes the caret is at the end of the text if there is no LF
477 if self
._tokenizerChars
[i
] == 1:
479 elif self
._tokenizerChars
[i
] == 2:
480 startQuoteCount
= startQuoteCount
+ 1
481 elif self
._tokenizerChars
[i
] == 3:
482 endQuoteCount
= endQuoteCount
+ 1
483 elif text
[i
] == '(': # Would be nice to use a dict for this, but the code is much more readable this way
484 startParenCount
= startParenCount
+ 1
486 endParenCount
= endParenCount
+ 1
488 startSquareBracketCount
= startSquareBracketCount
+ 1
490 endSquareBracketCount
= endSquareBracketCount
+ 1
492 startCurlyBracketCount
= startCurlyBracketCount
+ 1
494 endCurlyBracketCount
= endCurlyBracketCount
+ 1
498 if startQuoteCount
> endQuoteCount
or startParenCount
> endParenCount
or startSquareBracketCount
> endSquareBracketCount
or startCurlyBracketCount
> endCurlyBracketCount
:
499 if i
+ 1 >= caretPos
: # Caret is right at the open paren, so just do indent as if colon was there
503 spaces
= " " * (i
+ 1)
507 spaces
= text
[0:len(text
) - len(string
.lstrip(text
))]
508 if caretPos
< len(spaces
): # If within the opening spaces of a line
509 spaces
= spaces
[:caretPos
]
512 if commentStart
!= -1:
513 text
= text
[0:commentStart
]
515 textNoTrailingSpaces
= text
[0:caretPos
].rstrip()
516 if doExtraIndent
or len(textNoTrailingSpaces
) and textNoTrailingSpaces
[-1] == ':':
517 spaces
= spaces
+ ' ' * self
.GetIndent()
518 self
.AddText('\n' + spaces
)
521 # Callback for tokenizer in self.DoIndent
522 def __call__(self
, toktype
, toktext
, (srow
,scol
), (erow
,ecol
), line
):
523 if toktype
== tokenize
.COMMENT
:
524 for i
in range(scol
, ecol
+ 1):
525 self
._validChars
[i
] = False
526 elif toktype
== token
.STRING
:
527 self
._tokenizerChars
[scol
] = 2 # Open quote
528 self
._tokenizerChars
[ecol
- 1] = 3 # Close quote
529 for i
in range(scol
+ 1, ecol
- 2):
530 self
._tokenizerChars
[i
] = 1 # Part of string, 1 == ignore the char
533 class PythonOptionsPanel(wx
.Panel
):
535 def __init__(self
, parent
, id):
536 wx
.Panel
.__init
__(self
, parent
, id)
537 pathLabel
= wx
.StaticText(self
, -1, _("python.exe Path:"))
538 config
= wx
.ConfigBase_Get()
539 path
= config
.Read("ActiveGridPythonLocation")
540 self
._pathTextCtrl
= wx
.TextCtrl(self
, -1, path
, size
= (150, -1))
541 self
._pathTextCtrl
.SetToolTipString(self
._pathTextCtrl
.GetValue())
542 self
._pathTextCtrl
.SetInsertionPointEnd()
543 choosePathButton
= wx
.Button(self
, -1, _("Browse..."))
544 pathSizer
= wx
.BoxSizer(wx
.HORIZONTAL
)
546 pathSizer
.Add(pathLabel
, 0, wx
.ALIGN_LEFT | wx
.LEFT | wx
.RIGHT | wx
.TOP
, HALF_SPACE
)
547 pathSizer
.Add(self
._pathTextCtrl
, 0, wx
.ALIGN_LEFT | wx
.EXPAND | wx
.RIGHT
, HALF_SPACE
)
548 pathSizer
.Add(choosePathButton
, 0, wx
.ALIGN_RIGHT | wx
.LEFT
, HALF_SPACE
)
549 wx
.EVT_BUTTON(self
, choosePathButton
.GetId(), self
.OnChoosePath
)
550 mainSizer
= wx
.BoxSizer(wx
.VERTICAL
)
551 mainSizer
.Add(pathSizer
, 0, wx
.LEFT | wx
.RIGHT | wx
.TOP
, 10)
553 self
._otherOptions
= STCTextEditor
.TextOptionsPanel(self
, -1, configPrefix
= "Python", label
= "Python", hasWordWrap
= False, hasTabs
= True, addPage
=False)
554 mainSizer
.Add(self
._otherOptions
)
555 self
.SetSizer(mainSizer
)
556 parent
.AddPage(self
, _("Python"))
558 def OnChoosePath(self
, event
):
560 wildcard
= _("*.exe")
563 path
= wx
.FileSelector(_("Select a File"),
566 wildcard
= wildcard
,
567 flags
= wx
.HIDE_READONLY
,
568 parent
= wx
.GetApp().GetTopWindow())
570 self
._pathTextCtrl
.SetValue(path
)
571 self
._pathTextCtrl
.SetToolTipString(self
._pathTextCtrl
.GetValue())
572 self
._pathTextCtrl
.SetInsertionPointEnd()
574 def OnOK(self
, optionsDialog
):
575 if len(self
._pathTextCtrl
.GetValue()) > 0:
576 config
= wx
.ConfigBase_Get()
577 config
.Write("ActiveGridPythonLocation", self
._pathTextCtrl
.GetValue())
579 self
._otherOptions
.OnOK(optionsDialog
)
580 #----------------------------------------------------------------------------
581 # Icon Bitmaps - generated by encode_bitmaps.py
582 #----------------------------------------------------------------------------
583 from wx
import ImageFromStream
, BitmapFromImage
589 "\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\
590 \x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\
591 \x00\x00\xd5IDAT8\x8d\x8d\x93Y\x0e\xc3 \x0cD\x9fM\xcf\xddNr2.\x96\xb8\x1f\
592 \x05\n\x84.#Y\x10\xa3\x19o\xb1\x99'*\xe2<\x82\x0e\xe6\xc9\xf8\x01\xef?\xa4\
593 \xf7)]\x05\x970O\xcdr\xce!\x119\xe7\x00\x02\x88\xfe}i\xb5\x848\x8f\xa8\x19\
594 \xcc\x19}+\xc5\xcc\xd3\x92<CZ\x0b\x99\xc4\xb2N\x01<\x80\xad\xdc?\x88\xf8\x1c\
595 X\x8f7\xe1\x1f\xdc*\xa9a+\xe1\xa3\xdc\xe7\xb4\xf6\xd1\xe5\xb6'\xc3@\xc5\xa0#\
596 \xab\x94\xd1\x0bL\xf0\xe6\x17\xa8v\xc3\x8aS\xa0.\x8be\x13\xe3\x15\x8f\xe1\
597 \xa5D\xee\xc9\xdb~%\xc7y\x84\xbb'sO\xd6\xd4\x17\xe4~\xc4\xf5\xef\xac\xa7\r\
598 \xbbp?b&\x0f\x89i\x14\x93\xca\x14z\xc5oh\x02E\xc4<\xd92\x03\xe0:B^\xc4K#\xe7\
599 \xe5\x00\x02\xfd\xb9H\x9ex\x02\x9a\x05a\xd2\xd3c\xc0\xcc\x00\x00\x00\x00IEND\
603 def getPythonBitmap():
604 return BitmapFromImage(getPythonImage())
606 def getPythonImage():
607 stream
= cStringIO
.StringIO(getPythonData())
608 return ImageFromStream(stream
)
611 return wx
.IconFromBitmap(getPythonBitmap())