blob: b590b1dd617cedc9e62a122758c315dae3ae165b [file] [log] [blame]
Jack Jansen1df16d01996-05-07 15:25:36 +00001# A minimal text editor.
2#
3# To be done:
4# - Functionality: find, etc.
5
Jack Jansen5a6fdcd2001-08-25 12:15:04 +00006from Carbon.Menu import DrawMenuBar
Jack Jansen1df16d01996-05-07 15:25:36 +00007from FrameWork import *
Jack Jansen5a6fdcd2001-08-25 12:15:04 +00008from Carbon import Win
9from Carbon import Qd
10from Carbon import Res
11from Carbon import Fm
Jack Jansen1df16d01996-05-07 15:25:36 +000012import waste
13import WASTEconst
Jack Jansen5a6fdcd2001-08-25 12:15:04 +000014from Carbon import Scrap
Jack Jansen1df16d01996-05-07 15:25:36 +000015import os
16import macfs
Jack Jansen01a2d9e2001-01-29 15:32:00 +000017import MACFS
Jack Jansen1df16d01996-05-07 15:25:36 +000018import string
19import htmllib
20
21WATCH = Qd.GetCursor(4).data
22
23LEFTMARGIN=0
24
25UNDOLABELS = [ # Indexed by WEGetUndoInfo() value
26 None, "", "typing", "Cut", "Paste", "Clear", "Drag", "Style"]
27
28# Style and size menu. Note that style order is important (tied to bit values)
29STYLES = [
30 ("Bold", "B"), ("Italic", "I"), ("Underline", "U"), ("Outline", "O"),
31 ("Shadow", ""), ("Condensed", ""), ("Extended", "")
32 ]
33SIZES = [ 9, 10, 12, 14, 18, 24]
34
35# Sizes for HTML tag types
36HTML_SIZE={
37 'h1': 18,
38 'h2': 14
39}
40
41BIGREGION=Qd.NewRgn()
42Qd.SetRectRgn(BIGREGION, -16000, -16000, 16000, 16000)
43
44class WasteWindow(ScrolledWindow):
45 def open(self, path, name, data):
46 self.path = path
47 self.name = name
48 r = windowbounds(400, 400)
Jack Jansencbed91b2001-08-03 13:31:36 +000049 w = Win.NewWindow(r, name, 1, 0, -1, 1, 0)
Jack Jansen1df16d01996-05-07 15:25:36 +000050 self.wid = w
51 vr = LEFTMARGIN, 0, r[2]-r[0]-15, r[3]-r[1]-15
52 dr = (0, 0, vr[2], 0)
53 Qd.SetPort(w)
54 Qd.TextFont(4)
55 Qd.TextSize(9)
56 flags = WASTEconst.weDoAutoScroll | WASTEconst.weDoOutlineHilite | \
57 WASTEconst.weDoMonoStyled | WASTEconst.weDoUndo
58 self.ted = waste.WENew(dr, vr, flags)
Jack Jansen70e413d1996-10-23 15:40:48 +000059 self.ted.WEInstallTabHooks()
Jack Jansen1df16d01996-05-07 15:25:36 +000060 style, soup = self.getstylesoup(self.path)
61 self.ted.WEInsert(data, style, soup)
62 self.ted.WESetSelection(0,0)
63 self.ted.WECalText()
64 self.ted.WEResetModCount()
65 w.DrawGrowIcon()
66 self.scrollbars()
67 self.do_postopen()
68 self.do_activate(1, None)
69
70 def getstylesoup(self, pathname):
71 if not pathname:
72 return None, None
73 oldrf = Res.CurResFile()
74 try:
Jack Jansen8eff33b2000-06-20 22:01:04 +000075 rf = Res.FSpOpenResFile(self.path, 1)
Jack Jansen1df16d01996-05-07 15:25:36 +000076 except Res.Error:
77 return None, None
78 try:
79 hstyle = Res.Get1Resource('styl', 128)
80 hstyle.DetachResource()
81 except Res.Error:
82 hstyle = None
83 try:
84 hsoup = Res.Get1Resource('SOUP', 128)
85 hsoup.DetachResource()
86 except Res.Error:
87 hsoup = None
88 Res.CloseResFile(rf)
89 Res.UseResFile(oldrf)
90 return hstyle, hsoup
91
92 def do_idle(self, event):
93 (what, message, when, where, modifiers) = event
94 Qd.SetPort(self.wid)
95 self.ted.WEIdle()
96 if self.ted.WEAdjustCursor(where, BIGREGION):
97 return
98 Qd.SetCursor(Qd.qd.arrow)
99
100 def getscrollbarvalues(self):
101 dr = self.ted.WEGetDestRect()
102 vr = self.ted.WEGetViewRect()
103 vx = self.scalebarvalue(dr[0], dr[2], vr[0], vr[2])
104 vy = self.scalebarvalue(dr[1], dr[3], vr[1], vr[3])
105 return vx, vy
106
107 def scrollbar_callback(self, which, what, value):
108 if which == 'y':
109 #
110 # "line" size is minimum of top and bottom line size
111 #
112 topline_off,dummy = self.ted.WEGetOffset((1,1))
113 topline_num = self.ted.WEOffsetToLine(topline_off)
114 toplineheight = self.ted.WEGetHeight(topline_num, topline_num+1)
115
116 botlinepos = self.ted.WEGetViewRect()[3]
117 botline_off, dummy = self.ted.WEGetOffset((1, botlinepos-1))
118 botline_num = self.ted.WEOffsetToLine(botline_off)
119 botlineheight = self.ted.WEGetHeight(botline_num, botline_num+1)
120
121 if botlineheight == 0:
122 botlineheight = self.ted.WEGetHeight(botline_num-1, botline_num)
123 if botlineheight < toplineheight:
124 lineheight = botlineheight
125 else:
126 lineheight = toplineheight
127 if lineheight <= 0:
128 lineheight = 1
129 #
130 # Now do the command.
131 #
132 if what == 'set':
133 height = self.ted.WEGetHeight(0, 0x3fffffff)
134 cur = self.getscrollbarvalues()[1]
135 delta = (cur-value)*height/32767
136 if what == '-':
137 delta = lineheight
138 elif what == '--':
139 delta = (self.ted.WEGetViewRect()[3]-lineheight)
140 if delta <= 0:
141 delta = lineheight
142 elif what == '+':
143 delta = -lineheight
144 elif what == '++':
145 delta = -(self.ted.WEGetViewRect()[3]-lineheight)
146 if delta >= 0:
147 delta = -lineheight
148 self.ted.WEScroll(0, delta)
149 else:
150 if what == 'set':
151 return # XXXX
152 vr = self.ted.WEGetViewRect()
153 winwidth = vr[2]-vr[0]
154 if what == '-':
155 delta = winwidth/10
156 elif what == '--':
157 delta = winwidth/2
158 elif what == '+':
159 delta = -winwidth/10
160 elif what == '++':
161 delta = -winwidth/2
162 self.ted.WEScroll(delta, 0)
163 # Pin the scroll
164 l, t, r, b = self.ted.WEGetDestRect()
165 vl, vt, vr, vb = self.ted.WEGetViewRect()
166 if t > 0 or l > 0:
167 dx = dy = 0
168 if t > 0: dy = -t
169 if l > 0: dx = -l
170 self.ted.WEScroll(dx, dy)
171 elif b < vb:
172 self.ted.WEScroll(0, vb-b)
173
174
175 def do_activate(self, onoff, evt):
176 Qd.SetPort(self.wid)
177 ScrolledWindow.do_activate(self, onoff, evt)
178 if onoff:
179 self.ted.WEActivate()
180 self.parent.active = self
181 self.parent.updatemenubar()
182 else:
183 self.ted.WEDeactivate()
184
185 def do_update(self, wid, event):
186 region = wid.GetWindowPort().visRgn
187 if Qd.EmptyRgn(region):
188 return
189 Qd.EraseRgn(region)
190 self.ted.WEUpdate(region)
191 self.updatescrollbars()
192
193 def do_postresize(self, width, height, window):
194 l, t, r, b = self.ted.WEGetViewRect()
195 vr = (l, t, l+width-15, t+height-15)
196 self.ted.WESetViewRect(vr)
Jack Jansen73023402001-01-23 14:58:20 +0000197 self.wid.InvalWindowRect(vr)
Jack Jansen1df16d01996-05-07 15:25:36 +0000198 ScrolledWindow.do_postresize(self, width, height, window)
199
200 def do_contentclick(self, local, modifiers, evt):
201 (what, message, when, where, modifiers) = evt
202 self.ted.WEClick(local, modifiers, when)
203 self.updatescrollbars()
204 self.parent.updatemenubar()
205
206 def do_char(self, ch, event):
207 self.ted.WESelView()
208 (what, message, when, where, modifiers) = event
209 self.ted.WEKey(ord(ch), modifiers)
210 self.updatescrollbars()
211 self.parent.updatemenubar()
212
213 def close(self):
214 if self.ted.WEGetModCount():
215 save = EasyDialogs.AskYesNoCancel('Save window "%s" before closing?'%self.name, 1)
216 if save > 0:
217 self.menu_save()
218 elif save < 0:
219 return
220 if self.parent.active == self:
221 self.parent.active = None
222 self.parent.updatemenubar()
223 del self.ted
224 self.do_postclose()
225
226 def menu_save(self):
227 if not self.path:
228 self.menu_save_as()
229 return # Will call us recursively
230 #
231 # First save data
232 #
233 dhandle = self.ted.WEGetText()
234 data = dhandle.data
235 fp = open(self.path, 'wb') # NOTE: wb, because data has CR for end-of-line
236 fp.write(data)
237 if data[-1] <> '\r': fp.write('\r')
238 fp.close()
239 #
240 # Now save style and soup
241 #
242 oldresfile = Res.CurResFile()
243 try:
Jack Jansen8eff33b2000-06-20 22:01:04 +0000244 rf = Res.FSpOpenResFile(self.path, 3)
Jack Jansen1df16d01996-05-07 15:25:36 +0000245 except Res.Error:
Jack Jansen01a2d9e2001-01-29 15:32:00 +0000246 Res.FSpCreateResFile(self.path, '????', 'TEXT', MACFS.smAllScripts)
Jack Jansen8eff33b2000-06-20 22:01:04 +0000247 rf = Res.FSpOpenResFile(self.path, 3)
Jack Jansen1df16d01996-05-07 15:25:36 +0000248 styles = Res.Resource('')
249 soup = Res.Resource('')
250 self.ted.WECopyRange(0, 0x3fffffff, None, styles, soup)
251 styles.AddResource('styl', 128, '')
252 soup.AddResource('SOUP', 128, '')
253 Res.CloseResFile(rf)
254 Res.UseResFile(oldresfile)
255
256 self.ted.WEResetModCount()
257
258 def menu_save_as(self):
259 fss, ok = macfs.StandardPutFile('Save as:')
260 if not ok: return
261 self.path = fss.as_pathname()
262 self.name = os.path.split(self.path)[-1]
263 self.wid.SetWTitle(self.name)
264 self.menu_save()
265
266 def menu_insert(self, fp):
267 self.ted.WESelView()
268 data = fp.read()
269 self.ted.WEInsert(data, None, None)
270 self.updatescrollbars()
271 self.parent.updatemenubar()
272
273 def menu_insert_html(self, fp):
274 import htmllib
275 import formatter
276 f = formatter.AbstractFormatter(self)
277
278 # Remember where we are, and don't update
279 Qd.SetCursor(WATCH)
280 start, dummy = self.ted.WEGetSelection()
281 self.ted.WEFeatureFlag(WASTEconst.weFInhibitRecal, 1)
282
283 self.html_init()
284 p = MyHTMLParser(f)
285 p.feed(fp.read())
286
287 # Restore updating, recalc, set focus
288 dummy, end = self.ted.WEGetSelection()
289 self.ted.WECalText()
290 self.ted.WESetSelection(start, end)
291 self.ted.WESelView()
292 self.ted.WEFeatureFlag(WASTEconst.weFInhibitRecal, 0)
Jack Jansen73023402001-01-23 14:58:20 +0000293 self.wid.InvalWindowRect(self.ted.WEGetViewRect())
Jack Jansen1df16d01996-05-07 15:25:36 +0000294
295 self.updatescrollbars()
296 self.parent.updatemenubar()
297
298 def menu_cut(self):
299 self.ted.WESelView()
Jack Jansen9cf00dd2001-12-31 15:02:56 +0000300 if hasattr(Scrap, 'ZeroScrap'):
301 Scrap.ZeroScrap()
302 else:
303 Scrap.ClearCurrentScrap()
Jack Jansen1df16d01996-05-07 15:25:36 +0000304 self.ted.WECut()
305 self.updatescrollbars()
306 self.parent.updatemenubar()
307
308 def menu_copy(self):
Jack Jansen9cf00dd2001-12-31 15:02:56 +0000309 if hasattr(Scrap, 'ZeroScrap'):
310 Scrap.ZeroScrap()
311 else:
312 Scrap.ClearCurrentScrap()
Jack Jansen1df16d01996-05-07 15:25:36 +0000313 self.ted.WECopy()
314 self.updatescrollbars()
315 self.parent.updatemenubar()
316
317 def menu_paste(self):
318 self.ted.WESelView()
319 self.ted.WEPaste()
320 self.updatescrollbars()
321 self.parent.updatemenubar()
322
323 def menu_clear(self):
324 self.ted.WESelView()
325 self.ted.WEDelete()
326 self.updatescrollbars()
327 self.parent.updatemenubar()
328
329 def menu_undo(self):
330 self.ted.WEUndo()
331 self.updatescrollbars()
332 self.parent.updatemenubar()
333
334 def menu_setfont(self, font):
335 font = Fm.GetFNum(font)
336 self.mysetstyle(WASTEconst.weDoFont, (font, 0, 0, (0,0,0)))
337 self.parent.updatemenubar()
338
339 def menu_modface(self, face):
340 self.mysetstyle(WASTEconst.weDoFace|WASTEconst.weDoToggleFace,
341 (0, face, 0, (0,0,0)))
342
343 def menu_setface(self, face):
344 self.mysetstyle(WASTEconst.weDoFace|WASTEconst.weDoReplaceFace,
345 (0, face, 0, (0,0,0)))
346
347 def menu_setsize(self, size):
348 self.mysetstyle(WASTEconst.weDoSize, (0, 0, size, (0,0,0)))
349
350 def menu_incsize(self, size):
351 self.mysetstyle(WASTEconst.weDoAddSize, (0, 0, size, (0,0,0)))
352
353 def mysetstyle(self, which, how):
354 self.ted.WESelView()
355 self.ted.WESetStyle(which, how)
356 self.parent.updatemenubar()
357
358 def have_selection(self):
359 start, stop = self.ted.WEGetSelection()
360 return start < stop
361
362 def can_paste(self):
363 return self.ted.WECanPaste()
364
365 def can_undo(self):
366 which, redo = self.ted.WEGetUndoInfo()
367 which = UNDOLABELS[which]
368 if which == None: return None
369 if redo:
370 return "Redo "+which
371 else:
372 return "Undo "+which
373
374 def getruninfo(self):
375 all = (WASTEconst.weDoFont | WASTEconst.weDoFace | WASTEconst.weDoSize)
376 dummy, mode, (font, face, size, color) = self.ted.WEContinuousStyle(all)
377 if not (mode & WASTEconst.weDoFont):
378 font = None
379 else:
380 font = Fm.GetFontName(font)
381 if not (mode & WASTEconst.weDoFace): fact = None
382 if not (mode & WASTEconst.weDoSize): size = None
383 return font, face, size
384
385 #
386 # Methods for writer class for html formatter
387 #
388
389 def html_init(self):
390 self.html_font = [12, 0, 0, 0]
391 self.html_style = 0
392 self.html_color = (0,0,0)
393 self.new_font(self.html_font)
394
395 def new_font(self, font):
396 if font == None:
397 font = (12, 0, 0, 0)
398 font = map(lambda x:x, font)
399 for i in range(len(font)):
400 if font[i] == None:
401 font[i] = self.html_font[i]
402 [size, italic, bold, tt] = font
403 self.html_font = font[:]
404 if tt:
405 font = Fm.GetFNum('Courier')
406 else:
407 font = Fm.GetFNum('Times')
408 if HTML_SIZE.has_key(size):
409 size = HTML_SIZE[size]
410 else:
411 size = 12
412 face = 0
413 if bold: face = face | 1
414 if italic: face = face | 2
415 face = face | self.html_style
416 self.ted.WESetStyle(WASTEconst.weDoFont | WASTEconst.weDoFace |
417 WASTEconst.weDoSize | WASTEconst.weDoColor,
418 (font, face, size, self.html_color))
419
420 def new_margin(self, margin, level):
421 self.ted.WEInsert('[Margin %s %s]'%(margin, level), None, None)
422
423 def new_spacing(self, spacing):
424 self.ted.WEInsert('[spacing %s]'%spacing, None, None)
425
426 def new_styles(self, styles):
427 self.html_style = 0
428 self.html_color = (0,0,0)
429 if 'anchor' in styles:
430 self.html_style = self.html_style | 4
431 self.html_color = (0xffff, 0, 0)
432 self.new_font(self.html_font)
433
434 def send_paragraph(self, blankline):
435 self.ted.WEInsert('\r'*(blankline+1), None, None)
436
437 def send_line_break(self):
438 self.ted.WEInsert('\r', None, None)
439
440 def send_hor_rule(self, *args, **kw):
441 # Ignore ruler options, for now
442 dummydata = Res.Resource('')
443 self.ted.WEInsertObject('rulr', dummydata, (0,0))
444
445 def send_label_data(self, data):
446 self.ted.WEInsert(data, None, None)
447
448 def send_flowing_data(self, data):
449 self.ted.WEInsert(data, None, None)
450
451 def send_literal_data(self, data):
Jack Jansencbed91b2001-08-03 13:31:36 +0000452 data = string.replace(data, '\n', '\r')
Jack Jansen1df16d01996-05-07 15:25:36 +0000453 data = string.expandtabs(data)
454 self.ted.WEInsert(data, None, None)
455
456class Wed(Application):
457 def __init__(self):
458 Application.__init__(self)
459 self.num = 0
460 self.active = None
461 self.updatemenubar()
462 waste.STDObjectHandlers()
463 # Handler for horizontal ruler
464 waste.WEInstallObjectHandler('rulr', 'new ', self.newRuler)
465 waste.WEInstallObjectHandler('rulr', 'draw', self.drawRuler)
466
467 def makeusermenus(self):
468 self.filemenu = m = Menu(self.menubar, "File")
469 self.newitem = MenuItem(m, "New window", "N", self.open)
470 self.openitem = MenuItem(m, "Open...", "O", self.openfile)
471 self.closeitem = MenuItem(m, "Close", "W", self.closewin)
472 m.addseparator()
473 self.saveitem = MenuItem(m, "Save", "S", self.save)
474 self.saveasitem = MenuItem(m, "Save as...", "", self.saveas)
475 m.addseparator()
476 self.insertitem = MenuItem(m, "Insert plaintext...", "", self.insertfile)
477 self.htmlitem = MenuItem(m, "Insert HTML...", "", self.inserthtml)
478 m.addseparator()
479 self.quititem = MenuItem(m, "Quit", "Q", self.quit)
480
481 self.editmenu = m = Menu(self.menubar, "Edit")
482 self.undoitem = MenuItem(m, "Undo", "Z", self.undo)
483 self.cutitem = MenuItem(m, "Cut", "X", self.cut)
484 self.copyitem = MenuItem(m, "Copy", "C", self.copy)
485 self.pasteitem = MenuItem(m, "Paste", "V", self.paste)
486 self.clearitem = MenuItem(m, "Clear", "", self.clear)
487
488 self.makefontmenu()
489
490 # Groups of items enabled together:
491 self.windowgroup = [self.closeitem, self.saveitem, self.saveasitem,
492 self.editmenu, self.fontmenu, self.facemenu, self.sizemenu,
493 self.insertitem]
494 self.focusgroup = [self.cutitem, self.copyitem, self.clearitem]
495 self.windowgroup_on = -1
496 self.focusgroup_on = -1
497 self.pastegroup_on = -1
498 self.undo_label = "never"
499 self.ffs_values = ()
500
501 def makefontmenu(self):
502 self.fontmenu = Menu(self.menubar, "Font")
503 self.fontnames = getfontnames()
504 self.fontitems = []
505 for n in self.fontnames:
506 m = MenuItem(self.fontmenu, n, "", self.selfont)
507 self.fontitems.append(m)
508 self.facemenu = Menu(self.menubar, "Style")
509 self.faceitems = []
510 for n, shortcut in STYLES:
511 m = MenuItem(self.facemenu, n, shortcut, self.selface)
512 self.faceitems.append(m)
513 self.facemenu.addseparator()
514 self.faceitem_normal = MenuItem(self.facemenu, "Normal", "N",
515 self.selfacenormal)
516 self.sizemenu = Menu(self.menubar, "Size")
517 self.sizeitems = []
518 for n in SIZES:
519 m = MenuItem(self.sizemenu, `n`, "", self.selsize)
520 self.sizeitems.append(m)
521 self.sizemenu.addseparator()
522 self.sizeitem_bigger = MenuItem(self.sizemenu, "Bigger", "+",
523 self.selsizebigger)
524 self.sizeitem_smaller = MenuItem(self.sizemenu, "Smaller", "-",
525 self.selsizesmaller)
526
527 def selfont(self, id, item, *rest):
528 if self.active:
529 font = self.fontnames[item-1]
530 self.active.menu_setfont(font)
531 else:
532 EasyDialogs.Message("No active window?")
533
534 def selface(self, id, item, *rest):
535 if self.active:
536 face = (1<<(item-1))
537 self.active.menu_modface(face)
538 else:
539 EasyDialogs.Message("No active window?")
540
541 def selfacenormal(self, *rest):
542 if self.active:
543 self.active.menu_setface(0)
544 else:
545 EasyDialogs.Message("No active window?")
546
547 def selsize(self, id, item, *rest):
548 if self.active:
549 size = SIZES[item-1]
550 self.active.menu_setsize(size)
551 else:
552 EasyDialogs.Message("No active window?")
553
554 def selsizebigger(self, *rest):
555 if self.active:
556 self.active.menu_incsize(2)
557 else:
558 EasyDialogs.Message("No active window?")
559
560 def selsizesmaller(self, *rest):
561 if self.active:
562 self.active.menu_incsize(-2)
563 else:
564 EasyDialogs.Message("No active window?")
565
566 def updatemenubar(self):
567 changed = 0
568 on = (self.active <> None)
569 if on <> self.windowgroup_on:
570 for m in self.windowgroup:
571 m.enable(on)
572 self.windowgroup_on = on
573 changed = 1
574 if on:
575 # only if we have an edit menu
576 on = self.active.have_selection()
577 if on <> self.focusgroup_on:
578 for m in self.focusgroup:
579 m.enable(on)
580 self.focusgroup_on = on
581 changed = 1
582 on = self.active.can_paste()
583 if on <> self.pastegroup_on:
584 self.pasteitem.enable(on)
585 self.pastegroup_on = on
586 changed = 1
587 on = self.active.can_undo()
588 if on <> self.undo_label:
589 if on:
590 self.undoitem.enable(1)
591 self.undoitem.settext(on)
592 self.undo_label = on
593 else:
594 self.undoitem.settext("Nothing to undo")
595 self.undoitem.enable(0)
596 changed = 1
597 if self.updatefontmenus():
598 changed = 1
599 if changed:
600 DrawMenuBar()
601
602 def updatefontmenus(self):
603 info = self.active.getruninfo()
604 if info == self.ffs_values:
605 return 0
606 # Remove old checkmarks
607 if self.ffs_values == ():
608 self.ffs_values = (None, None, None)
609 font, face, size = self.ffs_values
610 if font <> None:
611 fnum = self.fontnames.index(font)
612 self.fontitems[fnum].check(0)
613 if face <> None:
614 for i in range(len(self.faceitems)):
615 if face & (1<<i):
616 self.faceitems[i].check(0)
617 if size <> None:
618 for i in range(len(self.sizeitems)):
619 if SIZES[i] == size:
620 self.sizeitems[i].check(0)
621
622 self.ffs_values = info
623 # Set new checkmarks
624 font, face, size = self.ffs_values
625 if font <> None:
626 fnum = self.fontnames.index(font)
627 self.fontitems[fnum].check(1)
628 if face <> None:
629 for i in range(len(self.faceitems)):
630 if face & (1<<i):
631 self.faceitems[i].check(1)
632 if size <> None:
633 for i in range(len(self.sizeitems)):
634 if SIZES[i] == size:
635 self.sizeitems[i].check(1)
636 # Set outline/normal for sizes
637 if font:
638 exists = getfontsizes(font, SIZES)
639 for i in range(len(self.sizeitems)):
640 if exists[i]:
641 self.sizeitems[i].setstyle(0)
642 else:
643 self.sizeitems[i].setstyle(8)
644
645 #
646 # Apple menu
647 #
648
649 def do_about(self, id, item, window, event):
650 EasyDialogs.Message("A simple single-font text editor based on WASTE")
651
652 #
653 # File menu
654 #
655
656 def open(self, *args):
657 self._open(0)
658
659 def openfile(self, *args):
660 self._open(1)
661
662 def _open(self, askfile):
663 if askfile:
664 fss, ok = macfs.StandardGetFile('TEXT')
665 if not ok:
666 return
667 path = fss.as_pathname()
668 name = os.path.split(path)[-1]
669 try:
670 fp = open(path, 'rb') # NOTE binary, we need cr as end-of-line
671 data = fp.read()
672 fp.close()
673 except IOError, arg:
674 EasyDialogs.Message("IOERROR: "+`arg`)
675 return
676 else:
677 path = None
678 name = "Untitled %d"%self.num
679 data = ''
680 w = WasteWindow(self)
681 w.open(path, name, data)
682 self.num = self.num + 1
683
684 def insertfile(self, *args):
685 if self.active:
686 fss, ok = macfs.StandardGetFile('TEXT')
687 if not ok:
688 return
689 path = fss.as_pathname()
690 try:
691 fp = open(path, 'rb') # NOTE binary, we need cr as end-of-line
692 except IOError, arg:
693 EasyDialogs.Message("IOERROR: "+`arg`)
694 return
695 self.active.menu_insert(fp)
696 else:
697 EasyDialogs.Message("No active window?")
698
699 def inserthtml(self, *args):
700 if self.active:
701 fss, ok = macfs.StandardGetFile('TEXT')
702 if not ok:
703 return
704 path = fss.as_pathname()
705 try:
706 fp = open(path, 'r')
707 except IOError, arg:
708 EasyDialogs.Message("IOERROR: "+`arg`)
709 return
710 self.active.menu_insert_html(fp)
711 else:
712 EasyDialogs.Message("No active window?")
713
714
715 def closewin(self, *args):
716 if self.active:
717 self.active.close()
718 else:
719 EasyDialogs.Message("No active window?")
720
721 def save(self, *args):
722 if self.active:
723 self.active.menu_save()
724 else:
725 EasyDialogs.Message("No active window?")
726
727 def saveas(self, *args):
728 if self.active:
729 self.active.menu_save_as()
730 else:
731 EasyDialogs.Message("No active window?")
732
733
734 def quit(self, *args):
735 for w in self._windows.values():
736 w.close()
737 if self._windows:
738 return
Jack Jansenef5cd051996-09-17 12:39:12 +0000739 self._quit()
Jack Jansen1df16d01996-05-07 15:25:36 +0000740
741 #
742 # Edit menu
743 #
744
745 def undo(self, *args):
746 if self.active:
747 self.active.menu_undo()
748 else:
749 EasyDialogs.Message("No active window?")
750
751 def cut(self, *args):
752 if self.active:
753 self.active.menu_cut()
754 else:
755 EasyDialogs.Message("No active window?")
756
757 def copy(self, *args):
758 if self.active:
759 self.active.menu_copy()
760 else:
761 EasyDialogs.Message("No active window?")
762
763 def paste(self, *args):
764 if self.active:
765 self.active.menu_paste()
766 else:
767 EasyDialogs.Message("No active window?")
768
769 def clear(self, *args):
770 if self.active:
771 self.active.menu_clear()
772 else:
773 EasyDialogs.Message("No active window?")
774
775 #
776 # Other stuff
777 #
778
779 def idle(self, event):
780 if self.active:
781 self.active.do_idle(event)
Jack Jansencbed91b2001-08-03 13:31:36 +0000782 else:
783 Qd.SetCursor(Qd.qd.arrow)
Jack Jansen1df16d01996-05-07 15:25:36 +0000784
785 def newRuler(self, obj):
786 """Insert a new ruler. Make it as wide as the window minus 2 pxls"""
787 ted = obj.WEGetObjectOwner()
788 l, t, r, b = ted.WEGetDestRect()
789 return r-l, 4
790
791 def drawRuler(self, (l, t, r, b), obj):
792 y = (t+b)/2
793 Qd.MoveTo(l+2, y)
794 Qd.LineTo(r-2, y)
795 return 0
796
797class MyHTMLParser(htmllib.HTMLParser):
798
799 def anchor_bgn(self, href, name, type):
Jack Jansenb8fd1f11998-04-15 14:35:16 +0000800 self.anchor = href
801 if self.anchor:
802 self.anchorlist.append(href)
803 self.formatter.push_style('anchor')
Jack Jansen1df16d01996-05-07 15:25:36 +0000804
805 def anchor_end(self):
Jack Jansenb8fd1f11998-04-15 14:35:16 +0000806 if self.anchor:
807 self.anchor = None
808 self.formatter.pop_style()
Jack Jansen1df16d01996-05-07 15:25:36 +0000809
810
811def getfontnames():
812 names = []
813 for i in range(256):
814 n = Fm.GetFontName(i)
815 if n: names.append(n)
816 return names
817
818def getfontsizes(name, sizes):
819 exist = []
820 num = Fm.GetFNum(name)
821 for sz in sizes:
822 if Fm.RealFont(num, sz):
823 exist.append(1)
824 else:
825 exist.append(0)
826 return exist
827
828def main():
829 App = Wed()
830 App.mainloop()
831
832if __name__ == '__main__':
833 main()
834