EditorWindow.py revision 83118c6cb36cf9a424bec1b9a2ef8c8760bae8f5
17aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport sys
27aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport os
37aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport string
47aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport re
57aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport imp
67aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererfrom Tkinter import *
77aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport tkSimpleDialog
87aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport tkMessageBox
9fd182cd9d36adefba00d86542eb3134119cdc804Kurt B. Kaiser
10fd182cd9d36adefba00d86542eb3134119cdc804Kurt B. Kaiserimport webbrowser
117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport idlever
127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererimport WindowList
13c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gavaimport SearchDialog
14c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gavaimport GrepDialog
15c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gavaimport ReplaceDialog
16dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava#from IdleConf import idleconf
17dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gavafrom configHandler import idleConf
183b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gavaimport aboutDialog, textView, configDialog
197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer# The default tab setting for a Text widget, in average-width characters.
217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David SchererTK_TABWIDTH_DEFAULT = 8
227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer# File menu
247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<open-module>>
267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ win <Alt-m>
277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ unix <Control-x><Control-m>
287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<open-class-browser>>
307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ win <Alt-c>
317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ unix <Control-x><Control-b>
327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<open-path-browser>>
347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<close-window>>
36afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser
377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ unix <Control-x><Control-0>
387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ unix <Control-x><Key-0>
397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ win <Alt-F4>
407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer# Edit menu
427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<Copy>>
447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ win <Control-c>
457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ unix <Alt-w>
467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<Cut>>
487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ win <Control-x>
497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ unix <Control-w>
507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<Paste>>
527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ win <Control-v>
537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ unix <Control-y>
547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<select-all>>
567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ win <Alt-a>
577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ unix <Alt-a>
587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer# Help menu
607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<help>>
627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ win <F1>
637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ unix <F1>
647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<about-idle>>
667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer# Events without menu entries
687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<remove-selection>>
707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ win <Escape>
717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<center-insert>>
737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ win <Control-l>
747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ unix <Control-l>
757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ event <<do-nothing>>
777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer#$ unix <Control-x>
787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererclass EditorWindow:
807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    from Percolator import Percolator
817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    from ColorDelegator import ColorDelegator
827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    from UndoDelegator import UndoDelegator
837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    from IOBinding import IOBinding
847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    import Bindings
857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    from Tkinter import Toplevel
867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    from MultiStatusBar import MultiStatusBar
877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    vars = {}
897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def __init__(self, flist=None, filename=None, key=None, root=None):
91dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava        currentTheme=idleConf.CurrentTheme()
927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.flist = flist
937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        root = root or flist.root
947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.root = root
957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.menubar = Menu(root)
967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.top = top = self.Toplevel(root, menu=self.menubar)
970c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava        if flist:
980c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava            self.vars = flist.vars
990c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava            #self.top.instanceDict makes flist.inversedict avalable to
1000c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava            #configDialog.py so it can access all EditorWindow instaces
1010c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava            self.top.instanceDict=flist.inversedict
1021d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        self.recentFilesPath=os.path.join(idleConf.GetUserCfgDir(),
1031d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                'recent-files.lst')
1047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.vbar = vbar = Scrollbar(top, name='vbar')
1057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text_frame = text_frame = Frame(top)
106dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava        self.text = text = Text(text_frame, name='text', padx=5, wrap=None,
107dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                foreground=idleConf.GetHighlight(currentTheme,
108dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                        'normal',fgBg='fg'),
109dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                background=idleConf.GetHighlight(currentTheme,
110dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                        'normal',fgBg='bg'),
111dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                highlightcolor=idleConf.GetHighlight(currentTheme,
112dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                        'hilite',fgBg='fg'),
113dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                highlightbackground=idleConf.GetHighlight(currentTheme,
114dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                        'hilite',fgBg='bg'),
115dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                insertbackground=idleConf.GetHighlight(currentTheme,
116dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                        'cursor',fgBg='fg'),
117dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                width=idleConf.GetOption('main','EditorWindow','width'),
118dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava                height=idleConf.GetOption('main','EditorWindow','height') )
1197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.createmenubar()
1217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.apply_bindings()
1227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.top.protocol("WM_DELETE_WINDOW", self.close)
1247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.top.bind("<<close-window>>", self.close_event)
1257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<center-insert>>", self.center_insert_event)
1267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<help>>", self.help_dialog)
1277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<good-advice>>", self.good_advice)
128abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava        text.bind("<<view-readme>>", self.view_readme)
1297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<python-docs>>", self.python_docs)
1307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<about-idle>>", self.about_dialog)
1313b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava        text.bind("<<open-config-dialog>>", self.config_dialog)
1327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<open-module>>", self.open_module)
1337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<do-nothing>>", lambda event: "break")
1347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<select-all>>", self.select_all)
1357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<<remove-selection>>", self.remove_selection)
136c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.bind("<<find>>", self.find_event)
137c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.bind("<<find-again>>", self.find_again_event)
138c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.bind("<<find-in-files>>", self.find_in_files_event)
139c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.bind("<<find-selection>>", self.find_selection_event)
140c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.bind("<<replace>>", self.replace_event)
141c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.bind("<<goto-line>>", self.goto_line_event)
1427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.bind("<3>", self.right_menu_event)
1437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if flist:
1447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            flist.inversedict[self] = key
1457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if key:
1467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                flist.dict[key] = self
1477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            text.bind("<<open-new-window>>", self.flist.new_callback)
1487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            text.bind("<<close-all-windows>>", self.flist.close_all_callback)
1497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            text.bind("<<open-class-browser>>", self.open_class_browser)
1507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            text.bind("<<open-path-browser>>", self.open_path_browser)
1517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
152898a365c276951ab2471afe2e24bbc910666d361Steven M. Gava        self.set_status_bar()
153898a365c276951ab2471afe2e24bbc910666d361Steven M. Gava
1547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        vbar['command'] = text.yview
1557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        vbar.pack(side=RIGHT, fill=Y)
1567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text['yscrollcommand'] = vbar.set
158b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava        fontWeight='normal'
159b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava        if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'):
160b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava            fontWeight='bold'
161dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava        text.config(font=(idleConf.GetOption('main','EditorWindow','font'),
162b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava                idleConf.GetOption('main','EditorWindow','font-size'),
163b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava                fontWeight))
1647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text_frame.pack(side=LEFT, fill=BOTH, expand=1)
1657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.pack(side=TOP, fill=BOTH, expand=1)
1667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.focus_set()
1677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per = per = self.Percolator(text)
1697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.ispythonsource(filename):
1707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.color = color = self.ColorDelegator(); per.insertfilter(color)
1717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            ##print "Initial colorizer"
1727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
1737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            ##print "No initial colorizer"
1747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.color = None
1757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.undo = undo = self.UndoDelegator(); per.insertfilter(undo)
1767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.io = io = self.IOBinding(self)
1771d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        #create the Recent Files submenu
1781d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        self.menuRecentFiles=Menu(self.menubar)
1791d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        self.menudict['file'].insert_cascade(3,label='Recent Files',
1801d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                underline=0,menu=self.menuRecentFiles)
1811d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        self.UpdateRecentFilesList()
1827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.undo_block_start = undo.undo_block_start
1847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.undo_block_stop = undo.undo_block_stop
1857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        undo.set_saved_change_hook(self.saved_change_hook)
1867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        io.set_filename_change_hook(self.filename_change_hook)
1877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if filename:
1897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if os.path.exists(filename):
1907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                io.loadfile(filename)
1917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            else:
1927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                io.set_filename(filename)
1937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.saved_change_hook()
1957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.load_extensions()
1977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
1987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        menu = self.menudict.get('windows')
1997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if menu:
2007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            end = menu.index("end")
2017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if end is None:
2027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                end = -1
2037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if end >= 0:
2047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                menu.add_separator()
2057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                end = end + 1
2067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.wmenu_end = end
2077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            WindowList.register_callback(self.postwindowsmenu)
2087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # Some abstractions so IDLE extensions are cross-IDE
2107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.askyesno = tkMessageBox.askyesno
2117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.askinteger = tkSimpleDialog.askinteger
2127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.showerror = tkMessageBox.showerror
2137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.extensions.has_key('AutoIndent'):
2157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.extensions['AutoIndent'].set_indentation_params(
2167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                self.ispythonsource(filename))
2170c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava
2187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def set_status_bar(self):
219898a365c276951ab2471afe2e24bbc910666d361Steven M. Gava        self.status_bar = self.MultiStatusBar(self.top)
2207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.status_bar.set_label('column', 'Col: ?', side=RIGHT)
2217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.status_bar.set_label('line', 'Ln: ?', side=RIGHT)
2227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.status_bar.pack(side=BOTTOM, fill=X)
2237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.bind('<KeyRelease>', self.set_line_and_column)
2247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.bind('<ButtonRelease>', self.set_line_and_column)
2257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.after_idle(self.set_line_and_column)
2267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def set_line_and_column(self, event=None):
2287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        line, column = string.split(self.text.index(INSERT), '.')
2297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.status_bar.set_label('column', 'Col: %s' % column)
2307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.status_bar.set_label('line', 'Ln: %s' % line)
2317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def wakeup(self):
2337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.top.wm_state() == "iconic":
2347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.top.wm_deiconify()
2357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
2367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.top.tkraise()
2377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.focus_set()
2387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    menu_specs = [
2407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("file", "_File"),
2417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("edit", "_Edit"),
2427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("format", "F_ormat"),
2437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("run", "_Run"),
24482c6682bb776bb59e10a522897534af69938194fSteven M. Gava        ("settings", "_Settings"),
2457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("windows", "_Windows"),
2467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("help", "_Help"),
2477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    ]
2487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def createmenubar(self):
2507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        mbar = self.menubar
2517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.menudict = menudict = {}
2527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        for name, label in self.menu_specs:
2537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            underline, label = prepstr(label)
2547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            menudict[name] = menu = Menu(mbar, name=name)
2557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            mbar.add_cascade(label=label, menu=menu, underline=underline)
2567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.fill_menus()
2571d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        #create the ExtraHelp menu, if required
2580c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava        self.ResetExtraHelpMenu()
2597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def postwindowsmenu(self):
2617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # Only called when Windows menu exists
2627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # XXX Actually, this Just-In-Time updating interferes badly
2637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # XXX with the tear-off feature.  It would be better to update
2647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # XXX all Windows menus whenever the list of windows changes.
2657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        menu = self.menudict['windows']
2667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        end = menu.index("end")
2677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if end is None:
2687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            end = -1
2697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if end > self.wmenu_end:
2707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            menu.delete(self.wmenu_end+1, end)
2717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        WindowList.add_windows_to_menu(menu)
2727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    rmenu = None
2747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def right_menu_event(self, event):
2767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.tag_remove("sel", "1.0", "end")
2777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.mark_set("insert", "@%d,%d" % (event.x, event.y))
2787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not self.rmenu:
2797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.make_rmenu()
2807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        rmenu = self.rmenu
2817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.event = event
2827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        iswin = sys.platform[:3] == 'win'
2837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if iswin:
2847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.text.config(cursor="arrow")
2857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        rmenu.tk_popup(event.x_root, event.y_root)
2867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if iswin:
2877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.text.config(cursor="ibeam")
2887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    rmenu_specs = [
2907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # ("Label", "<<virtual-event>>"), ...
2917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ("Close", "<<close-window>>"), # Example
2927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    ]
2937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
2947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def make_rmenu(self):
2957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        rmenu = Menu(self.text, tearoff=0)
2967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        for label, eventname in self.rmenu_specs:
2977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            def command(text=self.text, eventname=eventname):
2987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                text.event_generate(eventname)
2997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            rmenu.add_command(label=label, command=command)
3007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.rmenu = rmenu
3017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
3027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def about_dialog(self, event=None):
3037d9ed726fb6ec15dbfb8e922d35aa8816cbd0b0cSteven M. Gava        aboutDialog.AboutDialog(self.top,'About IDLEfork')
3047d9ed726fb6ec15dbfb8e922d35aa8816cbd0b0cSteven M. Gava
3053b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava    def config_dialog(self, event=None):
3063b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava        configDialog.ConfigDialog(self.top,'Settings')
3073b55a891a197212b34b0c077f72cb3af752468ecSteven M. Gava
3087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def good_advice(self, event=None):
3097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        tkMessageBox.showinfo('Advice', "Don't Panic!", master=self.text)
3107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
311abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava    def view_readme(self, event=None):
312abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava        fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'README.txt')
313abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava        textView.TextViewer(self.top,'IDLEfork - README',fn)
314abdfc4147d1f1334bb4dbaf5d9dd66af1db175adSteven M. Gava
3157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def help_dialog(self, event=None):
316b9d07b5a8b8b70268ffa520895e7843ab594a486Steven M. Gava        fn=os.path.join(os.path.abspath(os.path.dirname(__file__)),'help.txt')
317b9d07b5a8b8b70268ffa520895e7843ab594a486Steven M. Gava        textView.TextViewer(self.top,'Help',fn)
318b9d07b5a8b8b70268ffa520895e7843ab594a486Steven M. Gava
3197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    help_url = "http://www.python.org/doc/current/"
320afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser    if sys.platform[:3] == "win":
321afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser        fn = os.path.dirname(__file__)
322931625dc77cfd527b059e579615d517d8d994110Steven M. Gava        fn = os.path.join(fn, os.pardir, os.pardir, "pythlp.chm")
323afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser        fn = os.path.normpath(fn)
324afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser        if os.path.isfile(fn):
325afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser            help_url = fn
326931625dc77cfd527b059e579615d517d8d994110Steven M. Gava        else:
327931625dc77cfd527b059e579615d517d8d994110Steven M. Gava            fn = os.path.dirname(__file__)
328931625dc77cfd527b059e579615d517d8d994110Steven M. Gava            fn = os.path.join(fn, os.pardir, os.pardir, "Doc", "index.html")
329931625dc77cfd527b059e579615d517d8d994110Steven M. Gava            fn = os.path.normpath(fn)
330931625dc77cfd527b059e579615d517d8d994110Steven M. Gava            if os.path.isfile(fn):
331931625dc77cfd527b059e579615d517d8d994110Steven M. Gava                help_url = fn
332afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser        del fn
333931625dc77cfd527b059e579615d517d8d994110Steven M. Gava        def python_docs(self, event=None):
334931625dc77cfd527b059e579615d517d8d994110Steven M. Gava            os.startfile(self.help_url)
335931625dc77cfd527b059e579615d517d8d994110Steven M. Gava    else:
336931625dc77cfd527b059e579615d517d8d994110Steven M. Gava        def python_docs(self, event=None):
337931625dc77cfd527b059e579615d517d8d994110Steven M. Gava            self.display_docs(self.help_url)
3380c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava
3390c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava    def display_docs(self, url):
3400c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava        webbrowser.open(url)
3417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
3427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def select_all(self, event=None):
3437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.tag_add("sel", "1.0", "end-1c")
3447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.mark_set("insert", "1.0")
3457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.see("insert")
3467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return "break"
3477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
3487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def remove_selection(self, event=None):
3497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.tag_remove("sel", "1.0", "end")
3507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text.see("insert")
3517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
352c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava    def find_event(self, event):
353c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        SearchDialog.find(self.text)
354c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        return "break"
355c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava
356c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava    def find_again_event(self, event):
357c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        SearchDialog.find_again(self.text)
358c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        return "break"
359c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava
360c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava    def find_selection_event(self, event):
361c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        SearchDialog.find_selection(self.text)
362c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        return "break"
363c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava
364c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava    def find_in_files_event(self, event):
365c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        GrepDialog.grep(self.text, self.io, self.flist)
366c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        return "break"
367c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava
368c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava    def replace_event(self, event):
369c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        ReplaceDialog.replace(self.text)
370c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        return "break"
371c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava
372c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava    def goto_line_event(self, event):
373c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text = self.text
374c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        lineno = tkSimpleDialog.askinteger("Goto",
375c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava                "Go to line number:",parent=text)
376c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        if lineno is None:
377c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava            return "break"
378c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        if lineno <= 0:
379c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava            text.bell()
380c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava            return "break"
381c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.mark_set("insert", "%d.0" % lineno)
382c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava        text.see("insert")
383c597640515a9ca3aa1807cc633b8d7bf2aa4a4e6Steven M. Gava
3847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def open_module(self, event=None):
3857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # XXX Shouldn't this be in IOBinding or in FileList?
3867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        try:
3877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            name = self.text.get("sel.first", "sel.last")
3887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        except TclError:
3897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            name = ""
3907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
3917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            name = string.strip(name)
3927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not name:
3937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            name = tkSimpleDialog.askstring("Module",
3947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                     "Enter the name of a Python module\n"
3957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                     "to search on sys.path and open:",
3967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                     parent=self.text)
3977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if name:
3987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                name = string.strip(name)
3997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if not name:
4007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                return
4017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # XXX Ought to support package syntax
4027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        # XXX Ought to insert current file's directory in front of path
4037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        try:
4047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            (f, file, (suffix, mode, type)) = imp.find_module(name)
4057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        except (NameError, ImportError), msg:
4067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            tkMessageBox.showerror("Import error", str(msg), parent=self.text)
4077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return
4087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if type != imp.PY_SOURCE:
4097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            tkMessageBox.showerror("Unsupported type",
4107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                "%s is not a source module" % name, parent=self.text)
4117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return
4127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if f:
4137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            f.close()
4147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.flist:
4157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.flist.open(file)
4167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
4177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.io.loadfile(file)
4187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def open_class_browser(self, event=None):
4207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        filename = self.io.filename
4217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not filename:
4227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            tkMessageBox.showerror(
4237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                "No filename",
4247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                "This buffer has no associated filename",
4257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                master=self.text)
4267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.text.focus_set()
4277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return None
4287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        head, tail = os.path.split(filename)
4297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        base, ext = os.path.splitext(tail)
4307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        import ClassBrowser
4317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ClassBrowser.ClassBrowser(self.flist, base, [head])
4327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def open_path_browser(self, event=None):
4347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        import PathBrowser
4357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        PathBrowser.PathBrowser(self.flist)
4367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def gotoline(self, lineno):
4387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if lineno is not None and lineno > 0:
4397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.text.mark_set("insert", "%d.0" % lineno)
4407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.text.tag_remove("sel", "1.0", "end")
4417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.text.tag_add("sel", "insert", "insert +1l")
4427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.center()
4437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def ispythonsource(self, filename):
4457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not filename:
4467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return 1
4477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        base, ext = os.path.splitext(os.path.basename(filename))
4487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if os.path.normcase(ext) in (".py", ".pyw"):
4497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return 1
4507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        try:
4517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            f = open(filename)
4527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            line = f.readline()
4537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            f.close()
4547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        except IOError:
4557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return 0
4567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return line[:2] == '#!' and string.find(line, 'python') >= 0
4577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def close_hook(self):
4597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.flist:
4607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.flist.close_edit(self)
4617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def set_close_hook(self, close_hook):
4637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.close_hook = close_hook
4647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def filename_change_hook(self):
4667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.flist:
4677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.flist.filename_changed_edit(self)
4687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.saved_change_hook()
4697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.ispythonsource(self.io.filename):
4707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.addcolorizer()
4717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
4727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.rmcolorizer()
4737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def addcolorizer(self):
4757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.color:
4767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return
4777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ##print "Add colorizer"
4787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.removefilter(self.undo)
4797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.color = self.ColorDelegator()
4807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.insertfilter(self.color)
4817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.insertfilter(self.undo)
4827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
4837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def rmcolorizer(self):
4847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not self.color:
4857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return
4867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ##print "Remove colorizer"
4877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.removefilter(self.undo)
4887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.removefilter(self.color)
4897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.color = None
4907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.insertfilter(self.undo)
491b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava
492b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava    def ResetColorizer(self):
49383118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        "Update the colour theme if it is changed"
49483118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        # Called from configDialog.py
495b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava        if self.color:
496b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava            self.color = self.ColorDelegator()
497b77d343bc846c2049a4cffb1dfd65eb49d1728b4Steven M. Gava            self.per.insertfilter(self.color)
4987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
499b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava    def ResetFont(self):
50083118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        "Update the text widgets' font if it is changed"
50183118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        # Called from configDialog.py
502b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava        fontWeight='normal'
503b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava        if idleConf.GetOption('main','EditorWindow','font-bold',type='bool'):
504b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava            fontWeight='bold'
505b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava        self.text.config(font=(idleConf.GetOption('main','EditorWindow','font'),
506b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava                idleConf.GetOption('main','EditorWindow','font-size'),
507b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava                fontWeight))
508b1585417d1f7ae8984ca72b16fd5a21746949ae5Steven M. Gava
509dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava    def ResetKeybindings(self):
51083118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        "Update the keybindings if they are changed"
51183118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        # Called from configDialog.py
512dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        self.Bindings.default_keydefs=idleConf.GetCurrentKeySet()
513dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        keydefs = self.Bindings.default_keydefs
514dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        for event, keylist in keydefs.items():
515dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava            self.text.event_delete(event)
516dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        self.apply_bindings()
517dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        #update menu accelerators
518dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        menuEventDict={}
519dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        for menu in self.Bindings.menudefs:
520dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava            menuEventDict[menu[0]]={}
521dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava            for item in menu[1]:
522dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                if item:
523dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                    menuEventDict[menu[0]][prepstr(item[0])[1]]=item[1]
524dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava        for menubarItem in self.menudict.keys():
525dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava            menu=self.menudict[menubarItem]
526dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava            end=menu.index(END)+1
527dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava            for index in range(0,end):
528dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                if menu.type(index)=='command':
529dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                    accel=menu.entrycget(index,'accelerator')
530dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                    if accel:
531dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                        itemName=menu.entrycget(index,'label')
532dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                        event=''
533dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                        if menuEventDict.has_key(menubarItem):
534dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                            if menuEventDict[menubarItem].has_key(itemName):
535dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                                event=menuEventDict[menubarItem][itemName]
536dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                        if event:
537dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                            #print 'accel was:',accel
538dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                            accel=get_accelerator(keydefs, event)
539dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                            menu.entryconfig(index,accelerator=accel)
540dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava                            #print 'accel now:',accel,'\n'
541dbfe92cd27f08d38cc8a2882c147c4289b6b5db1Steven M. Gava
5420c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava    def ResetExtraHelpMenu(self):
54383118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        "Load or update the Extra Help menu if required"
5440c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava        menuList=idleConf.GetAllExtraHelpSourcesList()
5450c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava        helpMenu=self.menudict['help']
5460c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava        cascadeIndex=helpMenu.index(END)-1
5470c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava        if menuList:
5480c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava            if not hasattr(self,'menuExtraHelp'):
5490c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava                self.menuExtraHelp=Menu(self.menubar)
5500c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava                helpMenu.insert_cascade(cascadeIndex,label='Extra Help',
5510c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava                        underline=1,menu=self.menuExtraHelp)
5520c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava            self.menuExtraHelp.delete(1,END)
5530c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava            for menuItem in menuList:
5540c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava                self.menuExtraHelp.add_command(label=menuItem[0],
5551d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                        command=self.__DisplayExtraHelpCallback(menuItem[1]))
5560c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava        else: #no extra help items
5570c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava            if hasattr(self,'menuExtraHelp'):
5580c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava                helpMenu.delete(cascadeIndex-1)
5590c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava                del(self.menuExtraHelp)
5601d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava
5611d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava    def __DisplayExtraHelpCallback(self,helpFile):
5621d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        def DisplayExtraHelp(helpFile=helpFile):
5631d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            self.display_docs(helpFile)
5641d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        return DisplayExtraHelp
5650c5bc8c9518fd18d41aedede536c4a9aa8dfa619Steven M. Gava
5661d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava    def UpdateRecentFilesList(self,newFile=None):
56783118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        "Load or update the recent files list, and menu if required"
5681d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        rfList=[]
5691d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        if os.path.exists(self.recentFilesPath):
5701d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            RFfile=open(self.recentFilesPath,'r')
5711d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            try:
5721d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                rfList=RFfile.readlines()
5731d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            finally:
5741d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                RFfile.close()
5751d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        if newFile:
5761d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            newFile=os.path.abspath(newFile)+'\n'
5771d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            if newFile in rfList:
5781d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                rfList.remove(newFile)
5791d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            rfList.insert(0,newFile)
5801d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        rfList=self.__CleanRecentFiles(rfList)
58183118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        #print self.flist.inversedict
58283118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        #print self.top.instanceDict
58383118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        #print self
5841d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        if rfList:
5851d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            for instance in self.top.instanceDict.keys():
5861d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                instance.menuRecentFiles.delete(1,END)
5871d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                for file in rfList:
5881d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                    fileName=file[0:-1]
5891d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                    instance.menuRecentFiles.add_command(label=fileName,
5901d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                            command=instance.__RecentFileCallback(fileName))
5911d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava
5921d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava    def __CleanRecentFiles(self,rfList):
5931d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        origRfList=rfList[:]
5941d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        count=0
5951d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        nonFiles=[]
5961d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        for path in rfList:
5971d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            if not os.path.exists(path[0:-1]):
5981d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                nonFiles.append(count)
5991d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            count=count+1
6001d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        if nonFiles:
6011d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            nonFiles.reverse()
6021d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            for index in nonFiles:
6031d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava                del(rfList[index])
6041d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        if len(rfList)>19:
6051d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            rfList=rfList[0:19]
6061d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        #if rfList != origRfList:
6071d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        RFfile=open(self.recentFilesPath,'w')
6081d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        try:
6091d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            RFfile.writelines(rfList)
6101d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        finally:
6111d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            RFfile.close()
6121d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        return rfList
6131d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava
6141d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava    def __RecentFileCallback(self,fileName):
6151d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        def OpenRecentFile(fileName=fileName):
6161d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            self.io.open(editFile=fileName)
6171d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        return OpenRecentFile
6181d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava
6197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def saved_change_hook(self):
6207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        short = self.short_title()
6217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        long = self.long_title()
6227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if short and long:
6237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            title = short + " - " + long
6247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        elif short:
6257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            title = short
6267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        elif long:
6277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            title = long
6287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
6297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            title = "Untitled"
6307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        icon = short or long or title
6317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not self.get_saved():
6327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            title = "*%s*" % title
6337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            icon = "*%s" % icon
6347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.top.wm_title(title)
6357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.top.wm_iconname(icon)
6367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def get_saved(self):
6387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return self.undo.get_saved()
6397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def set_saved(self, flag):
6417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.undo.set_saved(flag)
6427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def reset_undo(self):
6447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.undo.reset_undo()
6457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def short_title(self):
6477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        filename = self.io.filename
6487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if filename:
6497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            filename = os.path.basename(filename)
6507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return filename
6517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def long_title(self):
6537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return self.io.filename or ""
6547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def center_insert_event(self, event):
6567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.center()
6577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def center(self, mark="insert"):
6597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text = self.text
6607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        top, bot = self.getwindowlines()
6617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        lineno = self.getlineno(mark)
6627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        height = bot - top
6637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        newtop = max(1, lineno - height/2)
6647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.yview(float(newtop))
6657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def getwindowlines(self):
6677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text = self.text
6687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        top = self.getlineno("@0,0")
6697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        bot = self.getlineno("@0,65535")
6707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if top == bot and text.winfo_height() == 1:
6717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            # Geometry manager hasn't run yet
6727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            height = int(text['height'])
6737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            bot = top + height - 1
6747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return top, bot
6757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def getlineno(self, mark="insert"):
6777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text = self.text
6787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return int(float(text.index(mark)))
6797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def close_event(self, event):
6817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.close()
6827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def maybesave(self):
6847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.io:
68567716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava            if not self.get_saved():
68667716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava                if self.top.state()!='normal':
68767716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava                    self.top.deiconify()
68867716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava                self.top.lower()
68967716b5f53715e57d147cde9539b8d76a5a56e11Steven M. Gava                self.top.lift()
6907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return self.io.maybesave()
6917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def close(self):
6937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        reply = self.maybesave()
6947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if reply != "cancel":
6957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self._close()
6967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return reply
6977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
6987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def _close(self):
69983118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        #print self.io.filename
7001d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava        if self.io.filename:
7011d46e40f58b21dd6c30e21a841d65e9bcbc899b1Steven M. Gava            self.UpdateRecentFilesList(newFile=self.io.filename)
70283118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        shell = self.flist.pyshell
70383118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        if shell and shell.interp.debugger:
70483118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser            shell.interp.debugger.clear_file_breaks(self)
7057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        WindowList.unregister_callback(self.postwindowsmenu)
7067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.close_hook:
7077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.close_hook()
7087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.flist = None
7097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        colorizing = 0
7107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.unload_extensions()
7117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.io.close(); self.io = None
7127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.undo = None # XXX
7137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.color:
7147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            colorizing = self.color.colorizing
7157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            doh = colorizing and self.top
7167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.color.close(doh) # Cancel colorization
7177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.text = None
7187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.vars = None
7197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.per.close(); self.per = None
7207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not colorizing:
7217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.top.destroy()
7227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def load_extensions(self):
7247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.extensions = {}
7257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.load_standard_extensions()
7267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def unload_extensions(self):
7287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        for ins in self.extensions.values():
7297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if hasattr(ins, "close"):
7307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                ins.close()
7317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.extensions = {}
7327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def load_standard_extensions(self):
7347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        for name in self.get_standard_extension_names():
7357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            try:
7367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                self.load_extension(name)
7377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            except:
7387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                print "Failed to load extension", `name`
7397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                import traceback
7407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                traceback.print_exc()
7417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def get_standard_extension_names(self):
743dc72f48e262a7aaf177a37676c79ced4ddce0fffSteven M. Gava        return idleConf.GetExtensions()
7447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def load_extension(self, name):
7467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        mod = __import__(name, globals(), locals(), [])
7477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        cls = getattr(mod, name)
7487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        ins = cls(self)
7497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        self.extensions[name] = ins
75072c3bf076f785aaf54d63a7e8cae29bc8282920eSteven M. Gava        keydefs=idleConf.GetExtensionBindings(name)
7517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if keydefs:
7527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.apply_bindings(keydefs)
7537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            for vevent in keydefs.keys():
7547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                methodname = string.replace(vevent, "-", "_")
7557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                while methodname[:1] == '<':
7567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    methodname = methodname[1:]
7577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                while methodname[-1:] == '>':
7587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    methodname = methodname[:-1]
7597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                methodname = methodname + "_event"
7607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                if hasattr(ins, methodname):
7617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    self.text.bind(vevent, getattr(ins, methodname))
7627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if hasattr(ins, "menudefs"):
7637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.fill_menus(ins.menudefs, keydefs)
7647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return ins
7657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def apply_bindings(self, keydefs=None):
7677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if keydefs is None:
7687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            keydefs = self.Bindings.default_keydefs
7697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text = self.text
7707aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text.keydefs = keydefs
7717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        for event, keylist in keydefs.items():
7727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if keylist:
7737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                apply(text.event_add, (event,) + tuple(keylist))
7747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
7757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def fill_menus(self, defs=None, keydefs=None):
77683118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        """Add appropriate entries to the menus and submenus
77783118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser
77883118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        Menus that are absent or None in self.menudict are ignored.
77983118c6cb36cf9a424bec1b9a2ef8c8760bae8f5Kurt B. Kaiser        """
7807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if defs is None:
7817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            defs = self.Bindings.menudefs
7827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if keydefs is None:
7837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            keydefs = self.Bindings.default_keydefs
7847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        menudict = self.menudict
7857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text = self.text
7867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        for mname, itemlist in defs:
7877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            menu = menudict.get(mname)
7887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            if not menu:
7897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                continue
7907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            for item in itemlist:
7917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                if not item:
7927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    menu.add_separator()
7937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                else:
7947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    label, event = item
7957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    checkbutton = (label[:1] == '!')
7967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    if checkbutton:
7977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                        label = label[1:]
7987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    underline, label = prepstr(label)
7997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    accelerator = get_accelerator(keydefs, event)
8007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    def command(text=text, event=event):
8017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                        text.event_generate(event)
8027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    if checkbutton:
8037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                        var = self.getrawvar(event, BooleanVar)
8047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                        menu.add_checkbutton(label=label, underline=underline,
8057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                            command=command, accelerator=accelerator,
8067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                            variable=var)
8077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                    else:
8087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                        menu.add_command(label=label, underline=underline,
8097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                            command=command, accelerator=accelerator)
8107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def getvar(self, name):
8127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        var = self.getrawvar(name)
8137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if var:
8147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return var.get()
8157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def setvar(self, name, value, vartype=None):
8177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        var = self.getrawvar(name, vartype)
8187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if var:
8197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            var.set(value)
8207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def getrawvar(self, name, vartype=None):
8227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        var = self.vars.get(name)
8237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if not var and vartype:
8247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            self.vars[name] = var = vartype(self.text)
8257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return var
8267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # Tk implementations of "virtual text methods" -- each platform
8287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # reusing IDLE's support code needs to define these for its GUI's
8297aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # flavor of widget.
8307aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8317aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # Is character at text_index in a Python string?  Return 0 for
8327aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # "guaranteed no", true for anything else.  This info is expensive
8337aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # to compute ab initio, but is probably already known by the
8347aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # platform's colorizer.
8357aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8367aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def is_char_in_string(self, text_index):
8377aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.color:
8387aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            # Return true iff colorizer hasn't (re)gotten this far
8397aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            # yet, or the character is tagged as being in a string
8407aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return self.text.tag_prevrange("TODO", text_index) or \
8417aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                   "STRING" in self.text.tag_names(text_index)
8427aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        else:
8437aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            # The colorizer is missing: assume the worst
8447aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return 1
8457aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8467aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # If a selection is defined in the text widget, return (start,
8477aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # end) as Tkinter text indices, otherwise return (None, None)
8487aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def get_selection_indices(self):
8497aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        try:
8507aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            first = self.text.index("sel.first")
8517aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            last = self.text.index("sel.last")
8527aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return first, last
8537aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        except TclError:
8547aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            return None, None
8557aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8567aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # Return the text widget's current view of what a tab stop means
8577aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # (equivalent width in spaces).
8587aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8597aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def get_tabwidth(self):
8607aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        current = self.text['tabs'] or TK_TABWIDTH_DEFAULT
8617aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return int(current)
8627aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8637aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # Set the text widget's current view of what a tab stop means.
8647aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8657aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    def set_tabwidth(self, newtabwidth):
8667aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        text = self.text
8677aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        if self.get_tabwidth() != newtabwidth:
8687aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            pixels = text.tk.call("font", "measure", text["font"],
8697aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer                                  "-displayof", text.master,
870afdf71b9eefdfb5904e40602984836b28318bad0Kurt B. Kaiser                                  "n" * newtabwidth)
8717aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer            text.configure(tabs=pixels)
8727aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8737aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef prepstr(s):
8747aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # Helper to extract the underscore from a string, e.g.
8757aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # prepstr("Co_py") returns (2, "Copy").
8767aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    i = string.find(s, '_')
8777aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    if i >= 0:
8787aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        s = s[:i] + s[i+1:]
8797aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    return i, s
8807aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8817aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8827aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererkeynames = {
8837aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 'bracketleft': '[',
8847aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 'bracketright': ']',
8857aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer 'slash': '/',
8867aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer}
8877aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
8887aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef get_accelerator(keydefs, event):
8897aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    keylist = keydefs.get(event)
8907aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    if not keylist:
8917aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        return ""
8927aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = keylist[0]
8937aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub(r"-[a-z]\b", lambda m: string.upper(m.group()), s)
8947aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub(r"\b\w+\b", lambda m: keynames.get(m.group(), m.group()), s)
8957aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub("Key-", "", s)
8967aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub("Cancel","Ctrl-Break",s)   # dscherer@cmu.edu
8977aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub("Control-", "Ctrl-", s)
8987aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub("-", "+", s)
8997aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub("><", " ", s)
9007aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub("<", "", s)
9017aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    s = re.sub(">", "", s)
9027aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    return s
9037aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
9047aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
9057aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef fixwordbreaks(root):
9067aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # Make sure that Tk's double-click and next/previous word
9077aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    # operations use our definition of a word (i.e. an identifier)
9087aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    tk = root.tk
9097aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    tk.call('tcl_wordBreakAfter', 'a b', 0) # make sure word.tcl is loaded
9107aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    tk.call('set', 'tcl_wordchars', '[a-zA-Z0-9_]')
9117aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    tk.call('set', 'tcl_nonwordchars', '[^a-zA-Z0-9_]')
9127aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
9137aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
9147aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererdef test():
9157aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    root = Tk()
9167aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    fixwordbreaks(root)
9177aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    root.withdraw()
9187aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    if sys.argv[1:]:
9197aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        filename = sys.argv[1]
9207aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    else:
9217aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer        filename = None
9227aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    edit = EditorWindow(root=root, filename=filename)
9237aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    edit.set_close_hook(root.quit)
9247aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    root.mainloop()
9257aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    root.destroy()
9267aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer
9277aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Schererif __name__ == '__main__':
9287aced17437a6b05bc4b0b5ff93aa6a5d3a374d68David Scherer    test()
929