2 #---------------------------------------------------------------------------- 
   4 # Purpose:      Testing lots of stuff, controls, window types, etc. 
   8 # Created:      A long time ago, in a galaxy far, far away... 
  10 # Copyright:    (c) 1999 by Total Control Software 
  11 # Licence:      wxWindows license 
  12 #---------------------------------------------------------------------------- 
  15 # * Problems with flickering related to ERASE_BACKGROUND 
  16 #     and the splitters. Might be a problem with this 2.5 beta...? 
  17 #     UPDATE: can't see on 2.5.2 GTK - maybe just a faster machine :) 
  19 # * Annoying switching between tabs and resulting flicker 
  20 #     how to replace a page in the notebook without deleting/adding? 
  21 #     Where is SetPage!? tried freeze...tried reparent of dummy panel.... 
  24 # * UI design more prefessional 
  25 # * save file positions (new field in demoModules) (@ LoadDemoSource) 
  26 # * Update main overview 
  28 # * Why don't we move _treeList into a separate module 
  30 import sys
, os
, time
, traceback
, types
 
  32 import wx                  
# This module uses the new wx namespace 
  39 ##print "wx.VERSION_STRING = %s (%s)" % (wx.VERSION_STRING, wx.USE_UNICODE and 'unicode' or 'ansi') 
  40 ##print "pid:", os.getpid() 
  41 ##raw_input("Press Enter...") 
  44 #--------------------------------------------------------------------------- 
  49     ('Recent Additions/Updates', [ 
  51         'AUI_DockingWindowMgr', 
  70     # managed windows == things with a (optional) caption you can close 
  71     ('Frames and Dialogs', [ 
  72         'AUI_DockingWindowMgr', 
  96     # dialogs from libraries 
  99         'ScrolledMessageDialog', 
 103     ('Core Windows/Controls', [ 
 140     ('"Book" Controls', [ 
 149     ('Custom Controls', [ 
 165     # controls coming from other libraries 
 166     ('More Windows/Controls', [ 
 167         'ActiveX_FlashWindow', 
 168         'ActiveX_IEHtmlWindow', 
 170         #'RightTextCtrl',     deprecated as we have wxTE_RIGHT now. 
 173         'CheckListCtrlMixin', 
 189         'MaskedEditControls', 
 192         'MultiSplitterWindow', 
 209     # How to lay out the controls in a frame/dialog 
 219         'XmlResourceHandler', 
 220         'XmlResourceSubclass', 
 224     ('Process and Events', [ 
 232         ##'infoframe',    # needs better explanation and some fixing 
 236     ('Clipboard and DnD', [ 
 262         ##'DialogUnits',   # needs more explanations 
 281     ('Check out the samples dir too', [ 
 288 #--------------------------------------------------------------------------- 
 289 # Show how to derive a custom wxLog class 
 291 class MyLog(wx
.PyLog
): 
 292     def __init__(self
, textCtrl
, logTime
=0): 
 293         wx
.PyLog
.__init
__(self
) 
 295         self
.logTime 
= logTime
 
 297     def DoLogString(self
, message
, timeStamp
): 
 298         #print message, timeStamp 
 300         #    message = time.strftime("%X", time.localtime(timeStamp)) + \ 
 303             self
.tc
.AppendText(message 
+ '\n') 
 306 class MyTP(wx
.PyTipProvider
): 
 308         return "This is my tip" 
 310 #--------------------------------------------------------------------------- 
 311 # A class to be used to simply display a message in the demo pane 
 312 # rather than running the sample itself. 
 314 class MessagePanel(wx
.Panel
): 
 315     def __init__(self
, parent
, message
, caption
='', flags
=0): 
 316         wx
.Panel
.__init
__(self
, parent
) 
 321             if flags 
& wx
.ICON_EXCLAMATION
: 
 322                 artid 
= wx
.ART_WARNING            
 
 323             elif flags 
& wx
.ICON_ERROR
: 
 325             elif flags 
& wx
.ICON_QUESTION
: 
 326                 artid 
= wx
.ART_QUESTION
 
 327             elif flags 
& wx
.ICON_INFORMATION
: 
 328                 artid 
= wx
.ART_INFORMATION
 
 330             if artid 
is not None: 
 331                 bmp 
= wx
.ArtProvider
.GetBitmap(artid
, wx
.ART_MESSAGE_BOX
, (32,32)) 
 332                 icon 
= wx
.StaticBitmap(self
, -1, bmp
) 
 334                 icon 
= (32,32) # make a spacer instead 
 337             caption 
= wx
.StaticText(self
, -1, caption
) 
 338             caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
)) 
 340         message 
= wx
.StaticText(self
, -1, message
) 
 342         # add to sizers for layout 
 343         tbox 
= wx
.BoxSizer(wx
.VERTICAL
) 
 349         hbox 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 356         box 
= wx
.BoxSizer(wx
.VERTICAL
) 
 358         box
.Add(hbox
, 0, wx
.EXPAND
) 
 365 #--------------------------------------------------------------------------- 
 366 # A class to be used to display source code in the demo.  Try using the 
 367 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl 
 368 # if there is an error, such as the stc module not being present. 
 372     ##raise ImportError     # for testing the alternate implementation 
 374     from StyledTextCtrl_2 
import PythonSTC
 
 376     class DemoCodeEditor(PythonSTC
): 
 377         def __init__(self
, parent
): 
 378             PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
) 
 381         # Some methods to make it compatible with how the wxTextCtrl is used 
 382         def SetValue(self
, value
): 
 384                 value 
= value
.decode('iso8859_1') 
 386             self
.EmptyUndoBuffer() 
 389         def IsModified(self
): 
 390             return self
.GetModify() 
 395         def SetInsertionPoint(self
, pos
): 
 396             self
.SetCurrentPos(pos
) 
 399         def ShowPosition(self
, pos
): 
 400             line 
= self
.LineFromPosition(pos
) 
 401             #self.EnsureVisible(line) 
 404         def GetLastPosition(self
): 
 405             return self
.GetLength() 
 407         def GetPositionFromLine(self
, line
): 
 408             return self
.PositionFromLine(line
) 
 410         def GetRange(self
, start
, end
): 
 411             return self
.GetTextRange(start
, end
) 
 413         def GetSelection(self
): 
 414             return self
.GetAnchor(), self
.GetCurrentPos() 
 416         def SetSelection(self
, start
, end
): 
 417             self
.SetSelectionStart(start
) 
 418             self
.SetSelectionEnd(end
) 
 420         def SelectLine(self
, line
): 
 421             start 
= self
.PositionFromLine(line
) 
 422             end 
= self
.GetLineEndPosition(line
) 
 423             self
.SetSelection(start
, end
) 
 425         def SetUpEditor(self
): 
 427             This method carries out the work of setting up the demo editor.             
 428             It's seperate so as not to clutter up the init code. 
 432             self
.SetLexer(stc
.STC_LEX_PYTHON
) 
 433             self
.SetKeyWords(0, " ".join(keyword
.kwlist
)) 
 436             self
.SetProperty("fold", "1" )  
 438             # Highlight tab/space mixing (shouldn't be any) 
 439             self
.SetProperty("tab.timmy.whinge.level", "1") 
 441             # Set left and right margins 
 444             # Set up the numbers in the margin for margin #1 
 445             self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
) 
 446             # Reasonable value for, say, 4-5 digits using a mono font (40 pix) 
 447             self
.SetMarginWidth(1, 40) 
 449             # Indentation and tab stuff 
 450             self
.SetIndent(4)               # Proscribed indent size for wx 
 451             self
.SetIndentationGuides(True) # Show indent guides 
 452             self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space 
 453             self
.SetTabIndents(True)        # Tab key indents 
 454             self
.SetTabWidth(4)             # Proscribed tab size for wx 
 455             self
.SetUseTabs(False)          # Use spaces rather than tabs, or 
 456                                             # TabTimmy will complain!     
 458             self
.SetViewWhiteSpace(False)   # Don't view white space 
 460             # EOL: Since we are loading/saving ourselves, and the 
 461             # strings will always have \n's in them, set the STC to 
 462             # edit them that way.             
 463             self
.SetEOLMode(wx
.stc
.STC_EOL_LF
) 
 464             self
.SetViewEOL(False) 
 466             # No right-edge mode indicator 
 467             self
.SetEdgeMode(stc
.STC_EDGE_NONE
) 
 469             # Setup a margin to hold fold markers 
 470             self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
) 
 471             self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
) 
 472             self
.SetMarginSensitive(2, True) 
 473             self
.SetMarginWidth(2, 12) 
 475             # and now set up the fold markers 
 476             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
,     stc
.STC_MARK_BOXPLUSCONNECTED
,  "white", "black") 
 477             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black") 
 478             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
,  "white", "black") 
 479             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
,    stc
.STC_MARK_LCORNER
,  "white", "black") 
 480             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
,     stc
.STC_MARK_VLINE
,    "white", "black") 
 481             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
,        stc
.STC_MARK_BOXPLUS
,  "white", "black") 
 482             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
,    stc
.STC_MARK_BOXMINUS
, "white", "black") 
 484             # Global default style 
 485             if wx
.Platform 
== '__WXMSW__': 
 486                 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,  
 487                                   'fore:#000000,back:#FFFFFF,face:Courier New,size:9') 
 489                 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,  
 490                                   'fore:#000000,back:#FFFFFF,face:Courier,size:9') 
 492             # Clear styles and revert to default. 
 495             # Following style specs only indicate differences from default. 
 496             # The rest remains unchanged. 
 498             # Line numbers in margin 
 499             self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')     
 501             self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00') 
 503             self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000') 
 505             self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD") 
 508             self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000') 
 510             self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
,  'fore:#008000,back:#F0FFF0') 
 511             self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0') 
 513             self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080') 
 514             # Strings and characters 
 515             self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080') 
 516             self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080') 
 518             self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold') 
 520             self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA') 
 521             self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA') 
 523             self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold') 
 525             self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold') 
 527             self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold') 
 528             # Identifiers. I leave this as not bold because everything seems 
 529             # to be an identifier if it doesn't match the above criterae 
 530             self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000') 
 533             self
.SetCaretForeground("BLUE") 
 534             # Selection background 
 535             self
.SetSelBackground(1, '#66CCFF') 
 537             self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
)) 
 538             self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
)) 
 540         def RegisterModifiedEvent(self
, eventHandler
): 
 541             self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
) 
 545     class DemoCodeEditor(wx
.TextCtrl
): 
 546         def __init__(self
, parent
): 
 547             wx
.TextCtrl
.__init
__(self
, parent
, -1, style 
= 
 548                                  wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
) 
 550         def RegisterModifiedEvent(self
, eventHandler
): 
 551             self
.Bind(wx
.EVT_TEXT
, eventHandler
) 
 553         def SetReadOnly(self
, flag
): 
 554             self
.SetEditable(not flag
) 
 555             # NOTE: STC already has this method 
 558             return self
.GetValue() 
 560         def GetPositionFromLine(self
, line
): 
 561             return self
.XYToPosition(0,line
) 
 563         def GotoLine(self
, line
): 
 564             pos 
= self
.GetPositionFromLine(line
) 
 565             self
.SetInsertionPoint(pos
) 
 566             self
.ShowPosition(pos
) 
 568         def SelectLine(self
, line
): 
 569             start 
= self
.GetPositionFromLine(line
) 
 570             end 
= start 
+ self
.GetLineLength(line
) 
 571             self
.SetSelection(start
, end
) 
 574 #--------------------------------------------------------------------------- 
 575 # Constants for module versions 
 579 modDefault 
= modOriginal
 
 581 #--------------------------------------------------------------------------- 
 583 class DemoCodePanel(wx
.Panel
): 
 584     """Panel for the 'Demo Code' tab""" 
 585     def __init__(self
, parent
, mainFrame
): 
 586         wx
.Panel
.__init
__(self
, parent
, size
=(1,1)) 
 587         if 'wxMSW' in wx
.PlatformInfo
: 
 589         self
.mainFrame 
= mainFrame
 
 590         self
.editor 
= DemoCodeEditor(self
) 
 591         self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
) 
 593         self
.btnSave 
= wx
.Button(self
, -1, "Save Changes") 
 594         self
.btnRestore 
= wx
.Button(self
, -1, "Delete Modified") 
 595         self
.btnSave
.Enable(False) 
 596         self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
) 
 597         self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
) 
 599         self
.radioButtons 
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style 
= wx
.RB_GROUP
), 
 600                               modModified
: wx
.RadioButton(self
, -1, "Modified") } 
 602         self
.controlBox 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 603         self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0, 
 604                             wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5) 
 605         for modID
, radioButton 
in self
.radioButtons
.items(): 
 606             self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5) 
 607             radioButton
.modID 
= modID 
# makes it easier for the event handler 
 608             radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
) 
 610         self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5) 
 611         self
.controlBox
.Add(self
.btnRestore
, 0) 
 613         self
.box 
= wx
.BoxSizer(wx
.VERTICAL
) 
 614         self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
) 
 615         self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
) 
 616         self
.box
.Add(self
.editor
, 1, wx
.EXPAND
) 
 619         self
.SetSizer(self
.box
) 
 622     # Loads a demo from a DemoModules object 
 623     def LoadDemo(self
, demoModules
): 
 624         self
.demoModules 
= demoModules
 
 625         if (modDefault 
== modModified
) and demoModules
.Exists(modModified
): 
 626             demoModules
.SetActive(modModified
) 
 628             demoModules
.SetActive(modOriginal
) 
 629         self
.radioButtons
[demoModules
.GetActiveID()].Enable(True) 
 630         self
.ActiveModuleChanged() 
 633     def ActiveModuleChanged(self
): 
 634         self
.LoadDemoSource(self
.demoModules
.GetSource()) 
 635         self
.UpdateControlState() 
 639     def LoadDemoSource(self
, source
): 
 641         self
.editor
.SetValue(source
) 
 643         self
.btnSave
.Enable(False) 
 646     def JumpToLine(self
, line
, highlight
=False): 
 647         self
.editor
.GotoLine(line
) 
 648         self
.editor
.SetFocus() 
 650             self
.editor
.SelectLine(line
) 
 653     def UpdateControlState(self
): 
 654         active 
= self
.demoModules
.GetActiveID() 
 655         # Update the radio/restore buttons 
 656         for moduleID 
in self
.radioButtons
: 
 657             btn 
= self
.radioButtons
[moduleID
] 
 658             if moduleID 
== active
: 
 663             if self
.demoModules
.Exists(moduleID
): 
 665                 if moduleID 
== modModified
: 
 666                     self
.btnRestore
.Enable(True) 
 669                 if moduleID 
== modModified
: 
 670                     self
.btnRestore
.Enable(False) 
 673     def OnRadioButton(self
, event
): 
 674         radioSelected 
= event
.GetEventObject() 
 675         modSelected 
= radioSelected
.modID
 
 676         if modSelected 
!= self
.demoModules
.GetActiveID(): 
 677             busy 
= wx
.BusyInfo("Reloading demo module...") 
 678             self
.demoModules
.SetActive(modSelected
) 
 679             self
.ActiveModuleChanged() 
 682     def ReloadDemo(self
): 
 683         if self
.demoModules
.name 
!= __name__
: 
 684             self
.mainFrame
.RunModule() 
 687     def OnCodeModified(self
, event
): 
 688         self
.btnSave
.Enable(self
.editor
.IsModified()) 
 691     def OnSave(self
, event
): 
 692         if self
.demoModules
.Exists(modModified
): 
 693             if self
.demoModules
.GetActiveID() == modOriginal
: 
 694                 overwriteMsg 
= "You are about to overwrite an already existing modified copy\n" + \
 
 695                                "Do you want to continue?" 
 696                 dlg 
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo", 
 697                                        wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
) 
 698                 result 
= dlg
.ShowModal() 
 699                 if result 
== wx
.ID_NO
: 
 703         self
.demoModules
.SetActive(modModified
) 
 704         modifiedFilename 
= GetModifiedFilename(self
.demoModules
.name
) 
 706         # Create the demo directory if one doesn't already exist 
 707         if not os
.path
.exists(GetModifiedDirectory()): 
 709                 os
.makedirs(GetModifiedDirectory()) 
 710                 if not os
.path
.exists(GetModifiedDirectory()): 
 711                     wx
.LogMessage("BUG: Created demo directory but it still doesn't exist") 
 714                 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory()) 
 717                 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory()) 
 720         f 
= open(modifiedFilename
, "wt") 
 721         source 
= self
.editor
.GetText() 
 727         busy 
= wx
.BusyInfo("Reloading demo module...") 
 728         self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
) 
 729         self
.ActiveModuleChanged() 
 732     def OnRestore(self
, event
): # Handles the "Delete Modified" button 
 733         modifiedFilename 
= GetModifiedFilename(self
.demoModules
.name
) 
 734         self
.demoModules
.Delete(modModified
) 
 735         os
.unlink(modifiedFilename
) # Delete the modified copy 
 736         busy 
= wx
.BusyInfo("Reloading demo module...") 
 737         self
.ActiveModuleChanged() 
 740 #--------------------------------------------------------------------------- 
 743     """Convert paths to the platform-specific separator""" 
 744     str = apply(os
.path
.join
, tuple(path
.split('/'))) 
 745     # HACK: on Linux, a leading / gets lost... 
 746     if path
.startswith('/'): 
 751 def GetModifiedDirectory(): 
 753     Returns the directory where modified versions of the demo files 
 756     return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/") 
 759 def GetModifiedFilename(name
): 
 761     Returns the filename of the modified version of the specified demo 
 763     if not name
.endswith(".py"): 
 765     return GetModifiedDirectory() + name
 
 768 def GetOriginalFilename(name
): 
 770     Returns the filename of the original version of the specified demo 
 772     if not name
.endswith(".py"): 
 777 def DoesModifiedExist(name
): 
 778     """Returns whether the specified demo has a modified copy""" 
 779     if os
.path
.exists(GetModifiedFilename(name
)): 
 785 #--------------------------------------------------------------------------- 
 787 class ModuleDictWrapper
: 
 788     """Emulates a module with a dynamically compiled __dict__""" 
 789     def __init__(self
, dict): 
 792     def __getattr__(self
, name
): 
 793         if name 
in self
.dict: 
 794             return self
.dict[name
] 
 800     Dynamically manages the original/modified versions of a demo 
 803     def __init__(self
, name
): 
 807         #              (dict , source ,  filename , description   , error information )         
 808         #              (  0  ,   1    ,     2     ,      3        ,          4        )         
 809         self
.modules 
= [[None,  ""    ,    ""     , "<original>"  ,        None], 
 810                         [None,  ""    ,    ""     , "<modified>"  ,        None]] 
 812         # load original module 
 813         self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
)) 
 814         self
.SetActive(modOriginal
) 
 816         # load modified module (if one exists) 
 817         if DoesModifiedExist(name
): 
 818            self
.LoadFromFile(modModified
, GetModifiedFilename(name
)) 
 821     def LoadFromFile(self
, modID
, filename
): 
 822         self
.modules
[modID
][2] = filename
 
 823         file = open(filename
, "rt") 
 824         self
.LoadFromSource(modID
, file.read()) 
 828     def LoadFromSource(self
, modID
, source
): 
 829         self
.modules
[modID
][1] = source
 
 833     def LoadDict(self
, modID
): 
 834         if self
.name 
!= __name__
: 
 835             source 
= self
.modules
[modID
][1] 
 836             #description = self.modules[modID][3] 
 837             description 
= self
.modules
[modID
][2] 
 840                 self
.modules
[modID
][0] = {} 
 841                 code 
= compile(source
, description
, "exec")         
 842                 exec code 
in self
.modules
[modID
][0] 
 844                 self
.modules
[modID
][4] = DemoError(sys
.exc_info()) 
 845                 self
.modules
[modID
][0] = None 
 847                 self
.modules
[modID
][4] = None 
 850     def SetActive(self
, modID
): 
 851         if modID 
!= modOriginal 
and modID 
!= modModified
: 
 854             self
.modActive 
= modID
 
 858         dict = self
.modules
[self
.modActive
][0] 
 862             return ModuleDictWrapper(dict) 
 865     def GetActiveID(self
): 
 866         return self
.modActive
 
 869     def GetSource(self
, modID 
= None): 
 871             modID 
= self
.modActive
 
 872         return self
.modules
[modID
][1] 
 875     def GetFilename(self
, modID 
= None): 
 877             modID 
= self
.modActive
 
 878         return self
.modules
[self
.modActive
][2] 
 881     def GetErrorInfo(self
, modID 
= None): 
 883             modID 
= self
.modActive
 
 884         return self
.modules
[self
.modActive
][4] 
 887     def Exists(self
, modID
): 
 888         return self
.modules
[modID
][1] != "" 
 891     def UpdateFile(self
, modID 
= None): 
 892         """Updates the file from which a module was loaded 
 893         with (possibly updated) source""" 
 895             modID 
= self
.modActive
 
 897         source 
= self
.modules
[modID
][1] 
 898         filename 
= self
.modules
[modID
][2] 
 901             file = open(filename
, "wt") 
 907     def Delete(self
, modID
): 
 908         if self
.modActive 
== modID
: 
 911         self
.modules
[modID
][0] = None 
 912         self
.modules
[modID
][1] = "" 
 913         self
.modules
[modID
][2] = "" 
 916 #--------------------------------------------------------------------------- 
 919     """Wraps and stores information about the current exception""" 
 920     def __init__(self
, exc_info
): 
 923         excType
, excValue 
= exc_info
[:2] 
 924         # traceback list entries: (filename, line number, function name, text) 
 925         self
.traceback 
= traceback
.extract_tb(exc_info
[2]) 
 927         # --Based on traceback.py::format_exception_only()-- 
 928         if type(excType
) == types
.ClassType
: 
 929             self
.exception_type 
= excType
.__name
__ 
 931             self
.exception_type 
= excType
 
 933         # If it's a syntax error, extra information needs 
 934         # to be added to the traceback 
 935         if excType 
is SyntaxError: 
 937                 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
 
 942                     filename 
= "<string>" 
 944                 self
.traceback
.append( (filename
, lineno
, "", line
) ) 
 947             self
.exception_details 
= str(excValue
) 
 949             self
.exception_details 
= "<unprintable %s object>" & type(excValue
).__name
__ 
 956         Details  : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details 
) 
 959 #--------------------------------------------------------------------------- 
 961 class DemoErrorPanel(wx
.Panel
): 
 962     """Panel put into the demo tab when the demo fails to run due  to errors""" 
 964     def __init__(self
, parent
, codePanel
, demoError
, log
): 
 965         wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE) 
 966         self
.codePanel 
= codePanel
 
 970         self
.box 
= wx
.BoxSizer(wx
.VERTICAL
) 
 973         self
.box
.Add(wx
.StaticText(self
, -1, "An error has occurred while trying to run the demo") 
 974                      , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10) 
 976         # Exception Information 
 977         boxInfo      
= wx
.StaticBox(self
, -1, "Exception Info" ) 
 978         boxInfoSizer 
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL 
) # Used to center the grid within the box 
 979         boxInfoGrid  
= wx
.FlexGridSizer(0, 2, 0, 0) 
 980         textFlags    
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
 
 981         boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 ) 
 982         boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_type
) , 0, textFlags
, 5 ) 
 983         boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 ) 
 984         boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 ) 
 985         boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 ) 
 986         self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5) 
 988         # Set up the traceback list 
 989         # This one automatically resizes last column to take up remaining space 
 990         from ListCtrl 
import TestListCtrl
 
 991         self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT  | wx
.SUNKEN_BORDER
) 
 992         self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
) 
 993         self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
) 
 994         self
.list.InsertColumn(0, "Filename") 
 995         self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
) 
 996         self
.list.InsertColumn(2, "Function") 
 997         self
.list.InsertColumn(3, "Code") 
 998         self
.InsertTraceback(self
.list, demoError
.traceback
) 
 999         self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
) 
1000         self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
) 
1001         self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:") 
1002                      , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5) 
1003         self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5) 
1004         self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n" 
1005                                            + "Double-click on them to go to the offending line") 
1006                      , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5) 
1009         self
.SetSizer(self
.box
) 
1012     def InsertTraceback(self
, list, traceback
): 
1013         #Add the traceback data 
1014         for x 
in range(len(traceback
)): 
1016             list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename 
1017             list.SetStringItem(x
, 1, str(data
[1]))              # Line 
1018             list.SetStringItem(x
, 2, str(data
[2]))              # Function 
1019             list.SetStringItem(x
, 3, str(data
[3]))              # Code 
1021             # Check whether this entry is from the demo module 
1022             if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised 
1023                 self
.list.SetItemData(x
, int(data
[1]))   # Store line number for easy access 
1024                 # Give it a blue colour 
1025                 item 
= self
.list.GetItem(x
) 
1026                 item
.SetTextColour(wx
.BLUE
) 
1027                 self
.list.SetItem(item
) 
1029                 self
.list.SetItemData(x
, -1)        # Editor can't jump into this one's code 
1032     def OnItemSelected(self
, event
): 
1033         # This occurs before OnDoubleClick and can be used to set the 
1034         # currentItem. OnDoubleClick doesn't get a wxListEvent.... 
1035         self
.currentItem 
= event
.m_itemIndex
 
1039     def OnDoubleClick(self
, event
): 
1040         # If double-clicking on a demo's entry, jump to the line number 
1041         line 
= self
.list.GetItemData(self
.currentItem
) 
1043             self
.nb
.SetSelection(1) # Switch to the code viewer tab 
1044             wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True) 
1048 #--------------------------------------------------------------------------- 
1050 class DemoTaskBarIcon(wx
.TaskBarIcon
): 
1051     TBMENU_RESTORE 
= wx
.NewId() 
1052     TBMENU_CLOSE   
= wx
.NewId() 
1053     TBMENU_CHANGE  
= wx
.NewId() 
1054     TBMENU_REMOVE  
= wx
.NewId() 
1056     def __init__(self
, frame
): 
1057         wx
.TaskBarIcon
.__init
__(self
) 
1061         icon 
= self
.MakeIcon(images
.getWXPdemoImage()) 
1062         self
.SetIcon(icon
, "wxPython Demo") 
1066         self
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
) 
1067         self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
) 
1068         self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
) 
1069         self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarChange
, id=self
.TBMENU_CHANGE
) 
1070         self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRemove
, id=self
.TBMENU_REMOVE
) 
1073     def CreatePopupMenu(self
): 
1075         This method is called by the base class when it needs to popup 
1076         the menu for the default EVT_RIGHT_DOWN event.  Just create 
1077         the menu how you want it and return it from this function, 
1078         the base class takes care of the rest. 
1081         menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo") 
1082         menu
.Append(self
.TBMENU_CLOSE
,   "Close wxPython Demo") 
1083         menu
.AppendSeparator() 
1084         menu
.Append(self
.TBMENU_CHANGE
, "Change the TB Icon") 
1085         menu
.Append(self
.TBMENU_REMOVE
, "Remove the TB Icon") 
1089     def MakeIcon(self
, img
): 
1091         The various platforms have different requirements for the 
1094         if "wxMSW" in wx
.PlatformInfo
: 
1095             img 
= img
.Scale(16, 16) 
1096         elif "wxGTK" in wx
.PlatformInfo
: 
1097             img 
= img
.Scale(22, 22) 
1098         # wxMac can be any size upto 128x128, so leave the source img alone.... 
1099         icon 
= wx
.IconFromBitmap(img
.ConvertToBitmap() ) 
1103     def OnTaskBarActivate(self
, evt
): 
1104         if self
.frame
.IsIconized(): 
1105             self
.frame
.Iconize(False) 
1106         if not self
.frame
.IsShown(): 
1107             self
.frame
.Show(True) 
1111     def OnTaskBarClose(self
, evt
): 
1115     def OnTaskBarChange(self
, evt
): 
1116         names 
= [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]                   
1117         name 
= names
[self
.imgidx
] 
1119         getFunc 
= getattr(images
, "get%sImage" % name
) 
1121         if self
.imgidx 
>= len(names
): 
1124         icon 
= self
.MakeIcon(getFunc()) 
1125         self
.SetIcon(icon
, "This is a new icon: " + name
) 
1128     def OnTaskBarRemove(self
, evt
): 
1132 #--------------------------------------------------------------------------- 
1133 class wxPythonDemo(wx
.Frame
): 
1134     overviewText 
= "wxPython Overview" 
1136     def __init__(self
, parent
, title
): 
1137         wx
.Frame
.__init
__(self
, parent
, -1, title
, size 
= (950, 720), 
1138                           style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
) 
1140         self
.SetMinSize((640,480)) 
1143         self
.cwd 
= os
.getcwd() 
1144         self
.curOverview 
= "" 
1145         self
.demoPage 
= None 
1146         self
.codePage 
= None 
1148         self
.firstTime 
= True 
1151         icon 
= images
.getWXPdemoIcon() 
1155             self
.tbicon 
= DemoTaskBarIcon(self
) 
1159         wx
.CallAfter(self
.ShowTip
) 
1161         self
.otherWin 
= None 
1162         self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
) 
1163         self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
) 
1164         self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
) 
1165         self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
) 
1167         self
.Centre(wx
.BOTH
) 
1168         self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
) 
1170         splitter 
= wx
.SplitterWindow(self
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
) 
1171         splitter2 
= wx
.SplitterWindow(splitter
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
) 
1173         def EmptyHandler(evt
): pass 
1174         #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler) 
1175         #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler) 
1177         # Prevent TreeCtrl from displaying all items after destruction when True 
1181         self
.nb 
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
) 
1184         self
.mainmenu 
= wx
.MenuBar() 
1186         item 
= menu
.Append(-1, '&Redirect Output', 
1187                            'Redirect print statements to a window', 
1189         self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
) 
1191         item 
= menu
.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!') 
1192         self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, item
) 
1193         wx
.App
.SetMacExitMenuItemId(item
.GetId()) 
1194         self
.mainmenu
.Append(menu
, '&File') 
1198         for item 
in _treeList
: 
1200             for childItem 
in item
[1]: 
1201                 mi 
= submenu
.Append(-1, childItem
) 
1202                 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
) 
1203             menu
.AppendMenu(wx
.NewId(), item
[0], submenu
) 
1204         self
.mainmenu
.Append(menu
, '&Demo') 
1209         findItem 
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code') 
1210         findnextItem 
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next') 
1211         menu
.AppendSeparator() 
1213         shellItem 
= menu
.Append(-1, 'Open Py&Shell Window\tF5', 
1214                                 'An interactive interpreter window with the demo app and frame objects in the namesapce') 
1215         menu
.AppendSeparator() 
1216         helpItem 
= menu
.Append(-1, '&About wxPython Demo', 'wxPython RULES!!!') 
1217         wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId()) 
1219         self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
) 
1220         self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
) 
1221         self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
,  findItem
) 
1222         self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
,  findnextItem
) 
1223         self
.Bind(wx
.EVT_FIND
, self
.OnFind
) 
1224         self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
) 
1225         self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
) 
1226         self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
) 
1227         self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findnextItem
) 
1228         self
.mainmenu
.Append(menu
, '&Help') 
1229         self
.SetMenuBar(self
.mainmenu
) 
1231         self
.finddata 
= wx
.FindReplaceData() 
1232         self
.finddata
.SetFlags(wx
.FR_DOWN
) 
1235             # This is another way to set Accelerators, in addition to 
1236             # using the '\t<key>' syntax in the menu items. 
1237             aTable 
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
,  ord('X'), exitID
), 
1238                                           (wx
.ACCEL_CTRL
, ord('H'), helpID
), 
1239                                           (wx
.ACCEL_CTRL
, ord('F'), findID
), 
1240                                           (wx
.ACCEL_NORMAL
, WXK_F3
, findnextID
) 
1242             self
.SetAcceleratorTable(aTable
) 
1248         self
.tree 
= wx
.TreeCtrl(splitter
, tID
, style 
= 
1249                                 wx
.TR_DEFAULT_STYLE 
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT 
1252         root 
= self
.tree
.AddRoot("wxPython Overview") 
1254         for item 
in _treeList
: 
1255             child 
= self
.tree
.AppendItem(root
, item
[0]) 
1256             if not firstChild
: firstChild 
= child
 
1257             for childItem 
in item
[1]: 
1258                 theDemo 
= self
.tree
.AppendItem(child
, childItem
) 
1259                 self
.treeMap
[childItem
] = theDemo
 
1261         self
.tree
.Expand(root
) 
1262         self
.tree
.Expand(firstChild
) 
1263         self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
) 
1264         self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
) 
1265         self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
) 
1266         self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
) 
1268         # Set up a wx.html.HtmlWindow on the Overview Notebook page 
1269         # we put it in a panel first because there seems to be a 
1270         # refresh bug of some sort (wxGTK) when it is directly in 
1273             self
.ovr 
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400)) 
1274             self
.nb
.AddPage(self
.ovr
, self
.overviewText
) 
1276         else:  # hopefully I can remove this hacky code soon, see SF bug #216861 
1277             panel 
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
) 
1278             self
.ovr 
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400)) 
1279             self
.nb
.AddPage(panel
, self
.overviewText
) 
1281             def OnOvrSize(evt
, ovr
=self
.ovr
): 
1282                 ovr
.SetSize(evt
.GetSize()) 
1283             panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
) 
1284             panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
) 
1286         if "gtk2" in wx
.PlatformInfo
: 
1287             self
.ovr
.SetStandardFonts() 
1288         self
.SetOverview(self
.overviewText
, mainOverview
) 
1291         # Set up a log window 
1292         self
.log 
= wx
.TextCtrl(splitter2
, -1, 
1293                               style 
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
) 
1295         # Set the wxWindows log target to be this textctrl 
1296         #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log)) 
1298         # But instead of the above we want to show how to use our own wx.Log class 
1299         wx
.Log_SetActiveTarget(MyLog(self
.log
)) 
1301         # for serious debugging 
1302         #wx.Log_SetActiveTarget(wx.LogStderr()) 
1303         #wx.Log_SetTraceMask(wx.TraceMessages) 
1306         self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
) 
1307         wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
) 
1309         # add the windows to the splitter and split it. 
1310         splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160) 
1311         splitter
.SplitVertically(self
.tree
, splitter2
, 200) 
1313         splitter
.SetMinimumPaneSize(120) 
1314         splitter2
.SetMinimumPaneSize(60) 
1316         # Make the splitter on the right expand the top window when resized 
1317         def SplitterOnSize(evt
): 
1318             splitter 
= evt
.GetEventObject() 
1319             sz 
= splitter
.GetSize() 
1320             splitter
.SetSashPosition(sz
.height 
- 160, False) 
1323         splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
) 
1325         # select initial items 
1326         self
.nb
.SetSelection(0) 
1327         self
.tree
.SelectItem(root
) 
1329         # Load 'Main' module 
1330         self
.LoadDemo(self
.overviewText
) 
1333         # select some other initial module? 
1334         if len(sys
.argv
) > 1: 
1336             if arg
.endswith('.py'): 
1338             selectedDemo 
= self
.treeMap
.get(arg
, None) 
1340                 self
.tree
.SelectItem(selectedDemo
) 
1341                 self
.tree
.EnsureVisible(selectedDemo
) 
1344     #--------------------------------------------- 
1345     def WriteText(self
, text
): 
1346         if text
[-1:] == '\n': 
1350     def write(self
, txt
): 
1353     #--------------------------------------------- 
1354     def OnItemExpanded(self
, event
): 
1355         item 
= event
.GetItem() 
1356         wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
)) 
1359     #--------------------------------------------- 
1360     def OnItemCollapsed(self
, event
): 
1361         item 
= event
.GetItem() 
1362         wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
)) 
1365     #--------------------------------------------- 
1366     def OnTreeLeftDown(self
, event
): 
1367         # reset the overview text if the tree item is clicked on again 
1368         pt 
= event
.GetPosition(); 
1369         item
, flags 
= self
.tree
.HitTest(pt
) 
1370         if item 
== self
.tree
.GetSelection(): 
1371             self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
) 
1374     #--------------------------------------------- 
1375     def OnSelChanged(self
, event
): 
1376         if self
.dying 
or  not self
.loaded
: 
1379         item 
= event
.GetItem() 
1380         itemText 
= self
.tree
.GetItemText(item
) 
1381         self
.LoadDemo(itemText
) 
1383     #--------------------------------------------- 
1384     def LoadDemo(self
, demoName
): 
1386             wx
.BeginBusyCursor() 
1389             self
.ShutdownDemoModule() 
1391             if demoName 
== self
.overviewText
: 
1392                 # User selected the "wxPython Overview" node 
1394                 # Changing the main window at runtime not yet supported... 
1395                 self
.demoModules 
= DemoModules(__name__
) 
1396                 self
.SetOverview(self
.overviewText
, mainOverview
) 
1397                 self
.LoadDemoSource() 
1398                 self
.UpdateNotebook(0) 
1400                 if os
.path
.exists(GetOriginalFilename(demoName
)): 
1401                     wx
.LogMessage("Loading demo %s.py..." % demoName
) 
1402                     self
.demoModules 
= DemoModules(demoName
) 
1403                     self
.LoadDemoSource() 
1406                     self
.SetOverview("wxPython", mainOverview
) 
1407                     self
.codePage 
= None 
1408                     self
.UpdateNotebook(0) 
1412     #--------------------------------------------- 
1413     def LoadDemoSource(self
): 
1414         self
.codePage 
= None 
1415         self
.codePage 
= DemoCodePanel(self
.nb
, self
) 
1416         self
.codePage
.LoadDemo(self
.demoModules
) 
1418     #--------------------------------------------- 
1419     def RunModule(self
): 
1420         """Runs the active module""" 
1422         module 
= self
.demoModules
.GetActive() 
1423         self
.ShutdownDemoModule() 
1426         # o The RunTest() for all samples must now return a window that can 
1427         #   be palced in a tab in the main notebook. 
1428         # o If an error occurs (or has occurred before) an error tab is created. 
1430         if module 
is not None: 
1431             wx
.LogMessage("Running demo module...") 
1432             if hasattr(module
, "overview"): 
1433                 overviewText 
= module
.overview
 
1436                 self
.demoPage 
= module
.runTest(self
, self
.nb
, self
) 
1438                 self
.demoPage 
= DemoErrorPanel(self
.nb
, self
.codePage
, 
1439                                                DemoError(sys
.exc_info()), self
) 
1441             assert self
.demoPage 
is not None, "runTest must return a window!" 
1444             # There was a previous error in compiling or exec-ing 
1445             self
.demoPage 
= DemoErrorPanel(self
.nb
, self
.codePage
, 
1446                                            self
.demoModules
.GetErrorInfo(), self
) 
1448         self
.SetOverview(self
.demoModules
.name 
+ " Overview", overviewText
) 
1451             # cahnge to the demo page the first time a module is run 
1452             self
.UpdateNotebook(2) 
1453             self
.firstTime 
= False 
1455             # otherwise just stay on the same tab in case the user has changed to another one 
1456             self
.UpdateNotebook() 
1458     #--------------------------------------------- 
1459     def ShutdownDemoModule(self
): 
1461             # inform the window that it's time to quit if it cares 
1462             if hasattr(self
.demoPage
, "ShutdownDemo"): 
1463                 self
.demoPage
.ShutdownDemo() 
1464             wx
.YieldIfNeeded() # in case the page has pending events 
1465             self
.demoPage 
= None 
1467     #--------------------------------------------- 
1468     def UpdateNotebook(self
, select 
= -1): 
1472         def UpdatePage(page
, pageText
): 
1475             for i 
in range(nb
.GetPageCount()): 
1476                 if nb
.GetPageText(i
) == pageText
: 
1484                     nb
.AddPage(page
, pageText
) 
1485                     if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
) 
1487                     if nb
.GetPage(pagePos
) != page
: 
1488                         # Reload an existing page 
1490                         nb
.DeletePage(pagePos
) 
1491                         nb
.InsertPage(pagePos
, page
, pageText
) 
1493                         if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
) 
1495                         # Excellent! No redraw/flicker 
1496                         if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
) 
1499                 nb
.DeletePage(pagePos
) 
1500                 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
) 
1502                 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
) 
1505             select 
= nb
.GetSelection() 
1507         UpdatePage(self
.codePage
, "Demo Code") 
1508         UpdatePage(self
.demoPage
, "Demo") 
1510         if select 
>= 0 and select 
< nb
.GetPageCount(): 
1511             nb
.SetSelection(select
) 
1513     #--------------------------------------------- 
1514     def SetOverview(self
, name
, text
): 
1515         self
.curOverview 
= text
 
1517         if lead 
!= '<html>' and lead 
!= '<HTML>': 
1518             text 
= '<br>'.join(text
.split('\n')) 
1520             text 
= text
.decode('iso8859_1')   
1521         self
.ovr
.SetPage(text
) 
1522         self
.nb
.SetPageText(0, name
) 
1524     #--------------------------------------------- 
1526     def OnFileExit(self
, *event
): 
1529     def OnToggleRedirect(self
, event
): 
1533             print "Print statements and other standard output will now be directed to this window." 
1536             print "Print statements and other standard output will now be sent to the usual location." 
1538     def OnHelpAbout(self
, event
): 
1539         from About 
import MyAboutBox
 
1540         about 
= MyAboutBox(self
) 
1544     def OnHelpFind(self
, event
): 
1545         if self
.finddlg 
!= None: 
1548         self
.nb
.SetSelection(1) 
1549         self
.finddlg 
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find", 
1550                         wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
) 
1551         self
.finddlg
.Show(True) 
1554     def OnUpdateFindItems(self
, evt
): 
1555         evt
.Enable(self
.finddlg 
== None) 
1558     def OnFind(self
, event
): 
1559         editor 
= self
.codePage
.editor
 
1560         self
.nb
.SetSelection(1) 
1561         end 
= editor
.GetLastPosition() 
1562         textstring 
= editor
.GetRange(0, end
).lower() 
1563         findstring 
= self
.finddata
.GetFindString().lower() 
1564         backward 
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
) 
1566             start 
= editor
.GetSelection()[0] 
1567             loc 
= textstring
.rfind(findstring
, 0, start
) 
1569             start 
= editor
.GetSelection()[1] 
1570             loc 
= textstring
.find(findstring
, start
) 
1571         if loc 
== -1 and start 
!= 0: 
1572             # string not found, start at beginning 
1575                 loc 
= textstring
.rfind(findstring
, 0, start
) 
1578                 loc 
= textstring
.find(findstring
, start
) 
1580             dlg 
= wx
.MessageDialog(self
, 'Find String Not Found', 
1581                           'Find String Not Found in Demo File', 
1582                           wx
.OK | wx
.ICON_INFORMATION
) 
1587                 self
.finddlg
.SetFocus() 
1590                 self
.finddlg
.Destroy() 
1592         editor
.ShowPosition(loc
) 
1593         editor
.SetSelection(loc
, loc 
+ len(findstring
)) 
1597     def OnFindNext(self
, event
): 
1598         if self
.finddata
.GetFindString(): 
1601             self
.OnHelpFind(event
) 
1603     def OnFindClose(self
, event
): 
1604         event
.GetDialog().Destroy() 
1608     def OnOpenShellWindow(self
, evt
): 
1610             # if it already exists then just make sure it's visible 
1616             # Make a PyShell window 
1618             namespace 
= { 'wx'    : wx
, 
1619                           'app'   : wx
.GetApp(), 
1622             self
.shell 
= py
.shell
.ShellFrame(None, locals=namespace
) 
1623             self
.shell
.SetSize((640,480)) 
1626             # Hook the close event of the main frame window so that we 
1627             # close the shell at the same time if it still exists             
1628             def CloseShell(evt
): 
1632             self
.Bind(wx
.EVT_CLOSE
, CloseShell
) 
1635     #--------------------------------------------- 
1636     def OnCloseWindow(self
, event
): 
1638         self
.demoPage 
= None 
1639         self
.codePage 
= None 
1640         self
.mainmenu 
= None 
1641         if self
.tbicon 
is not None: 
1642             self
.tbicon
.Destroy() 
1646     #--------------------------------------------- 
1647     def OnIdle(self
, event
): 
1649             self
.otherWin
.Raise() 
1650             self
.demoPage 
= self
.otherWin
 
1651             self
.otherWin 
= None 
1654     #--------------------------------------------- 
1657             showTipText 
= open(opj("data/showTips")).read() 
1658             showTip
, index 
= eval(showTipText
) 
1660             showTip
, index 
= (1, 0) 
1662             tp 
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
) 
1664             showTip 
= wx
.ShowTip(self
, tp
) 
1665             index 
= tp
.GetCurrentTip() 
1666             open(opj("data/showTips"), "w").write(str( (showTip
, index
) )) 
1669     #--------------------------------------------- 
1670     def OnDemoMenu(self
, event
): 
1672             selectedDemo 
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())] 
1676             self
.tree
.SelectItem(selectedDemo
) 
1677             self
.tree
.EnsureVisible(selectedDemo
) 
1681     #--------------------------------------------- 
1682     def OnIconfiy(self
, evt
): 
1683         wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized()) 
1686     #--------------------------------------------- 
1687     def OnMaximize(self
, evt
): 
1688         wx
.LogMessage("OnMaximize") 
1691     #--------------------------------------------- 
1692     def OnActivate(self
, evt
): 
1693         wx
.LogMessage("OnActivate: %s" % evt
.GetActive()) 
1696     #--------------------------------------------- 
1697     def OnAppActivate(self
, evt
): 
1698         wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive()) 
1701 #--------------------------------------------------------------------------- 
1702 #--------------------------------------------------------------------------- 
1704 class MySplashScreen(wx
.SplashScreen
): 
1706         bmp 
= wx
.Image(opj("bitmaps/splash.png")).ConvertToBitmap() 
1707         wx
.SplashScreen
.__init
__(self
, bmp
, 
1708                                  wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
, 
1710         self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
) 
1711         self
.fc 
= wx
.FutureCall(2000, self
.ShowMain
) 
1714     def OnClose(self
, evt
): 
1715         # Make sure the default handler runs too so this window gets 
1720         # if the timer is still running then go ahead and show the 
1722         if self
.fc
.IsRunning(): 
1728         frame 
= wxPythonDemo(None, "wxPython: (A Demonstration)") 
1730         if self
.fc
.IsRunning(): 
1734 class MyApp(wx
.App
): 
1737         Create and show the splash screen.  It will then create and show 
1738         the main frame when it is time to do so. 
1741         wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1) 
1744         #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG) 
1746         # Normally when using a SplashScreen you would create it, show 
1747         # it and then continue on with the applicaiton's 
1748         # initialization, finally creating and showing the main 
1749         # application window(s).  In this case we have nothing else to 
1750         # do so we'll delay showing the main frame until later (see 
1751         # ShowMain above) so the users can see the SplashScreen effect.         
1752         splash 
= MySplashScreen() 
1759 #--------------------------------------------------------------------------- 
1763         demoPath 
= os
.path
.dirname(__file__
) 
1770 #--------------------------------------------------------------------------- 
1773 mainOverview 
= """<html><body> 
1776 <p> wxPython is a <b>GUI toolkit</b> for the Python programming 
1777 language.  It allows Python programmers to create programs with a 
1778 robust, highly functional graphical user interface, simply and easily. 
1779 It is implemented as a Python extension module (native code) that 
1780 wraps the popular wxWindows cross platform GUI library, which is 
1783 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which 
1784 means that it is free for anyone to use and the source code is 
1785 available for anyone to look at and modify.  Or anyone can contribute 
1786 fixes or enhancements to the project. 
1788 <p> wxPython is a <b>cross-platform</b> toolkit.  This means that the 
1789 same program will run on multiple platforms without modification. 
1790 Currently supported platforms are 32-bit Microsoft Windows, most Unix 
1791 or unix-like systems, and Macintosh OS X. Since the language is 
1792 Python, wxPython programs are <b>simple, easy</b> to write and easy to 
1795 <p> <b>This demo</b> is not only a collection of test cases for 
1796 wxPython, but is also designed to help you learn about and how to use 
1797 wxPython.  Each sample is listed in the tree control on the left. 
1798 When a sample is selected in the tree then a module is loaded and run 
1799 (usually in a tab of this notebook,) and the source code of the module 
1800 is loaded in another tab for you to browse and learn from. 
1805 #---------------------------------------------------------------------------- 
1806 #---------------------------------------------------------------------------- 
1808 if __name__ 
== '__main__': 
1812 #----------------------------------------------------------------------------