Use full package paths in imports.
[python/dscho.git] / Mac / Demo / mlte / mlted.py
blob2ae77e78623bd10894d6f677bb60b89ec4057c5e
1 # A minimal text editor using MLTE. Based on wed.py.
3 # To be done:
4 # - Functionality: find, etc.
6 from Menu import DrawMenuBar
7 from FrameWork import *
8 from Carbon import Win
9 from Carbon import Ctl
10 from Carbon import Qd
11 from Carbon import Res
12 from Carbon import Scrap
13 import os
14 import macfs
15 from Carbon import MacTextEditor
16 from Carbon import Mlte
18 UNDOLABELS = [ # Indexed by MLTECanUndo() value
19 "Typing", "Cut", "Paste", "Clear", "Font Change", "Color Change", "Size Change",
20 "Style Change", "Align Left", "Align Center", "Align Right", "Drop", "Move"]
22 class MlteWindow(Window):
23 def open(self, path, name, data):
24 self.path = path
25 self.name = name
26 r = windowbounds(400, 400)
27 w = Win.NewWindow(r, name, 1, 0, -1, 1, 0)
28 self.wid = w
29 flags = MacTextEditor.kTXNDrawGrowIconMask|MacTextEditor.kTXNWantHScrollBarMask| \
30 MacTextEditor.kTXNWantVScrollBarMask
31 self.ted, self.frameid = Mlte.TXNNewObject(None, w, None, flags, MacTextEditor.kTXNTextEditStyleFrameType,
32 MacTextEditor.kTXNTextFile, MacTextEditor.kTXNMacOSEncoding)
33 self.ted.TXNSetData(MacTextEditor.kTXNTextData, data, 0, 0x7fffffff)
34 self.changed = 0
35 self.do_postopen()
36 self.do_activate(1, None)
38 def do_idle(self, event):
39 self.ted.TXNIdle()
40 self.ted.TXNAdjustCursor(None)
44 def do_activate(self, onoff, evt):
45 if onoff:
46 ## self.ted.TXNActivate(self.frameid, 0)
47 self.ted.TXNFocus(1)
48 self.parent.active = self
49 else:
50 self.ted.TXNFocus(0)
51 self.parent.active = None
52 self.parent.updatemenubar()
54 def do_update(self, wid, event):
55 self.ted.TXNDraw(None)
57 def do_postresize(self, width, height, window):
58 self.ted.TXNResizeFrame(width, height, self.frameid)
60 def do_contentclick(self, local, modifiers, evt):
61 self.ted.TXNClick(evt)
62 self.parent.updatemenubar()
64 def do_char(self, ch, event):
65 self.ted.TXNKeyDown(event)
66 self.parent.updatemenubar()
68 def close(self):
69 if self.changed:
70 save = EasyDialogs.AskYesNoCancel('Save window "%s" before closing?'%self.name, 1)
71 if save > 0:
72 self.menu_save()
73 elif save < 0:
74 return
75 if self.parent.active == self:
76 self.parent.active = None
77 self.ted.TXNDeleteObject()
78 del self.ted
79 ## del self.tedtexthandle
80 self.do_postclose()
82 def menu_save(self):
83 if not self.path:
84 self.menu_save_as()
85 return # Will call us recursively
86 dhandle = self.ted.TXNGetData(0, 0x7fffffff)
87 data = dhandle.data
88 fp = open(self.path, 'wb') # NOTE: wb, because data has CR for end-of-line
89 fp.write(data)
90 if data[-1] <> '\r': fp.write('\r')
91 fp.close()
92 self.changed = 0
94 def menu_save_as(self):
95 fss, ok = macfs.StandardPutFile('Save as:')
96 if not ok: return
97 self.path = fss.as_pathname()
98 self.name = os.path.split(self.path)[-1]
99 self.wid.SetWTitle(self.name)
100 self.menu_save()
102 def menu_cut(self):
103 ## self.ted.WESelView()
104 self.ted.TXNCut()
105 ### Mlte.ConvertToPublicScrap()
106 ## Scrap.ZeroScrap()
107 ## self.ted.WECut()
108 ## self.updatescrollbars()
109 self.parent.updatemenubar()
110 self.changed = 1
112 def menu_copy(self):
113 ## Scrap.ZeroScrap()
114 self.ted.TXNCopy()
115 ### Mlte.ConvertToPublicScrap()
116 ## self.updatescrollbars()
117 self.parent.updatemenubar()
119 def menu_paste(self):
120 ### Mlte.ConvertFromPublicScrap()
121 self.ted.TXNPaste()
122 ## self.updatescrollbars()
123 self.parent.updatemenubar()
124 self.changed = 1
126 def menu_clear(self):
127 ## self.ted.WESelView()
128 self.ted.TXNClear()
129 ## self.updatescrollbars()
130 self.parent.updatemenubar()
131 self.changed = 1
133 def menu_undo(self):
134 self.ted.TXNUndo()
135 ## self.updatescrollbars()
136 self.parent.updatemenubar()
138 def menu_redo(self):
139 self.ted.TXNRedo()
140 ## self.updatescrollbars()
141 self.parent.updatemenubar()
143 def have_selection(self):
144 start, stop = self.ted.TXNGetSelection()
145 return start < stop
147 def can_paste(self):
148 return Mlte.TXNIsScrapPastable()
150 def can_undo(self):
151 can, which = self.ted.TXNCanUndo()
152 if not can:
153 return None
154 if which >= len(UNDOLABELS):
155 # Unspecified undo
156 return "Undo"
157 which = UNDOLABELS[which]
159 return "Undo "+which
161 def can_redo(self):
162 can, which = self.ted.TXNCanRedo()
163 if not can:
164 return None
165 if which >= len(UNDOLABELS):
166 # Unspecified undo
167 return "Redo"
168 which = UNDOLABELS[which]
170 return "Redo "+which
172 class Mlted(Application):
173 def __init__(self):
174 Application.__init__(self)
175 self.num = 0
176 self.active = None
177 self.updatemenubar()
179 def makeusermenus(self):
180 self.filemenu = m = Menu(self.menubar, "File")
181 self.newitem = MenuItem(m, "New window", "N", self.open)
182 self.openitem = MenuItem(m, "Open...", "O", self.openfile)
183 self.closeitem = MenuItem(m, "Close", "W", self.closewin)
184 m.addseparator()
185 self.saveitem = MenuItem(m, "Save", "S", self.save)
186 self.saveasitem = MenuItem(m, "Save as...", "", self.saveas)
187 m.addseparator()
188 self.quititem = MenuItem(m, "Quit", "Q", self.quit)
190 self.editmenu = m = Menu(self.menubar, "Edit")
191 self.undoitem = MenuItem(m, "Undo", "Z", self.undo)
192 self.redoitem = MenuItem(m, "Redo", None, self.redo)
193 m.addseparator()
194 self.cutitem = MenuItem(m, "Cut", "X", self.cut)
195 self.copyitem = MenuItem(m, "Copy", "C", self.copy)
196 self.pasteitem = MenuItem(m, "Paste", "V", self.paste)
197 self.clearitem = MenuItem(m, "Clear", "", self.clear)
199 # Groups of items enabled together:
200 self.windowgroup = [self.closeitem, self.saveitem, self.saveasitem, self.editmenu]
201 self.focusgroup = [self.cutitem, self.copyitem, self.clearitem]
202 self.windowgroup_on = -1
203 self.focusgroup_on = -1
204 self.pastegroup_on = -1
205 self.undo_label = "never"
206 self.redo_label = "never"
208 def updatemenubar(self):
209 changed = 0
210 on = (self.active <> None)
211 if on <> self.windowgroup_on:
212 for m in self.windowgroup:
213 m.enable(on)
214 self.windowgroup_on = on
215 changed = 1
216 if on:
217 # only if we have an edit menu
218 on = self.active.have_selection()
219 if on <> self.focusgroup_on:
220 for m in self.focusgroup:
221 m.enable(on)
222 self.focusgroup_on = on
223 changed = 1
224 on = self.active.can_paste()
225 if on <> self.pastegroup_on:
226 self.pasteitem.enable(on)
227 self.pastegroup_on = on
228 changed = 1
229 on = self.active.can_undo()
230 if on <> self.undo_label:
231 if on:
232 self.undoitem.enable(1)
233 self.undoitem.settext(on)
234 self.undo_label = on
235 else:
236 self.undoitem.settext("Nothing to undo")
237 self.undoitem.enable(0)
238 changed = 1
239 on = self.active.can_redo()
240 if on <> self.redo_label:
241 if on:
242 self.redoitem.enable(1)
243 self.redoitem.settext(on)
244 self.redo_label = on
245 else:
246 self.redoitem.settext("Nothing to redo")
247 self.redoitem.enable(0)
248 changed = 1
249 if changed:
250 DrawMenuBar()
253 # Apple menu
256 def do_about(self, id, item, window, event):
257 EasyDialogs.Message("A simple single-font text editor based on MacTextEditor")
260 # File menu
263 def open(self, *args):
264 self._open(0)
266 def openfile(self, *args):
267 self._open(1)
269 def _open(self, askfile):
270 if askfile:
271 fss, ok = macfs.StandardGetFile('TEXT')
272 if not ok:
273 return
274 path = fss.as_pathname()
275 name = os.path.split(path)[-1]
276 try:
277 fp = open(path, 'rb') # NOTE binary, we need cr as end-of-line
278 data = fp.read()
279 fp.close()
280 except IOError, arg:
281 EasyDialogs.Message("IOERROR: "+`arg`)
282 return
283 else:
284 path = None
285 name = "Untitled %d"%self.num
286 data = ''
287 w = MlteWindow(self)
288 w.open(path, name, data)
289 self.num = self.num + 1
291 def closewin(self, *args):
292 if self.active:
293 self.active.close()
294 else:
295 EasyDialogs.Message("No active window?")
297 def save(self, *args):
298 if self.active:
299 self.active.menu_save()
300 else:
301 EasyDialogs.Message("No active window?")
303 def saveas(self, *args):
304 if self.active:
305 self.active.menu_save_as()
306 else:
307 EasyDialogs.Message("No active window?")
310 def quit(self, *args):
311 for w in self._windows.values():
312 w.close()
313 if self._windows:
314 return
315 self._quit()
318 # Edit menu
321 def undo(self, *args):
322 if self.active:
323 self.active.menu_undo()
324 else:
325 EasyDialogs.Message("No active window?")
327 def redo(self, *args):
328 if self.active:
329 self.active.menu_redo()
330 else:
331 EasyDialogs.Message("No active window?")
333 def cut(self, *args):
334 if self.active:
335 self.active.menu_cut()
336 else:
337 EasyDialogs.Message("No active window?")
339 def copy(self, *args):
340 if self.active:
341 self.active.menu_copy()
342 else:
343 EasyDialogs.Message("No active window?")
345 def paste(self, *args):
346 if self.active:
347 self.active.menu_paste()
348 else:
349 EasyDialogs.Message("No active window?")
351 def clear(self, *args):
352 if self.active:
353 self.active.menu_clear()
354 else:
355 EasyDialogs.Message("No active window?")
358 # Other stuff
361 def idle(self, event):
362 if self.active:
363 self.active.do_idle(event)
364 else:
365 Qd.SetCursor(Qd.qd.arrow)
367 def main():
368 Mlte.TXNInitTextension(0)
369 try:
370 App = Mlted()
371 App.mainloop()
372 finally:
373 Mlte.TXNTerminateTextension()
375 if __name__ == '__main__':
376 main()