#!/usr/bin/python # Based roughly on Owen Taylor's make-todo script. import signal import xmllib import sys import string import re import gtk import gnome.ui from gtk import TRUE; import GdkImlib class ParseError (Exception): pass def error_dialog (str): dialog = gnome.ui.GnomeMessageBox (str, "error", gnome.ui.STOCK_BUTTON_CLOSE) dialog.connect("clicked", gtk.mainquit) dialog.connect("destroy", gtk.mainquit) dialog.set_modal(TRUE) dialog.show_all() gtk.mainloop() sys.exit (1) class Unit: def __init__(self): self.title = None self.text = None self.watermark = None self.image = None self.type = "standard" def is_ok(self): if self.title == None: raise ParseError, " must have a section." if self.text == None: raise ParseError, "<unit> must have a <text> section." if self.watermark == None: raise ParseError, "<unit> must have a <watermark> section." if self.image == None: raise ParseError, "<unit> must have a <image> section." if (string.lower (self.type) != "standard" and string.lower (self.type) != "start" and string.lower (self.type) != "finish"): raise ParseError, "<unit> must have a type of start, standard or finish" def get_page(self): if string.lower (self.type) == "standard": page = gnome.ui.GnomeDruidPageStandard(self.title, self.watermark) frame = gtk.GtkFrame () frame.add (self.image) label = gtk.GtkLabel (self.text) label.set_line_wrap (TRUE) label.set_usize (450, -1) label.set_justify (gtk.JUSTIFY_LEFT) page.vbox.pack_start (frame) page.vbox.pack_start (label) elif string.lower (self.type) == "start": page = gnome.ui.GnomeDruidPageStart(self.title, self.text, self.watermark, None) else: page = gnome.ui.GnomeDruidPageFinish(self.title, self.text, self.watermark, None) return page def output(self): print ("Unit '%s' has:\n%s\nas it's text\n\n" % (self.title, self.text)) class TutorParser (xmllib.XMLParser): def __init__(self): xmllib.XMLParser.__init__(self) self.data="" self.in_tutor = 0 self.in_data = 0 self.title = None self.unit = None self.watermark = None self.units = [] self.entitydefs = {} def start_tutor(self,attributes): if self.in_tutor: raise ParseError, "<tutor> tags may not be nested" self.in_todo = 1 def end_tutor(self): self.in_tutor = 0 def start_unit(self,attributes): if self.unit: raise ParseError, "<unit> tags may not be nested" self.unit = Unit() if attributes.has_key ("type"): self.unit.type = attributes["type"] def end_unit(self): if self.unit.watermark == None: self.unit.watermark = self.watermark self.unit.is_ok() self.units.append(self.unit) self.unit = None self.data = "" def start_title(self,attributes): if self.in_data: raise ParseError, "Unexpected <title> tag in content" self.in_data = 1 def end_title(self): self.in_data = 0 if self.unit: self.unit.title = self.data else: self.title = self.data self.data = "" def start_watermark(self,attributes): if self.in_data: raise ParseError, "Unexpected <watermark> tag in content" self.in_data = 1 def end_watermark(self): self.in_data = 0 try: watermark = GdkImlib.Image(self.data) except RuntimeError: raise ParseError, "invalid filename or image in <watermark> tags" if self.unit: self.unit.watermark = watermark else: self.watermark = watermark self.data = "" def start_text(self,attributes): if not self.unit: raise ParseError, "<text> tag must be in <unit>" if self.in_data: raise ParseError, "Unexpected <text> tag in content" self.in_data = 1 def end_text(self): self.in_data = 0 self.unit.text = self.data self.data = "" def start_image(self,attributes): if not self.unit: raise ParseError, "<text> tag must be in <unit>" if self.in_data: raise ParseError, "Unexpected <text> tag in content" self.in_data = 1 def end_image(self): self.in_data = 0 try: self.unit.image = gnome.ui.GnomePixmap(self.data) except RuntimeError: raise ParseError, "invalid filename or image in <image> tags" self.data = "" def handle_data(self,data): if self.in_data: self.data = self.data + data def unknown_starttag(self,tag,attributes): if not self.in_data: raise ParseError, "Unexpected start tag: " + tag else: self.data = self.data + "<" + tag for (key,val) in attributes.items(): self.data = self.data + ' %s="%s"' % (key,val) self.data = self.data + ">" def unknown_endtag(self,tag): if not self.in_data: raise ParseError, "Unexpected end tag: " + tag else: self.data = self.data + "</%s>" % tag def syntax_error(self, err): if re.match("reference to unknown entity", err): pass else: xmllib.XMLParser.syntax_error (self, err) def unknown_entityref(self,ref): if not self.in_data: raise ParseError, "Unknown entity &" + ref + ";" else: self.data = self.data + "&" + ref + ";" def is_ok(self): if self.title == None: raise ParseError, "<tutor> must have a <title> section." if self.units == []: raise ParseError, "<tutor> must have at least one <unit>" def main(): if len(sys.argv) == 1: error_dialog ("gnome-tutor.py run without a tutor file.") try: file = open(sys.argv[1]) except IOError, (num, err): error_dialog ("IOError %d: %s\nwhile trying to open \"%s\"" % (num, err, sys.argv[1])) parser = TutorParser() lineno = 1 while 1: line = file.readline() if line == "": break try: parser.feed(line) except ParseError, err: error_dialog ("Parse error at line " + `lineno` + ": " + err.__str__() + "\n") except RuntimeError, err: error_dialog(err.__str__()) lineno = lineno + 1 parser.close() try: parser.is_ok() except ParseError, err: error_dialog ("Parse error at line " + `lineno` + ": " + err.__str__() + "\n") win = gtk.GtkWindow() druid = gnome.ui.GnomeDruid() win.connect("destroy", gtk.mainquit) druid.connect("cancel", gtk.mainquit) win.add (druid) for unit in parser.units: page = unit.get_page() druid.append_page (page) win.show_all() gtk.mainloop() if __name__ == "__main__": signal.signal(signal.SIGINT, signal.SIG_DFL) # for control-C main()