Whitespace normalization.
[python/dscho.git] / Mac / Demo / waste / htmled.py
blob871076633a6e6efc4a67c0fd1710d0f0a5c545f3
1 # A minimal text editor.
3 # To be done:
4 # - Functionality: find, etc.
6 from Carbon.Menu import DrawMenuBar
7 from FrameWork import *
8 from Carbon import Win
9 from Carbon import Qd
10 from Carbon import Res
11 from Carbon import Fm
12 import waste
13 import WASTEconst
14 from Carbon import Scrap
15 import os
16 import EasyDialogs
17 import macfs
18 import string
19 import htmllib
21 WATCH = Qd.GetCursor(4).data
23 LEFTMARGIN=0
25 UNDOLABELS = [ # Indexed by WEGetUndoInfo() value
26 None, "", "typing", "Cut", "Paste", "Clear", "Drag", "Style"]
28 # Style and size menu. Note that style order is important (tied to bit values)
29 STYLES = [
30 ("Bold", "B"), ("Italic", "I"), ("Underline", "U"), ("Outline", "O"),
31 ("Shadow", ""), ("Condensed", ""), ("Extended", "")
33 SIZES = [ 9, 10, 12, 14, 18, 24]
35 # Sizes for HTML tag types
36 HTML_SIZE={
37 'h1': 18,
38 'h2': 14
41 BIGREGION=Qd.NewRgn()
42 Qd.SetRectRgn(BIGREGION, -16000, -16000, 16000, 16000)
44 class WasteWindow(ScrolledWindow):
45 def open(self, path, name, data):
46 self.path = path
47 self.name = name
48 r = windowbounds(400, 400)
49 w = Win.NewWindow(r, name, 1, 0, -1, 1, 0)
50 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)
59 self.ted.WEInstallTabHooks()
60 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)
70 def getstylesoup(self, pathname):
71 if not pathname:
72 return None, None
73 oldrf = Res.CurResFile()
74 try:
75 rf = Res.FSpOpenResFile(self.path, 1)
76 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
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.GetQDGlobalsArrow())
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
107 def scrollbar_callback(self, which, what, value):
108 if which == 'y':
110 # "line" size is minimum of top and bottom line size
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)
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)
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
130 # Now do the command.
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)
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()
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()
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)
197 self.wid.InvalWindowRect(vr)
198 ScrolledWindow.do_postresize(self, width, height, window)
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()
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()
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()
226 def menu_save(self):
227 if not self.path:
228 self.menu_save_as()
229 return # Will call us recursively
231 # First save data
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()
240 # Now save style and soup
242 oldresfile = Res.CurResFile()
243 try:
244 rf = Res.FSpOpenResFile(self.path, 3)
245 except Res.Error:
246 Res.FSpCreateResFile(self.path, '????', 'TEXT', macfs.smAllScripts)
247 rf = Res.FSpOpenResFile(self.path, 3)
248 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)
256 self.ted.WEResetModCount()
258 def menu_save_as(self):
259 path = EasyDialogs.AskFileForSave(message='Save as:')
260 if not path: return
261 self.path = path
262 self.name = os.path.split(self.path)[-1]
263 self.wid.SetWTitle(self.name)
264 self.menu_save()
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()
273 def menu_insert_html(self, fp):
274 import htmllib
275 import formatter
276 f = formatter.AbstractFormatter(self)
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)
283 self.html_init()
284 p = MyHTMLParser(f)
285 p.feed(fp.read())
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)
293 self.wid.InvalWindowRect(self.ted.WEGetViewRect())
295 self.updatescrollbars()
296 self.parent.updatemenubar()
298 def menu_cut(self):
299 self.ted.WESelView()
300 if hasattr(Scrap, 'ZeroScrap'):
301 Scrap.ZeroScrap()
302 else:
303 Scrap.ClearCurrentScrap()
304 self.ted.WECut()
305 self.updatescrollbars()
306 self.parent.updatemenubar()
308 def menu_copy(self):
309 if hasattr(Scrap, 'ZeroScrap'):
310 Scrap.ZeroScrap()
311 else:
312 Scrap.ClearCurrentScrap()
313 self.ted.WECopy()
314 self.updatescrollbars()
315 self.parent.updatemenubar()
317 def menu_paste(self):
318 self.ted.WESelView()
319 self.ted.WEPaste()
320 self.updatescrollbars()
321 self.parent.updatemenubar()
323 def menu_clear(self):
324 self.ted.WESelView()
325 self.ted.WEDelete()
326 self.updatescrollbars()
327 self.parent.updatemenubar()
329 def menu_undo(self):
330 self.ted.WEUndo()
331 self.updatescrollbars()
332 self.parent.updatemenubar()
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()
339 def menu_modface(self, face):
340 self.mysetstyle(WASTEconst.weDoFace|WASTEconst.weDoToggleFace,
341 (0, face, 0, (0,0,0)))
343 def menu_setface(self, face):
344 self.mysetstyle(WASTEconst.weDoFace|WASTEconst.weDoReplaceFace,
345 (0, face, 0, (0,0,0)))
347 def menu_setsize(self, size):
348 self.mysetstyle(WASTEconst.weDoSize, (0, 0, size, (0,0,0)))
350 def menu_incsize(self, size):
351 self.mysetstyle(WASTEconst.weDoAddSize, (0, 0, size, (0,0,0)))
353 def mysetstyle(self, which, how):
354 self.ted.WESelView()
355 self.ted.WESetStyle(which, how)
356 self.parent.updatemenubar()
358 def have_selection(self):
359 start, stop = self.ted.WEGetSelection()
360 return start < stop
362 def can_paste(self):
363 return self.ted.WECanPaste()
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
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
386 # Methods for writer class for html formatter
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)
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))
420 def new_margin(self, margin, level):
421 self.ted.WEInsert('[Margin %s %s]'%(margin, level), None, None)
423 def new_spacing(self, spacing):
424 self.ted.WEInsert('[spacing %s]'%spacing, None, None)
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)
434 def send_paragraph(self, blankline):
435 self.ted.WEInsert('\r'*(blankline+1), None, None)
437 def send_line_break(self):
438 self.ted.WEInsert('\r', None, None)
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))
445 def send_label_data(self, data):
446 self.ted.WEInsert(data, None, None)
448 def send_flowing_data(self, data):
449 self.ted.WEInsert(data, None, None)
451 def send_literal_data(self, data):
452 data = string.replace(data, '\n', '\r')
453 data = string.expandtabs(data)
454 self.ted.WEInsert(data, None, None)
456 class 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)
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)
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)
488 self.makefontmenu()
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 = ()
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, repr(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)
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?")
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?")
541 def selfacenormal(self, *rest):
542 if self.active:
543 self.active.menu_setface(0)
544 else:
545 EasyDialogs.Message("No active window?")
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?")
554 def selsizebigger(self, *rest):
555 if self.active:
556 self.active.menu_incsize(2)
557 else:
558 EasyDialogs.Message("No active window?")
560 def selsizesmaller(self, *rest):
561 if self.active:
562 self.active.menu_incsize(-2)
563 else:
564 EasyDialogs.Message("No active window?")
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()
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)
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)
646 # Apple menu
649 def do_about(self, id, item, window, event):
650 EasyDialogs.Message("A simple single-font text editor based on WASTE")
653 # File menu
656 def open(self, *args):
657 self._open(0)
659 def openfile(self, *args):
660 self._open(1)
662 def _open(self, askfile):
663 if askfile:
664 path = EasyDialogs.AskFileForOpen(typeList=('TEXT',))
665 if not path:
666 return
667 name = os.path.split(path)[-1]
668 try:
669 fp = open(path, 'rb') # NOTE binary, we need cr as end-of-line
670 data = fp.read()
671 fp.close()
672 except IOError, arg:
673 EasyDialogs.Message("IOERROR: %r" % (arg,))
674 return
675 else:
676 path = None
677 name = "Untitled %d"%self.num
678 data = ''
679 w = WasteWindow(self)
680 w.open(path, name, data)
681 self.num = self.num + 1
683 def insertfile(self, *args):
684 if self.active:
685 path = EasyDialogs.AskFileForOpen(typeList=('TEXT',))
686 if not path:
687 return
688 try:
689 fp = open(path, 'rb') # NOTE binary, we need cr as end-of-line
690 except IOError, arg:
691 EasyDialogs.Message("IOERROR: %r" % (args,))
692 return
693 self.active.menu_insert(fp)
694 else:
695 EasyDialogs.Message("No active window?")
697 def inserthtml(self, *args):
698 if self.active:
699 path = EasyDialogs.AskFileForOpen(typeList=('TEXT',))
700 if not path:
701 return
702 try:
703 fp = open(path, 'r')
704 except IOError, arg:
705 EasyDialogs.Message("IOERROR: %r" % (arg,))
706 return
707 self.active.menu_insert_html(fp)
708 else:
709 EasyDialogs.Message("No active window?")
712 def closewin(self, *args):
713 if self.active:
714 self.active.close()
715 else:
716 EasyDialogs.Message("No active window?")
718 def save(self, *args):
719 if self.active:
720 self.active.menu_save()
721 else:
722 EasyDialogs.Message("No active window?")
724 def saveas(self, *args):
725 if self.active:
726 self.active.menu_save_as()
727 else:
728 EasyDialogs.Message("No active window?")
731 def quit(self, *args):
732 for w in self._windows.values():
733 w.close()
734 if self._windows:
735 return
736 self._quit()
739 # Edit menu
742 def undo(self, *args):
743 if self.active:
744 self.active.menu_undo()
745 else:
746 EasyDialogs.Message("No active window?")
748 def cut(self, *args):
749 if self.active:
750 self.active.menu_cut()
751 else:
752 EasyDialogs.Message("No active window?")
754 def copy(self, *args):
755 if self.active:
756 self.active.menu_copy()
757 else:
758 EasyDialogs.Message("No active window?")
760 def paste(self, *args):
761 if self.active:
762 self.active.menu_paste()
763 else:
764 EasyDialogs.Message("No active window?")
766 def clear(self, *args):
767 if self.active:
768 self.active.menu_clear()
769 else:
770 EasyDialogs.Message("No active window?")
773 # Other stuff
776 def idle(self, event):
777 if self.active:
778 self.active.do_idle(event)
779 else:
780 Qd.SetCursor(Qd.GetQDGlobalsArrow())
782 def newRuler(self, obj):
783 """Insert a new ruler. Make it as wide as the window minus 2 pxls"""
784 ted = obj.WEGetObjectOwner()
785 l, t, r, b = ted.WEGetDestRect()
786 return r-l, 4
788 def drawRuler(self, (l, t, r, b), obj):
789 y = (t+b)/2
790 Qd.MoveTo(l+2, y)
791 Qd.LineTo(r-2, y)
792 return 0
794 class MyHTMLParser(htmllib.HTMLParser):
796 def anchor_bgn(self, href, name, type):
797 self.anchor = href
798 if self.anchor:
799 self.anchorlist.append(href)
800 self.formatter.push_style('anchor')
802 def anchor_end(self):
803 if self.anchor:
804 self.anchor = None
805 self.formatter.pop_style()
808 def getfontnames():
809 names = []
810 for i in range(256):
811 n = Fm.GetFontName(i)
812 if n: names.append(n)
813 return names
815 def getfontsizes(name, sizes):
816 exist = []
817 num = Fm.GetFNum(name)
818 for sz in sizes:
819 if Fm.RealFont(num, sz):
820 exist.append(1)
821 else:
822 exist.append(0)
823 return exist
825 def main():
826 App = Wed()
827 App.mainloop()
829 if __name__ == '__main__':
830 main()