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 = ", wx.VERSION_STRING 
  41 ##raw_input("Press Enter...") 
  44 #--------------------------------------------------------------------------- 
  49     ('Recent Additions/Updates', [ 
  53         'MultiSplitterWindow', 
  59     # managed windows == things with a (optional) caption you can close 
  60     ('Frames and Dialogs', [ 
  84     # dialogs from libraries 
  87         'ScrolledMessageDialog', 
  91     ('Core Windows/Controls', [ 
 131     ('Custom Controls', [ 
 144     # controls coming from other libraries 
 145     ('More Windows/Controls', [ 
 146         'ActiveX_FlashWindow', 
 147         'ActiveX_IEHtmlWindow', 
 149         #'RightTextCtrl',     deprecated as we have wxTE_RIGHT now. 
 166         'MaskedEditControls', 
 169         'MultiSplitterWindow', 
 184     # How to lay out the controls in a frame/dialog 
 194         'XmlResourceHandler', 
 195         'XmlResourceSubclass', 
 199     ('Process and Events', [ 
 206         ##'infoframe',    # needs better explanation and some fixing 
 210     ('Clipboard and DnD', [ 
 232         ##'DialogUnits',   # needs more explanations 
 249     ('Check out the samples dir too', [ 
 256 #--------------------------------------------------------------------------- 
 257 # Show how to derive a custom wxLog class 
 259 class MyLog(wx
.PyLog
): 
 260     def __init__(self
, textCtrl
, logTime
=0): 
 261         wx
.PyLog
.__init
__(self
) 
 263         self
.logTime 
= logTime
 
 265     def DoLogString(self
, message
, timeStamp
): 
 266         #print message, timeStamp 
 268         #    message = time.strftime("%X", time.localtime(timeStamp)) + \ 
 271             self
.tc
.AppendText(message 
+ '\n') 
 274 class MyTP(wx
.PyTipProvider
): 
 276         return "This is my tip" 
 278 #--------------------------------------------------------------------------- 
 279 # A class to be used to simply display a message in the demo pane 
 280 # rather than running the sample itself. 
 282 class MessagePanel(wx
.Panel
): 
 283     def __init__(self
, parent
, message
, caption
='', flags
=0): 
 284         wx
.Panel
.__init
__(self
, parent
) 
 289             if flags 
& wx
.ICON_EXCLAMATION
: 
 290                 artid 
= wx
.ART_WARNING            
 
 291             elif flags 
& wx
.ICON_ERROR
: 
 293             elif flags 
& wx
.ICON_QUESTION
: 
 294                 artid 
= wx
.ART_QUESTION
 
 295             elif flags 
& wx
.ICON_INFORMATION
: 
 296                 artid 
= wx
.ART_INFORMATION
 
 298             if artid 
is not None: 
 299                 bmp 
= wx
.ArtProvider
.GetBitmap(artid
, wx
.ART_MESSAGE_BOX
, (32,32)) 
 300                 icon 
= wx
.StaticBitmap(self
, -1, bmp
) 
 302                 icon 
= (32,32) # make a spacer instead 
 305             caption 
= wx
.StaticText(self
, -1, caption
) 
 306             caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
)) 
 308         message 
= wx
.StaticText(self
, -1, message
) 
 310         # add to sizers for layout 
 311         tbox 
= wx
.BoxSizer(wx
.VERTICAL
) 
 317         hbox 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 324         box 
= wx
.BoxSizer(wx
.VERTICAL
) 
 326         box
.Add(hbox
, 0, wx
.EXPAND
) 
 333 #--------------------------------------------------------------------------- 
 334 # A class to be used to display source code in the demo.  Try using the 
 335 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl 
 336 # if there is an error, such as the stc module not being present. 
 340     ##raise ImportError     # for testing the alternate implementation 
 342     from StyledTextCtrl_2 
import PythonSTC
 
 344     class DemoCodeEditor(PythonSTC
): 
 345         def __init__(self
, parent
): 
 346             PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
) 
 349         # Some methods to make it compatible with how the wxTextCtrl is used 
 350         def SetValue(self
, value
): 
 352                 value 
= value
.decode('iso8859_1') 
 354             self
.EmptyUndoBuffer() 
 357         def IsModified(self
): 
 358             return self
.GetModify() 
 363         def SetInsertionPoint(self
, pos
): 
 364             self
.SetCurrentPos(pos
) 
 367         def ShowPosition(self
, pos
): 
 368             line 
= self
.LineFromPosition(pos
) 
 369             #self.EnsureVisible(line) 
 372         def GetLastPosition(self
): 
 373             return self
.GetLength() 
 375         def GetPositionFromLine(self
, line
): 
 376             return self
.PositionFromLine(line
) 
 378         def GetRange(self
, start
, end
): 
 379             return self
.GetTextRange(start
, end
) 
 381         def GetSelection(self
): 
 382             return self
.GetAnchor(), self
.GetCurrentPos() 
 384         def SetSelection(self
, start
, end
): 
 385             self
.SetSelectionStart(start
) 
 386             self
.SetSelectionEnd(end
) 
 388         def SelectLine(self
, line
): 
 389             start 
= self
.PositionFromLine(line
) 
 390             end 
= self
.GetLineEndPosition(line
) 
 391             self
.SetSelection(start
, end
) 
 393         def SetUpEditor(self
): 
 395             This method carries out the work of setting up the demo editor.             
 396             It's seperate so as not to clutter up the init code. 
 400             self
.SetLexer(stc
.STC_LEX_PYTHON
) 
 401             self
.SetKeyWords(0, " ".join(keyword
.kwlist
)) 
 404             self
.SetProperty("fold", "1" )  
 406             # Highlight tab/space mixing (shouldn't be any) 
 407             self
.SetProperty("tab.timmy.whinge.level", "1") 
 409             # Set left and right margins 
 412             # Set up the numbers in the margin for margin #1 
 413             self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
) 
 414             # Reasonable value for, say, 4-5 digits using a mono font (40 pix) 
 415             self
.SetMarginWidth(1, 40) 
 417             # Indentation and tab stuff 
 418             self
.SetIndent(4)               # Proscribed indent size for wx 
 419             self
.SetIndentationGuides(True) # Show indent guides 
 420             self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space 
 421             self
.SetTabIndents(True)        # Tab key indents 
 422             self
.SetTabWidth(4)             # Proscribed tab size for wx 
 423             self
.SetUseTabs(False)          # Use spaces rather than tabs, or 
 424                                             # TabTimmy will complain!     
 426             self
.SetViewWhiteSpace(False)   # Don't view white space 
 428             # EOL: Since we are loading/saving ourselves, and the 
 429             # strings will always have \n's in them, set the STC to 
 430             # edit them that way.             
 431             self
.SetEOLMode(wx
.stc
.STC_EOL_LF
) 
 432             self
.SetViewEOL(False) 
 434             # No right-edge mode indicator 
 435             self
.SetEdgeMode(stc
.STC_EDGE_NONE
) 
 437             # Setup a margin to hold fold markers 
 438             self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
) 
 439             self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
) 
 440             self
.SetMarginSensitive(2, True) 
 441             self
.SetMarginWidth(2, 12) 
 443             # and now set up the fold markers 
 444             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
,     stc
.STC_MARK_BOXPLUSCONNECTED
,  "white", "black") 
 445             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black") 
 446             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
,  "white", "black") 
 447             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
,    stc
.STC_MARK_LCORNER
,  "white", "black") 
 448             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
,     stc
.STC_MARK_VLINE
,    "white", "black") 
 449             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
,        stc
.STC_MARK_BOXPLUS
,  "white", "black") 
 450             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
,    stc
.STC_MARK_BOXMINUS
, "white", "black") 
 452             # Global default style 
 453             if wx
.Platform 
== '__WXMSW__': 
 454                 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,  
 455                                   'fore:#000000,back:#FFFFFF,face:Courier New,size:9') 
 457                 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,  
 458                                   'fore:#000000,back:#FFFFFF,face:Courier,size:12') 
 460             # Clear styles and revert to default. 
 463             # Following style specs only indicate differences from default. 
 464             # The rest remains unchanged. 
 466             # Line numbers in margin 
 467             self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')     
 469             self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00') 
 471             self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000') 
 473             self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD") 
 476             self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000') 
 478             self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
,  'fore:#008000,back:#F0FFF0') 
 479             self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0') 
 481             self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080') 
 482             # Strings and characters 
 483             self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080') 
 484             self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080') 
 486             self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold') 
 488             self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA') 
 489             self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA') 
 491             self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold') 
 493             self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold') 
 495             self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold') 
 496             # Identifiers. I leave this as not bold because everything seems 
 497             # to be an identifier if it doesn't match the above criterae 
 498             self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000') 
 501             self
.SetCaretForeground("BLUE") 
 502             # Selection background 
 503             self
.SetSelBackground(1, '#66CCFF') 
 505             self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
)) 
 506             self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
)) 
 508         def RegisterModifiedEvent(self
, eventHandler
): 
 509             self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
) 
 513     class DemoCodeEditor(wx
.TextCtrl
): 
 514         def __init__(self
, parent
): 
 515             wx
.TextCtrl
.__init
__(self
, parent
, -1, style 
= 
 516                                  wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
) 
 518         def RegisterModifiedEvent(self
, eventHandler
): 
 519             self
.Bind(wx
.EVT_TEXT
, eventHandler
) 
 521         def SetReadOnly(self
, flag
): 
 522             self
.SetEditable(not flag
) 
 523             # NOTE: STC already has this method 
 526             return self
.GetValue() 
 528         def GetPositionFromLine(self
, line
): 
 529             return self
.XYToPosition(0,line
) 
 531         def GotoLine(self
, line
): 
 532             pos 
= self
.GetPositionFromLine(line
) 
 533             self
.SetInsertionPoint(pos
) 
 534             self
.ShowPosition(pos
) 
 536         def SelectLine(self
, line
): 
 537             start 
= self
.GetPositionFromLine(line
) 
 538             end 
= start 
+ self
.GetLineLength(line
) 
 539             self
.SetSelection(start
, end
) 
 542 #--------------------------------------------------------------------------- 
 543 # Constants for module versions 
 547 modDefault 
= modOriginal
 
 549 #--------------------------------------------------------------------------- 
 551 class DemoCodePanel(wx
.Panel
): 
 552     """Panel for the 'Demo Code' tab""" 
 553     def __init__(self
, parent
, mainFrame
): 
 554         wx
.Panel
.__init
__(self
, parent
, size
=(1,1)) 
 555         if 'wxMSW' in wx
.PlatformInfo
: 
 557         self
.mainFrame 
= mainFrame
 
 558         self
.editor 
= DemoCodeEditor(self
) 
 559         self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
) 
 561         self
.btnSave 
= wx
.Button(self
, -1, "Save Changes") 
 562         self
.btnRestore 
= wx
.Button(self
, -1, "Delete Modified") 
 563         self
.btnSave
.Enable(False) 
 564         self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
) 
 565         self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
) 
 567         self
.radioButtons 
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style 
= wx
.RB_GROUP
), 
 568                               modModified
: wx
.RadioButton(self
, -1, "Modified") } 
 570         self
.controlBox 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 571         self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0, 
 572                             wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5) 
 573         for modID
, radioButton 
in self
.radioButtons
.items(): 
 574             self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5) 
 575             radioButton
.modID 
= modID 
# makes it easier for the event handler 
 576             radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
) 
 578         self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5) 
 579         self
.controlBox
.Add(self
.btnRestore
, 0) 
 581         self
.box 
= wx
.BoxSizer(wx
.VERTICAL
) 
 582         self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
) 
 583         self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
) 
 584         self
.box
.Add(self
.editor
, 1, wx
.EXPAND
) 
 587         self
.SetSizer(self
.box
) 
 590     # Loads a demo from a DemoModules object 
 591     def LoadDemo(self
, demoModules
): 
 592         self
.demoModules 
= demoModules
 
 593         if (modDefault 
== modModified
) and demoModules
.Exists(modModified
): 
 594             demoModules
.SetActive(modModified
) 
 596             demoModules
.SetActive(modOriginal
) 
 597         self
.radioButtons
[demoModules
.GetActiveID()].Enable(True) 
 598         self
.ActiveModuleChanged() 
 601     def ActiveModuleChanged(self
): 
 602         self
.LoadDemoSource(self
.demoModules
.GetSource()) 
 603         self
.UpdateControlState() 
 607     def LoadDemoSource(self
, source
): 
 609         self
.editor
.SetValue(source
) 
 611         self
.btnSave
.Enable(False) 
 614     def JumpToLine(self
, line
, highlight
=False): 
 615         self
.editor
.GotoLine(line
) 
 616         self
.editor
.SetFocus() 
 618             self
.editor
.SelectLine(line
) 
 621     def UpdateControlState(self
): 
 622         active 
= self
.demoModules
.GetActiveID() 
 623         # Update the radio/restore buttons 
 624         for moduleID 
in self
.radioButtons
: 
 625             btn 
= self
.radioButtons
[moduleID
] 
 626             if moduleID 
== active
: 
 631             if self
.demoModules
.Exists(moduleID
): 
 633                 if moduleID 
== modModified
: 
 634                     self
.btnRestore
.Enable(True) 
 637                 if moduleID 
== modModified
: 
 638                     self
.btnRestore
.Enable(False) 
 641     def OnRadioButton(self
, event
): 
 642         radioSelected 
= event
.GetEventObject() 
 643         modSelected 
= radioSelected
.modID
 
 644         if modSelected 
!= self
.demoModules
.GetActiveID(): 
 645             busy 
= wx
.BusyInfo("Reloading demo module...") 
 646             self
.demoModules
.SetActive(modSelected
) 
 647             self
.ActiveModuleChanged() 
 650     def ReloadDemo(self
): 
 651         if self
.demoModules
.name 
!= __name__
: 
 652             self
.mainFrame
.RunModule() 
 655     def OnCodeModified(self
, event
): 
 656         self
.btnSave
.Enable(self
.editor
.IsModified()) 
 659     def OnSave(self
, event
): 
 660         if self
.demoModules
.Exists(modModified
): 
 661             if self
.demoModules
.GetActiveID() == modOriginal
: 
 662                 overwriteMsg 
= "You are about to overwrite an already existing modified copy\n" + \
 
 663                                "Do you want to continue?" 
 664                 dlg 
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo", 
 665                                        wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
) 
 666                 result 
= dlg
.ShowModal() 
 667                 if result 
== wx
.ID_NO
: 
 671         self
.demoModules
.SetActive(modModified
) 
 672         modifiedFilename 
= GetModifiedFilename(self
.demoModules
.name
) 
 674         # Create the demo directory if one doesn't already exist 
 675         if not os
.path
.exists(GetModifiedDirectory()): 
 677                 os
.makedirs(GetModifiedDirectory()) 
 678                 if not os
.path
.exists(GetModifiedDirectory()): 
 679                     wx
.LogMessage("BUG: Created demo directory but it still doesn't exist") 
 682                 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory()) 
 685                 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory()) 
 688         f 
= open(modifiedFilename
, "wt") 
 689         source 
= self
.editor
.GetText() 
 695         busy 
= wx
.BusyInfo("Reloading demo module...") 
 696         self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
) 
 697         self
.ActiveModuleChanged() 
 700     def OnRestore(self
, event
): # Handles the "Delete Modified" button 
 701         modifiedFilename 
= GetModifiedFilename(self
.demoModules
.name
) 
 702         self
.demoModules
.Delete(modModified
) 
 703         os
.unlink(modifiedFilename
) # Delete the modified copy 
 704         busy 
= wx
.BusyInfo("Reloading demo module...") 
 705         self
.ActiveModuleChanged() 
 708 #--------------------------------------------------------------------------- 
 711     """Convert paths to the platform-specific separator""" 
 712     str = apply(os
.path
.join
, tuple(path
.split('/'))) 
 713     # HACK: on Linux, a leading / gets lost... 
 714     if path
.startswith('/'): 
 719 def GetModifiedDirectory(): 
 721     Returns the directory where modified versions of the demo files 
 724     return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/") 
 727 def GetModifiedFilename(name
): 
 729     Returns the filename of the modified version of the specified demo 
 731     if not name
.endswith(".py"): 
 733     return GetModifiedDirectory() + name
 
 736 def GetOriginalFilename(name
): 
 738     Returns the filename of the original version of the specified demo 
 740     if not name
.endswith(".py"): 
 745 def DoesModifiedExist(name
): 
 746     """Returns whether the specified demo has a modified copy""" 
 747     if os
.path
.exists(GetModifiedFilename(name
)): 
 753 #--------------------------------------------------------------------------- 
 755 class ModuleDictWrapper
: 
 756     """Emulates a module with a dynamically compiled __dict__""" 
 757     def __init__(self
, dict): 
 760     def __getattr__(self
, name
): 
 761         if name 
in self
.dict: 
 762             return self
.dict[name
] 
 768     Dynamically manages the original/modified versions of a demo 
 771     def __init__(self
, name
): 
 775         #              (dict , source ,  filename , description   , error information )         
 776         #              (  0  ,   1    ,     2     ,      3        ,          4        )         
 777         self
.modules 
= [[None,  ""    ,    ""     , "<original>"  ,        None], 
 778                         [None,  ""    ,    ""     , "<modified>"  ,        None]] 
 780         # load original module 
 781         self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
)) 
 782         self
.SetActive(modOriginal
) 
 784         # load modified module (if one exists) 
 785         if DoesModifiedExist(name
): 
 786            self
.LoadFromFile(modModified
, GetModifiedFilename(name
)) 
 789     def LoadFromFile(self
, modID
, filename
): 
 790         self
.modules
[modID
][2] = filename
 
 791         file = open(filename
, "rt") 
 792         self
.LoadFromSource(modID
, file.read()) 
 796     def LoadFromSource(self
, modID
, source
): 
 797         self
.modules
[modID
][1] = source
 
 801     def LoadDict(self
, modID
): 
 802         if self
.name 
!= __name__
: 
 803             source 
= self
.modules
[modID
][1] 
 804             #description = self.modules[modID][3] 
 805             description 
= self
.modules
[modID
][2] 
 808                 self
.modules
[modID
][0] = {} 
 809                 code 
= compile(source
, description
, "exec")         
 810                 exec code 
in self
.modules
[modID
][0] 
 812                 self
.modules
[modID
][4] = DemoError(sys
.exc_info()) 
 813                 self
.modules
[modID
][0] = None 
 815                 self
.modules
[modID
][4] = None 
 818     def SetActive(self
, modID
): 
 819         if modID 
!= modOriginal 
and modID 
!= modModified
: 
 822             self
.modActive 
= modID
 
 826         dict = self
.modules
[self
.modActive
][0] 
 830             return ModuleDictWrapper(dict) 
 833     def GetActiveID(self
): 
 834         return self
.modActive
 
 837     def GetSource(self
, modID 
= None): 
 839             modID 
= self
.modActive
 
 840         return self
.modules
[modID
][1] 
 843     def GetFilename(self
, modID 
= None): 
 845             modID 
= self
.modActive
 
 846         return self
.modules
[self
.modActive
][2] 
 849     def GetErrorInfo(self
, modID 
= None): 
 851             modID 
= self
.modActive
 
 852         return self
.modules
[self
.modActive
][4] 
 855     def Exists(self
, modID
): 
 856         return self
.modules
[modID
][1] != "" 
 859     def UpdateFile(self
, modID 
= None): 
 860         """Updates the file from which a module was loaded 
 861         with (possibly updated) source""" 
 863             modID 
= self
.modActive
 
 865         source 
= self
.modules
[modID
][1] 
 866         filename 
= self
.modules
[modID
][2] 
 869             file = open(filename
, "wt") 
 875     def Delete(self
, modID
): 
 876         if self
.modActive 
== modID
: 
 879         self
.modules
[modID
][0] = None 
 880         self
.modules
[modID
][1] = "" 
 881         self
.modules
[modID
][2] = "" 
 884 #--------------------------------------------------------------------------- 
 887     """Wraps and stores information about the current exception""" 
 888     def __init__(self
, exc_info
): 
 891         excType
, excValue 
= exc_info
[:2] 
 892         # traceback list entries: (filename, line number, function name, text) 
 893         self
.traceback 
= traceback
.extract_tb(exc_info
[2]) 
 895         # --Based on traceback.py::format_exception_only()-- 
 896         if type(excType
) == types
.ClassType
: 
 897             self
.exception_type 
= excType
.__name
__ 
 899             self
.exception_type 
= excType
 
 901         # If it's a syntax error, extra information needs 
 902         # to be added to the traceback 
 903         if excType 
is SyntaxError: 
 905                 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
 
 910                     filename 
= "<string>" 
 912                 self
.traceback
.append( (filename
, lineno
, "", line
) ) 
 915             self
.exception_details 
= str(excValue
) 
 917             self
.exception_details 
= "<unprintable %s object>" & type(excValue
).__name
__ 
 924         Details  : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details 
) 
 927 #--------------------------------------------------------------------------- 
 929 class DemoErrorPanel(wx
.Panel
): 
 930     """Panel put into the demo tab when the demo fails to run due  to errors""" 
 932     def __init__(self
, parent
, codePanel
, demoError
, log
): 
 933         wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE) 
 934         self
.codePanel 
= codePanel
 
 938         self
.box 
= wx
.BoxSizer(wx
.VERTICAL
) 
 941         self
.box
.Add(wx
.StaticText(self
, -1, "An error has occurred while trying to run the demo") 
 942                      , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10) 
 944         # Exception Information 
 945         boxInfo      
= wx
.StaticBox(self
, -1, "Exception Info" ) 
 946         boxInfoSizer 
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL 
) # Used to center the grid within the box 
 947         boxInfoGrid  
= wx
.FlexGridSizer(0, 2, 0, 0) 
 948         textFlags    
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
 
 949         boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 ) 
 950         boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_type
) , 0, textFlags
, 5 ) 
 951         boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 ) 
 952         boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 ) 
 953         boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 ) 
 954         self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5) 
 956         # Set up the traceback list 
 957         # This one automatically resizes last column to take up remaining space 
 958         from ListCtrl 
import TestListCtrl
 
 959         self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT  | wx
.SUNKEN_BORDER
) 
 960         self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
) 
 961         self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
) 
 962         self
.list.InsertColumn(0, "Filename") 
 963         self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
) 
 964         self
.list.InsertColumn(2, "Function") 
 965         self
.list.InsertColumn(3, "Code") 
 966         self
.InsertTraceback(self
.list, demoError
.traceback
) 
 967         self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
) 
 968         self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
) 
 969         self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:") 
 970                      , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5) 
 971         self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5) 
 972         self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n" 
 973                                            + "Double-click on them to go to the offending line") 
 974                      , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5) 
 977         self
.SetSizer(self
.box
) 
 980     def InsertTraceback(self
, list, traceback
): 
 981         #Add the traceback data 
 982         for x 
in range(len(traceback
)): 
 984             list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename 
 985             list.SetStringItem(x
, 1, str(data
[1]))              # Line 
 986             list.SetStringItem(x
, 2, str(data
[2]))              # Function 
 987             list.SetStringItem(x
, 3, str(data
[3]))              # Code 
 989             # Check whether this entry is from the demo module 
 990             if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised 
 991                 self
.list.SetItemData(x
, int(data
[1]))   # Store line number for easy access 
 992                 # Give it a blue colour 
 993                 item 
= self
.list.GetItem(x
) 
 994                 item
.SetTextColour(wx
.BLUE
) 
 995                 self
.list.SetItem(item
) 
 997                 self
.list.SetItemData(x
, -1)        # Editor can't jump into this one's code 
1000     def OnItemSelected(self
, event
): 
1001         # This occurs before OnDoubleClick and can be used to set the 
1002         # currentItem. OnDoubleClick doesn't get a wxListEvent.... 
1003         self
.currentItem 
= event
.m_itemIndex
 
1007     def OnDoubleClick(self
, event
): 
1008         # If double-clicking on a demo's entry, jump to the line number 
1009         line 
= self
.list.GetItemData(self
.currentItem
) 
1011             self
.nb
.SetSelection(1) # Switch to the code viewer tab 
1012             wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True) 
1016 #--------------------------------------------------------------------------- 
1018 class DemoTaskBarIcon(wx
.TaskBarIcon
): 
1019     TBMENU_RESTORE 
= wx
.NewId() 
1020     TBMENU_CLOSE   
= wx
.NewId() 
1021     TBMENU_CHANGE  
= wx
.NewId() 
1022     TBMENU_REMOVE  
= wx
.NewId() 
1024     def __init__(self
, frame
): 
1025         wx
.TaskBarIcon
.__init
__(self
) 
1029         icon 
= self
.MakeIcon(images
.getWXPdemoImage()) 
1030         self
.SetIcon(icon
, "wxPython Demo") 
1034         self
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
) 
1035         self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
) 
1036         self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
) 
1037         self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarChange
, id=self
.TBMENU_CHANGE
) 
1038         self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRemove
, id=self
.TBMENU_REMOVE
) 
1041     def CreatePopupMenu(self
): 
1043         This method is called by the base class when it needs to popup 
1044         the menu for the default EVT_RIGHT_DOWN event.  Just create 
1045         the menu how you want it and return it from this function, 
1046         the base class takes care of the rest. 
1049         menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo") 
1050         menu
.Append(self
.TBMENU_CLOSE
,   "Close wxPython Demo") 
1051         menu
.AppendSeparator() 
1052         menu
.Append(self
.TBMENU_CHANGE
, "Change the TB Icon") 
1053         menu
.Append(self
.TBMENU_REMOVE
, "Remove the TB Icon") 
1057     def MakeIcon(self
, img
): 
1059         The various platforms have different requirements for the 
1062         if "wxMSW" in wx
.PlatformInfo
: 
1063             img 
= img
.Scale(16, 16) 
1064         elif "wxGTK" in wx
.PlatformInfo
: 
1065             img 
= img
.Scale(22, 22) 
1066         # wxMac can be any size upto 128x128, so leave the source img alone.... 
1067         icon 
= wx
.IconFromBitmap(img
.ConvertToBitmap() ) 
1071     def OnTaskBarActivate(self
, evt
): 
1072         if self
.frame
.IsIconized(): 
1073             self
.frame
.Iconize(False) 
1074         if not self
.frame
.IsShown(): 
1075             self
.frame
.Show(True) 
1079     def OnTaskBarClose(self
, evt
): 
1083     def OnTaskBarChange(self
, evt
): 
1084         names 
= [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]                   
1085         name 
= names
[self
.imgidx
] 
1087         getFunc 
= getattr(images
, "get%sImage" % name
) 
1089         if self
.imgidx 
>= len(names
): 
1092         icon 
= self
.MakeIcon(getFunc()) 
1093         self
.SetIcon(icon
, "This is a new icon: " + name
) 
1096     def OnTaskBarRemove(self
, evt
): 
1100 #--------------------------------------------------------------------------- 
1101 class wxPythonDemo(wx
.Frame
): 
1102     overviewText 
= "wxPython Overview" 
1104     def __init__(self
, parent
, title
): 
1105         wx
.Frame
.__init
__(self
, parent
, -1, title
, size 
= (950, 720), 
1106                           style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
) 
1108         self
.SetMinSize((640,480)) 
1111         self
.cwd 
= os
.getcwd() 
1112         self
.curOverview 
= "" 
1113         self
.demoPage 
= None 
1114         self
.codePage 
= None 
1116         self
.firstTime 
= True 
1119         icon 
= images
.getWXPdemoIcon() 
1122         self
.tbicon 
= DemoTaskBarIcon(self
) 
1124         wx
.CallAfter(self
.ShowTip
) 
1126         self
.otherWin 
= None 
1127         self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
) 
1128         self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
) 
1129         self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
) 
1130         self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
) 
1132         self
.Centre(wx
.BOTH
) 
1133         self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
) 
1135         splitter 
= wx
.SplitterWindow(self
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
) 
1136         splitter2 
= wx
.SplitterWindow(splitter
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
) 
1138         def EmptyHandler(evt
): pass 
1139         #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler) 
1140         #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler) 
1142         # Prevent TreeCtrl from displaying all items after destruction when True 
1146         self
.nb 
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
) 
1149         self
.mainmenu 
= wx
.MenuBar() 
1151         item 
= menu
.Append(-1, '&Redirect Output', 
1152                            'Redirect print statements to a window', 
1154         self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
) 
1156         item 
= menu
.Append(-1, 'E&xit\tAlt-X', 'Get the heck outta here!') 
1157         self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, item
) 
1158         wx
.App
.SetMacExitMenuItemId(item
.GetId()) 
1159         self
.mainmenu
.Append(menu
, '&File') 
1163         for item 
in _treeList
: 
1165             for childItem 
in item
[1]: 
1166                 mi 
= submenu
.Append(-1, childItem
) 
1167                 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
) 
1168             menu
.AppendMenu(wx
.NewId(), item
[0], submenu
) 
1169         self
.mainmenu
.Append(menu
, '&Demo') 
1171         # Make a Demo Code menu 
1172         #TODO: Add new menu items 
1173         #       Like the option-enabled entries to select the 
1175         #TODO: should we bother? 
1178         #saveID = wx.NewId() 
1179         #restoreID = wx.NewId() 
1181         #menu.Append(saveID, '&Save\tCtrl-S', 'Save edited demo') 
1182         #menu.Append(restoreID, '&Delete Modified\tCtrl-R', 'Delete modified copy') 
1183         #self.Bind(wx.EVT_MENU, self.codePage.OnSave, id=saveID) 
1184         #self.Bind(wx.EVT_MENU, self.codePage.OnRestore, id=restoreID) 
1185         #self.mainmenu.Append(menu, 'Demo &Code') 
1190         findItem 
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code') 
1191         findnextItem 
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next') 
1192         menu
.AppendSeparator() 
1194         shellItem 
= menu
.Append(-1, 'Open Py&Shell Window\tF5', 
1195                                 'An interactive interpreter window with the demo app and frame objects in the namesapce') 
1196         menu
.AppendSeparator() 
1197         helpItem 
= menu
.Append(-1, '&About\tCtrl-H', 'wxPython RULES!!!') 
1198         wx
.App
.SetMacAboutMenuItemId(helpItem
.GetId()) 
1200         self
.Bind(wx
.EVT_MENU
, self
.OnOpenShellWindow
, shellItem
) 
1201         self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
) 
1202         self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
,  findItem
) 
1203         self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
,  findnextItem
) 
1204         self
.Bind(wx
.EVT_FIND
, self
.OnFind
) 
1205         self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
) 
1206         self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
) 
1207         self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
) 
1208         self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findnextItem
) 
1209         self
.mainmenu
.Append(menu
, '&Help') 
1210         self
.SetMenuBar(self
.mainmenu
) 
1212         self
.finddata 
= wx
.FindReplaceData() 
1213         self
.finddata
.SetFlags(wx
.FR_DOWN
) 
1216             # This is another way to set Accelerators, in addition to 
1217             # using the '\t<key>' syntax in the menu items. 
1218             aTable 
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
,  ord('X'), exitID
), 
1219                                           (wx
.ACCEL_CTRL
, ord('H'), helpID
), 
1220                                           (wx
.ACCEL_CTRL
, ord('F'), findID
), 
1221                                           (wx
.ACCEL_NORMAL
, WXK_F3
, findnextID
) 
1223             self
.SetAcceleratorTable(aTable
) 
1229         self
.tree 
= wx
.TreeCtrl(splitter
, tID
, style 
= 
1230                                 wx
.TR_DEFAULT_STYLE 
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT 
1233         root 
= self
.tree
.AddRoot("wxPython Overview") 
1235         for item 
in _treeList
: 
1236             child 
= self
.tree
.AppendItem(root
, item
[0]) 
1237             if not firstChild
: firstChild 
= child
 
1238             for childItem 
in item
[1]: 
1239                 theDemo 
= self
.tree
.AppendItem(child
, childItem
) 
1240                 self
.treeMap
[childItem
] = theDemo
 
1242         self
.tree
.Expand(root
) 
1243         self
.tree
.Expand(firstChild
) 
1244         self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
) 
1245         self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
) 
1246         self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
) 
1247         self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
) 
1249         # Set up a wx.html.HtmlWindow on the Overview Notebook page 
1250         # we put it in a panel first because there seems to be a 
1251         # refresh bug of some sort (wxGTK) when it is directly in 
1254             self
.ovr 
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400)) 
1255             self
.nb
.AddPage(self
.ovr
, self
.overviewText
) 
1257         else:  # hopefully I can remove this hacky code soon, see SF bug #216861 
1258             panel 
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
) 
1259             self
.ovr 
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400)) 
1260             self
.nb
.AddPage(panel
, self
.overviewText
) 
1262             def OnOvrSize(evt
, ovr
=self
.ovr
): 
1263                 ovr
.SetSize(evt
.GetSize()) 
1264             panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
) 
1265             panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
) 
1267         if "gtk2" in wx
.PlatformInfo
: 
1268             self
.ovr
.SetStandardFonts() 
1269         self
.SetOverview(self
.overviewText
, mainOverview
) 
1272         # Set up a log window 
1273         self
.log 
= wx
.TextCtrl(splitter2
, -1, 
1274                               style 
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
) 
1276         # Set the wxWindows log target to be this textctrl 
1277         #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log)) 
1279         # But instead of the above we want to show how to use our own wx.Log class 
1280         wx
.Log_SetActiveTarget(MyLog(self
.log
)) 
1282         # for serious debugging 
1283         #wx.Log_SetActiveTarget(wx.LogStderr()) 
1284         #wx.Log_SetTraceMask(wx.TraceMessages) 
1287         self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
) 
1288         wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
) 
1290         # add the windows to the splitter and split it. 
1291         splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160) 
1292         splitter
.SplitVertically(self
.tree
, splitter2
, 200) 
1294         splitter
.SetMinimumPaneSize(120) 
1295         splitter2
.SetMinimumPaneSize(60) 
1297         # Make the splitter on the right expand the top window when resized 
1298         def SplitterOnSize(evt
): 
1299             splitter 
= evt
.GetEventObject() 
1300             sz 
= splitter
.GetSize() 
1301             splitter
.SetSashPosition(sz
.height 
- 160, False) 
1304         splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
) 
1306         # select initial items 
1307         self
.nb
.SetSelection(0) 
1308         self
.tree
.SelectItem(root
) 
1310         # Load 'Main' module 
1311         self
.LoadDemo(self
.overviewText
) 
1314         # select some other initial module? 
1315         if len(sys
.argv
) > 1: 
1317             if arg
.endswith('.py'): 
1319             selectedDemo 
= self
.treeMap
.get(arg
, None) 
1321                 self
.tree
.SelectItem(selectedDemo
) 
1322                 self
.tree
.EnsureVisible(selectedDemo
) 
1325     #--------------------------------------------- 
1326     def WriteText(self
, text
): 
1327         if text
[-1:] == '\n': 
1331     def write(self
, txt
): 
1334     #--------------------------------------------- 
1335     def OnItemExpanded(self
, event
): 
1336         item 
= event
.GetItem() 
1337         wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
)) 
1340     #--------------------------------------------- 
1341     def OnItemCollapsed(self
, event
): 
1342         item 
= event
.GetItem() 
1343         wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
)) 
1346     #--------------------------------------------- 
1347     def OnTreeLeftDown(self
, event
): 
1348         # reset the overview text if the tree item is clicked on again 
1349         pt 
= event
.GetPosition(); 
1350         item
, flags 
= self
.tree
.HitTest(pt
) 
1351         if item 
== self
.tree
.GetSelection(): 
1352             self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
) 
1355     #--------------------------------------------- 
1356     def OnSelChanged(self
, event
): 
1357         if self
.dying 
or  not self
.loaded
: 
1360         item 
= event
.GetItem() 
1361         itemText 
= self
.tree
.GetItemText(item
) 
1362         self
.LoadDemo(itemText
) 
1364     #--------------------------------------------- 
1365     def LoadDemo(self
, demoName
): 
1367             wx
.BeginBusyCursor() 
1370             self
.ShutdownDemoModule() 
1372             if demoName 
== self
.overviewText
: 
1373                 # User selected the "wxPython Overview" node 
1375                 # Changing the main window at runtime not yet supported... 
1376                 self
.demoModules 
= DemoModules(__name__
) 
1377                 self
.SetOverview(self
.overviewText
, mainOverview
) 
1378                 self
.LoadDemoSource() 
1379                 self
.UpdateNotebook(0) 
1381                 if os
.path
.exists(GetOriginalFilename(demoName
)): 
1382                     wx
.LogMessage("Loading demo %s.py..." % demoName
) 
1383                     self
.demoModules 
= DemoModules(demoName
) 
1384                     self
.LoadDemoSource() 
1387                     self
.SetOverview("wxPython", mainOverview
) 
1388                     self
.codePage 
= None 
1389                     self
.UpdateNotebook(0) 
1393     #--------------------------------------------- 
1394     def LoadDemoSource(self
): 
1395         self
.codePage 
= None 
1396         self
.codePage 
= DemoCodePanel(self
.nb
, self
) 
1397         self
.codePage
.LoadDemo(self
.demoModules
) 
1399     #--------------------------------------------- 
1400     def RunModule(self
): 
1401         """Runs the active module""" 
1403         module 
= self
.demoModules
.GetActive() 
1404         self
.ShutdownDemoModule() 
1407         # o The RunTest() for all samples must now return a window that can 
1408         #   be palced in a tab in the main notebook. 
1409         # o If an error occurs (or has occurred before) an error tab is created. 
1411         if module 
is not None: 
1412             wx
.LogMessage("Running demo module...") 
1413             if hasattr(module
, "overview"): 
1414                 overviewText 
= module
.overview
 
1417                 self
.demoPage 
= module
.runTest(self
, self
.nb
, self
) 
1419                 self
.demoPage 
= DemoErrorPanel(self
.nb
, self
.codePage
, 
1420                                                DemoError(sys
.exc_info()), self
) 
1422             assert self
.demoPage 
is not None, "runTest must return a window!" 
1425             # There was a previous error in compiling or exec-ing 
1426             self
.demoPage 
= DemoErrorPanel(self
.nb
, self
.codePage
, 
1427                                            self
.demoModules
.GetErrorInfo(), self
) 
1429         self
.SetOverview(self
.demoModules
.name 
+ " Overview", overviewText
) 
1432             # cahnge to the demo page the first time a module is run 
1433             self
.UpdateNotebook(2) 
1434             self
.firstTime 
= False 
1436             # otherwise just stay on the same tab in case the user has changed to another one 
1437             self
.UpdateNotebook() 
1439     #--------------------------------------------- 
1440     def ShutdownDemoModule(self
): 
1442             # inform the window that it's time to quit if it cares 
1443             if hasattr(self
.demoPage
, "ShutdownDemo"): 
1444                 self
.demoPage
.ShutdownDemo() 
1445             wx
.YieldIfNeeded() # in case the page has pending events 
1446             self
.demoPage 
= None 
1448     #--------------------------------------------- 
1449     def UpdateNotebook(self
, select 
= -1): 
1453         def UpdatePage(page
, pageText
): 
1456             for i 
in range(nb
.GetPageCount()): 
1457                 if nb
.GetPageText(i
) == pageText
: 
1465                     nb
.AddPage(page
, pageText
) 
1466                     if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
) 
1468                     if nb
.GetPage(pagePos
) != page
: 
1469                         # Reload an existing page 
1471                         nb
.DeletePage(pagePos
) 
1472                         nb
.InsertPage(pagePos
, page
, pageText
) 
1474                         if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
) 
1476                         # Excellent! No redraw/flicker 
1477                         if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
) 
1480                 nb
.DeletePage(pagePos
) 
1481                 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
) 
1483                 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
) 
1486             select 
= nb
.GetSelection() 
1488         UpdatePage(self
.codePage
, "Demo Code") 
1489         UpdatePage(self
.demoPage
, "Demo") 
1491         if select 
>= 0 and select 
< nb
.GetPageCount(): 
1492             nb
.SetSelection(select
) 
1494     #--------------------------------------------- 
1495     def SetOverview(self
, name
, text
): 
1496         self
.curOverview 
= text
 
1498         if lead 
!= '<html>' and lead 
!= '<HTML>': 
1499             text 
= '<br>'.join(text
.split('\n')) 
1501             text 
= text
.decode('iso8859_1')   
1502         self
.ovr
.SetPage(text
) 
1503         self
.nb
.SetPageText(0, name
) 
1505     #--------------------------------------------- 
1507     def OnFileExit(self
, *event
): 
1510     def OnToggleRedirect(self
, event
): 
1514             print "Print statements and other standard output will now be directed to this window." 
1517             print "Print statements and other standard output will now be sent to the usual location." 
1519     def OnHelpAbout(self
, event
): 
1520         from About 
import MyAboutBox
 
1521         about 
= MyAboutBox(self
) 
1525     def OnHelpFind(self
, event
): 
1526         if self
.finddlg 
!= None: 
1529         self
.nb
.SetSelection(1) 
1530         self
.finddlg 
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find", 
1531                         wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
) 
1532         self
.finddlg
.Show(True) 
1535     def OnUpdateFindItems(self
, evt
): 
1536         evt
.Enable(self
.finddlg 
== None) 
1539     def OnFind(self
, event
): 
1540         editor 
= self
.codePage
.editor
 
1541         self
.nb
.SetSelection(1) 
1542         end 
= editor
.GetLastPosition() 
1543         textstring 
= editor
.GetRange(0, end
).lower() 
1544         findstring 
= self
.finddata
.GetFindString().lower() 
1545         backward 
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
) 
1547             start 
= editor
.GetSelection()[0] 
1548             loc 
= textstring
.rfind(findstring
, 0, start
) 
1550             start 
= editor
.GetSelection()[1] 
1551             loc 
= textstring
.find(findstring
, start
) 
1552         if loc 
== -1 and start 
!= 0: 
1553             # string not found, start at beginning 
1556                 loc 
= textstring
.rfind(findstring
, 0, start
) 
1559                 loc 
= textstring
.find(findstring
, start
) 
1561             dlg 
= wx
.MessageDialog(self
, 'Find String Not Found', 
1562                           'Find String Not Found in Demo File', 
1563                           wx
.OK | wx
.ICON_INFORMATION
) 
1568                 self
.finddlg
.SetFocus() 
1571                 self
.finddlg
.Destroy() 
1573         editor
.ShowPosition(loc
) 
1574         editor
.SetSelection(loc
, loc 
+ len(findstring
)) 
1578     def OnFindNext(self
, event
): 
1579         if self
.finddata
.GetFindString(): 
1582             self
.OnHelpFind(event
) 
1584     def OnFindClose(self
, event
): 
1585         event
.GetDialog().Destroy() 
1589     def OnOpenShellWindow(self
, evt
): 
1591             # if it already exists then just make sure it's visible 
1597             # Make a PyShell window 
1599             namespace 
= { 'wx'    : wx
, 
1600                           'app'   : wx
.GetApp(), 
1603             self
.shell 
= py
.shell
.ShellFrame(None, locals=namespace
) 
1604             self
.shell
.SetSize((640,480)) 
1607             # Hook the close event of the main frame window so that we 
1608             # close the shell at the same time if it still exists             
1609             def CloseShell(evt
): 
1613             self
.Bind(wx
.EVT_CLOSE
, CloseShell
) 
1616     #--------------------------------------------- 
1617     def OnCloseWindow(self
, event
): 
1619         self
.demoPage 
= None 
1620         self
.codePage 
= None 
1621         self
.mainmenu 
= None 
1622         self
.tbicon
.Destroy() 
1626     #--------------------------------------------- 
1627     def OnIdle(self
, event
): 
1629             self
.otherWin
.Raise() 
1630             self
.demoPage 
= self
.otherWin
 
1631             self
.otherWin 
= None 
1634     #--------------------------------------------- 
1637             showTipText 
= open(opj("data/showTips")).read() 
1638             showTip
, index 
= eval(showTipText
) 
1640             showTip
, index 
= (1, 0) 
1642             tp 
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
) 
1644             showTip 
= wx
.ShowTip(self
, tp
) 
1645             index 
= tp
.GetCurrentTip() 
1646             open(opj("data/showTips"), "w").write(str( (showTip
, index
) )) 
1649     #--------------------------------------------- 
1650     def OnDemoMenu(self
, event
): 
1652             selectedDemo 
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())] 
1656             self
.tree
.SelectItem(selectedDemo
) 
1657             self
.tree
.EnsureVisible(selectedDemo
) 
1661     #--------------------------------------------- 
1662     def OnIconfiy(self
, evt
): 
1663         wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized()) 
1666     #--------------------------------------------- 
1667     def OnMaximize(self
, evt
): 
1668         wx
.LogMessage("OnMaximize") 
1671     #--------------------------------------------- 
1672     def OnActivate(self
, evt
): 
1673         wx
.LogMessage("OnActivate: %s" % evt
.GetActive()) 
1676     #--------------------------------------------- 
1677     def OnAppActivate(self
, evt
): 
1678         wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive()) 
1681 #--------------------------------------------------------------------------- 
1682 #--------------------------------------------------------------------------- 
1684 class MySplashScreen(wx
.SplashScreen
): 
1686         bmp 
= wx
.Image(opj("bitmaps/splash.png")).ConvertToBitmap() 
1687         wx
.SplashScreen
.__init
__(self
, bmp
, 
1688                                  wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
, 
1690         self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
) 
1691         self
.fc 
= wx
.FutureCall(2000, self
.ShowMain
) 
1694     def OnClose(self
, evt
): 
1695         # Make sure the default handler runs too so this window gets 
1700         # if the timer is still running then go ahead and show the 
1702         if self
.fc
.IsRunning(): 
1708         frame 
= wxPythonDemo(None, "wxPython: (A Demonstration)") 
1710         if self
.fc
.IsRunning(): 
1714 class MyApp(wx
.App
): 
1717         Create and show the splash screen.  It will then create and show 
1718         the main frame when it is time to do so. 
1721         wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1) 
1724         #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG) 
1726         # Normally when using a SplashScreen you would create it, show 
1727         # it and then continue on with the applicaiton's 
1728         # initialization, finally creating and showing the main 
1729         # application window(s).  In this case we have nothing else to 
1730         # do so we'll delay showing the main frame until later (see 
1731         # ShowMain above) so the users can see the SplashScreen effect.         
1732         splash 
= MySplashScreen() 
1739 #--------------------------------------------------------------------------- 
1743         demoPath 
= os
.path
.dirname(__file__
) 
1750 #--------------------------------------------------------------------------- 
1753 mainOverview 
= """<html><body> 
1756 <p> wxPython is a <b>GUI toolkit</b> for the Python programming 
1757 language.  It allows Python programmers to create programs with a 
1758 robust, highly functional graphical user interface, simply and easily. 
1759 It is implemented as a Python extension module (native code) that 
1760 wraps the popular wxWindows cross platform GUI library, which is 
1763 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which 
1764 means that it is free for anyone to use and the source code is 
1765 available for anyone to look at and modify.  Or anyone can contribute 
1766 fixes or enhancements to the project. 
1768 <p> wxPython is a <b>cross-platform</b> toolkit.  This means that the 
1769 same program will run on multiple platforms without modification. 
1770 Currently supported platforms are 32-bit Microsoft Windows, most Unix 
1771 or unix-like systems, and Macintosh OS X. Since the language is 
1772 Python, wxPython programs are <b>simple, easy</b> to write and easy to 
1775 <p> <b>This demo</b> is not only a collection of test cases for 
1776 wxPython, but is also designed to help you learn about and how to use 
1777 wxPython.  Each sample is listed in the tree control on the left. 
1778 When a sample is selected in the tree then a module is loaded and run 
1779 (usually in a tab of this notebook,) and the source code of the module 
1780 is loaded in another tab for you to browse and learn from. 
1785 #---------------------------------------------------------------------------- 
1786 #---------------------------------------------------------------------------- 
1788 if __name__ 
== '__main__': 
1792 #----------------------------------------------------------------------------