Ejemplo n.º 1
0
def main():
    from Percolator import Percolator
    root = Tk()
    root.wm_protocol("WM_DELETE_WINDOW", root.quit)
    text = Text(background="white")
    text.pack(expand=1, fill="both")
    text.focus_set()
    p = Percolator(text)
    d = ColorDelegator()
    p.insertfilter(d)
    root.mainloop()
Ejemplo n.º 2
0
def main():
    from Percolator import Percolator
    root = Tk()
    root.wm_protocol("WM_DELETE_WINDOW", root.quit)
    text = Text()
    text.pack()
    text.focus_set()
    p = Percolator(text)
    d = UndoDelegator()
    p.insertfilter(d)
    root.mainloop()
Ejemplo n.º 3
0
def main():
    from Percolator import Percolator
    root = Tk()
    root.wm_protocol("WM_DELETE_WINDOW", root.quit)
    text = Text()
    text.pack()
    text.focus_set()
    p = Percolator(text)
    d = UndoDelegator()
    p.insertfilter(d)
    root.mainloop()
Ejemplo n.º 4
0
def main():
    from Percolator import Percolator
    root = Tk()
    root.wm_protocol("WM_DELETE_WINDOW", root.quit)
    text = Text(background="white")
    text.pack(expand=1, fill="both")
    text.focus_set()
    p = Percolator(text)
    d = ColorDelegator()
    p.insertfilter(d)
    root.mainloop()
Ejemplo n.º 5
0
def main():
    from Percolator import Percolator
    root = Tk()
    root.wm_protocol("WM_DELETE_WINDOW", root.quit)
    text = Text()
    text.pack()
    text.focus_set()
    p = Percolator(text)
    d = UndoDelegator()
    p.insertfilter(d)
    keylist = ['<Control-KeyPress-z>', '<Control-KeyPress-Z>']
    text.event_add("<<undo>>", *keylist)
    #root.bind( '<Control-KeyPress-z>',lambda e=None,d=d:d.event_generate("<<undo>>") )
    root.mainloop()
Ejemplo n.º 6
0
def main():
    from Percolator import Percolator
    root = Tk()
    root.wm_protocol("WM_DELETE_WINDOW", root.quit)
    text = Text()
    text.pack()
    text.focus_set()
    p = Percolator(text)
    d = UndoDelegator()
    p.insertfilter(d)
    keylist = ['<Control-KeyPress-z>','<Control-KeyPress-Z>']
    text.event_add("<<undo>>", *keylist)
    #root.bind( '<Control-KeyPress-z>',lambda e=None,d=d:d.event_generate("<<undo>>") )
    root.mainloop()
Ejemplo n.º 7
0
def _color_delegator(parent):  # htest #
    from tkinter import Toplevel, Text
    from Percolator import Percolator

    top = Toplevel(parent)
    top.title("Test ColorDelegator")
    top.geometry("200x100+%d+%d" % (parent.winfo_rootx() + 200,
                  parent.winfo_rooty() + 150))
    source = "if somename: x = 'abc' # comment\nprint\n"
    text = Text(top, background="white")
    text.pack(expand=1, fill="both")
    text.insert("insert", source)
    text.focus_set()

    p = Percolator(text)
    d = ColorDelegator()
    p.insertfilter(d)
Ejemplo n.º 8
0
    def __init__(self, parent_frame, editwin, title=None, **kwargs):
        self.editwin = editwin
        self.title = title
        self.tab_initialized = False
        kwargs.setdefault('width',
                          idleConf.GetOption('main', 'EditorPage', 'width'))
        kwargs.setdefault('height',
                          idleConf.GetOption('main', 'EditorPage', 'height'))

        self.text = MultiCallCreator(Text)(parent_frame, **kwargs)
        self.color = None  # initialized in reset_colorizer
        self.per = Percolator(self.text)
        self.undo = self.editwin.UndoDelegator()
        self.per.insertfilter(self.undo)
        self.text.undo_block_start = self.undo.undo_block_start
        self.text.undo_block_stop = self.undo.undo_block_stop
        self.io = IOBinding.IOBinding(self)

        self.undo.set_saved_change_hook(self.saved_change_hook)
        self.io.set_filename_change_hook(self.filename_change_hook)
        self.reset_colorizer()
        self._setup_bindings()
Ejemplo n.º 9
0
def _undo_delegator(parent):
    from Percolator import Percolator
    root = Tk()
    root.title("Test UndoDelegator")
    width, height, x, y = list(map(int, re.split('[x+]', parent.geometry())))
    root.geometry("+%d+%d"%(x, y + 150))

    text = Text(root)
    text.config(height=10)
    text.pack()
    text.focus_set()
    p = Percolator(text)
    d = UndoDelegator()
    p.insertfilter(d)

    undo = Button(root, text="Undo", command=lambda:d.undo_event(None))
    undo.pack(side='left')
    redo = Button(root, text="Redo", command=lambda:d.redo_event(None))
    redo.pack(side='left')
    dump = Button(root, text="Dump", command=lambda:d.dump_event(None))
    dump.pack(side='left')

    root.mainloop()
Ejemplo n.º 10
0
def _undo_delegator(parent):
    from Percolator import Percolator
    root = Tk()
    root.title("Test UndoDelegator")
    width, height, x, y = list(map(int, re.split('[x+]', parent.geometry())))
    root.geometry("+%d+%d"%(x, y + 150))

    text = Text(root)
    text.config(height=10)
    text.pack()
    text.focus_set()
    p = Percolator(text)
    d = UndoDelegator()
    p.insertfilter(d)

    undo = Button(root, text="Undo", command=lambda:d.undo_event(None))
    undo.pack(side='left')
    redo = Button(root, text="Redo", command=lambda:d.redo_event(None))
    redo.pack(side='left')
    dump = Button(root, text="Dump", command=lambda:d.dump_event(None))
    dump.pack(side='left')

    root.mainloop()
Ejemplo n.º 11
0
def addFiltersFromIDLE(self):
    """
  Adds syntax colors, undo, replace, find, goto, indent, commment 
  functionality from IDLE to the text widget
  """
    textWidget = self.textWidget

    p = Percolator(textWidget)
    p.insertfilter(ColorDelegator())  # Python syntax coloring
    undo = UndoDelegator()
    p.insertfilter(undo)  # Undo/Redo feature

    # This is used to undo stuff done with replace, indent, comment, etc.
    textWidget.undo_block_start = undo.undo_block_start
    textWidget.undo_block_stop = undo.undo_block_stop

    #----------------- Bind virtual events to the text widget ------------------
    textWidget.bind(
        "<<replace>>",
        lambda e=None, self=self: ReplaceDialog.replace(self.textWidget))
    textWidget.bind(
        "<<find>>",
        lambda e=None, self=self: SearchDialog.find(self.textWidget))
    textWidget.bind("<<goto-line>>",
                    lambda e=None, self=self: goto_line_event(self))
    textWidget.bind("<<add-indent>>",
                    lambda e=None, self=self: indent_region_event(self))
    textWidget.bind("<<del-indent>>",
                    lambda e=None, self=self: dedent_region_event(self))
    textWidget.bind("<<add-comment>>",
                    lambda e=None, self=self: comment_region_event(self))
    textWidget.bind("<<del-comment>>",
                    lambda e=None, self=self: uncomment_region_event(self))
    textWidget.bind("<<select-all>>",
                    lambda e=None, self=self: select_all(self))
    textWidget.bind("<<deselect-all>>",
                    lambda e=None, self=self: deselect_all(self))
    textWidget.bind("<<paste>>", lambda e=None, self=self: paste(self))
    textWidget.bind("<<copy>>", lambda e=None, self=self: copy(self))
    textWidget.bind("<<cut>>", lambda e=None, self=self: cut(self))
    textWidget.bind("<<popup-menu>>",
                    lambda e=None, self=self: popupMenu(self, e))
    textWidget.bind("<<open>>", lambda e=None, self=self: Open(self))
    textWidget.bind("<<save>>", lambda e=None, self=self: SaveAs(self))

    #---------------- Give virtual events a concrete keybinding ----------------
    for key, value in KEY_DICT.iteritems():
        textWidget.event_add(key, *value)
Ejemplo n.º 12
0
    def __init__(self, parent_frame, editwin, title=None, **kwargs):
        self.editwin = editwin
        self.title = title
        self.tab_initialized = False
        kwargs.setdefault('width', idleConf.GetOption('main', 'EditorPage',
            'width'))
        kwargs.setdefault('height', idleConf.GetOption('main', 'EditorPage',
            'height'))

        self.text = MultiCallCreator(Text)(parent_frame, **kwargs)
        self.color = None # initialized in reset_colorizer
        self.per = Percolator(self.text)
        self.undo = self.editwin.UndoDelegator()
        self.per.insertfilter(self.undo)
        self.text.undo_block_start = self.undo.undo_block_start
        self.text.undo_block_stop = self.undo.undo_block_stop
        self.io = IOBinding.IOBinding(self)

        self.undo.set_saved_change_hook(self.saved_change_hook)
        self.io.set_filename_change_hook(self.filename_change_hook)
        self.reset_colorizer()
        self._setup_bindings()
Ejemplo n.º 13
0
import time
Ejemplo n.º 14
0
import sys
Ejemplo n.º 15
0
import sys
Ejemplo n.º 16
0
class EditorPage(object):
    rmenu = None
    rmenu_specs = [
        ("Set Breakpoint", "<<set-breakpoint-here>>"),
        ("Clear Breakpoint", "<<clear-breakpoint-here>>")
    ]

    def __init__(self, parent_frame, editwin, title=None, **kwargs):
        self.editwin = editwin
        self.title = title
        self.tab_initialized = False
        kwargs.setdefault('width', idleConf.GetOption('main', 'EditorPage',
            'width'))
        kwargs.setdefault('height', idleConf.GetOption('main', 'EditorPage',
            'height'))

        self.text = MultiCallCreator(Text)(parent_frame, **kwargs)
        self.color = None # initialized in reset_colorizer
        self.per = Percolator(self.text)
        self.undo = self.editwin.UndoDelegator()
        self.per.insertfilter(self.undo)
        self.text.undo_block_start = self.undo.undo_block_start
        self.text.undo_block_stop = self.undo.undo_block_stop
        self.io = IOBinding.IOBinding(self)

        self.undo.set_saved_change_hook(self.saved_change_hook)
        self.io.set_filename_change_hook(self.filename_change_hook)
        self.reset_colorizer()
        self._setup_bindings()

    def post_init(self, filename=None, update_window_title=False):
        if filename:
            if os.path.exists(filename) and not os.path.isdir(filename):
                self.io.loadfile(filename)
            else:
                self.io.set_filename(filename)
        self.saved_change_hook(update_window_title=update_window_title)
        self.tab_initialized = True

    def close_tab(self, event=None):
        """Close current tab, if no more tabs present, close the window."""
        if hasattr(self.editwin, 'interp'):
            # this is a PyShell, don't ask to save
            reply = 'yes'
        else:
            reply = str(self.maybesave())
        if reply != "cancel":
            if self.io.filename:
                self.editwin.update_recent_files_list(new_file=self.io.filename)
            self.close()
            self.editwin.text_notebook.remove_page(self.title)
            self.editwin.top.event_generate('<<tab-closed>>')

        return reply

    def close(self):
        """Perform necessary cleanup for this page before closing it."""
        self.io.close()
        self.io = None

        self.undo = None

        if self.color:
            self.color.close(False)
            self.color = None

        self.per.close()
        self.per = None
        self.text = None

    # XXX (1) mark where these functions are used
    def saved_change_hook(self,update_window_title=False,update_tab_title=True):
        short = self.editwin.short_title()
        long = self.long_title()

        if short and long:
            title = short + " - " + long
            tabtitle = os.path.split(long)[-1]
        elif short:
            title = short
            tabtitle = short
        elif long:
            title = long
            tabtitle = os.path.split(long)[-1]
        else:
            title = tabtitle = "Untitled"
        icon = short or long or title
        if not self.get_saved():
            title = "*%s*" % title
            tabtitle = "*%s*" % tabtitle
            icon = "*%s" % icon

        if update_tab_title:
            self.editwin.text_notebook.update_tabtitle(self, tabtitle)
        if update_window_title or (
           update_window_title is None and self.tab_initialized):
            self.editwin.top.wm_title(title)
            self.editwin.top.wm_iconname(icon)

    def get_saved(self):
        return self.undo.get_saved()

    def set_saved(self, flag):
        self.undo.set_saved(flag)

    def filename_change_hook(self):
        if self.editwin.flist:
            self.editwin.flist.filename_changed_edit(self, self.editwin)
        self.saved_change_hook(self.tab_initialized)
        self.editwin.top.update_windowlist_registry(self.editwin)
        self.reset_colorizer()

    def reset_undo(self):
        self.undo.reset_undo()

    def reset_colorizer(self):
        "Update the colour theme"
        # Called from self.filename_change_hook and from configDialog.py
        self.__rmcolorizer()
        self.__addcolorizer()
        theme = idleConf.GetOption('main','Theme','name')
        normal_colors = idleConf.GetHighlight(theme, 'normal')
        cursor_color = idleConf.GetHighlight(theme, 'cursor', fgBg='fg')
        select_colors = idleConf.GetHighlight(theme, 'hilite')

        self.text.config(
            foreground=normal_colors['foreground'],
            background=normal_colors['background'],
            insertbackground=cursor_color,
            selectforeground=select_colors['foreground'],
            selectbackground=select_colors['background'])

    def short_title(self):
        filename = self.io.filename
        if filename:
            filename = os.path.basename(filename)
        # return unicode string to display non-ASCII chars correctly
        return filename_to_unicode(filename)

    def long_title(self):
        # return unicode string to display non-ASCII chars correctly
        return filename_to_unicode(self.io.filename or "")

    def maybesave(self):
        if self.io:
            if not self.get_saved():
                if self.editwin.top.state()!= 'normal':
                    self.editiwn.top.deiconify()
                self.editwin.top.lower()
                self.editwin.top.lift()
            return self.io.maybesave()
    # XXX (1) end

    def center(self, mark="insert"):
        # Used by EditorWindow.gotoline
        text = self.text
        top, bot = self._getwindowlines()
        lineno = self._getlineno(mark)
        height = bot - top
        newtop = max(1, lineno - height//2)
        text.yview(float(newtop))

    def ispythonsource(self, filename):
        if not filename or os.path.isdir(filename):
            return True
        base, ext = os.path.splitext(os.path.basename(filename))
        if os.path.normcase(ext) in (".py", ".pyw"):
            return True
        try:
            f = open(filename)
            line = f.readline()
            f.close()
        except IOError:
            return False
        return line.startswith('#!') and line.find('python') >= 0

    def newline_and_indent_event(self, event):
        # Used by EditorWindow.newline_and_indent_event which is used by PyShell
        text = self.text
        first, last = self.get_selection_indices()
        text.undo_block_start()
        try:
            if first and last:
                text.delete(first, last)
                text.mark_set("insert", first)
            line = text.get("insert linestart", "insert")
            i, n = 0, len(line)
            while i < n and line[i] in " \t":
                i = i+1
            if i == n:
                # the cursor is in or at leading indentation in a continuation
                # line; just inject an empty line at the start
                text.insert("insert linestart", '\n')
                return "break"
            indent = line[:i]
            # strip whitespace before insert point unless it's in the prompt
            i = 0
            last_line_of_prompt = sys.ps1.split('\n')[-1]
            while line and line[-1] in " \t" and line != last_line_of_prompt:
                line = line[:-1]
                i = i+1
            if i:
                text.delete("insert - %d chars" % i, "insert")
            # strip whitespace after insert point
            while text.get("insert") in " \t":
                text.delete("insert")
            # start new line
            text.insert("insert", '\n')

            # adjust indentation for continuations and block
            # open/close first need to find the last stmt
            lno = index2line(text.index('insert'))
            #print self.editwin.indentwidth, self.editwin.tabwidth
            y = PyParse.Parser(self.editwin.indentwidth, self.editwin.tabwidth)
            if not self.editwin.context_use_ps1:
                for context in self.editwin.num_context_lines:
                    startat = max(lno - context, 1)
                    startatindex = `startat` + ".0"
                    rawtext = text.get(startatindex, "insert")
                    y.set_str(rawtext)
                    bod = y.find_good_parse_start(
                              self.editwin.context_use_ps1,
                              self.build_char_in_string_func(startatindex))
                    if bod is not None or startat == 1:
                        break
                y.set_lo(bod or 0)
            else:
                r = text.tag_prevrange("console", "insert")
                if r:
                    startatindex = r[1]
                else:
                    startatindex = "1.0"
                rawtext = text.get(startatindex, "insert")
                y.set_str(rawtext)
                y.set_lo(0)

            c = y.get_continuation_type()
            if c != PyParse.C_NONE:
                # The current stmt hasn't ended yet.
                if c == PyParse.C_STRING_FIRST_LINE:
                    # after the first line of a string; do not indent at all
                    pass
                elif c == PyParse.C_STRING_NEXT_LINES:
                    # inside a string which started before this line;
                    # just mimic the current indent
                    text.insert("insert", indent)
                elif c == PyParse.C_BRACKET:
                    # line up with the first (if any) element of the
                    # last open bracket structure; else indent one
                    # level beyond the indent of the line with the
                    # last open bracket
                    self.__reindent_to(y.compute_bracket_indent())
                elif c == PyParse.C_BACKSLASH:
                    # if more than one line in this stmt already, just
                    # mimic the current indent; else if initial line
                    # has a start on an assignment stmt, indent to
                    # beyond leftmost =; else to beyond first chunk of
                    # non-whitespace on initial line
                    if y.get_num_lines_in_stmt() > 1:
                        text.insert("insert", indent)
                    else:
                        self.__reindent_to(y.compute_backslash_indent())
                else:
                    assert 0, "bogus continuation type %r" % (c,)
                return "break"

            # This line starts a brand new stmt; indent relative to
            # indentation of initial line of closest preceding
            # interesting stmt.
            indent = y.get_base_indent_string()
            text.insert("insert", indent)
            if y.is_block_opener():
                self._smart_indent_event(event)
            elif indent and y.is_block_closer():
                self._smart_backspace_event(event)
            return "break"
        finally:
            text.see("insert")
            text.undo_block_stop()

    # If a selection is defined in the text widget, return (start,
    # end) as Tkinter text indices, otherwise return (None, None)
    def get_selection_indices(self):
        # Used by EditorWindow.get_selection_indices which is used by
        # FormatParagraph
        try:
            first = self.text.index("sel.first")
            last = self.text.index("sel.last")
            return first, last
        except TclError:
            return None, None

    # Our editpage provides a __is_char_in_string function that works
    # with a Tk text index, but PyParse only knows about offsets into
    # a string. This builds a function for PyParse that accepts an
    # offset.
    def build_char_in_string_func(self, startindex):
        # Used by EditorWindow.build_char_in_string_func which is used by
        # HyperParser
        def inner(offset, _startindex=startindex,
                  _icis=self.__is_char_in_string):
            return _icis(_startindex + "+%dc" % offset)
        return inner

    def _setup_bindings(self):
        text = self.text
        def bind_them(to_bind, prefix='_%s'):
            for tb in to_bind:
                prefix_size = tb.count('<')
                method_name = tb[prefix_size:-prefix_size].replace('-', '_')
                text.bind(tb, getattr(self, prefix % method_name.lower()))
            
        actions = ('<<help>>', '<<python-docs>>',
            '<<about-idle>>', '<<open-config-dialog>>', '<<open-module>>',
            '<<cut>>', '<<copy>>', '<<paste>>', '<<select-all>>',
            '<<remove-selection>>', '<<del-word-left>>', '<<del-word-right>>',
            '<<beginning-of-line>>')
        events = ('<<find>>', '<<center-insert>>', '<<find-again>>',
            '<<find-in-files>>', '<<find-selection>>', '<<replace>>',
            '<<goto-line>>', '<<smart-backspace>>', '<<smart-indent>>',
            '<<indent-region>>', '<<dedent-region>>', '<<comment-region>>',
            '<<tabify-region>>', '<<untabify-region>>', '<<toggle-tabs>>',
            '<<change-indentwidth>>')
        parent_actions = ('<<new-tab>>', '<<next-tab>>', '<<prev-tab>>')

        bind_them(actions)
        bind_them(events, prefix="_%s_event")
        for action in parent_actions:
            prefix_size = action.count('<')
            method_name = action[prefix_size:-prefix_size].replace('-', '_')
            text.bind(action, getattr(self.editwin, method_name))

        text.bind('<<close-tab>>', self.close_tab)
        text.bind('<<newline-and-indent>>', self.newline_and_indent_event)
        text.bind("<<do-nothing>>", lambda event: "break")
        text.bind("<Left>", self._move_at_edge_if_selection(0))
        text.bind("<Right>", self._move_at_edge_if_selection(1))
        text.bind("<3>", self._right_menu)
        text.bind('<<set-line-and-column>>', self.editwin.set_line_and_column)
        text.event_add("<<set-line-and-column>>",
                                    "<KeyRelease>", "<ButtonRelease>")

        if self.editwin.flist:
            text.bind("<<open-new-window>>",
                utils.callback(self.editwin.new_callback, self))
            text.bind("<<close-all-windows>>",
                self.editwin.flist.close_all_callback)
            text.bind("<<open-class-browser>>", self._open_class_browser)
            text.bind("<<open-path-browser>>", self._open_path_browser)

        if macosxSupport.runningAsOSXApp():
            # Command-W on editorwindows doesn't work without this.
            text.bind('<<close-window>>', self.editwin.close_event)

    def _help(self, event=None):
        fn = os.path.join(os.path.abspath(os.path.dirname(__file__)),
            'help.txt')
        textView.view_file(self.text, 'Help', fn)

    def _python_docs(self, event=None):
        if sys.platform[:3] == 'win':
            os.startfile(self.editwin.help_url)
        else:
            webbrowser.open(self.editwin.help_url)
        return "break"

    def _about_idle(self, event=None):
        aboutDialog.AboutDialog(self.text, 'About IDLE')

    def _open_class_browser(self, event=None):
        filename = self.io.filename
        if not filename:
            tkMessageBox.showerror("No filename",
                "This buffer has no associated filename",
                master=self.text)
            self.text.focus_set()
            return None
        head, tail = os.path.split(filename)
        base, ext = os.path.splitext(tail)
        ClassBrowser.ClassBrowser(self.editwin.flist, base, [head])

    def _open_path_browser(self, event=None):
        PathBrowser.PathBrowser(self.editwin.flist)

    def _open_config_dialog(self, event=None):
        # When changing colors and saving it, it requires the attribute
        # instance_dict making necessary to pass self.editwin.top as the
        # parent
        configDialog.ConfigDialog(self.editwin.top, 'Settings')

    def _open_module(self, event=None):
        try:
            name = self.text.get("sel.first", "sel.last")
        except TclError:
            name = ""
        else:
            name = name.strip()

        name = tkSimpleDialog.askstring("Module",
            "Enter the name of a Python module\n"
            "to search on sys.path and open:",
            parent=self.text, initialvalue=name)

        if name:
            name = name.strip()
        if not name:
            return
        # XXX Ought to insert current file's directory in front of path
        try:
            (f, file, (suffix, mode, type)) = _find_module(name)
        except (NameError, ImportError), msg:
            tkMessageBox.showerror("Import error", str(msg), parent=self.text)
            return

        if type != imp.PY_SOURCE:
            tkMessageBox.showerror("Unsupported type",
                "%s is not a source module" % name, parent=self.text)
            return
        if f:
            f.close()
        if self.editwin.flist:
            if idleConf.GetOption('main', 'EditorWindow', 'file-in-tab',
               default=1, type='bool'):
                self.editwin.flist.open(file)
        else:
            self.io.loadfile(file)
Ejemplo n.º 17
0
class EditorPage(object):
    rmenu = None
    rmenu_specs = [("Set Breakpoint", "<<set-breakpoint-here>>"),
                   ("Clear Breakpoint", "<<clear-breakpoint-here>>")]

    def __init__(self, parent_frame, editwin, title=None, **kwargs):
        self.editwin = editwin
        self.title = title
        self.tab_initialized = False
        kwargs.setdefault('width',
                          idleConf.GetOption('main', 'EditorPage', 'width'))
        kwargs.setdefault('height',
                          idleConf.GetOption('main', 'EditorPage', 'height'))

        self.text = MultiCallCreator(Text)(parent_frame, **kwargs)
        self.color = None  # initialized in reset_colorizer
        self.per = Percolator(self.text)
        self.undo = self.editwin.UndoDelegator()
        self.per.insertfilter(self.undo)
        self.text.undo_block_start = self.undo.undo_block_start
        self.text.undo_block_stop = self.undo.undo_block_stop
        self.io = IOBinding.IOBinding(self)

        self.undo.set_saved_change_hook(self.saved_change_hook)
        self.io.set_filename_change_hook(self.filename_change_hook)
        self.reset_colorizer()
        self._setup_bindings()

    def post_init(self, filename=None, update_window_title=False):
        if filename:
            if os.path.exists(filename) and not os.path.isdir(filename):
                self.io.loadfile(filename)
            else:
                self.io.set_filename(filename)
        self.saved_change_hook(update_window_title=update_window_title)
        self.tab_initialized = True

    def close_tab(self, event=None):
        """Close current tab, if no more tabs present, close the window."""
        if hasattr(self.editwin, 'interp'):
            # this is a PyShell, don't ask to save
            reply = 'yes'
        else:
            reply = str(self.maybesave())
        if reply != "cancel":
            if self.io.filename:
                self.editwin.update_recent_files_list(
                    new_file=self.io.filename)
            self.close()
            self.editwin.text_notebook.remove_page(self.title)
            self.editwin.top.event_generate('<<tab-closed>>')

        return reply

    def close(self):
        """Perform necessary cleanup for this page before closing it."""
        self.io.close()
        self.io = None

        self.undo = None

        if self.color:
            self.color.close(False)
            self.color = None

        self.per.close()
        self.per = None
        self.text = None

    # XXX (1) mark where these functions are used
    def saved_change_hook(self,
                          update_window_title=False,
                          update_tab_title=True):
        short = self.editwin.short_title()
        long = self.long_title()

        if short and long:
            title = short + " - " + long
            tabtitle = os.path.split(long)[-1]
        elif short:
            title = short
            tabtitle = short
        elif long:
            title = long
            tabtitle = os.path.split(long)[-1]
        else:
            title = tabtitle = "Untitled"
        icon = short or long or title
        if not self.get_saved():
            title = "*%s*" % title
            tabtitle = "*%s*" % tabtitle
            icon = "*%s" % icon

        if update_tab_title:
            self.editwin.text_notebook.update_tabtitle(self, tabtitle)
        if update_window_title or (update_window_title is None
                                   and self.tab_initialized):
            self.editwin.top.wm_title(title)
            self.editwin.top.wm_iconname(icon)

    def get_saved(self):
        return self.undo.get_saved()

    def set_saved(self, flag):
        self.undo.set_saved(flag)

    def filename_change_hook(self):
        if self.editwin.flist:
            self.editwin.flist.filename_changed_edit(self, self.editwin)
        self.saved_change_hook(self.tab_initialized)
        self.editwin.top.update_windowlist_registry(self.editwin)
        self.reset_colorizer()

    def reset_undo(self):
        self.undo.reset_undo()

    def reset_colorizer(self):
        "Update the colour theme"
        # Called from self.filename_change_hook and from configDialog.py
        self.__rmcolorizer()
        self.__addcolorizer()
        theme = idleConf.GetOption('main', 'Theme', 'name')
        normal_colors = idleConf.GetHighlight(theme, 'normal')
        cursor_color = idleConf.GetHighlight(theme, 'cursor', fgBg='fg')
        select_colors = idleConf.GetHighlight(theme, 'hilite')

        self.text.config(foreground=normal_colors['foreground'],
                         background=normal_colors['background'],
                         insertbackground=cursor_color,
                         selectforeground=select_colors['foreground'],
                         selectbackground=select_colors['background'])

    def short_title(self):
        filename = self.io.filename
        if filename:
            filename = os.path.basename(filename)
        # return unicode string to display non-ASCII chars correctly
        return filename_to_unicode(filename)

    def long_title(self):
        # return unicode string to display non-ASCII chars correctly
        return filename_to_unicode(self.io.filename or "")

    def maybesave(self):
        if self.io:
            if not self.get_saved():
                if self.editwin.top.state() != 'normal':
                    self.editiwn.top.deiconify()
                self.editwin.top.lower()
                self.editwin.top.lift()
            return self.io.maybesave()

    # XXX (1) end

    def center(self, mark="insert"):
        # Used by EditorWindow.gotoline
        text = self.text
        top, bot = self._getwindowlines()
        lineno = self._getlineno(mark)
        height = bot - top
        newtop = max(1, lineno - height // 2)
        text.yview(float(newtop))

    def ispythonsource(self, filename):
        if not filename or os.path.isdir(filename):
            return True
        base, ext = os.path.splitext(os.path.basename(filename))
        if os.path.normcase(ext) in (".py", ".pyw"):
            return True
        try:
            f = open(filename)
            line = f.readline()
            f.close()
        except IOError:
            return False
        return line.startswith('#!') and line.find('python') >= 0

    def newline_and_indent_event(self, event):
        # Used by EditorWindow.newline_and_indent_event which is used by PyShell
        text = self.text
        first, last = self.get_selection_indices()
        text.undo_block_start()
        try:
            if first and last:
                text.delete(first, last)
                text.mark_set("insert", first)
            line = text.get("insert linestart", "insert")
            i, n = 0, len(line)
            while i < n and line[i] in " \t":
                i = i + 1
            if i == n:
                # the cursor is in or at leading indentation in a continuation
                # line; just inject an empty line at the start
                text.insert("insert linestart", '\n')
                return "break"
            indent = line[:i]
            # strip whitespace before insert point unless it's in the prompt
            i = 0
            last_line_of_prompt = sys.ps1.split('\n')[-1]
            while line and line[-1] in " \t" and line != last_line_of_prompt:
                line = line[:-1]
                i = i + 1
            if i:
                text.delete("insert - %d chars" % i, "insert")
            # strip whitespace after insert point
            while text.get("insert") in " \t":
                text.delete("insert")
            # start new line
            text.insert("insert", '\n')

            # adjust indentation for continuations and block
            # open/close first need to find the last stmt
            lno = index2line(text.index('insert'))
            #print self.editwin.indentwidth, self.editwin.tabwidth
            y = PyParse.Parser(self.editwin.indentwidth, self.editwin.tabwidth)
            if not self.editwin.context_use_ps1:
                for context in self.editwin.num_context_lines:
                    startat = max(lno - context, 1)
                    startatindex = ` startat ` + ".0"
                    rawtext = text.get(startatindex, "insert")
                    y.set_str(rawtext)
                    bod = y.find_good_parse_start(
                        self.editwin.context_use_ps1,
                        self.build_char_in_string_func(startatindex))
                    if bod is not None or startat == 1:
                        break
                y.set_lo(bod or 0)
            else:
                r = text.tag_prevrange("console", "insert")
                if r:
                    startatindex = r[1]
                else:
                    startatindex = "1.0"
                rawtext = text.get(startatindex, "insert")
                y.set_str(rawtext)
                y.set_lo(0)

            c = y.get_continuation_type()
            if c != PyParse.C_NONE:
                # The current stmt hasn't ended yet.
                if c == PyParse.C_STRING_FIRST_LINE:
                    # after the first line of a string; do not indent at all
                    pass
                elif c == PyParse.C_STRING_NEXT_LINES:
                    # inside a string which started before this line;
                    # just mimic the current indent
                    text.insert("insert", indent)
                elif c == PyParse.C_BRACKET:
                    # line up with the first (if any) element of the
                    # last open bracket structure; else indent one
                    # level beyond the indent of the line with the
                    # last open bracket
                    self.__reindent_to(y.compute_bracket_indent())
                elif c == PyParse.C_BACKSLASH:
                    # if more than one line in this stmt already, just
                    # mimic the current indent; else if initial line
                    # has a start on an assignment stmt, indent to
                    # beyond leftmost =; else to beyond first chunk of
                    # non-whitespace on initial line
                    if y.get_num_lines_in_stmt() > 1:
                        text.insert("insert", indent)
                    else:
                        self.__reindent_to(y.compute_backslash_indent())
                else:
                    assert 0, "bogus continuation type %r" % (c, )
                return "break"

            # This line starts a brand new stmt; indent relative to
            # indentation of initial line of closest preceding
            # interesting stmt.
            indent = y.get_base_indent_string()
            text.insert("insert", indent)
            if y.is_block_opener():
                self._smart_indent_event(event)
            elif indent and y.is_block_closer():
                self._smart_backspace_event(event)
            return "break"
        finally:
            text.see("insert")
            text.undo_block_stop()

    # If a selection is defined in the text widget, return (start,
    # end) as Tkinter text indices, otherwise return (None, None)
    def get_selection_indices(self):
        # Used by EditorWindow.get_selection_indices which is used by
        # FormatParagraph
        try:
            first = self.text.index("sel.first")
            last = self.text.index("sel.last")
            return first, last
        except TclError:
            return None, None

    # Our editpage provides a __is_char_in_string function that works
    # with a Tk text index, but PyParse only knows about offsets into
    # a string. This builds a function for PyParse that accepts an
    # offset.
    def build_char_in_string_func(self, startindex):
        # Used by EditorWindow.build_char_in_string_func which is used by
        # HyperParser
        def inner(offset,
                  _startindex=startindex,
                  _icis=self.__is_char_in_string):
            return _icis(_startindex + "+%dc" % offset)

        return inner

    def _setup_bindings(self):
        text = self.text

        def bind_them(to_bind, prefix='_%s'):
            for tb in to_bind:
                prefix_size = tb.count('<')
                method_name = tb[prefix_size:-prefix_size].replace('-', '_')
                text.bind(tb, getattr(self, prefix % method_name.lower()))

        actions = ('<<help>>', '<<python-docs>>', '<<about-idle>>',
                   '<<open-config-dialog>>', '<<open-module>>', '<<cut>>',
                   '<<copy>>', '<<paste>>', '<<select-all>>',
                   '<<remove-selection>>', '<<del-word-left>>',
                   '<<del-word-right>>', '<<beginning-of-line>>')
        events = ('<<find>>', '<<center-insert>>', '<<find-again>>',
                  '<<find-in-files>>', '<<find-selection>>', '<<replace>>',
                  '<<goto-line>>', '<<smart-backspace>>', '<<smart-indent>>',
                  '<<indent-region>>', '<<dedent-region>>',
                  '<<comment-region>>', '<<tabify-region>>',
                  '<<untabify-region>>', '<<toggle-tabs>>',
                  '<<change-indentwidth>>')
        parent_actions = ('<<new-tab>>', '<<next-tab>>', '<<prev-tab>>')

        bind_them(actions)
        bind_them(events, prefix="_%s_event")
        for action in parent_actions:
            prefix_size = action.count('<')
            method_name = action[prefix_size:-prefix_size].replace('-', '_')
            text.bind(action, getattr(self.editwin, method_name))

        text.bind('<<close-tab>>', self.close_tab)
        text.bind('<<newline-and-indent>>', self.newline_and_indent_event)
        text.bind("<<do-nothing>>", lambda event: "break")
        text.bind("<Left>", self._move_at_edge_if_selection(0))
        text.bind("<Right>", self._move_at_edge_if_selection(1))
        text.bind("<3>", self._right_menu)
        text.bind('<<set-line-and-column>>', self.editwin.set_line_and_column)
        text.event_add("<<set-line-and-column>>", "<KeyRelease>",
                       "<ButtonRelease>")

        if self.editwin.flist:
            text.bind("<<open-new-window>>",
                      utils.callback(self.editwin.new_callback, self))
            text.bind("<<close-all-windows>>",
                      self.editwin.flist.close_all_callback)
            text.bind("<<open-class-browser>>", self._open_class_browser)
            text.bind("<<open-path-browser>>", self._open_path_browser)

        if macosxSupport.runningAsOSXApp():
            # Command-W on editorwindows doesn't work without this.
            text.bind('<<close-window>>', self.editwin.close_event)

    def _help(self, event=None):
        fn = os.path.join(os.path.abspath(os.path.dirname(__file__)),
                          'help.txt')
        textView.view_file(self.text, 'Help', fn)

    def _python_docs(self, event=None):
        if sys.platform[:3] == 'win':
            os.startfile(self.editwin.help_url)
        else:
            webbrowser.open(self.editwin.help_url)
        return "break"

    def _about_idle(self, event=None):
        aboutDialog.AboutDialog(self.text, 'About IDLE')

    def _open_class_browser(self, event=None):
        filename = self.io.filename
        if not filename:
            tkMessageBox.showerror("No filename",
                                   "This buffer has no associated filename",
                                   master=self.text)
            self.text.focus_set()
            return None
        head, tail = os.path.split(filename)
        base, ext = os.path.splitext(tail)
        ClassBrowser.ClassBrowser(self.editwin.flist, base, [head])

    def _open_path_browser(self, event=None):
        PathBrowser.PathBrowser(self.editwin.flist)

    def _open_config_dialog(self, event=None):
        # When changing colors and saving it, it requires the attribute
        # instance_dict making necessary to pass self.editwin.top as the
        # parent
        configDialog.ConfigDialog(self.editwin.top, 'Settings')

    def _open_module(self, event=None):
        try:
            name = self.text.get("sel.first", "sel.last")
        except TclError:
            name = ""
        else:
            name = name.strip()

        name = tkSimpleDialog.askstring("Module",
                                        "Enter the name of a Python module\n"
                                        "to search on sys.path and open:",
                                        parent=self.text,
                                        initialvalue=name)

        if name:
            name = name.strip()
        if not name:
            return
        # XXX Ought to insert current file's directory in front of path
        try:
            (f, file, (suffix, mode, type)) = _find_module(name)
        except (NameError, ImportError), msg:
            tkMessageBox.showerror("Import error", str(msg), parent=self.text)
            return

        if type != imp.PY_SOURCE:
            tkMessageBox.showerror("Unsupported type",
                                   "%s is not a source module" % name,
                                   parent=self.text)
            return
        if f:
            f.close()
        if self.editwin.flist:
            if idleConf.GetOption('main',
                                  'EditorWindow',
                                  'file-in-tab',
                                  default=1,
                                  type='bool'):
                self.editwin.flist.open(file)
        else:
            self.io.loadfile(file)