1ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# changes by dscherer@cmu.edu
2ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#   - IOBinding.open() replaces the current window with the opened file,
3ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#     if the current window is both unmodified and unnamed
4ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#   - IOBinding.loadfile() interprets Windows, UNIX, and Macintosh
5ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#     end-of-line conventions, instead of relying on the standard library,
6ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh#     which will only understand the local convention.
7ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
8ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport os
9ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport types
10ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport pipes
11ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport sys
12ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport codecs
13ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport tempfile
14ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport tkFileDialog
15ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport tkMessageBox
16ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehimport re
17ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom Tkinter import *
18ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom SimpleDialog import SimpleDialog
19ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
20ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfrom idlelib.configHandler import idleConf
21ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
22ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehtry:
23ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    from codecs import BOM_UTF8
24ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehexcept ImportError:
25ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # only available since Python 2.3
26ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    BOM_UTF8 = '\xef\xbb\xbf'
27ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
28ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Try setting the locale, so that we can find out
29ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# what encoding to use
30ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehtry:
31ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    import locale
32ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    locale.setlocale(locale.LC_CTYPE, "")
33ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehexcept (ImportError, locale.Error):
34ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    pass
35ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
36ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh# Encoding for file names
37ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehfilesystemencoding = sys.getfilesystemencoding()
38ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
39ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehencoding = "ascii"
40ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehif sys.platform == 'win32':
41ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # On Windows, we could use "mbcs". However, to give the user
42ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # a portable encoding name, we need to find the code page
43ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    try:
44ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        encoding = locale.getdefaultlocale()[1]
45ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        codecs.lookup(encoding)
46ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    except LookupError:
47ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        pass
48ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehelse:
49ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    try:
50ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Different things can fail here: the locale module may not be
51ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # loaded, it may not offer nl_langinfo, or CODESET, or the
52ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # resulting codeset may be unknown to Python. We ignore all
53ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # these problems, falling back to ASCII
54ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        encoding = locale.nl_langinfo(locale.CODESET)
55ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if encoding is None or encoding is '':
56ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # situation occurs on Mac OS X
57ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            encoding = 'ascii'
58ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        codecs.lookup(encoding)
59ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    except (NameError, AttributeError, LookupError):
60ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try getdefaultlocale well: it parses environment variables,
61ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # which may give a clue. Unfortunately, getdefaultlocale has
62ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # bugs that can cause ValueError.
63ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
64ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            encoding = locale.getdefaultlocale()[1]
65ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if encoding is None or encoding is '':
66ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # situation occurs on Mac OS X
67ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                encoding = 'ascii'
68ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            codecs.lookup(encoding)
69ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except (ValueError, LookupError):
70ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            pass
71ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
72ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehencoding = encoding.lower()
73ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
74ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehcoding_re = re.compile("coding[:=]\s*([-\w_.]+)")
75ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
76ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass EncodingMessage(SimpleDialog):
77ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    "Inform user that an encoding declaration is needed."
78ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __init__(self, master, enc):
79ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.should_edit = False
80ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
81ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.root = top = Toplevel(master)
82ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        top.bind("<Return>", self.return_event)
83ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        top.bind("<Escape>", self.do_ok)
84ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        top.protocol("WM_DELETE_WINDOW", self.wm_delete_window)
85ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        top.wm_title("I/O Warning")
86ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        top.wm_iconname("I/O Warning")
87ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.top = top
88ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
89ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        l1 = Label(top,
90ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            text="Non-ASCII found, yet no encoding declared. Add a line like")
91ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        l1.pack(side=TOP, anchor=W)
92ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        l2 = Entry(top, font="courier")
93ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        l2.insert(0, "# -*- coding: %s -*-" % enc)
94ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # For some reason, the text is not selectable anymore if the
95ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # widget is disabled.
96ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # l2['state'] = DISABLED
97ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        l2.pack(side=TOP, anchor = W, fill=X)
98ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        l3 = Label(top, text="to your file\n"
99ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                   "Choose OK to save this file as %s\n"
100ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                   "Edit your general options to silence this warning" % enc)
101ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        l3.pack(side=TOP, anchor = W)
102ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
103ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        buttons = Frame(top)
104ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        buttons.pack(side=TOP, fill=X)
105ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Both return and cancel mean the same thing: do nothing
106ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.default = self.cancel = 0
107ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b1 = Button(buttons, text="Ok", default="active",
108ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    command=self.do_ok)
109ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b1.pack(side=LEFT, fill=BOTH, expand=1)
110ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b2 = Button(buttons, text="Edit my file",
111ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    command=self.do_edit)
112ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        b2.pack(side=LEFT, fill=BOTH, expand=1)
113ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
114ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self._set_transient(master)
115ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
116ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def do_ok(self):
117ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.done(0)
118ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
119ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def do_edit(self):
120ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.done(1)
121ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
122ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef coding_spec(str):
123ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """Return the encoding declaration according to PEP 263.
124ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
125ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    Raise LookupError if the encoding is declared but unknown.
126ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    """
127ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Only consider the first two lines
128ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    str = str.split("\n")[:2]
129ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    str = "\n".join(str)
130ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
131ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    match = coding_re.search(str)
132ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    if not match:
133ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return None
134ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    name = match.group(1)
135ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    # Check whether the encoding is known
136ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    import codecs
137ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    try:
138ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        codecs.lookup(name)
139ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    except LookupError:
140ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # The standard encoding error does not indicate the encoding
141ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        raise LookupError, "Unknown encoding "+name
142ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    return name
143ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
144ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
145ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehclass IOBinding:
146ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
147ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def __init__(self, editwin):
148ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.editwin = editwin
149ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text = editwin.text
150ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.__id_open = self.text.bind("<<open-window-from-file>>", self.open)
151ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.__id_save = self.text.bind("<<save-window>>", self.save)
152ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.__id_saveas = self.text.bind("<<save-window-as-file>>",
153ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                          self.save_as)
154ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.__id_savecopy = self.text.bind("<<save-copy-of-window-as-file>>",
155ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                            self.save_a_copy)
156ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.fileencoding = None
157ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.__id_print = self.text.bind("<<print-window>>", self.print_window)
158ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
159ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def close(self):
160ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Undo command bindings
161ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.unbind("<<open-window-from-file>>", self.__id_open)
162ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.unbind("<<save-window>>", self.__id_save)
163ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.unbind("<<save-window-as-file>>",self.__id_saveas)
164ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.unbind("<<save-copy-of-window-as-file>>", self.__id_savecopy)
165ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.unbind("<<print-window>>", self.__id_print)
166ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Break cycles
167ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.editwin = None
168ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text = None
169ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.filename_change_hook = None
170ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
171ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def get_saved(self):
172ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return self.editwin.get_saved()
173ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
174ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def set_saved(self, flag):
175ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.editwin.set_saved(flag)
176ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
177ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def reset_undo(self):
178ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.editwin.reset_undo()
179ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
180ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    filename_change_hook = None
181ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
182ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def set_filename_change_hook(self, hook):
183ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.filename_change_hook = hook
184ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
185ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    filename = None
186ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    dirname = None
187ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
188ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def set_filename(self, filename):
189ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if filename and os.path.isdir(filename):
190ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.filename = None
191ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.dirname = filename
192ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
193ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.filename = filename
194ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.dirname = None
195ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.set_saved(1)
196ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if self.filename_change_hook:
197ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.filename_change_hook()
198ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
199ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def open(self, event=None, editFile=None):
200ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        flist = self.editwin.flist
201ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Save in case parent window is closed (ie, during askopenfile()).
202ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if flist:
203ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if not editFile:
204ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                filename = self.askopenfile()
205ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
206ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                filename=editFile
207ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if filename:
208ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # If editFile is valid and already open, flist.open will
209ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # shift focus to its existing window.
210ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # If the current window exists and is a fresh unnamed,
211ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # unmodified editor window (not an interpreter shell),
212ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # pass self.loadfile to flist.open so it will load the file
213ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # in the current window (if the file is not already open)
214ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # instead of a new window.
215ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if (self.editwin and
216ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        not getattr(self.editwin, 'interp', None) and
217ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        not self.filename and
218ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                        self.get_saved()):
219ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    flist.open(filename, self.loadfile)
220ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                else:
221ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    flist.open(filename)
222ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
223ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                if self.text:
224ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.text.focus_set()
225ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return "break"
226ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
227ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Code for use outside IDLE:
228ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.get_saved():
229ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            reply = self.maybesave()
230ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if reply == "cancel":
231ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.text.focus_set()
232ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return "break"
233ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not editFile:
234ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            filename = self.askopenfile()
235ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
236ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            filename=editFile
237ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if filename:
238ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.loadfile(filename)
239ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
240ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.focus_set()
241ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
242ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
243ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    eol = r"(\r\n)|\n|\r"  # \r\n (Windows), \n (UNIX), or \r (Mac)
244ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    eol_re = re.compile(eol)
245ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    eol_convention = os.linesep # Default
246ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
247ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def loadfile(self, filename):
248ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
249ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # open the file in binary mode so that we can handle
250ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            #   end-of-line convention ourselves.
251ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            f = open(filename,'rb')
252ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            chars = f.read()
253ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            f.close()
254ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except IOError, msg:
255ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            tkMessageBox.showerror("I/O Error", str(msg), master=self.text)
256ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return False
257ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
258ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        chars = self.decode(chars)
259ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # We now convert all end-of-lines to '\n's
260ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        firsteol = self.eol_re.search(chars)
261ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if firsteol:
262ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.eol_convention = firsteol.group(0)
263ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if isinstance(self.eol_convention, unicode):
264ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # Make sure it is an ASCII string
265ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.eol_convention = self.eol_convention.encode("ascii")
266ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            chars = self.eol_re.sub(r"\n", chars)
267ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
268ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.delete("1.0", "end")
269ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.set_filename(None)
270ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.insert("1.0", chars)
271ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.reset_undo()
272ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.set_filename(filename)
273ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.mark_set("insert", "1.0")
274ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.yview("insert")
275ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.updaterecentfileslist(filename)
276ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return True
277ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
278ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def decode(self, chars):
279ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """Create a Unicode string
280ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
281ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        If that fails, let Tcl try its best
282ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        """
283ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Check presence of a UTF-8 signature first
284ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if chars.startswith(BOM_UTF8):
285ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
286ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                chars = chars[3:].decode("utf-8")
287ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except UnicodeError:
288ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # has UTF-8 signature, but fails to decode...
289ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return chars
290ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
291ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # Indicates that this file originally had a BOM
292ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.fileencoding = BOM_UTF8
293ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return chars
294ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Next look for coding specification
295ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
296ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            enc = coding_spec(chars)
297ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except LookupError, name:
298ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            tkMessageBox.showerror(
299ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                title="Error loading the file",
300ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                message="The encoding '%s' is not known to this Python "\
301ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                "installation. The file may not display correctly" % name,
302ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                master = self.text)
303ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            enc = None
304ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if enc:
305ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
306ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return unicode(chars, enc)
307ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except UnicodeError:
308ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                pass
309ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # If it is ASCII, we need not to record anything
310ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
311ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return unicode(chars, 'ascii')
312ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except UnicodeError:
313ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            pass
314ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Finally, try the locale's encoding. This is deprecated;
315ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # the user should declare a non-ASCII encoding
316ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
317ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            chars = unicode(chars, encoding)
318ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.fileencoding = encoding
319ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except UnicodeError:
320ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            pass
321ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return chars
322ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
323ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def maybesave(self):
324ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.get_saved():
325ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return "yes"
326ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        message = "Do you want to save %s before closing?" % (
327ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.filename or "this untitled document")
328ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        confirm = tkMessageBox.askyesnocancel(
329ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  title="Save On Close",
330ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  message=message,
331ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  default=tkMessageBox.YES,
332ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  master=self.text)
333ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if confirm:
334ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            reply = "yes"
335ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.save(None)
336ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if not self.get_saved():
337ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                reply = "cancel"
338ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        elif confirm is None:
339ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            reply = "cancel"
340ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
341ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            reply = "no"
342ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.focus_set()
343ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return reply
344ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
345ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def save(self, event):
346ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.filename:
347ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.save_as(event)
348ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
349ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if self.writefile(self.filename):
350ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.set_saved(True)
351ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                try:
352ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.editwin.store_file_breaks()
353ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                except AttributeError:  # may be a PyShell
354ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    pass
355ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.focus_set()
356ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
357ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
358ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def save_as(self, event):
359ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        filename = self.asksavefile()
360ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if filename:
361ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if self.writefile(filename):
362ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.set_filename(filename)
363ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.set_saved(1)
364ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                try:
365ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    self.editwin.store_file_breaks()
366ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                except AttributeError:
367ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    pass
368ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.focus_set()
369ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.updaterecentfileslist(filename)
370ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
371ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
372ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def save_a_copy(self, event):
373ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        filename = self.asksavefile()
374ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if filename:
375ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.writefile(filename)
376ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.text.focus_set()
377ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.updaterecentfileslist(filename)
378ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
379ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
380ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def writefile(self, filename):
381ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.fixlastline()
382ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        chars = self.encode(self.text.get("1.0", "end-1c"))
383ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.eol_convention != "\n":
384ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            chars = chars.replace("\n", self.eol_convention)
385ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
386ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            f = open(filename, "wb")
387ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            f.write(chars)
388ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            f.flush()
389ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            f.close()
390ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return True
391ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except IOError, msg:
392ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            tkMessageBox.showerror("I/O Error", str(msg),
393ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                   master=self.text)
394ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return False
395ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
396ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def encode(self, chars):
397ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if isinstance(chars, types.StringType):
398ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # This is either plain ASCII, or Tk was returning mixed-encoding
399ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # text to us. Don't try to guess further.
400ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return chars
401ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # See whether there is anything non-ASCII in it.
402ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # If not, no need to figure out the encoding.
403ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
404ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return chars.encode('ascii')
405ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except UnicodeError:
406ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            pass
407ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # If there is an encoding declared, try this first.
408ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
409ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            enc = coding_spec(chars)
410ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            failed = None
411ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except LookupError, msg:
412ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            failed = msg
413ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            enc = None
414ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if enc:
415ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
416ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return chars.encode(enc)
417ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except UnicodeError:
418ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                failed = "Invalid encoding '%s'" % enc
419ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if failed:
420ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            tkMessageBox.showerror(
421ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                "I/O Error",
422ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                "%s. Saving as UTF-8" % failed,
423ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                master = self.text)
424ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # If there was a UTF-8 signature, use that. This should not fail
425ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.fileencoding == BOM_UTF8 or failed:
426ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return BOM_UTF8 + chars.encode("utf-8")
427ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Try the original file encoding next, if any
428ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.fileencoding:
429ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
430ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return chars.encode(self.fileencoding)
431ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except UnicodeError:
432ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                tkMessageBox.showerror(
433ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    "I/O Error",
434ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    "Cannot save this as '%s' anymore. Saving as UTF-8" \
435ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    % self.fileencoding,
436ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                    master = self.text)
437ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return BOM_UTF8 + chars.encode("utf-8")
438ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # Nothing was declared, and we had not determined an encoding
439ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # on loading. Recommend an encoding line.
440ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        config_encoding = idleConf.GetOption("main","EditorWindow",
441ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                             "encoding")
442ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if config_encoding == 'utf-8':
443ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # User has requested that we save files as UTF-8
444ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return BOM_UTF8 + chars.encode("utf-8")
445ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ask_user = True
446ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        try:
447ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            chars = chars.encode(encoding)
448ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            enc = encoding
449ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if config_encoding == 'locale':
450ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                ask_user = False
451ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        except UnicodeError:
452ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            chars = BOM_UTF8 + chars.encode("utf-8")
453ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            enc = "utf-8"
454ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not ask_user:
455ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return chars
456ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dialog = EncodingMessage(self.editwin.top, enc)
457ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dialog.go()
458ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if dialog.num == 1:
459ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # User asked us to edit the file
460ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            encline = "# -*- coding: %s -*-\n" % enc
461ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            firstline = self.text.get("1.0", "2.0")
462ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if firstline.startswith("#!"):
463ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                # Insert encoding after #! line
464ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.text.insert("2.0", encline)
465ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            else:
466ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                self.text.insert("1.0", encline)
467ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return self.encode(self.text.get("1.0", "end-1c"))
468ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return chars
469ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
470ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def fixlastline(self):
471ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        c = self.text.get("end-2c")
472ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if c != '\n':
473ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.insert("end-1c", "\n")
474ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
475ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def print_window(self, event):
476ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        confirm = tkMessageBox.askokcancel(
477ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  title="Print",
478ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  message="Print to Default Printer",
479ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  default=tkMessageBox.OK,
480ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                  master=self.text)
481ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not confirm:
482ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.focus_set()
483ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return "break"
484ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        tempfilename = None
485ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        saved = self.get_saved()
486ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if saved:
487ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            filename = self.filename
488ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        # shell undo is reset after every prompt, looks saved, probably isn't
489ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not saved or filename is None:
490ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            (tfd, tempfilename) = tempfile.mkstemp(prefix='IDLE_tmp_')
491ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            filename = tempfilename
492ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            os.close(tfd)
493ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if not self.writefile(tempfilename):
494ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                os.unlink(tempfilename)
495ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                return "break"
496ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        platform = os.name
497ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        printPlatform = True
498ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if platform == 'posix': #posix platform
499ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            command = idleConf.GetOption('main','General',
500ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                         'print-command-posix')
501ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            command = command + " 2>&1"
502ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        elif platform == 'nt': #win32 platform
503ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            command = idleConf.GetOption('main','General','print-command-win')
504ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else: #no printing for this platform
505ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            printPlatform = False
506ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if printPlatform:  #we can try to print for this platform
507ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            command = command % pipes.quote(filename)
508ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            pipe = os.popen(command, "r")
509ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            # things can get ugly on NT if there is no printer available.
510ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            output = pipe.read().strip()
511ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            status = pipe.close()
512ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if status:
513ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                output = "Printing failed (exit status 0x%x)\n" % \
514ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                         status + output
515ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            if output:
516ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                output = "Printing command: %s\n" % repr(command) + output
517ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                tkMessageBox.showerror("Print status", output, master=self.text)
518ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:  #no printing for this platform
519ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            message = "Printing is not enabled for this platform: %s" % platform
520ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            tkMessageBox.showinfo("Print status", message, master=self.text)
521ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if tempfilename:
522ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            os.unlink(tempfilename)
523ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return "break"
524ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
525ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    opendialog = None
526ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    savedialog = None
527ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
528ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    filetypes = [
529ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ("Python files", "*.py *.pyw", "TEXT"),
530ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ("Text files", "*.txt", "TEXT"),
531ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ("All files", "*"),
532ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        ]
533ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
534ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def askopenfile(self):
535ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dir, base = self.defaultfilename("open")
536ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.opendialog:
537ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.opendialog = tkFileDialog.Open(master=self.text,
538ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                                filetypes=self.filetypes)
539ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        filename = self.opendialog.show(initialdir=dir, initialfile=base)
540ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if isinstance(filename, unicode):
541ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            filename = filename.encode(filesystemencoding)
542ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return filename
543ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
544ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def defaultfilename(self, mode="open"):
545ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if self.filename:
546ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return os.path.split(self.filename)
547ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        elif self.dirname:
548ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return self.dirname, ""
549ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        else:
550ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            try:
551ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                pwd = os.getcwd()
552ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            except os.error:
553ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                pwd = ""
554ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            return pwd, ""
555ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
556ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def asksavefile(self):
557ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        dir, base = self.defaultfilename("save")
558ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if not self.savedialog:
559ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.savedialog = tkFileDialog.SaveAs(master=self.text,
560ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh                                                  filetypes=self.filetypes)
561ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        filename = self.savedialog.show(initialdir=dir, initialfile=base)
562ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        if isinstance(filename, unicode):
563ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            filename = filename.encode(filesystemencoding)
564ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        return filename
565ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
566ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    def updaterecentfileslist(self,filename):
567ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        "Update recent file list on all editor windows"
568ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        self.editwin.update_recent_files_list(filename)
569ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
570ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehdef test():
571ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    root = Tk()
572ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    class MyEditWin:
573ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        def __init__(self, text):
574ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text = text
575ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.flist = None
576ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.bind("<Control-o>", self.open)
577ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.bind("<Control-s>", self.save)
578ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.bind("<Alt-s>", self.save_as)
579ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.bind("<Alt-z>", self.save_a_copy)
580ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        def get_saved(self): return 0
581ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        def set_saved(self, flag): pass
582ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        def reset_undo(self): pass
583ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        def open(self, event):
584ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.event_generate("<<open-window-from-file>>")
585ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        def save(self, event):
586ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.event_generate("<<save-window>>")
587ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        def save_as(self, event):
588ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.event_generate("<<save-window-as-file>>")
589ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh        def save_a_copy(self, event):
590ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh            self.text.event_generate("<<save-copy-of-window-as-file>>")
591ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    text = Text(root)
592ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    text.pack()
593ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    text.focus_set()
594ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    editwin = MyEditWin(text)
595ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    io = IOBinding(editwin)
596ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    root.mainloop()
597ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh
598ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsiehif __name__ == "__main__":
599ffab958fd8d42ed7227d83007350e61555a1fa36Andrew Hsieh    test()
600