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', [ 
  52     # managed windows == things with a (optional) caption you can close 
  53     ('Frames and Dialogs', [ 
  54         'AUI_DockingWindowMgr', 
  80     # dialogs from libraries 
  83         'ScrolledMessageDialog', 
  87     ('Core Windows/Controls', [ 
 125     ('"Book" Controls', [ 
 134     ('Custom Controls', [ 
 151     # controls coming from other libraries 
 152     ('More Windows/Controls', [ 
 153         'ActiveX_FlashWindow', 
 154         'ActiveX_IEHtmlWindow', 
 159         'CheckListCtrlMixin', 
 176         'MaskedEditControls', 
 179         'MultiSplitterWindow', 
 180         'OwnerDrawnComboBox', 
 198     # How to lay out the controls in a frame/dialog 
 209         'XmlResourceHandler', 
 210         'XmlResourceSubclass', 
 214     ('Process and Events', [ 
 222         ##'infoframe',    # needs better explanation and some fixing 
 226     ('Clipboard and DnD', [ 
 253         ##'DialogUnits',   # needs more explanations 
 274     ('Check out the samples dir too', [ 
 281 #--------------------------------------------------------------------------- 
 282 # Show how to derive a custom wxLog class 
 284 class MyLog(wx
.PyLog
): 
 285     def __init__(self
, textCtrl
, logTime
=0): 
 286         wx
.PyLog
.__init
__(self
) 
 288         self
.logTime 
= logTime
 
 290     def DoLogString(self
, message
, timeStamp
): 
 291         #print message, timeStamp 
 293         #    message = time.strftime("%X", time.localtime(timeStamp)) + \ 
 296             self
.tc
.AppendText(message 
+ '\n') 
 299 class MyTP(wx
.PyTipProvider
): 
 301         return "This is my tip" 
 303 #--------------------------------------------------------------------------- 
 304 # A class to be used to simply display a message in the demo pane 
 305 # rather than running the sample itself. 
 307 class MessagePanel(wx
.Panel
): 
 308     def __init__(self
, parent
, message
, caption
='', flags
=0): 
 309         wx
.Panel
.__init
__(self
, parent
) 
 314             if flags 
& wx
.ICON_EXCLAMATION
: 
 315                 artid 
= wx
.ART_WARNING            
 
 316             elif flags 
& wx
.ICON_ERROR
: 
 318             elif flags 
& wx
.ICON_QUESTION
: 
 319                 artid 
= wx
.ART_QUESTION
 
 320             elif flags 
& wx
.ICON_INFORMATION
: 
 321                 artid 
= wx
.ART_INFORMATION
 
 323             if artid 
is not None: 
 324                 bmp 
= wx
.ArtProvider
.GetBitmap(artid
, wx
.ART_MESSAGE_BOX
, (32,32)) 
 325                 icon 
= wx
.StaticBitmap(self
, -1, bmp
) 
 327                 icon 
= (32,32) # make a spacer instead 
 330             caption 
= wx
.StaticText(self
, -1, caption
) 
 331             caption
.SetFont(wx
.Font(28, wx
.SWISS
, wx
.NORMAL
, wx
.BOLD
)) 
 333         message 
= wx
.StaticText(self
, -1, message
) 
 335         # add to sizers for layout 
 336         tbox 
= wx
.BoxSizer(wx
.VERTICAL
) 
 342         hbox 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 349         box 
= wx
.BoxSizer(wx
.VERTICAL
) 
 351         box
.Add(hbox
, 0, wx
.EXPAND
) 
 358 #--------------------------------------------------------------------------- 
 359 # A class to be used to display source code in the demo.  Try using the 
 360 # wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl 
 361 # if there is an error, such as the stc module not being present. 
 365     ##raise ImportError     # for testing the alternate implementation 
 367     from StyledTextCtrl_2 
import PythonSTC
 
 369     class DemoCodeEditor(PythonSTC
): 
 370         def __init__(self
, parent
): 
 371             PythonSTC
.__init
__(self
, parent
, -1, style
=wx
.BORDER_NONE
) 
 374         # Some methods to make it compatible with how the wxTextCtrl is used 
 375         def SetValue(self
, value
): 
 377                 value 
= value
.decode('iso8859_1') 
 379             self
.EmptyUndoBuffer() 
 382         def IsModified(self
): 
 383             return self
.GetModify() 
 388         def SetInsertionPoint(self
, pos
): 
 389             self
.SetCurrentPos(pos
) 
 392         def ShowPosition(self
, pos
): 
 393             line 
= self
.LineFromPosition(pos
) 
 394             #self.EnsureVisible(line) 
 397         def GetLastPosition(self
): 
 398             return self
.GetLength() 
 400         def GetPositionFromLine(self
, line
): 
 401             return self
.PositionFromLine(line
) 
 403         def GetRange(self
, start
, end
): 
 404             return self
.GetTextRange(start
, end
) 
 406         def GetSelection(self
): 
 407             return self
.GetAnchor(), self
.GetCurrentPos() 
 409         def SetSelection(self
, start
, end
): 
 410             self
.SetSelectionStart(start
) 
 411             self
.SetSelectionEnd(end
) 
 413         def SelectLine(self
, line
): 
 414             start 
= self
.PositionFromLine(line
) 
 415             end 
= self
.GetLineEndPosition(line
) 
 416             self
.SetSelection(start
, end
) 
 418         def SetUpEditor(self
): 
 420             This method carries out the work of setting up the demo editor.             
 421             It's seperate so as not to clutter up the init code. 
 425             self
.SetLexer(stc
.STC_LEX_PYTHON
) 
 426             self
.SetKeyWords(0, " ".join(keyword
.kwlist
)) 
 429             self
.SetProperty("fold", "1" )  
 431             # Highlight tab/space mixing (shouldn't be any) 
 432             self
.SetProperty("tab.timmy.whinge.level", "1") 
 434             # Set left and right margins 
 437             # Set up the numbers in the margin for margin #1 
 438             self
.SetMarginType(1, wx
.stc
.STC_MARGIN_NUMBER
) 
 439             # Reasonable value for, say, 4-5 digits using a mono font (40 pix) 
 440             self
.SetMarginWidth(1, 40) 
 442             # Indentation and tab stuff 
 443             self
.SetIndent(4)               # Proscribed indent size for wx 
 444             self
.SetIndentationGuides(True) # Show indent guides 
 445             self
.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space 
 446             self
.SetTabIndents(True)        # Tab key indents 
 447             self
.SetTabWidth(4)             # Proscribed tab size for wx 
 448             self
.SetUseTabs(False)          # Use spaces rather than tabs, or 
 449                                             # TabTimmy will complain!     
 451             self
.SetViewWhiteSpace(False)   # Don't view white space 
 453             # EOL: Since we are loading/saving ourselves, and the 
 454             # strings will always have \n's in them, set the STC to 
 455             # edit them that way.             
 456             self
.SetEOLMode(wx
.stc
.STC_EOL_LF
) 
 457             self
.SetViewEOL(False) 
 459             # No right-edge mode indicator 
 460             self
.SetEdgeMode(stc
.STC_EDGE_NONE
) 
 462             # Setup a margin to hold fold markers 
 463             self
.SetMarginType(2, stc
.STC_MARGIN_SYMBOL
) 
 464             self
.SetMarginMask(2, stc
.STC_MASK_FOLDERS
) 
 465             self
.SetMarginSensitive(2, True) 
 466             self
.SetMarginWidth(2, 12) 
 468             # and now set up the fold markers 
 469             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEREND
,     stc
.STC_MARK_BOXPLUSCONNECTED
,  "white", "black") 
 470             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPENMID
, stc
.STC_MARK_BOXMINUSCONNECTED
, "white", "black") 
 471             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERMIDTAIL
, stc
.STC_MARK_TCORNER
,  "white", "black") 
 472             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERTAIL
,    stc
.STC_MARK_LCORNER
,  "white", "black") 
 473             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDERSUB
,     stc
.STC_MARK_VLINE
,    "white", "black") 
 474             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDER
,        stc
.STC_MARK_BOXPLUS
,  "white", "black") 
 475             self
.MarkerDefine(stc
.STC_MARKNUM_FOLDEROPEN
,    stc
.STC_MARK_BOXMINUS
, "white", "black") 
 477             # Global default style 
 478             if wx
.Platform 
== '__WXMSW__': 
 479                 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,  
 480                                   'fore:#000000,back:#FFFFFF,face:Courier New,size:9') 
 481             elif wx
.Platform 
== '__WXMAC__': 
 482                 # TODO: if this looks fine on Linux too, remove the Mac-specific case  
 483                 # and use this whenever OS != MSW. 
 484                 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,  
 485                                   'fore:#000000,back:#FFFFFF,face:Courier') 
 487                 self
.StyleSetSpec(stc
.STC_STYLE_DEFAULT
,  
 488                                   'fore:#000000,back:#FFFFFF,face:Courier,size:9') 
 490             # Clear styles and revert to default. 
 493             # Following style specs only indicate differences from default. 
 494             # The rest remains unchanged. 
 496             # Line numbers in margin 
 497             self
.StyleSetSpec(wx
.stc
.STC_STYLE_LINENUMBER
,'fore:#000000,back:#99A9C2')     
 499             self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACELIGHT
,'fore:#00009D,back:#FFFF00') 
 501             self
.StyleSetSpec(wx
.stc
.STC_STYLE_BRACEBAD
,'fore:#00009D,back:#FF0000') 
 503             self
.StyleSetSpec(wx
.stc
.STC_STYLE_INDENTGUIDE
, "fore:#CDCDCD") 
 506             self
.StyleSetSpec(wx
.stc
.STC_P_DEFAULT
, 'fore:#000000') 
 508             self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTLINE
,  'fore:#008000,back:#F0FFF0') 
 509             self
.StyleSetSpec(wx
.stc
.STC_P_COMMENTBLOCK
, 'fore:#008000,back:#F0FFF0') 
 511             self
.StyleSetSpec(wx
.stc
.STC_P_NUMBER
, 'fore:#008080') 
 512             # Strings and characters 
 513             self
.StyleSetSpec(wx
.stc
.STC_P_STRING
, 'fore:#800080') 
 514             self
.StyleSetSpec(wx
.stc
.STC_P_CHARACTER
, 'fore:#800080') 
 516             self
.StyleSetSpec(wx
.stc
.STC_P_WORD
, 'fore:#000080,bold') 
 518             self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLE
, 'fore:#800080,back:#FFFFEA') 
 519             self
.StyleSetSpec(wx
.stc
.STC_P_TRIPLEDOUBLE
, 'fore:#800080,back:#FFFFEA') 
 521             self
.StyleSetSpec(wx
.stc
.STC_P_CLASSNAME
, 'fore:#0000FF,bold') 
 523             self
.StyleSetSpec(wx
.stc
.STC_P_DEFNAME
, 'fore:#008080,bold') 
 525             self
.StyleSetSpec(wx
.stc
.STC_P_OPERATOR
, 'fore:#800000,bold') 
 526             # Identifiers. I leave this as not bold because everything seems 
 527             # to be an identifier if it doesn't match the above criterae 
 528             self
.StyleSetSpec(wx
.stc
.STC_P_IDENTIFIER
, 'fore:#000000') 
 531             self
.SetCaretForeground("BLUE") 
 532             # Selection background 
 533             self
.SetSelBackground(1, '#66CCFF') 
 535             self
.SetSelBackground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHT
)) 
 536             self
.SetSelForeground(True, wx
.SystemSettings_GetColour(wx
.SYS_COLOUR_HIGHLIGHTTEXT
)) 
 538         def RegisterModifiedEvent(self
, eventHandler
): 
 539             self
.Bind(wx
.stc
.EVT_STC_CHANGE
, eventHandler
) 
 543     class DemoCodeEditor(wx
.TextCtrl
): 
 544         def __init__(self
, parent
): 
 545             wx
.TextCtrl
.__init
__(self
, parent
, -1, style 
= 
 546                                  wx
.TE_MULTILINE | wx
.HSCROLL | wx
.TE_RICH2 | wx
.TE_NOHIDESEL
) 
 548         def RegisterModifiedEvent(self
, eventHandler
): 
 549             self
.Bind(wx
.EVT_TEXT
, eventHandler
) 
 551         def SetReadOnly(self
, flag
): 
 552             self
.SetEditable(not flag
) 
 553             # NOTE: STC already has this method 
 556             return self
.GetValue() 
 558         def GetPositionFromLine(self
, line
): 
 559             return self
.XYToPosition(0,line
) 
 561         def GotoLine(self
, line
): 
 562             pos 
= self
.GetPositionFromLine(line
) 
 563             self
.SetInsertionPoint(pos
) 
 564             self
.ShowPosition(pos
) 
 566         def SelectLine(self
, line
): 
 567             start 
= self
.GetPositionFromLine(line
) 
 568             end 
= start 
+ self
.GetLineLength(line
) 
 569             self
.SetSelection(start
, end
) 
 572 #--------------------------------------------------------------------------- 
 573 # Constants for module versions 
 577 modDefault 
= modOriginal
 
 579 #--------------------------------------------------------------------------- 
 581 class DemoCodePanel(wx
.Panel
): 
 582     """Panel for the 'Demo Code' tab""" 
 583     def __init__(self
, parent
, mainFrame
): 
 584         wx
.Panel
.__init
__(self
, parent
, size
=(1,1)) 
 585         if 'wxMSW' in wx
.PlatformInfo
: 
 587         self
.mainFrame 
= mainFrame
 
 588         self
.editor 
= DemoCodeEditor(self
) 
 589         self
.editor
.RegisterModifiedEvent(self
.OnCodeModified
) 
 591         self
.btnSave 
= wx
.Button(self
, -1, "Save Changes") 
 592         self
.btnRestore 
= wx
.Button(self
, -1, "Delete Modified") 
 593         self
.btnSave
.Enable(False) 
 594         self
.btnSave
.Bind(wx
.EVT_BUTTON
, self
.OnSave
) 
 595         self
.btnRestore
.Bind(wx
.EVT_BUTTON
, self
.OnRestore
) 
 597         self
.radioButtons 
= { modOriginal
: wx
.RadioButton(self
, -1, "Original", style 
= wx
.RB_GROUP
), 
 598                               modModified
: wx
.RadioButton(self
, -1, "Modified") } 
 600         self
.controlBox 
= wx
.BoxSizer(wx
.HORIZONTAL
) 
 601         self
.controlBox
.Add(wx
.StaticText(self
, -1, "Active Version:"), 0, 
 602                             wx
.RIGHT | wx
.LEFT | wx
.ALIGN_CENTER_VERTICAL
, 5) 
 603         for modID
, radioButton 
in self
.radioButtons
.items(): 
 604             self
.controlBox
.Add(radioButton
, 0, wx
.EXPAND | wx
.RIGHT
, 5) 
 605             radioButton
.modID 
= modID 
# makes it easier for the event handler 
 606             radioButton
.Bind(wx
.EVT_RADIOBUTTON
, self
.OnRadioButton
) 
 608         self
.controlBox
.Add(self
.btnSave
, 0, wx
.RIGHT
, 5) 
 609         self
.controlBox
.Add(self
.btnRestore
, 0) 
 611         self
.box 
= wx
.BoxSizer(wx
.VERTICAL
) 
 612         self
.box
.Add(self
.controlBox
, 0, wx
.EXPAND
) 
 613         self
.box
.Add(wx
.StaticLine(self
), 0, wx
.EXPAND
) 
 614         self
.box
.Add(self
.editor
, 1, wx
.EXPAND
) 
 617         self
.SetSizer(self
.box
) 
 620     # Loads a demo from a DemoModules object 
 621     def LoadDemo(self
, demoModules
): 
 622         self
.demoModules 
= demoModules
 
 623         if (modDefault 
== modModified
) and demoModules
.Exists(modModified
): 
 624             demoModules
.SetActive(modModified
) 
 626             demoModules
.SetActive(modOriginal
) 
 627         self
.radioButtons
[demoModules
.GetActiveID()].Enable(True) 
 628         self
.ActiveModuleChanged() 
 631     def ActiveModuleChanged(self
): 
 632         self
.LoadDemoSource(self
.demoModules
.GetSource()) 
 633         self
.UpdateControlState() 
 637     def LoadDemoSource(self
, source
): 
 639         self
.editor
.SetValue(source
) 
 641         self
.btnSave
.Enable(False) 
 644     def JumpToLine(self
, line
, highlight
=False): 
 645         self
.editor
.GotoLine(line
) 
 646         self
.editor
.SetFocus() 
 648             self
.editor
.SelectLine(line
) 
 651     def UpdateControlState(self
): 
 652         active 
= self
.demoModules
.GetActiveID() 
 653         # Update the radio/restore buttons 
 654         for moduleID 
in self
.radioButtons
: 
 655             btn 
= self
.radioButtons
[moduleID
] 
 656             if moduleID 
== active
: 
 661             if self
.demoModules
.Exists(moduleID
): 
 663                 if moduleID 
== modModified
: 
 664                     self
.btnRestore
.Enable(True) 
 667                 if moduleID 
== modModified
: 
 668                     self
.btnRestore
.Enable(False) 
 671     def OnRadioButton(self
, event
): 
 672         radioSelected 
= event
.GetEventObject() 
 673         modSelected 
= radioSelected
.modID
 
 674         if modSelected 
!= self
.demoModules
.GetActiveID(): 
 675             busy 
= wx
.BusyInfo("Reloading demo module...") 
 676             self
.demoModules
.SetActive(modSelected
) 
 677             self
.ActiveModuleChanged() 
 680     def ReloadDemo(self
): 
 681         if self
.demoModules
.name 
!= __name__
: 
 682             self
.mainFrame
.RunModule() 
 685     def OnCodeModified(self
, event
): 
 686         self
.btnSave
.Enable(self
.editor
.IsModified()) 
 689     def OnSave(self
, event
): 
 690         if self
.demoModules
.Exists(modModified
): 
 691             if self
.demoModules
.GetActiveID() == modOriginal
: 
 692                 overwriteMsg 
= "You are about to overwrite an already existing modified copy\n" + \
 
 693                                "Do you want to continue?" 
 694                 dlg 
= wx
.MessageDialog(self
, overwriteMsg
, "wxPython Demo", 
 695                                        wx
.YES_NO | wx
.NO_DEFAULT| wx
.ICON_EXCLAMATION
) 
 696                 result 
= dlg
.ShowModal() 
 697                 if result 
== wx
.ID_NO
: 
 701         self
.demoModules
.SetActive(modModified
) 
 702         modifiedFilename 
= GetModifiedFilename(self
.demoModules
.name
) 
 704         # Create the demo directory if one doesn't already exist 
 705         if not os
.path
.exists(GetModifiedDirectory()): 
 707                 os
.makedirs(GetModifiedDirectory()) 
 708                 if not os
.path
.exists(GetModifiedDirectory()): 
 709                     wx
.LogMessage("BUG: Created demo directory but it still doesn't exist") 
 712                 wx
.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory()) 
 715                 wx
.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory()) 
 718         f 
= open(modifiedFilename
, "wt") 
 719         source 
= self
.editor
.GetText() 
 725         busy 
= wx
.BusyInfo("Reloading demo module...") 
 726         self
.demoModules
.LoadFromFile(modModified
, modifiedFilename
) 
 727         self
.ActiveModuleChanged() 
 730     def OnRestore(self
, event
): # Handles the "Delete Modified" button 
 731         modifiedFilename 
= GetModifiedFilename(self
.demoModules
.name
) 
 732         self
.demoModules
.Delete(modModified
) 
 733         os
.unlink(modifiedFilename
) # Delete the modified copy 
 734         busy 
= wx
.BusyInfo("Reloading demo module...") 
 735         self
.ActiveModuleChanged() 
 738 #--------------------------------------------------------------------------- 
 741     """Convert paths to the platform-specific separator""" 
 742     str = apply(os
.path
.join
, tuple(path
.split('/'))) 
 743     # HACK: on Linux, a leading / gets lost... 
 744     if path
.startswith('/'): 
 749 def GetModifiedDirectory(): 
 751     Returns the directory where modified versions of the demo files 
 754     return opj(wx
.GetHomeDir() + "/.wxPyDemo/modified/") 
 757 def GetModifiedFilename(name
): 
 759     Returns the filename of the modified version of the specified demo 
 761     if not name
.endswith(".py"): 
 763     return GetModifiedDirectory() + name
 
 766 def GetOriginalFilename(name
): 
 768     Returns the filename of the original version of the specified demo 
 770     if not name
.endswith(".py"): 
 775 def DoesModifiedExist(name
): 
 776     """Returns whether the specified demo has a modified copy""" 
 777     if os
.path
.exists(GetModifiedFilename(name
)): 
 783 #--------------------------------------------------------------------------- 
 785 class ModuleDictWrapper
: 
 786     """Emulates a module with a dynamically compiled __dict__""" 
 787     def __init__(self
, dict): 
 790     def __getattr__(self
, name
): 
 791         if name 
in self
.dict: 
 792             return self
.dict[name
] 
 798     Dynamically manages the original/modified versions of a demo 
 801     def __init__(self
, name
): 
 805         #              (dict , source ,  filename , description   , error information )         
 806         #              (  0  ,   1    ,     2     ,      3        ,          4        )         
 807         self
.modules 
= [[None,  ""    ,    ""     , "<original>"  ,        None], 
 808                         [None,  ""    ,    ""     , "<modified>"  ,        None]] 
 810         # load original module 
 811         self
.LoadFromFile(modOriginal
, GetOriginalFilename(name
)) 
 812         self
.SetActive(modOriginal
) 
 814         # load modified module (if one exists) 
 815         if DoesModifiedExist(name
): 
 816            self
.LoadFromFile(modModified
, GetModifiedFilename(name
)) 
 819     def LoadFromFile(self
, modID
, filename
): 
 820         self
.modules
[modID
][2] = filename
 
 821         file = open(filename
, "rt") 
 822         self
.LoadFromSource(modID
, file.read()) 
 826     def LoadFromSource(self
, modID
, source
): 
 827         self
.modules
[modID
][1] = source
 
 831     def LoadDict(self
, modID
): 
 832         if self
.name 
!= __name__
: 
 833             source 
= self
.modules
[modID
][1] 
 834             #description = self.modules[modID][3] 
 835             description 
= self
.modules
[modID
][2] 
 838                 self
.modules
[modID
][0] = {} 
 839                 code 
= compile(source
, description
, "exec")         
 840                 exec code 
in self
.modules
[modID
][0] 
 842                 self
.modules
[modID
][4] = DemoError(sys
.exc_info()) 
 843                 self
.modules
[modID
][0] = None 
 845                 self
.modules
[modID
][4] = None 
 848     def SetActive(self
, modID
): 
 849         if modID 
!= modOriginal 
and modID 
!= modModified
: 
 852             self
.modActive 
= modID
 
 856         dict = self
.modules
[self
.modActive
][0] 
 860             return ModuleDictWrapper(dict) 
 863     def GetActiveID(self
): 
 864         return self
.modActive
 
 867     def GetSource(self
, modID 
= None): 
 869             modID 
= self
.modActive
 
 870         return self
.modules
[modID
][1] 
 873     def GetFilename(self
, modID 
= None): 
 875             modID 
= self
.modActive
 
 876         return self
.modules
[self
.modActive
][2] 
 879     def GetErrorInfo(self
, modID 
= None): 
 881             modID 
= self
.modActive
 
 882         return self
.modules
[self
.modActive
][4] 
 885     def Exists(self
, modID
): 
 886         return self
.modules
[modID
][1] != "" 
 889     def UpdateFile(self
, modID 
= None): 
 890         """Updates the file from which a module was loaded 
 891         with (possibly updated) source""" 
 893             modID 
= self
.modActive
 
 895         source 
= self
.modules
[modID
][1] 
 896         filename 
= self
.modules
[modID
][2] 
 899             file = open(filename
, "wt") 
 905     def Delete(self
, modID
): 
 906         if self
.modActive 
== modID
: 
 909         self
.modules
[modID
][0] = None 
 910         self
.modules
[modID
][1] = "" 
 911         self
.modules
[modID
][2] = "" 
 914 #--------------------------------------------------------------------------- 
 917     """Wraps and stores information about the current exception""" 
 918     def __init__(self
, exc_info
): 
 921         excType
, excValue 
= exc_info
[:2] 
 922         # traceback list entries: (filename, line number, function name, text) 
 923         self
.traceback 
= traceback
.extract_tb(exc_info
[2]) 
 925         # --Based on traceback.py::format_exception_only()-- 
 926         if type(excType
) == types
.ClassType
: 
 927             self
.exception_type 
= excType
.__name
__ 
 929             self
.exception_type 
= excType
 
 931         # If it's a syntax error, extra information needs 
 932         # to be added to the traceback 
 933         if excType 
is SyntaxError: 
 935                 msg
, (filename
, lineno
, self
.offset
, line
) = excValue
 
 940                     filename 
= "<string>" 
 942                 self
.traceback
.append( (filename
, lineno
, "", line
) ) 
 945             self
.exception_details 
= str(excValue
) 
 947             self
.exception_details 
= "<unprintable %s object>" & type(excValue
).__name
__ 
 954         Details  : %s" % ( str(self
.exception_type
), str(self
.traceback
), self
.exception_details 
) 
 957 #--------------------------------------------------------------------------- 
 959 class DemoErrorPanel(wx
.Panel
): 
 960     """Panel put into the demo tab when the demo fails to run due  to errors""" 
 962     def __init__(self
, parent
, codePanel
, demoError
, log
): 
 963         wx
.Panel
.__init
__(self
, parent
, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE) 
 964         self
.codePanel 
= codePanel
 
 968         self
.box 
= wx
.BoxSizer(wx
.VERTICAL
) 
 971         self
.box
.Add(wx
.StaticText(self
, -1, "An error has occurred while trying to run the demo") 
 972                      , 0, wx
.ALIGN_CENTER | wx
.TOP
, 10) 
 974         # Exception Information 
 975         boxInfo      
= wx
.StaticBox(self
, -1, "Exception Info" ) 
 976         boxInfoSizer 
= wx
.StaticBoxSizer(boxInfo
, wx
.VERTICAL 
) # Used to center the grid within the box 
 977         boxInfoGrid  
= wx
.FlexGridSizer(0, 2, 0, 0) 
 978         textFlags    
= wx
.ALIGN_RIGHT | wx
.LEFT | wx
.RIGHT | wx
.TOP
 
 979         boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Type: "), 0, textFlags
, 5 ) 
 980         boxInfoGrid
.Add(wx
.StaticText(self
, -1, str(demoError
.exception_type
)) , 0, textFlags
, 5 ) 
 981         boxInfoGrid
.Add(wx
.StaticText(self
, -1, "Details: ") , 0, textFlags
, 5 ) 
 982         boxInfoGrid
.Add(wx
.StaticText(self
, -1, demoError
.exception_details
) , 0, textFlags
, 5 ) 
 983         boxInfoSizer
.Add(boxInfoGrid
, 0, wx
.ALIGN_CENTRE | wx
.ALL
, 5 ) 
 984         self
.box
.Add(boxInfoSizer
, 0, wx
.ALIGN_CENTER | wx
.ALL
, 5) 
 986         # Set up the traceback list 
 987         # This one automatically resizes last column to take up remaining space 
 988         from ListCtrl 
import TestListCtrl
 
 989         self
.list = TestListCtrl(self
, -1, style
=wx
.LC_REPORT  | wx
.SUNKEN_BORDER
) 
 990         self
.list.Bind(wx
.EVT_LEFT_DCLICK
, self
.OnDoubleClick
) 
 991         self
.list.Bind(wx
.EVT_LIST_ITEM_SELECTED
, self
.OnItemSelected
) 
 992         self
.list.InsertColumn(0, "Filename") 
 993         self
.list.InsertColumn(1, "Line", wx
.LIST_FORMAT_RIGHT
) 
 994         self
.list.InsertColumn(2, "Function") 
 995         self
.list.InsertColumn(3, "Code") 
 996         self
.InsertTraceback(self
.list, demoError
.traceback
) 
 997         self
.list.SetColumnWidth(0, wx
.LIST_AUTOSIZE
) 
 998         self
.list.SetColumnWidth(2, wx
.LIST_AUTOSIZE
) 
 999         self
.box
.Add(wx
.StaticText(self
, -1, "Traceback:") 
1000                      , 0, wx
.ALIGN_CENTER | wx
.TOP
, 5) 
1001         self
.box
.Add(self
.list, 1, wx
.GROW | wx
.ALIGN_CENTER | wx
.ALL
, 5) 
1002         self
.box
.Add(wx
.StaticText(self
, -1, "Entries from the demo module are shown in blue\n" 
1003                                            + "Double-click on them to go to the offending line") 
1004                      , 0, wx
.ALIGN_CENTER | wx
.BOTTOM
, 5) 
1007         self
.SetSizer(self
.box
) 
1010     def InsertTraceback(self
, list, traceback
): 
1011         #Add the traceback data 
1012         for x 
in range(len(traceback
)): 
1014             list.InsertStringItem(x
, os
.path
.basename(data
[0])) # Filename 
1015             list.SetStringItem(x
, 1, str(data
[1]))              # Line 
1016             list.SetStringItem(x
, 2, str(data
[2]))              # Function 
1017             list.SetStringItem(x
, 3, str(data
[3]))              # Code 
1019             # Check whether this entry is from the demo module 
1020             if data
[0] == "<original>" or data
[0] == "<modified>": # FIXME: make more generalised 
1021                 self
.list.SetItemData(x
, int(data
[1]))   # Store line number for easy access 
1022                 # Give it a blue colour 
1023                 item 
= self
.list.GetItem(x
) 
1024                 item
.SetTextColour(wx
.BLUE
) 
1025                 self
.list.SetItem(item
) 
1027                 self
.list.SetItemData(x
, -1)        # Editor can't jump into this one's code 
1030     def OnItemSelected(self
, event
): 
1031         # This occurs before OnDoubleClick and can be used to set the 
1032         # currentItem. OnDoubleClick doesn't get a wxListEvent.... 
1033         self
.currentItem 
= event
.m_itemIndex
 
1037     def OnDoubleClick(self
, event
): 
1038         # If double-clicking on a demo's entry, jump to the line number 
1039         line 
= self
.list.GetItemData(self
.currentItem
) 
1041             self
.nb
.SetSelection(1) # Switch to the code viewer tab 
1042             wx
.CallAfter(self
.codePanel
.JumpToLine
, line
-1, True) 
1046 #--------------------------------------------------------------------------- 
1048 class DemoTaskBarIcon(wx
.TaskBarIcon
): 
1049     TBMENU_RESTORE 
= wx
.NewId() 
1050     TBMENU_CLOSE   
= wx
.NewId() 
1051     TBMENU_CHANGE  
= wx
.NewId() 
1052     TBMENU_REMOVE  
= wx
.NewId() 
1054     def __init__(self
, frame
): 
1055         wx
.TaskBarIcon
.__init
__(self
) 
1059         icon 
= self
.MakeIcon(images
.getWXPdemoImage()) 
1060         self
.SetIcon(icon
, "wxPython Demo") 
1064         self
.Bind(wx
.EVT_TASKBAR_LEFT_DCLICK
, self
.OnTaskBarActivate
) 
1065         self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarActivate
, id=self
.TBMENU_RESTORE
) 
1066         self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarClose
, id=self
.TBMENU_CLOSE
) 
1067         self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarChange
, id=self
.TBMENU_CHANGE
) 
1068         self
.Bind(wx
.EVT_MENU
, self
.OnTaskBarRemove
, id=self
.TBMENU_REMOVE
) 
1071     def CreatePopupMenu(self
): 
1073         This method is called by the base class when it needs to popup 
1074         the menu for the default EVT_RIGHT_DOWN event.  Just create 
1075         the menu how you want it and return it from this function, 
1076         the base class takes care of the rest. 
1079         menu
.Append(self
.TBMENU_RESTORE
, "Restore wxPython Demo") 
1080         menu
.Append(self
.TBMENU_CLOSE
,   "Close wxPython Demo") 
1081         menu
.AppendSeparator() 
1082         menu
.Append(self
.TBMENU_CHANGE
, "Change the TB Icon") 
1083         menu
.Append(self
.TBMENU_REMOVE
, "Remove the TB Icon") 
1087     def MakeIcon(self
, img
): 
1089         The various platforms have different requirements for the 
1092         if "wxMSW" in wx
.PlatformInfo
: 
1093             img 
= img
.Scale(16, 16) 
1094         elif "wxGTK" in wx
.PlatformInfo
: 
1095             img 
= img
.Scale(22, 22) 
1096         # wxMac can be any size upto 128x128, so leave the source img alone.... 
1097         icon 
= wx
.IconFromBitmap(img
.ConvertToBitmap() ) 
1101     def OnTaskBarActivate(self
, evt
): 
1102         if self
.frame
.IsIconized(): 
1103             self
.frame
.Iconize(False) 
1104         if not self
.frame
.IsShown(): 
1105             self
.frame
.Show(True) 
1109     def OnTaskBarClose(self
, evt
): 
1113     def OnTaskBarChange(self
, evt
): 
1114         names 
= [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ]                   
1115         name 
= names
[self
.imgidx
] 
1117         getFunc 
= getattr(images
, "get%sImage" % name
) 
1119         if self
.imgidx 
>= len(names
): 
1122         icon 
= self
.MakeIcon(getFunc()) 
1123         self
.SetIcon(icon
, "This is a new icon: " + name
) 
1126     def OnTaskBarRemove(self
, evt
): 
1130 #--------------------------------------------------------------------------- 
1131 class wxPythonDemo(wx
.Frame
): 
1132     overviewText 
= "wxPython Overview" 
1134     def __init__(self
, parent
, title
): 
1135         wx
.Frame
.__init
__(self
, parent
, -1, title
, size 
= (950, 720), 
1136                           style
=wx
.DEFAULT_FRAME_STYLE | wx
.NO_FULL_REPAINT_ON_RESIZE
) 
1138         self
.SetMinSize((640,480)) 
1141         self
.cwd 
= os
.getcwd() 
1142         self
.curOverview 
= "" 
1143         self
.demoPage 
= None 
1144         self
.codePage 
= None 
1146         self
.firstTime 
= True 
1149         icon 
= images
.getWXPdemoIcon() 
1153             self
.tbicon 
= DemoTaskBarIcon(self
) 
1157         wx
.CallAfter(self
.ShowTip
) 
1159         self
.otherWin 
= None 
1160         self
.Bind(wx
.EVT_IDLE
, self
.OnIdle
) 
1161         self
.Bind(wx
.EVT_CLOSE
, self
.OnCloseWindow
) 
1162         self
.Bind(wx
.EVT_ICONIZE
, self
.OnIconfiy
) 
1163         self
.Bind(wx
.EVT_MAXIMIZE
, self
.OnMaximize
) 
1165         self
.Centre(wx
.BOTH
) 
1166         self
.CreateStatusBar(1, wx
.ST_SIZEGRIP
) 
1168         splitter 
= wx
.SplitterWindow(self
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
) 
1169         splitter2 
= wx
.SplitterWindow(splitter
, -1, style
=wx
.CLIP_CHILDREN | wx
.SP_LIVE_UPDATE | wx
.SP_3D
) 
1171         def EmptyHandler(evt
): pass 
1172         #splitter.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler) 
1173         #splitter2.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler) 
1175         # Prevent TreeCtrl from displaying all items after destruction when True 
1179         self
.nb 
= wx
.Notebook(splitter2
, -1, style
=wx
.CLIP_CHILDREN
) 
1182         self
.mainmenu 
= wx
.MenuBar() 
1184         item 
= menu
.Append(-1, '&Redirect Output', 
1185                            'Redirect print statements to a window', 
1187         self
.Bind(wx
.EVT_MENU
, self
.OnToggleRedirect
, item
) 
1189         exitItem 
= menu
.Append(-1, 'E&xit\tCtrl-Q', 'Get the heck outta here!') 
1190         self
.Bind(wx
.EVT_MENU
, self
.OnFileExit
, exitItem
) 
1191         wx
.App
.SetMacExitMenuItemId(exitItem
.GetId()) 
1192         self
.mainmenu
.Append(menu
, '&File') 
1196         for item 
in _treeList
[:-1]: 
1198             for childItem 
in item
[1]: 
1199                 mi 
= submenu
.Append(-1, childItem
) 
1200                 self
.Bind(wx
.EVT_MENU
, self
.OnDemoMenu
, mi
) 
1201             menu
.AppendMenu(wx
.NewId(), item
[0], submenu
) 
1202         self
.mainmenu
.Append(menu
, '&Demo') 
1207         findItem 
= menu
.Append(-1, '&Find\tCtrl-F', 'Find in the Demo Code') 
1208         findnextItem 
= menu
.Append(-1, 'Find &Next\tF3', 'Find Next') 
1209         menu
.AppendSeparator() 
1211         shellItem 
= menu
.Append(-1, 'Open Py&Shell Window\tF5', 
1212                                 'An interactive interpreter window with the demo app and frame objects in the namesapce') 
1213         inspToolItem 
= menu
.Append(-1, 'Open &Widget Inspector\tF6', 
1214                                 'A tool that lets you browse the live widgets and sizers in an application') 
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
.OnOpenWidgetInspector
, inspToolItem
) 
1221         self
.Bind(wx
.EVT_MENU
, self
.OnHelpAbout
, helpItem
) 
1222         self
.Bind(wx
.EVT_MENU
, self
.OnHelpFind
,  findItem
) 
1223         self
.Bind(wx
.EVT_MENU
, self
.OnFindNext
,  findnextItem
) 
1224         self
.Bind(wx
.EVT_FIND
, self
.OnFind
) 
1225         self
.Bind(wx
.EVT_FIND_NEXT
, self
.OnFind
) 
1226         self
.Bind(wx
.EVT_FIND_CLOSE
, self
.OnFindClose
) 
1227         self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findItem
) 
1228         self
.Bind(wx
.EVT_UPDATE_UI
, self
.OnUpdateFindItems
, findnextItem
) 
1229         self
.mainmenu
.Append(menu
, '&Help') 
1230         self
.SetMenuBar(self
.mainmenu
) 
1232         self
.finddata 
= wx
.FindReplaceData() 
1233         self
.finddata
.SetFlags(wx
.FR_DOWN
) 
1236             # This is another way to set Accelerators, in addition to 
1237             # using the '\t<key>' syntax in the menu items. 
1238             aTable 
= wx
.AcceleratorTable([(wx
.ACCEL_ALT
,  ord('X'), exitItem
.GetId()), 
1239                                           (wx
.ACCEL_CTRL
, ord('H'), helpItem
.GetId()), 
1240                                           (wx
.ACCEL_CTRL
, ord('F'), findItem
.GetId()), 
1241                                           (wx
.ACCEL_NORMAL
, wx
.WXK_F3
, findnextItem
.GetId()), 
1242                                           (wx
.ACCEL_NORMAL
, wx
.WXK_F9
, shellItem
.GetId()), 
1244             self
.SetAcceleratorTable(aTable
) 
1249         leftPanel 
= wx
.Panel(splitter
) 
1251         self
.filter = wx
.SearchCtrl(leftPanel
) 
1252         self
.filter.ShowCancelButton(True) 
1253         self
.filter.Bind(wx
.EVT_TEXT
, self
.RecreateTree
) 
1254         self
.filter.Bind(wx
.EVT_SEARCHCTRL_CANCEL_BTN
, 
1255                          lambda e
: self
.filter.SetValue('')) 
1258         self
.tree 
= wx
.TreeCtrl(leftPanel
, tID
, style 
= 
1259                                 wx
.TR_DEFAULT_STYLE 
#| wx.TR_HAS_VARIABLE_ROW_HEIGHT 
1262         self
.root 
= self
.tree
.AddRoot("wxPython Overview") 
1264         self
.tree
.Bind(wx
.EVT_TREE_ITEM_EXPANDED
, self
.OnItemExpanded
, id=tID
) 
1265         self
.tree
.Bind(wx
.EVT_TREE_ITEM_COLLAPSED
, self
.OnItemCollapsed
, id=tID
) 
1266         self
.tree
.Bind(wx
.EVT_TREE_SEL_CHANGED
, self
.OnSelChanged
, id=tID
) 
1267         self
.tree
.Bind(wx
.EVT_LEFT_DOWN
, self
.OnTreeLeftDown
) 
1269         # Set up a wx.html.HtmlWindow on the Overview Notebook page 
1270         # we put it in a panel first because there seems to be a 
1271         # refresh bug of some sort (wxGTK) when it is directly in 
1274             self
.ovr 
= wx
.html
.HtmlWindow(self
.nb
, -1, size
=(400, 400)) 
1275             self
.nb
.AddPage(self
.ovr
, self
.overviewText
) 
1277         else:  # hopefully I can remove this hacky code soon, see SF bug #216861 
1278             panel 
= wx
.Panel(self
.nb
, -1, style
=wx
.CLIP_CHILDREN
) 
1279             self
.ovr 
= wx
.html
.HtmlWindow(panel
, -1, size
=(400, 400)) 
1280             self
.nb
.AddPage(panel
, self
.overviewText
) 
1282             def OnOvrSize(evt
, ovr
=self
.ovr
): 
1283                 ovr
.SetSize(evt
.GetSize()) 
1284             panel
.Bind(wx
.EVT_SIZE
, OnOvrSize
) 
1285             panel
.Bind(wx
.EVT_ERASE_BACKGROUND
, EmptyHandler
) 
1287         if "gtk2" in wx
.PlatformInfo
: 
1288             self
.ovr
.SetStandardFonts() 
1289         self
.SetOverview(self
.overviewText
, mainOverview
) 
1292         # Set up a log window 
1293         self
.log 
= wx
.TextCtrl(splitter2
, -1, 
1294                               style 
= wx
.TE_MULTILINE|wx
.TE_READONLY|wx
.HSCROLL
) 
1295         if wx
.Platform 
== "__WXMAC__": 
1296             self
.log
.MacCheckSpelling(False) 
1298         # Set the wxWindows log target to be this textctrl 
1299         #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log)) 
1301         # But instead of the above we want to show how to use our own wx.Log class 
1302         wx
.Log_SetActiveTarget(MyLog(self
.log
)) 
1304         # for serious debugging 
1305         #wx.Log_SetActiveTarget(wx.LogStderr()) 
1306         #wx.Log_SetTraceMask(wx.TraceMessages) 
1309         self
.Bind(wx
.EVT_ACTIVATE
, self
.OnActivate
) 
1310         wx
.GetApp().Bind(wx
.EVT_ACTIVATE_APP
, self
.OnAppActivate
) 
1312         # add the windows to the splitter and split it. 
1313         splitter2
.SplitHorizontally(self
.nb
, self
.log
, -160) 
1314         leftBox 
= wx
.BoxSizer(wx
.VERTICAL
) 
1315         leftBox
.Add(self
.tree
, 1, wx
.EXPAND
) 
1316         leftBox
.Add(wx
.StaticText(leftPanel
, label 
= "Filter Demos:"), 0, wx
.TOP|wx
.LEFT
, 5) 
1317         leftBox
.Add(self
.filter, 0, wx
.EXPAND|wx
.ALL
, 5) 
1318         leftPanel
.SetSizer(leftBox
) 
1319         splitter
.SplitVertically(leftPanel
, splitter2
, 220) 
1321         splitter
.SetMinimumPaneSize(120) 
1322         splitter2
.SetMinimumPaneSize(60) 
1324         # Make the splitter on the right expand the top window when resized 
1325         def SplitterOnSize(evt
): 
1326             splitter 
= evt
.GetEventObject() 
1327             sz 
= splitter
.GetSize() 
1328             splitter
.SetSashPosition(sz
.height 
- 160, False) 
1331         splitter2
.Bind(wx
.EVT_SIZE
, SplitterOnSize
) 
1333         # select initial items 
1334         self
.nb
.SetSelection(0) 
1335         self
.tree
.SelectItem(self
.root
) 
1337         # Load 'Main' module 
1338         self
.LoadDemo(self
.overviewText
) 
1341         # select some other initial module? 
1342         if len(sys
.argv
) > 1: 
1344             if arg
.endswith('.py'): 
1346             selectedDemo 
= self
.treeMap
.get(arg
, None) 
1348                 self
.tree
.SelectItem(selectedDemo
) 
1349                 self
.tree
.EnsureVisible(selectedDemo
) 
1352     #--------------------------------------------- 
1354     def RecreateTree(self
, evt
=None): 
1356         self
.tree
.DeleteAllItems() 
1357         self
.root 
= self
.tree
.AddRoot("wxPython Overview") 
1359         filter = self
.filter.GetValue() 
1360         for category
, items 
in _treeList
: 
1362                 items 
= [item 
for item 
in items 
if filter.lower() in item
.lower()] 
1364                 child 
= self
.tree
.AppendItem(self
.root
, category
) 
1365                 if not firstChild
: firstChild 
= child
 
1366                 for childItem 
in items
: 
1367                     theDemo 
= self
.tree
.AppendItem(child
, childItem
) 
1368                     self
.treeMap
[childItem
] = theDemo
 
1370         self
.tree
.Expand(self
.root
) 
1372             self
.tree
.Expand(firstChild
) 
1374             self
.tree
.ExpandAll() 
1377     def WriteText(self
, text
): 
1378         if text
[-1:] == '\n': 
1382     def write(self
, txt
): 
1385     #--------------------------------------------- 
1386     def OnItemExpanded(self
, event
): 
1387         item 
= event
.GetItem() 
1388         wx
.LogMessage("OnItemExpanded: %s" % self
.tree
.GetItemText(item
)) 
1391     #--------------------------------------------- 
1392     def OnItemCollapsed(self
, event
): 
1393         item 
= event
.GetItem() 
1394         wx
.LogMessage("OnItemCollapsed: %s" % self
.tree
.GetItemText(item
)) 
1397     #--------------------------------------------- 
1398     def OnTreeLeftDown(self
, event
): 
1399         # reset the overview text if the tree item is clicked on again 
1400         pt 
= event
.GetPosition(); 
1401         item
, flags 
= self
.tree
.HitTest(pt
) 
1402         if item 
== self
.tree
.GetSelection(): 
1403             self
.SetOverview(self
.tree
.GetItemText(item
)+" Overview", self
.curOverview
) 
1406     #--------------------------------------------- 
1407     def OnSelChanged(self
, event
): 
1408         if self
.dying 
or  not self
.loaded
: 
1411         item 
= event
.GetItem() 
1412         itemText 
= self
.tree
.GetItemText(item
) 
1413         self
.LoadDemo(itemText
) 
1415     #--------------------------------------------- 
1416     def LoadDemo(self
, demoName
): 
1418             wx
.BeginBusyCursor() 
1421             self
.ShutdownDemoModule() 
1423             if demoName 
== self
.overviewText
: 
1424                 # User selected the "wxPython Overview" node 
1426                 # Changing the main window at runtime not yet supported... 
1427                 self
.demoModules 
= DemoModules(__name__
) 
1428                 self
.SetOverview(self
.overviewText
, mainOverview
) 
1429                 self
.LoadDemoSource() 
1430                 self
.UpdateNotebook(0) 
1432                 if os
.path
.exists(GetOriginalFilename(demoName
)): 
1433                     wx
.LogMessage("Loading demo %s.py..." % demoName
) 
1434                     self
.demoModules 
= DemoModules(demoName
) 
1435                     self
.LoadDemoSource() 
1438                     self
.SetOverview("wxPython", mainOverview
) 
1439                     self
.codePage 
= None 
1440                     self
.UpdateNotebook(0) 
1444     #--------------------------------------------- 
1445     def LoadDemoSource(self
): 
1446         self
.codePage 
= None 
1447         self
.codePage 
= DemoCodePanel(self
.nb
, self
) 
1448         self
.codePage
.LoadDemo(self
.demoModules
) 
1450     #--------------------------------------------- 
1451     def RunModule(self
): 
1452         """Runs the active module""" 
1454         module 
= self
.demoModules
.GetActive() 
1455         self
.ShutdownDemoModule() 
1458         # o The RunTest() for all samples must now return a window that can 
1459         #   be palced in a tab in the main notebook. 
1460         # o If an error occurs (or has occurred before) an error tab is created. 
1462         if module 
is not None: 
1463             wx
.LogMessage("Running demo module...") 
1464             if hasattr(module
, "overview"): 
1465                 overviewText 
= module
.overview
 
1468                 self
.demoPage 
= module
.runTest(self
, self
.nb
, self
) 
1470                 self
.demoPage 
= DemoErrorPanel(self
.nb
, self
.codePage
, 
1471                                                DemoError(sys
.exc_info()), self
) 
1473             assert self
.demoPage 
is not None, "runTest must return a window!" 
1476             # There was a previous error in compiling or exec-ing 
1477             self
.demoPage 
= DemoErrorPanel(self
.nb
, self
.codePage
, 
1478                                            self
.demoModules
.GetErrorInfo(), self
) 
1480         self
.SetOverview(self
.demoModules
.name 
+ " Overview", overviewText
) 
1483             # cahnge to the demo page the first time a module is run 
1484             self
.UpdateNotebook(2) 
1485             self
.firstTime 
= False 
1487             # otherwise just stay on the same tab in case the user has changed to another one 
1488             self
.UpdateNotebook() 
1490     #--------------------------------------------- 
1491     def ShutdownDemoModule(self
): 
1493             # inform the window that it's time to quit if it cares 
1494             if hasattr(self
.demoPage
, "ShutdownDemo"): 
1495                 self
.demoPage
.ShutdownDemo() 
1496             wx
.YieldIfNeeded() # in case the page has pending events 
1497             self
.demoPage 
= None 
1499     #--------------------------------------------- 
1500     def UpdateNotebook(self
, select 
= -1): 
1504         def UpdatePage(page
, pageText
): 
1507             for i 
in range(nb
.GetPageCount()): 
1508                 if nb
.GetPageText(i
) == pageText
: 
1516                     nb
.AddPage(page
, pageText
) 
1517                     if debug
: wx
.LogMessage("DBG: ADDED %s" % pageText
) 
1519                     if nb
.GetPage(pagePos
) != page
: 
1520                         # Reload an existing page 
1522                         nb
.DeletePage(pagePos
) 
1523                         nb
.InsertPage(pagePos
, page
, pageText
) 
1525                         if debug
: wx
.LogMessage("DBG: RELOADED %s" % pageText
) 
1527                         # Excellent! No redraw/flicker 
1528                         if debug
: wx
.LogMessage("DBG: SAVED from reloading %s" % pageText
) 
1531                 nb
.DeletePage(pagePos
) 
1532                 if debug
: wx
.LogMessage("DBG: DELETED %s" % pageText
) 
1534                 if debug
: wx
.LogMessage("DBG: STILL GONE - %s" % pageText
) 
1537             select 
= nb
.GetSelection() 
1539         UpdatePage(self
.codePage
, "Demo Code") 
1540         UpdatePage(self
.demoPage
, "Demo") 
1542         if select 
>= 0 and select 
< nb
.GetPageCount(): 
1543             nb
.SetSelection(select
) 
1545     #--------------------------------------------- 
1546     def SetOverview(self
, name
, text
): 
1547         self
.curOverview 
= text
 
1549         if lead 
!= '<html>' and lead 
!= '<HTML>': 
1550             text 
= '<br>'.join(text
.split('\n')) 
1552             text 
= text
.decode('iso8859_1')   
1553         self
.ovr
.SetPage(text
) 
1554         self
.nb
.SetPageText(0, name
) 
1556     #--------------------------------------------- 
1558     def OnFileExit(self
, *event
): 
1561     def OnToggleRedirect(self
, event
): 
1565             print "Print statements and other standard output will now be directed to this window." 
1568             print "Print statements and other standard output will now be sent to the usual location." 
1570     def OnHelpAbout(self
, event
): 
1571         from About 
import MyAboutBox
 
1572         about 
= MyAboutBox(self
) 
1576     def OnHelpFind(self
, event
): 
1577         if self
.finddlg 
!= None: 
1580         self
.nb
.SetSelection(1) 
1581         self
.finddlg 
= wx
.FindReplaceDialog(self
, self
.finddata
, "Find", 
1582                         wx
.FR_NOMATCHCASE | wx
.FR_NOWHOLEWORD
) 
1583         self
.finddlg
.Show(True) 
1586     def OnUpdateFindItems(self
, evt
): 
1587         evt
.Enable(self
.finddlg 
== None) 
1590     def OnFind(self
, event
): 
1591         editor 
= self
.codePage
.editor
 
1592         self
.nb
.SetSelection(1) 
1593         end 
= editor
.GetLastPosition() 
1594         textstring 
= editor
.GetRange(0, end
).lower() 
1595         findstring 
= self
.finddata
.GetFindString().lower() 
1596         backward 
= not (self
.finddata
.GetFlags() & wx
.FR_DOWN
) 
1598             start 
= editor
.GetSelection()[0] 
1599             loc 
= textstring
.rfind(findstring
, 0, start
) 
1601             start 
= editor
.GetSelection()[1] 
1602             loc 
= textstring
.find(findstring
, start
) 
1603         if loc 
== -1 and start 
!= 0: 
1604             # string not found, start at beginning 
1607                 loc 
= textstring
.rfind(findstring
, 0, start
) 
1610                 loc 
= textstring
.find(findstring
, start
) 
1612             dlg 
= wx
.MessageDialog(self
, 'Find String Not Found', 
1613                           'Find String Not Found in Demo File', 
1614                           wx
.OK | wx
.ICON_INFORMATION
) 
1619                 self
.finddlg
.SetFocus() 
1622                 self
.finddlg
.Destroy() 
1624         editor
.ShowPosition(loc
) 
1625         editor
.SetSelection(loc
, loc 
+ len(findstring
)) 
1629     def OnFindNext(self
, event
): 
1630         if self
.finddata
.GetFindString(): 
1633             self
.OnHelpFind(event
) 
1635     def OnFindClose(self
, event
): 
1636         event
.GetDialog().Destroy() 
1640     def OnOpenShellWindow(self
, evt
): 
1642             # if it already exists then just make sure it's visible 
1648             # Make a PyShell window 
1650             namespace 
= { 'wx'    : wx
, 
1651                           'app'   : wx
.GetApp(), 
1654             self
.shell 
= py
.shell
.ShellFrame(None, locals=namespace
) 
1655             self
.shell
.SetSize((640,480)) 
1658             # Hook the close event of the main frame window so that we 
1659             # close the shell at the same time if it still exists             
1660             def CloseShell(evt
): 
1664             self
.Bind(wx
.EVT_CLOSE
, CloseShell
) 
1667     def OnOpenWidgetInspector(self
, evt
): 
1668         # Activate the widget inspection tool 
1669         from wx
.lib
.inspection 
import InspectionTool
 
1670         if not InspectionTool().initialized
: 
1671             InspectionTool().Init() 
1673         # Find a widget to be selected in the tree.  Use either the 
1674         # one under the cursor, if any, or this frame. 
1675         wnd 
= wx
.FindWindowAtPointer() 
1678         InspectionTool().Show(wnd
, True) 
1681     #--------------------------------------------- 
1682     def OnCloseWindow(self
, event
): 
1684         self
.demoPage 
= None 
1685         self
.codePage 
= None 
1686         self
.mainmenu 
= None 
1687         if self
.tbicon 
is not None: 
1688             self
.tbicon
.Destroy() 
1692     #--------------------------------------------- 
1693     def OnIdle(self
, event
): 
1695             self
.otherWin
.Raise() 
1696             self
.demoPage 
= self
.otherWin
 
1697             self
.otherWin 
= None 
1700     #--------------------------------------------- 
1703             showTipText 
= open(opj("data/showTips")).read() 
1704             showTip
, index 
= eval(showTipText
) 
1706             showTip
, index 
= (1, 0) 
1708             tp 
= wx
.CreateFileTipProvider(opj("data/tips.txt"), index
) 
1710             showTip 
= wx
.ShowTip(self
, tp
) 
1711             index 
= tp
.GetCurrentTip() 
1712             open(opj("data/showTips"), "w").write(str( (showTip
, index
) )) 
1715     #--------------------------------------------- 
1716     def OnDemoMenu(self
, event
): 
1718             selectedDemo 
= self
.treeMap
[self
.mainmenu
.GetLabel(event
.GetId())] 
1722             self
.tree
.SelectItem(selectedDemo
) 
1723             self
.tree
.EnsureVisible(selectedDemo
) 
1727     #--------------------------------------------- 
1728     def OnIconfiy(self
, evt
): 
1729         wx
.LogMessage("OnIconfiy: %s" % evt
.Iconized()) 
1732     #--------------------------------------------- 
1733     def OnMaximize(self
, evt
): 
1734         wx
.LogMessage("OnMaximize") 
1737     #--------------------------------------------- 
1738     def OnActivate(self
, evt
): 
1739         wx
.LogMessage("OnActivate: %s" % evt
.GetActive()) 
1742     #--------------------------------------------- 
1743     def OnAppActivate(self
, evt
): 
1744         wx
.LogMessage("OnAppActivate: %s" % evt
.GetActive()) 
1747 #--------------------------------------------------------------------------- 
1748 #--------------------------------------------------------------------------- 
1750 class MySplashScreen(wx
.SplashScreen
): 
1752         bmp 
= wx
.Image(opj("bitmaps/splash.png")).ConvertToBitmap() 
1753         wx
.SplashScreen
.__init
__(self
, bmp
, 
1754                                  wx
.SPLASH_CENTRE_ON_SCREEN | wx
.SPLASH_TIMEOUT
, 
1756         self
.Bind(wx
.EVT_CLOSE
, self
.OnClose
) 
1757         self
.fc 
= wx
.FutureCall(2000, self
.ShowMain
) 
1760     def OnClose(self
, evt
): 
1761         # Make sure the default handler runs too so this window gets 
1766         # if the timer is still running then go ahead and show the 
1768         if self
.fc
.IsRunning(): 
1774         frame 
= wxPythonDemo(None, "wxPython: (A Demonstration)") 
1776         if self
.fc
.IsRunning(): 
1780 class MyApp(wx
.App
): 
1783         Create and show the splash screen.  It will then create and show 
1784         the main frame when it is time to do so. 
1787         wx
.SystemOptions
.SetOptionInt("mac.window-plain-transition", 1) 
1790         #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG) 
1792         # Normally when using a SplashScreen you would create it, show 
1793         # it and then continue on with the applicaiton's 
1794         # initialization, finally creating and showing the main 
1795         # application window(s).  In this case we have nothing else to 
1796         # do so we'll delay showing the main frame until later (see 
1797         # ShowMain above) so the users can see the SplashScreen effect.         
1798         splash 
= MySplashScreen() 
1805 #--------------------------------------------------------------------------- 
1809         demoPath 
= os
.path
.dirname(__file__
) 
1816 #--------------------------------------------------------------------------- 
1819 mainOverview 
= """<html><body> 
1822 <p> wxPython is a <b>GUI toolkit</b> for the Python programming 
1823 language.  It allows Python programmers to create programs with a 
1824 robust, highly functional graphical user interface, simply and easily. 
1825 It is implemented as a Python extension module (native code) that 
1826 wraps the popular wxWindows cross platform GUI library, which is 
1829 <p> Like Python and wxWindows, wxPython is <b>Open Source</b> which 
1830 means that it is free for anyone to use and the source code is 
1831 available for anyone to look at and modify.  Or anyone can contribute 
1832 fixes or enhancements to the project. 
1834 <p> wxPython is a <b>cross-platform</b> toolkit.  This means that the 
1835 same program will run on multiple platforms without modification. 
1836 Currently supported platforms are 32-bit Microsoft Windows, most Unix 
1837 or unix-like systems, and Macintosh OS X. Since the language is 
1838 Python, wxPython programs are <b>simple, easy</b> to write and easy to 
1841 <p> <b>This demo</b> is not only a collection of test cases for 
1842 wxPython, but is also designed to help you learn about and how to use 
1843 wxPython.  Each sample is listed in the tree control on the left. 
1844 When a sample is selected in the tree then a module is loaded and run 
1845 (usually in a tab of this notebook,) and the source code of the module 
1846 is loaded in another tab for you to browse and learn from. 
1851 #---------------------------------------------------------------------------- 
1852 #---------------------------------------------------------------------------- 
1854 if __name__ 
== '__main__': 
1858 #----------------------------------------------------------------------------