blob: 5a1599515a43b99a6f2976d9bb18e50d39dbd5dc [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001import os
Kurt B. Kaiser01166da2002-09-16 22:03:37 +00002import types
3import sys
4import codecs
Steven M. Gava7981ce52002-06-11 04:45:34 +00005import tempfile
David Scherer7aced172000-08-15 01:13:23 +00006import tkFileDialog
7import tkMessageBox
8import re
Kurt B. Kaisera053f332003-05-10 00:49:56 +00009from Tkinter import *
Kurt B. Kaiser3a4e24b2007-08-22 18:06:14 +000010from SimpleDialog import SimpleDialog
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000011
Kurt B. Kaiser3a4e24b2007-08-22 18:06:14 +000012from idlelib.configHandler import idleConf
David Scherer7aced172000-08-15 01:13:23 +000013
Kurt B. Kaiser1963ad32007-09-01 19:47:39 +000014from codecs import BOM_UTF8
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000015
16# Try setting the locale, so that we can find out
17# what encoding to use
18try:
19 import locale
20 locale.setlocale(locale.LC_CTYPE, "")
Kurt B. Kaiser188e25f2003-11-25 05:01:00 +000021except (ImportError, locale.Error):
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000022 pass
23
Martin v. Löwis307021f2005-11-27 16:59:04 +000024# Encoding for file names
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +000025filesystemencoding = sys.getfilesystemencoding() ### currently unused
Martin v. Löwis307021f2005-11-27 16:59:04 +000026
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +000027locale_encoding = 'ascii'
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000028if sys.platform == 'win32':
29 # On Windows, we could use "mbcs". However, to give the user
30 # a portable encoding name, we need to find the code page
31 try:
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +000032 locale_encoding = locale.getdefaultlocale()[1]
33 codecs.lookup(locale_encoding)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000034 except LookupError:
35 pass
36else:
37 try:
38 # Different things can fail here: the locale module may not be
39 # loaded, it may not offer nl_langinfo, or CODESET, or the
40 # resulting codeset may be unknown to Python. We ignore all
41 # these problems, falling back to ASCII
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +000042 locale_encoding = locale.nl_langinfo(locale.CODESET)
43 if locale_encoding is None or locale_encoding is '':
Tony Lowndse555fc72002-09-23 01:01:20 +000044 # situation occurs on Mac OS X
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +000045 locale_encoding = 'ascii'
46 codecs.lookup(locale_encoding)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000047 except (NameError, AttributeError, LookupError):
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +000048 # Try getdefaultlocale: it parses environment variables,
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000049 # which may give a clue. Unfortunately, getdefaultlocale has
50 # bugs that can cause ValueError.
51 try:
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +000052 locale_encoding = locale.getdefaultlocale()[1]
53 if locale_encoding is None or locale_encoding is '':
Tony Lowndse555fc72002-09-23 01:01:20 +000054 # situation occurs on Mac OS X
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +000055 locale_encoding = 'ascii'
56 codecs.lookup(locale_encoding)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000057 except (ValueError, LookupError):
58 pass
59
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +000060locale_encoding = locale_encoding.lower()
61
62encoding = locale_encoding ### KBK 07Sep07 This is used all over IDLE, check!
63 ### 'encoding' is used below in encode(), check!
Kurt B. Kaiser01166da2002-09-16 22:03:37 +000064
65coding_re = re.compile("coding[:=]\s*([-\w_.]+)")
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +000066
Kurt B. Kaisera053f332003-05-10 00:49:56 +000067class EncodingMessage(SimpleDialog):
68 "Inform user that an encoding declaration is needed."
69 def __init__(self, master, enc):
70 self.should_edit = False
Kurt B. Kaiser47674012003-05-18 02:24:32 +000071
Kurt B. Kaisera053f332003-05-10 00:49:56 +000072 self.root = top = Toplevel(master)
73 top.bind("<Return>", self.return_event)
74 top.bind("<Escape>", self.do_ok)
75 top.protocol("WM_DELETE_WINDOW", self.wm_delete_window)
76 top.wm_title("I/O Warning")
77 top.wm_iconname("I/O Warning")
78 self.top = top
79
80 l1 = Label(top,
81 text="Non-ASCII found, yet no encoding declared. Add a line like")
82 l1.pack(side=TOP, anchor=W)
83 l2 = Entry(top, font="courier")
84 l2.insert(0, "# -*- coding: %s -*-" % enc)
85 # For some reason, the text is not selectable anymore if the
86 # widget is disabled.
87 # l2['state'] = DISABLED
88 l2.pack(side=TOP, anchor = W, fill=X)
89 l3 = Label(top, text="to your file\n"
90 "Choose OK to save this file as %s\n"
91 "Edit your general options to silence this warning" % enc)
92 l3.pack(side=TOP, anchor = W)
93
94 buttons = Frame(top)
95 buttons.pack(side=TOP, fill=X)
96 # Both return and cancel mean the same thing: do nothing
97 self.default = self.cancel = 0
98 b1 = Button(buttons, text="Ok", default="active",
99 command=self.do_ok)
100 b1.pack(side=LEFT, fill=BOTH, expand=1)
101 b2 = Button(buttons, text="Edit my file",
102 command=self.do_edit)
103 b2.pack(side=LEFT, fill=BOTH, expand=1)
Kurt B. Kaiser47674012003-05-18 02:24:32 +0000104
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000105 self._set_transient(master)
106
107 def do_ok(self):
108 self.done(0)
109
110 def do_edit(self):
111 self.done(1)
112
Kurt B. Kaiser1963ad32007-09-01 19:47:39 +0000113def coding_spec(data):
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000114 """Return the encoding declaration according to PEP 263.
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000115
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000116 When checking encoded data, only the first two lines should be passed
117 in to avoid a UnicodeDecodeError if the rest of the data is not unicode.
118 The first two lines would contain the encoding specification.
119
120 Raise a LookupError if the encoding is declared but unknown.
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000121 """
Kurt B. Kaiser1963ad32007-09-01 19:47:39 +0000122 if isinstance(data, bytes):
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000123 try:
124 lines = data.decode('utf-8')
125 except UnicodeDecodeError:
126 return None
Kurt B. Kaiser1963ad32007-09-01 19:47:39 +0000127 else:
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000128 lines = data
129 # consider only the first two lines
130 if '\n' in lines:
131 lst = lines.split('\n')[:2]
132 elif '\r' in lines:
133 lst = lines.split('\r')[:2]
134 else:
135 lst = list(lines)
136 str = '\n'.join(lst)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000137 match = coding_re.search(str)
138 if not match:
139 return None
140 name = match.group(1)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000141 try:
142 codecs.lookup(name)
143 except LookupError:
144 # The standard encoding error does not indicate the encoding
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000145 raise LookupError("Unknown encoding: "+name)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000146 return name
David Scherer7aced172000-08-15 01:13:23 +0000147
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000148
David Scherer7aced172000-08-15 01:13:23 +0000149class IOBinding:
150
151 def __init__(self, editwin):
152 self.editwin = editwin
153 self.text = editwin.text
154 self.__id_open = self.text.bind("<<open-window-from-file>>", self.open)
155 self.__id_save = self.text.bind("<<save-window>>", self.save)
156 self.__id_saveas = self.text.bind("<<save-window-as-file>>",
157 self.save_as)
158 self.__id_savecopy = self.text.bind("<<save-copy-of-window-as-file>>",
159 self.save_a_copy)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000160 self.fileencoding = None
Steven M. Gava7981ce52002-06-11 04:45:34 +0000161 self.__id_print = self.text.bind("<<print-window>>", self.print_window)
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000162
David Scherer7aced172000-08-15 01:13:23 +0000163 def close(self):
164 # Undo command bindings
165 self.text.unbind("<<open-window-from-file>>", self.__id_open)
166 self.text.unbind("<<save-window>>", self.__id_save)
167 self.text.unbind("<<save-window-as-file>>",self.__id_saveas)
168 self.text.unbind("<<save-copy-of-window-as-file>>", self.__id_savecopy)
Steven M. Gava7981ce52002-06-11 04:45:34 +0000169 self.text.unbind("<<print-window>>", self.__id_print)
David Scherer7aced172000-08-15 01:13:23 +0000170 # Break cycles
171 self.editwin = None
172 self.text = None
173 self.filename_change_hook = None
174
175 def get_saved(self):
176 return self.editwin.get_saved()
177
178 def set_saved(self, flag):
179 self.editwin.set_saved(flag)
180
181 def reset_undo(self):
182 self.editwin.reset_undo()
183
184 filename_change_hook = None
185
186 def set_filename_change_hook(self, hook):
187 self.filename_change_hook = hook
188
189 filename = None
Kurt B. Kaiserd2f48612003-06-05 02:34:04 +0000190 dirname = None
David Scherer7aced172000-08-15 01:13:23 +0000191
192 def set_filename(self, filename):
Kurt B. Kaiserd2f48612003-06-05 02:34:04 +0000193 if filename and os.path.isdir(filename):
194 self.filename = None
195 self.dirname = filename
196 else:
197 self.filename = filename
198 self.dirname = None
199 self.set_saved(1)
200 if self.filename_change_hook:
201 self.filename_change_hook()
David Scherer7aced172000-08-15 01:13:23 +0000202
Steven M. Gava1d46e402002-03-27 08:40:46 +0000203 def open(self, event=None, editFile=None):
David Scherer7aced172000-08-15 01:13:23 +0000204 if self.editwin.flist:
Steven M. Gava1d46e402002-03-27 08:40:46 +0000205 if not editFile:
206 filename = self.askopenfile()
207 else:
208 filename=editFile
David Scherer7aced172000-08-15 01:13:23 +0000209 if filename:
Kurt B. Kaiser1bf4c2d2002-07-21 01:24:28 +0000210 # If the current window has no filename and hasn't been
211 # modified, we replace its contents (no loss). Otherwise
212 # we open a new window. But we won't replace the
213 # shell window (which has an interp(reter) attribute), which
214 # gets set to "not modified" at every new prompt.
215 try:
216 interp = self.editwin.interp
Thomas Wouterscf297e42007-02-23 15:07:44 +0000217 except AttributeError:
Kurt B. Kaiser1bf4c2d2002-07-21 01:24:28 +0000218 interp = None
219 if not self.filename and self.get_saved() and not interp:
David Scherer7aced172000-08-15 01:13:23 +0000220 self.editwin.flist.open(filename, self.loadfile)
221 else:
222 self.editwin.flist.open(filename)
223 else:
224 self.text.focus_set()
David Scherer7aced172000-08-15 01:13:23 +0000225 return "break"
Kurt B. Kaiser1bf4c2d2002-07-21 01:24:28 +0000226 #
David Scherer7aced172000-08-15 01:13:23 +0000227 # Code for use outside IDLE:
228 if self.get_saved():
229 reply = self.maybesave()
230 if reply == "cancel":
231 self.text.focus_set()
232 return "break"
Steven M. Gava1d46e402002-03-27 08:40:46 +0000233 if not editFile:
234 filename = self.askopenfile()
235 else:
236 filename=editFile
David Scherer7aced172000-08-15 01:13:23 +0000237 if filename:
238 self.loadfile(filename)
239 else:
240 self.text.focus_set()
241 return "break"
242
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000243 eol = r"(\r\n)|\n|\r" # \r\n (Windows), \n (UNIX), or \r (Mac)
244 eol_re = re.compile(eol)
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000245
David Scherer7aced172000-08-15 01:13:23 +0000246 def loadfile(self, filename):
247 try:
248 # open the file in binary mode so that we can handle
Kurt B. Kaiser3a4e24b2007-08-22 18:06:14 +0000249 # end-of-line convention ourselves.
David Scherer7aced172000-08-15 01:13:23 +0000250 f = open(filename,'rb')
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000251 two_lines = f.readline() + f.readline()
252 f.seek(0)
Kurt B. Kaiser1963ad32007-09-01 19:47:39 +0000253 bytes = f.read()
David Scherer7aced172000-08-15 01:13:23 +0000254 f.close()
Guido van Rossumb940e112007-01-10 16:19:56 +0000255 except IOError as msg:
David Scherer7aced172000-08-15 01:13:23 +0000256 tkMessageBox.showerror("I/O Error", str(msg), master=self.text)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000257 return False
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000258 chars = self._decode(two_lines, bytes)
259 if chars is None:
260 tkMessageBox.showerror("Decoding Error",
261 "File %s\nFailed to Decode" % filename,
262 parent=self.text)
263 return False
David Scherer7aced172000-08-15 01:13:23 +0000264 # We now convert all end-of-lines to '\n's
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000265 firsteol = self.eol_re.search(chars)
266 if firsteol:
267 self.eol_convention = firsteol.group(0)
268 chars = self.eol_re.sub(r"\n", chars)
David Scherer7aced172000-08-15 01:13:23 +0000269 self.text.delete("1.0", "end")
270 self.set_filename(None)
271 self.text.insert("1.0", chars)
272 self.reset_undo()
273 self.set_filename(filename)
274 self.text.mark_set("insert", "1.0")
275 self.text.see("insert")
Chui Tey993e81a2002-11-04 03:11:10 +0000276 self.updaterecentfileslist(filename)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000277 return True
278
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000279 def _decode(self, two_lines, bytes):
280 "Create a Unicode string."
281 chars = None
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000282 # Check presence of a UTF-8 signature first
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000283 if bytes.startswith(BOM_UTF8):
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000284 try:
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000285 chars = bytes[3:].decode("utf-8")
286 except UnicodeDecodeError:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000287 # has UTF-8 signature, but fails to decode...
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000288 return None
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000289 else:
290 # Indicates that this file originally had a BOM
Kurt B. Kaiser1963ad32007-09-01 19:47:39 +0000291 self.fileencoding = 'BOM'
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000292 return chars
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000293 # Next look for coding specification
294 try:
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000295 enc = coding_spec(two_lines)
Guido van Rossumb940e112007-01-10 16:19:56 +0000296 except LookupError as name:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000297 tkMessageBox.showerror(
298 title="Error loading the file",
299 message="The encoding '%s' is not known to this Python "\
300 "installation. The file may not display correctly" % name,
301 master = self.text)
302 enc = None
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000303 except UnicodeDecodeError:
304 return None
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000305 if enc:
306 try:
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000307 chars = str(bytes, enc)
308 self.fileencoding = enc
309 return chars
310 except UnicodeDecodeError:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000311 pass
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000312 # Try ascii:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000313 try:
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000314 chars = str(bytes, 'ascii')
315 self.fileencoding = None
316 return chars
317 except UnicodeDecodeError:
318 pass
319 # Try utf-8:
320 try:
321 chars = str(bytes, 'utf-8')
322 self.fileencoding = 'utf-8'
323 return chars
324 except UnicodeDecodeError:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000325 pass
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000326 # Finally, try the locale's encoding. This is deprecated;
327 # the user should declare a non-ASCII encoding
328 try:
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000329 chars = str(bytes, locale_encoding)
330 self.fileencoding = locale_encoding
331 except UnicodeDecodeError:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000332 pass
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000333 return chars # None on failure
David Scherer7aced172000-08-15 01:13:23 +0000334
335 def maybesave(self):
336 if self.get_saved():
337 return "yes"
338 message = "Do you want to save %s before closing?" % (
339 self.filename or "this untitled document")
340 m = tkMessageBox.Message(
341 title="Save On Close",
342 message=message,
343 icon=tkMessageBox.QUESTION,
344 type=tkMessageBox.YESNOCANCEL,
345 master=self.text)
346 reply = m.show()
347 if reply == "yes":
348 self.save(None)
349 if not self.get_saved():
350 reply = "cancel"
351 self.text.focus_set()
352 return reply
353
354 def save(self, event):
355 if not self.filename:
356 self.save_as(event)
357 else:
358 if self.writefile(self.filename):
359 self.set_saved(1)
Kurt B. Kaiserddeaf112003-03-04 04:42:04 +0000360 try:
361 self.editwin.store_file_breaks()
362 except AttributeError: # may be a PyShell
363 pass
David Scherer7aced172000-08-15 01:13:23 +0000364 self.text.focus_set()
365 return "break"
366
367 def save_as(self, event):
368 filename = self.asksavefile()
369 if filename:
370 if self.writefile(filename):
371 self.set_filename(filename)
372 self.set_saved(1)
Kurt B. Kaiserddeaf112003-03-04 04:42:04 +0000373 try:
374 self.editwin.store_file_breaks()
375 except AttributeError:
376 pass
David Scherer7aced172000-08-15 01:13:23 +0000377 self.text.focus_set()
Chui Tey993e81a2002-11-04 03:11:10 +0000378 self.updaterecentfileslist(filename)
David Scherer7aced172000-08-15 01:13:23 +0000379 return "break"
380
381 def save_a_copy(self, event):
382 filename = self.asksavefile()
383 if filename:
384 self.writefile(filename)
385 self.text.focus_set()
Chui Tey993e81a2002-11-04 03:11:10 +0000386 self.updaterecentfileslist(filename)
David Scherer7aced172000-08-15 01:13:23 +0000387 return "break"
388
389 def writefile(self, filename):
390 self.fixlastline()
Kurt B. Kaiser3e623ba2007-10-09 23:12:31 +0000391 text = self.text.get("1.0", "end-1c")
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000392 if self.eol_convention != "\n":
Kurt B. Kaiser3e623ba2007-10-09 23:12:31 +0000393 text = text.replace("\n", self.eol_convention)
394 chars = self.encode(self.text.get("1.0", "end-1c"))
David Scherer7aced172000-08-15 01:13:23 +0000395 try:
Guido van Rossumc2f77dd2003-04-25 18:36:31 +0000396 f = open(filename, "wb")
David Scherer7aced172000-08-15 01:13:23 +0000397 f.write(chars)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000398 f.flush()
David Scherer7aced172000-08-15 01:13:23 +0000399 f.close()
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000400 return True
Guido van Rossumb940e112007-01-10 16:19:56 +0000401 except IOError as msg:
David Scherer7aced172000-08-15 01:13:23 +0000402 tkMessageBox.showerror("I/O Error", str(msg),
403 master=self.text)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000404 return False
405
406 def encode(self, chars):
Martin v. Löwis4d9ed9f2007-08-13 13:30:04 +0000407 if isinstance(chars, bytes):
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000408 # This is either plain ASCII, or Tk was returning mixed-encoding
409 # text to us. Don't try to guess further.
410 return chars
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000411 # See whether there is anything non-ASCII in it.
412 # If not, no need to figure out the encoding.
413 try:
414 return chars.encode('ascii')
415 except UnicodeError:
416 pass
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000417 # Check if there is an encoding declared
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000418 try:
Kurt B. Kaiser44fa8f62007-09-07 05:06:21 +0000419 # a string, let coding_spec slice it to the first two lines
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000420 enc = coding_spec(chars)
421 failed = None
Guido van Rossumb940e112007-01-10 16:19:56 +0000422 except LookupError as msg:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000423 failed = msg
424 enc = None
425 if enc:
426 try:
427 return chars.encode(enc)
428 except UnicodeError:
429 failed = "Invalid encoding '%s'" % enc
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000430 if failed:
431 tkMessageBox.showerror(
432 "I/O Error",
Kurt B. Kaiser1963ad32007-09-01 19:47:39 +0000433 "%s.\nSaving as UTF-8" % failed,
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000434 master = self.text)
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000435 # If there was a UTF-8 signature, use that. This should not fail
Kurt B. Kaiser1963ad32007-09-01 19:47:39 +0000436 if self.fileencoding == 'BOM' or failed:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000437 return BOM_UTF8 + chars.encode("utf-8")
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000438 # Try the original file encoding next, if any
439 if self.fileencoding:
440 try:
441 return chars.encode(self.fileencoding)
442 except UnicodeError:
443 tkMessageBox.showerror(
444 "I/O Error",
445 "Cannot save this as '%s' anymore. Saving as UTF-8" \
446 % self.fileencoding,
447 master = self.text)
448 return BOM_UTF8 + chars.encode("utf-8")
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000449 # Nothing was declared, and we had not determined an encoding
450 # on loading. Recommend an encoding line.
Kurt B. Kaiser47674012003-05-18 02:24:32 +0000451 config_encoding = idleConf.GetOption("main","EditorWindow",
452 "encoding")
453 if config_encoding == 'utf-8':
454 # User has requested that we save files as UTF-8
455 return BOM_UTF8 + chars.encode("utf-8")
456 ask_user = True
457 try:
458 chars = chars.encode(encoding)
459 enc = encoding
460 if config_encoding == 'locale':
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000461 ask_user = False
Kurt B. Kaiser47674012003-05-18 02:24:32 +0000462 except UnicodeError:
463 chars = BOM_UTF8 + chars.encode("utf-8")
464 enc = "utf-8"
465 if not ask_user:
Kurt B. Kaisera053f332003-05-10 00:49:56 +0000466 return chars
Kurt B. Kaiser47674012003-05-18 02:24:32 +0000467 dialog = EncodingMessage(self.editwin.top, enc)
468 dialog.go()
469 if dialog.num == 1:
470 # User asked us to edit the file
471 encline = "# -*- coding: %s -*-\n" % enc
472 firstline = self.text.get("1.0", "2.0")
473 if firstline.startswith("#!"):
474 # Insert encoding after #! line
475 self.text.insert("2.0", encline)
476 else:
477 self.text.insert("1.0", encline)
478 return self.encode(self.text.get("1.0", "end-1c"))
479 return chars
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000480
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000481 def fixlastline(self):
482 c = self.text.get("end-2c")
483 if c != '\n':
484 self.text.insert("end-1c", "\n")
485
Steven M. Gava7981ce52002-06-11 04:45:34 +0000486 def print_window(self, event):
487 tempfilename = None
Kurt B. Kaiser9067c8d2003-06-09 03:12:42 +0000488 saved = self.get_saved()
489 if saved:
Steven M. Gava7981ce52002-06-11 04:45:34 +0000490 filename = self.filename
Kurt B. Kaiser9067c8d2003-06-09 03:12:42 +0000491 # shell undo is reset after every prompt, looks saved, probably isn't
492 if not saved or filename is None:
493 # XXX KBK 08Jun03 Wouldn't it be better to ask the user to save?
Kurt B. Kaiser61e2c9a2003-06-14 17:56:25 +0000494 (tfd, tempfilename) = tempfile.mkstemp(prefix='IDLE_tmp_')
495 filename = tempfilename
496 os.close(tfd)
497 if not self.writefile(tempfilename):
Steven M. Gava7981ce52002-06-11 04:45:34 +0000498 os.unlink(tempfilename)
499 return "break"
500 platform=os.name
501 printPlatform=1
502 if platform == 'posix': #posix platform
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000503 command = idleConf.GetOption('main','General',
504 'print-command-posix')
Steven M. Gava7981ce52002-06-11 04:45:34 +0000505 command = command + " 2>&1"
506 elif platform == 'nt': #win32 platform
507 command = idleConf.GetOption('main','General','print-command-win')
508 else: #no printing for this platform
509 printPlatform=0
510 if printPlatform: #we can try to print for this platform
511 command = command % filename
512 pipe = os.popen(command, "r")
Kurt B. Kaiser9067c8d2003-06-09 03:12:42 +0000513 # things can get ugly on NT if there is no printer available.
Steven M. Gava7981ce52002-06-11 04:45:34 +0000514 output = pipe.read().strip()
515 status = pipe.close()
516 if status:
Kurt B. Kaiser01166da2002-09-16 22:03:37 +0000517 output = "Printing failed (exit status 0x%x)\n" % \
518 status + output
Steven M. Gava7981ce52002-06-11 04:45:34 +0000519 if output:
520 output = "Printing command: %s\n" % repr(command) + output
521 tkMessageBox.showerror("Print status", output, master=self.text)
522 else: #no printing for this platform
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000523 message="Printing is not enabled for this platform: %s" % platform
Steven M. Gava7981ce52002-06-11 04:45:34 +0000524 tkMessageBox.showinfo("Print status", message, master=self.text)
Kurt B. Kaiser61e2c9a2003-06-14 17:56:25 +0000525 if tempfilename:
526 os.unlink(tempfilename)
Steven M. Gava7981ce52002-06-11 04:45:34 +0000527 return "break"
Kurt B. Kaiser6655e4b2002-12-31 16:03:23 +0000528
David Scherer7aced172000-08-15 01:13:23 +0000529 opendialog = None
530 savedialog = None
531
532 filetypes = [
533 ("Python and text files", "*.py *.pyw *.txt", "TEXT"),
534 ("All text files", "*", "TEXT"),
535 ("All files", "*"),
536 ]
537
538 def askopenfile(self):
539 dir, base = self.defaultfilename("open")
540 if not self.opendialog:
541 self.opendialog = tkFileDialog.Open(master=self.text,
542 filetypes=self.filetypes)
Martin v. Löwis307021f2005-11-27 16:59:04 +0000543 filename = self.opendialog.show(initialdir=dir, initialfile=base)
Martin v. Löwis307021f2005-11-27 16:59:04 +0000544 return filename
David Scherer7aced172000-08-15 01:13:23 +0000545
546 def defaultfilename(self, mode="open"):
547 if self.filename:
548 return os.path.split(self.filename)
Kurt B. Kaiserd2f48612003-06-05 02:34:04 +0000549 elif self.dirname:
550 return self.dirname, ""
David Scherer7aced172000-08-15 01:13:23 +0000551 else:
552 try:
553 pwd = os.getcwd()
554 except os.error:
555 pwd = ""
556 return pwd, ""
557
558 def asksavefile(self):
559 dir, base = self.defaultfilename("save")
560 if not self.savedialog:
561 self.savedialog = tkFileDialog.SaveAs(master=self.text,
562 filetypes=self.filetypes)
Martin v. Löwis307021f2005-11-27 16:59:04 +0000563 filename = self.savedialog.show(initialdir=dir, initialfile=base)
Martin v. Löwis307021f2005-11-27 16:59:04 +0000564 return filename
David Scherer7aced172000-08-15 01:13:23 +0000565
Chui Tey993e81a2002-11-04 03:11:10 +0000566 def updaterecentfileslist(self,filename):
Kurt B. Kaiserbfed3462002-12-14 04:38:51 +0000567 "Update recent file list on all editor windows"
Kurt B. Kaiser3a4e24b2007-08-22 18:06:14 +0000568 if self.editwin.flist:
569 self.editwin.update_recent_files_list(filename)
Chui Tey993e81a2002-11-04 03:11:10 +0000570
David Scherer7aced172000-08-15 01:13:23 +0000571def test():
David Scherer7aced172000-08-15 01:13:23 +0000572 root = Tk()
573 class MyEditWin:
574 def __init__(self, text):
575 self.text = text
576 self.flist = None
577 self.text.bind("<Control-o>", self.open)
578 self.text.bind("<Control-s>", self.save)
579 self.text.bind("<Alt-s>", self.save_as)
580 self.text.bind("<Alt-z>", self.save_a_copy)
581 def get_saved(self): return 0
582 def set_saved(self, flag): pass
583 def reset_undo(self): pass
584 def open(self, event):
585 self.text.event_generate("<<open-window-from-file>>")
586 def save(self, event):
587 self.text.event_generate("<<save-window>>")
588 def save_as(self, event):
589 self.text.event_generate("<<save-window-as-file>>")
590 def save_a_copy(self, event):
591 self.text.event_generate("<<save-copy-of-window-as-file>>")
592 text = Text(root)
593 text.pack()
594 text.focus_set()
595 editwin = MyEditWin(text)
596 io = IOBinding(editwin)
597 root.mainloop()
598
599if __name__ == "__main__":
David Scherer7aced172000-08-15 01:13:23 +0000600 test()