blob: eb901dc60e16f8d9c00dc7d54fc8c1fe7d49f9f2 [file] [log] [blame]
David Scherer7aced172000-08-15 01:13:23 +00001# changes by dscherer@cmu.edu
2# - IOBinding.open() replaces the current window with the opened file,
3# if the current window is both unmodified and unnamed
4# - IOBinding.loadfile() interprets Windows, UNIX, and Macintosh
5# end-of-line conventions, instead of relying on the standard library,
6# which will only understand the local convention.
7
8import os
Steven M. Gava7981ce52002-06-11 04:45:34 +00009import tempfile
David Scherer7aced172000-08-15 01:13:23 +000010import tkFileDialog
11import tkMessageBox
12import re
Steven M. Gava7981ce52002-06-11 04:45:34 +000013from configHandler import idleConf
David Scherer7aced172000-08-15 01:13:23 +000014
15#$ event <<open-window-from-file>>
16#$ win <Control-o>
17#$ unix <Control-x><Control-f>
18
19#$ event <<save-window>>
20#$ win <Control-s>
21#$ unix <Control-x><Control-s>
22
23#$ event <<save-window-as-file>>
24#$ win <Alt-s>
25#$ unix <Control-x><Control-w>
26
Steven M. Gava7981ce52002-06-11 04:45:34 +000027#$ event <<print-window>>
28#$ win <Control-p>
29#$ unix <Control-x><Control-p>
30
David Scherer7aced172000-08-15 01:13:23 +000031#$ event <<save-copy-of-window-as-file>>
32#$ win <Alt-Shift-s>
33#$ unix <Control-x><w>
34
35
36class IOBinding:
37
38 def __init__(self, editwin):
39 self.editwin = editwin
40 self.text = editwin.text
41 self.__id_open = self.text.bind("<<open-window-from-file>>", self.open)
42 self.__id_save = self.text.bind("<<save-window>>", self.save)
43 self.__id_saveas = self.text.bind("<<save-window-as-file>>",
44 self.save_as)
45 self.__id_savecopy = self.text.bind("<<save-copy-of-window-as-file>>",
46 self.save_a_copy)
Steven M. Gava7981ce52002-06-11 04:45:34 +000047 self.__id_print = self.text.bind("<<print-window>>", self.print_window)
48
David Scherer7aced172000-08-15 01:13:23 +000049 def close(self):
50 # Undo command bindings
51 self.text.unbind("<<open-window-from-file>>", self.__id_open)
52 self.text.unbind("<<save-window>>", self.__id_save)
53 self.text.unbind("<<save-window-as-file>>",self.__id_saveas)
54 self.text.unbind("<<save-copy-of-window-as-file>>", self.__id_savecopy)
Steven M. Gava7981ce52002-06-11 04:45:34 +000055 self.text.unbind("<<print-window>>", self.__id_print)
David Scherer7aced172000-08-15 01:13:23 +000056 # Break cycles
57 self.editwin = None
58 self.text = None
59 self.filename_change_hook = None
60
61 def get_saved(self):
62 return self.editwin.get_saved()
63
64 def set_saved(self, flag):
65 self.editwin.set_saved(flag)
66
67 def reset_undo(self):
68 self.editwin.reset_undo()
69
70 filename_change_hook = None
71
72 def set_filename_change_hook(self, hook):
73 self.filename_change_hook = hook
74
75 filename = None
76
77 def set_filename(self, filename):
78 self.filename = filename
79 self.set_saved(1)
80 if self.filename_change_hook:
81 self.filename_change_hook()
82
Steven M. Gava1d46e402002-03-27 08:40:46 +000083 def open(self, event=None, editFile=None):
David Scherer7aced172000-08-15 01:13:23 +000084 if self.editwin.flist:
Steven M. Gava1d46e402002-03-27 08:40:46 +000085 if not editFile:
86 filename = self.askopenfile()
87 else:
88 filename=editFile
David Scherer7aced172000-08-15 01:13:23 +000089 if filename:
90 # if the current window has no filename and hasn't been
91 # modified, we replace it's contents (no loss). Otherwise
92 # we open a new window.
93 if not self.filename and self.get_saved():
94 self.editwin.flist.open(filename, self.loadfile)
95 else:
96 self.editwin.flist.open(filename)
97 else:
98 self.text.focus_set()
99
100 return "break"
101 # Code for use outside IDLE:
102 if self.get_saved():
103 reply = self.maybesave()
104 if reply == "cancel":
105 self.text.focus_set()
106 return "break"
Steven M. Gava1d46e402002-03-27 08:40:46 +0000107 if not editFile:
108 filename = self.askopenfile()
109 else:
110 filename=editFile
David Scherer7aced172000-08-15 01:13:23 +0000111 if filename:
112 self.loadfile(filename)
113 else:
114 self.text.focus_set()
115 return "break"
116
117 def loadfile(self, filename):
118 try:
119 # open the file in binary mode so that we can handle
120 # end-of-line convention ourselves.
121 f = open(filename,'rb')
122 chars = f.read()
123 f.close()
124 except IOError, msg:
125 tkMessageBox.showerror("I/O Error", str(msg), master=self.text)
126 return 0
127
128 # We now convert all end-of-lines to '\n's
129 eol = r"(\r\n)|\n|\r" # \r\n (Windows), \n (UNIX), or \r (Mac)
130 chars = re.compile( eol ).sub( r"\n", chars )
131
132 self.text.delete("1.0", "end")
133 self.set_filename(None)
134 self.text.insert("1.0", chars)
135 self.reset_undo()
136 self.set_filename(filename)
137 self.text.mark_set("insert", "1.0")
138 self.text.see("insert")
139 return 1
140
141 def maybesave(self):
142 if self.get_saved():
143 return "yes"
144 message = "Do you want to save %s before closing?" % (
145 self.filename or "this untitled document")
146 m = tkMessageBox.Message(
147 title="Save On Close",
148 message=message,
149 icon=tkMessageBox.QUESTION,
150 type=tkMessageBox.YESNOCANCEL,
151 master=self.text)
152 reply = m.show()
153 if reply == "yes":
154 self.save(None)
155 if not self.get_saved():
156 reply = "cancel"
157 self.text.focus_set()
158 return reply
159
160 def save(self, event):
161 if not self.filename:
162 self.save_as(event)
163 else:
164 if self.writefile(self.filename):
165 self.set_saved(1)
166 self.text.focus_set()
167 return "break"
168
169 def save_as(self, event):
170 filename = self.asksavefile()
171 if filename:
172 if self.writefile(filename):
173 self.set_filename(filename)
174 self.set_saved(1)
175 self.text.focus_set()
176 return "break"
177
178 def save_a_copy(self, event):
179 filename = self.asksavefile()
180 if filename:
181 self.writefile(filename)
182 self.text.focus_set()
183 return "break"
184
185 def writefile(self, filename):
186 self.fixlastline()
187 try:
188 f = open(filename, "w")
Steven M. Gavaa2bc2592002-04-22 00:42:42 +0000189 chars = str(self.text.get("1.0", "end-1c"))
David Scherer7aced172000-08-15 01:13:23 +0000190 f.write(chars)
191 f.close()
192 ## print "saved to", `filename`
193 return 1
194 except IOError, msg:
195 tkMessageBox.showerror("I/O Error", str(msg),
196 master=self.text)
197 return 0
Steven M. Gava7981ce52002-06-11 04:45:34 +0000198
199 def print_window(self, event):
200 tempfilename = None
201 if self.get_saved():
202 filename = self.filename
203 else:
204 filename = tempfilename = tempfile.mktemp()
205 if not self.writefile(filename):
206 os.unlink(tempfilename)
207 return "break"
208 platform=os.name
209 printPlatform=1
210 if platform == 'posix': #posix platform
211 command = idleConf.GetOption('main','General','print-command-posix')
212 command = command + " 2>&1"
213 elif platform == 'nt': #win32 platform
214 command = idleConf.GetOption('main','General','print-command-win')
215 else: #no printing for this platform
216 printPlatform=0
217 if printPlatform: #we can try to print for this platform
218 command = command % filename
219 pipe = os.popen(command, "r")
220 output = pipe.read().strip()
221 status = pipe.close()
222 if status:
223 output = "Printing failed (exit status 0x%x)\n" % status + output
224 if output:
225 output = "Printing command: %s\n" % repr(command) + output
226 tkMessageBox.showerror("Print status", output, master=self.text)
227 else: #no printing for this platform
228 message="Printing is not enabled for this platform: %s" % platform
229 tkMessageBox.showinfo("Print status", message, master=self.text)
230 return "break"
231
David Scherer7aced172000-08-15 01:13:23 +0000232 def fixlastline(self):
233 c = self.text.get("end-2c")
234 if c != '\n':
235 self.text.insert("end-1c", "\n")
236
237 opendialog = None
238 savedialog = None
239
240 filetypes = [
241 ("Python and text files", "*.py *.pyw *.txt", "TEXT"),
242 ("All text files", "*", "TEXT"),
243 ("All files", "*"),
244 ]
245
246 def askopenfile(self):
247 dir, base = self.defaultfilename("open")
248 if not self.opendialog:
249 self.opendialog = tkFileDialog.Open(master=self.text,
250 filetypes=self.filetypes)
251 return self.opendialog.show(initialdir=dir, initialfile=base)
252
253 def defaultfilename(self, mode="open"):
254 if self.filename:
255 return os.path.split(self.filename)
256 else:
257 try:
258 pwd = os.getcwd()
259 except os.error:
260 pwd = ""
261 return pwd, ""
262
263 def asksavefile(self):
264 dir, base = self.defaultfilename("save")
265 if not self.savedialog:
266 self.savedialog = tkFileDialog.SaveAs(master=self.text,
267 filetypes=self.filetypes)
268 return self.savedialog.show(initialdir=dir, initialfile=base)
269
270
271def test():
David Scherer7aced172000-08-15 01:13:23 +0000272 root = Tk()
273 class MyEditWin:
274 def __init__(self, text):
275 self.text = text
276 self.flist = None
277 self.text.bind("<Control-o>", self.open)
278 self.text.bind("<Control-s>", self.save)
279 self.text.bind("<Alt-s>", self.save_as)
280 self.text.bind("<Alt-z>", self.save_a_copy)
281 def get_saved(self): return 0
282 def set_saved(self, flag): pass
283 def reset_undo(self): pass
284 def open(self, event):
285 self.text.event_generate("<<open-window-from-file>>")
286 def save(self, event):
287 self.text.event_generate("<<save-window>>")
288 def save_as(self, event):
289 self.text.event_generate("<<save-window-as-file>>")
290 def save_a_copy(self, event):
291 self.text.event_generate("<<save-copy-of-window-as-file>>")
292 text = Text(root)
293 text.pack()
294 text.focus_set()
295 editwin = MyEditWin(text)
296 io = IOBinding(editwin)
297 root.mainloop()
298
299if __name__ == "__main__":
Kurt B. Kaiser7eea2712001-07-13 04:18:32 +0000300 from Tkinter import *
David Scherer7aced172000-08-15 01:13:23 +0000301 test()