diff --git a/gramps2/src/AutoComp.py b/gramps2/src/AutoComp.py index 38e9e6e57..2127621d6 100644 --- a/gramps2/src/AutoComp.py +++ b/gramps2/src/AutoComp.py @@ -139,7 +139,8 @@ class AutoCombo(AutoCompBase): button1.connect("button-release-event",self.setval) self.vals = [""] self.inb = 0 - + widget.set_popdown_strings(plist) + def setval(self,widget,event): """Callback task called on the button release""" @@ -148,8 +149,6 @@ class AutoCombo(AutoCompBase): if self.nl == string.lower(text): gtk.Editable.set_position(self.entry.entry,self.l) gtk.Editable.select_region(self.entry.entry,self.l,-1) -# self.entry.entry.set_position(self.l) -# self.entry.entry.select_region(self.l, -1) def build_list(self,widget,event): """Internal task that builds the popdown strings. This task is called when the diff --git a/gramps2/src/EditPerson.py b/gramps2/src/EditPerson.py index e2b1f9b38..a40fea0c6 100644 --- a/gramps2/src/EditPerson.py +++ b/gramps2/src/EditPerson.py @@ -179,33 +179,33 @@ class EditPerson: self.plist = person.getAddressList()[:] # event display - etitles = [(_('Event'),0,150),(_('Description'),1,150), - (_('Date'),3,100),(_('Place'),4,100)] + etitles = [(_('Event'),-1,150),(_('Description'),-1,150), + (_('Date'),-1,100),(_('Place'),-1,100)] self.etree = ListModel.ListModel(self.event_list,etitles, self.on_event_select_row, self.on_event_update_clicked) # attribute display - atitles = [(_('Attribute'),0,150),(_('Value'),1,150)] + atitles = [(_('Attribute'),-1,150),(_('Value'),-1,150)] self.atree = ListModel.ListModel(self.attr_list,atitles, self.on_attr_select_row, self.on_update_attr_clicked) # address display - ptitles = [(_('Date'),0,150),(_('Address'),1,150)] + ptitles = [(_('Date'),-1,150),(_('Address'),-1,150)] self.ptree = ListModel.ListModel(self.addr_list, ptitles, self.on_addr_select_row, self.on_update_addr_clicked) # name display - ntitles = [(_('Name'),0,250),(_('Type'),1,100)] + ntitles = [(_('Name'),-1,250),(_('Type'),-1,100)] self.ntree = ListModel.ListModel(self.name_list,ntitles, self.on_name_select_row) self.ntree.tree.connect('event',self.aka_double_click) # web display - wtitles = [(_('Path'),0,250),(_('Description'),1,100)] + wtitles = [(_('Path'),-1,250),(_('Description'),-1,100)] self.wtree = ListModel.ListModel(self.web_list,wtitles, self.on_web_select_row, self.on_update_url_clicked) @@ -249,6 +249,7 @@ class EditPerson: self.event_list.drag_dest_set(gtk.DEST_DEFAULT_ALL,pycode_tgts,ACTION_COPY) self.event_list.drag_source_set(BUTTON1_MASK, pycode_tgts, ACTION_COPY) self.event_list.connect('drag_data_get', self.ev_drag_data_get) + self.event_list.connect('drag_begin', self.ev_drag_begin) self.event_list.connect('drag_data_received', self.ev_drag_data_received) @@ -349,7 +350,7 @@ class EditPerson: stat = 0 combo.entry.set_text("") -# AutoComp.AutoEntry(place,None,self.autoplace) + AutoComp.AutoEntry(place,None,self.autoplace) if ord and ord.getPlace(): place.set_text(ord.getPlace().get_title()) return stat @@ -465,99 +466,134 @@ class EditPerson: self.seal_stat = obj.get_data("val") def ev_drag_data_received(self,widget,context,x,y,sel_data,info,time): - print context, info, time + row = self.etree.get_row_at(x,y) + if sel_data and sel_data.data: exec 'data = %s' % sel_data.data exec 'mytype = "%s"' % data[0] exec 'person = "%s"' % data[1] - if person == self.person.getId() or mytype != 'pevent': + if mytype != 'pevent': return - foo = pickle.loads(data[2]); - for src in foo.getSourceRefList(): - base = src.getBase() - newbase = self.db.findSourceNoMap(base.getId()) - src.setBase(newbase) - place = foo.getPlace() - if place: - foo.setPlace(self.db.findPlaceNoMap(place.getId())) - self.elist.append(foo) + elif person == self.person.getId(): + self.move_element(self.elist,self.etree.get_selected_row(),row) + else: + foo = pickle.loads(data[2]); + for src in foo.getSourceRefList(): + base = src.getBase() + newbase = self.db.findSourceNoMap(base.getId()) + src.setBase(newbase) + place = foo.getPlace() + if place: + foo.setPlace(self.db.findPlaceNoMap(place.getId())) + self.elist.insert(row,foo) + self.lists_changed = 1 self.redraw_event_list() + def move_element(self,list,src,dest): + if src == -1: + return + obj = list[src] + list.remove(obj) + list.insert(dest,obj) + def ev_drag_data_get(self,widget, context, sel_data, info, time): - store, iter = widget.get_selection().get_selected() - ev = store.get_value(iter,4) + ev = self.etree.get_selected_objects() bits_per = 8; # we're going to pass a string - pickled = pickle.dumps(ev); + pickled = pickle.dumps(ev[0]); data = str(('pevent',self.person.getId(),pickled)); sel_data.set(sel_data.target, bits_per, data) + def ev_drag_begin(self, context, a): + return + icon = self.etree.get_icon() + t = self.etree.tree + (x,y) = icon.get_size() + mask = gtk.gdk.Pixmap(self.window.window,x,y,1) + mask.draw_rectangle(t.get_style().white_gc, gtk.TRUE, 0,0,x,y) + t.drag_source_set_icon(t.get_colormap(),icon,mask) + def url_drag_data_received(self,widget,context,x,y,sel_data,info,time): + row = self.wtree.get_row_at(x,y) + if sel_data and sel_data.data: exec 'data = %s' % sel_data.data exec 'mytype = "%s"' % data[0] exec 'person = "%s"' % data[1] - if person == self.person.getId() or mytype != 'url': + if mytype != "url": return - foo = pickle.loads(data[2]); - self.ulist.append(foo) + elif person == self.person.getId(): + self.move_element(self.ulist,self.wtree.get_selected_row(),row) + else: + foo = pickle.loads(data[2]); + self.ulist.append(foo) self.lists_changed = 1 self.redraw_url_list() def url_drag_data_get(self,widget, context, sel_data, info, time): - ev = widget.get_row_data(widget.focus_row) + ev = self.wtree.get_selected_objects() bits_per = 8; # we're going to pass a string - pickled = pickle.dumps(ev); + pickled = pickle.dumps(ev[0]); data = str(('url',self.person.getId(),pickled)); sel_data.set(sel_data.target, bits_per, data) def at_drag_data_received(self,widget,context,x,y,sel_data,info,time): + row = self.atree.get_row_at(x,y) + if sel_data and sel_data.data: exec 'data = %s' % sel_data.data exec 'mytype = "%s"' % data[0] exec 'person = "%s"' % data[1] - if person == self.person.getId() or mytype != 'pattr': + if mytype != 'pattr': return - foo = pickle.loads(data[2]); - for src in foo.getSourceRefList(): - base = src.getBase() - newbase = self.db.findSourceNoMap(base.getId()) - src.setBase(newbase) - self.alist.append(foo) + elif person == self.person.getId(): + self.move_element(self.alist,self.atree.get_selected_row(),row) + else: + foo = pickle.loads(data[2]); + for src in foo.getSourceRefList(): + base = src.getBase() + newbase = self.db.findSourceNoMap(base.getId()) + src.setBase(newbase) + self.alist.append(foo) self.lists_changed = 1 self.redraw_attr_list() def at_drag_data_get(self,widget, context, sel_data, info, time): - ev = widget.get_row_data(widget.focus_row) + ev = self.atree.get_selected_objects() bits_per = 8; # we're going to pass a string - pickled = pickle.dumps(ev); + pickled = pickle.dumps(ev[0]); data = str(('pattr',self.person.getId(),pickled)); sel_data.set(sel_data.target, bits_per, data) def ad_drag_data_received(self,widget,context,x,y,sel_data,info,time): + row = self.ptree.get_row_at(x,y) + if sel_data and sel_data.data: exec 'data = %s' % sel_data.data exec 'mytype = "%s"' % data[0] exec 'person = "%s"' % data[1] - if person == self.person.getId() or mytype != 'paddr': + if mytype != 'paddr': return - foo = pickle.loads(data[2]); - for src in foo.getSourceRefList(): - base = src.getBase() - newbase = self.db.findSourceNoMap(base.getId()) - src.setBase(newbase) - self.plist.append(foo) + elif person == self.person.getId(): + self.move_element(self.plist,self.ptree.get_selected_row(),row) + else: + foo = pickle.loads(data[2]); + for src in foo.getSourceRefList(): + base = src.getBase() + newbase = self.db.findSourceNoMap(base.getId()) + src.setBase(newbase) + self.plist.append(foo) self.lists_changed = 1 self.redraw_addr_list() def ad_drag_data_get(self,widget, context, sel_data, info, time): - ev = widget.get_row_data(widget.focus_row) + ev = self.ptree.get_selected_objects() bits_per = 8; # we're going to pass a string - pickled = pickle.dumps(ev); + pickled = pickle.dumps(ev[0]); data = str(('paddr',self.person.getId(),pickled)); sel_data.set(sel_data.target, bits_per, data) diff --git a/gramps2/src/EventEdit.py b/gramps2/src/EventEdit.py index 155729a25..827749ce9 100644 --- a/gramps2/src/EventEdit.py +++ b/gramps2/src/EventEdit.py @@ -101,7 +101,7 @@ class EventEditor: self.top.get_widget('add_src'), self.top.get_widget('del_src')) - AutoComp.AutoEntry(self.event_menu.entry,list) + AutoComp.AutoCombo(self.event_menu,list) AutoComp.AutoEntry(self.place_field,self.pmap.keys()) if event != None: diff --git a/gramps2/src/FamilyView.py b/gramps2/src/FamilyView.py index bbb9837e8..53468d79a 100644 --- a/gramps2/src/FamilyView.py +++ b/gramps2/src/FamilyView.py @@ -98,6 +98,7 @@ class FamilyView: self.selected_spouse = None self.child_list = self.top.get_widget('chlist') + self.child_list.set_reorderable(gtk.TRUE) self.child_model = gtk.ListStore(gobject.TYPE_INT, gobject.TYPE_STRING, gobject.TYPE_STRING,gobject.TYPE_STRING, gobject.TYPE_STRING,gobject.TYPE_STRING, diff --git a/gramps2/src/GenericFilter.py b/gramps2/src/GenericFilter.py index 51b6f42cc..f2c63b6ec 100644 --- a/gramps2/src/GenericFilter.py +++ b/gramps2/src/GenericFilter.py @@ -95,7 +95,7 @@ class Rule: def check(self): return len(self.list) == len(self.labels) - def apply(self,p): + def apply(self,db,p): return 1 def display_values(self): @@ -118,7 +118,7 @@ class Everyone(Rule): def name(self): return 'Everyone' - def apply(self,p): + def apply(self,db,p): return 1 #------------------------------------------------------------------------- @@ -134,7 +134,7 @@ class HasIdOf(Rule): def name(self): return 'Has the Id' - def apply(self,p): + def apply(self,db,p): return p.getId() == self.list[0] #------------------------------------------------------------------------- @@ -150,7 +150,7 @@ class IsFemale(Rule): def name(self): return 'Is a female' - def apply(self,p): + def apply(self,db,p): return p.getGender() == Person.female #------------------------------------------------------------------------- @@ -167,7 +167,7 @@ class IsDescendantOf(Rule): def name(self): return 'Is a descendant of' - def apply(self,p): + def apply(self,db,p): return self.search(p) def search(self,p): @@ -194,7 +194,7 @@ class IsDescendantFamilyOf(Rule): def name(self): return "Is a descendant family member of" - def apply(self,p): + def apply(self,db,p): return self.search(p,1) def search(self,p,val): @@ -230,7 +230,7 @@ class IsAncestorOf(Rule): def name(self): return 'Is an ancestor of' - def apply(self,p): + def apply(self,db,p): return self.search(p) def search(self,p): @@ -244,6 +244,44 @@ class IsAncestorOf(Rule): return 1 return 0 +#------------------------------------------------------------------------- +# +# HasCommonAncestorWith +# +#------------------------------------------------------------------------- +class HasCommonAncestorWith(Rule): + """Rule that checks for a person that has a common ancestor with a specified person""" + + labels = [ _('ID') ] + + def name(self): + return 'Has a common ancestor with' + + def __init__(self,list): + Rule.__init__(self,list) + # Keys in `ancestor_cache' are ancestors of list[0]. + # We delay the computation of ancestor_cache until the + # first use, because it's not uncommon to instantiate + # this class and not use it. + self.ancestor_cache = {} + + def init_ancestor_cache(self,db): + # list[0] is an Id, but we need to pass a Person to for_each_ancestor. + p = db.getPerson(self.list[0]) + if p: + def init(self,pid): self.ancestor_cache[pid] = 1 + for_each_ancestor([p],init,self) + + def apply(self,db,p): + # On the first call, we build the ancestor cache for the + # reference person. Then, for each person to test, + # we browse his ancestors until we found one in the cache. + if len(self.ancestor_cache) == 0: + self.init_ancestor_cache(db) + return for_each_ancestor([p], + lambda self,p: self.ancestor_cache.has_key(p), + self); + #------------------------------------------------------------------------- # # IsMale @@ -257,7 +295,7 @@ class IsMale(Rule): def name(self): return 'Is a male' - def apply(self,p): + def apply(self,db,p): return p.getGender() == Person.male #------------------------------------------------------------------------- @@ -281,7 +319,7 @@ class HasEvent(Rule): def name(self): return 'Has the personal event' - def apply(self,p): + def apply(self,db,p): for event in p.getEventList(): val = 1 if self.list[0] and event.getName() != self.list[0]: @@ -319,7 +357,7 @@ class HasFamilyEvent(Rule): def name(self): return 'Has the family event' - def apply(self,p): + def apply(self,db,p): for f in p.getFamilyList(): for event in f.getEventList(): val = 1 @@ -352,7 +390,7 @@ class HasRelationship(Rule): def name(self): return 'Has the relationships' - def apply(self,p): + def apply(self,db,p): rel_type = 0 cnt = 0 num_rel = len(p.getFamilyList()) @@ -408,7 +446,7 @@ class HasBirth(Rule): def name(self): return 'Has the birth' - def apply(self,p): + def apply(self,db,p): event = p.getBirth() if len(self.list) > 2 and find(event.getDescription(),self.list[2])==-1: return 0 @@ -440,7 +478,7 @@ class HasDeath(Rule): def name(self): return 'Has the death' - def apply(self,p): + def apply(self,db,p): event = p.getDeath() if self.list[2] and find(event.getDescription(),self.list[2])==-1: return 0 @@ -464,7 +502,7 @@ class HasAttribute(Rule): def name(self): return 'Has the personal attribute' - def apply(self,p): + def apply(self,db,p): for event in p.getAttributes(): if self.list[0] and event.getType() != self.list[0]: return 0 @@ -485,7 +523,7 @@ class HasFamilyAttribute(Rule): def name(self): return 'Has the family attribute' - def apply(self,p): + def apply(self,db,p): for f in p.getFamilyList(): for event in f.getAttributes(): val = 1 @@ -510,7 +548,7 @@ class HasNameOf(Rule): def name(self): return 'Has a name' - def apply(self,p): + def apply(self,db,p): self.f = self.list[0] self.l = self.list[1] self.s = self.list[2] @@ -538,7 +576,7 @@ class MatchesFilter(Rule): def name(self): return 'Matches the filter named' - def apply(self, p): + def apply(self,db,p): for filter in SystemFilters.get_filters(): if filter.get_name() == self.list[0]: return filter.check(p) @@ -605,13 +643,10 @@ class GenericFilter: def get_rules(self): return self.flist - def delete_rule(self,r): - self.flist.remove(r) - - def check_or(self,p): + def check_or(self,db,p): test = 0 for rule in self.flist: - test = test or rule.apply(p) + test = test or rule.apply(db,p) if test: break if self.invert: @@ -619,20 +654,20 @@ class GenericFilter: else: return test - def check_xor(self,p): + def check_xor(self,db,p): test = 0 for rule in self.flist: - temp = rule.apply(p) + temp = rule.apply(db,p) test = ((not test) and temp) or (test and (not temp)) if self.invert: return not test else: return test - def check_one(self,p): + def check_one(self,db,p): count = 0 for rule in self.flist: - if rule.apply(p): + if rule.apply(db,p): count = count + 1 if count > 1: break @@ -641,10 +676,10 @@ class GenericFilter: else: return count == 1 - def check_and(self,p): + def check_and(self,db,p): test = 1 for rule in self.flist: - test = test and rule.apply(p) + test = test and rule.apply(db,p) if not test: break if self.invert: @@ -652,21 +687,24 @@ class GenericFilter: else: return test - def check(self,p): + def get_check_func(self): try: m = getattr(self, 'check_' + self.logical_op) except AttributeError: m = self.check_and + return m - return m(p) + def check(self,db,p): + return self.get_check_func()(db,p) - def apply(self,list): - try: - m = getattr(self, 'check_' + self.logical_op) - except AttributeError: - m = self.check_and + def apply(self,db,list): + m = self.get_check_func() + res = [] + for p in list: + if m(db,p): + res.append(p) + return res - return filter(m, list) #------------------------------------------------------------------------- # @@ -683,6 +721,7 @@ tasks = { _("Is a descendant of") : IsDescendantOf, _("Is a descendant family member of"): IsDescendantFamilyOf, _("Is an ancestor of") : IsAncestorOf, + _("Has a common ancestor with") : HasCommonAncestorWith, _("Is a female") : IsFemale, _("Is a male") : IsMale, _("Has the personal event") : HasEvent, @@ -715,6 +754,8 @@ class GenericFilterList: try: parser = make_parser() parser.setContentHandler(FilterParser(self)) + if self.file[0:7] != "file://": + self.file = "file://" + self.file parser.parse(self.file) except (IOError,OSError,SAXParseException): pass diff --git a/gramps2/src/GrampsParser.py b/gramps2/src/GrampsParser.py index dfc85c9e3..60bc1e10f 100644 --- a/gramps2/src/GrampsParser.py +++ b/gramps2/src/GrampsParser.py @@ -445,7 +445,7 @@ class GrampsParser: d.set_calendar_val(int(attrs['calendar'])) if attrs.has_key("cformat"): - d.set_calendar(Calendar.find_calendar(attrs['calendar'])) + d.set_calendar(Calendar.find_calendar(attrs['cformat'])) d.get_start_date().setIsoDate(attrs['val']) diff --git a/gramps2/src/ImageSelect.py b/gramps2/src/ImageSelect.py index dfc5c94fd..c4db2ae98 100644 --- a/gramps2/src/ImageSelect.py +++ b/gramps2/src/ImageSelect.py @@ -83,7 +83,7 @@ class ImageSelect: self.dataobj = None self.parent = parent self.canvas_list = {} - self.p_map = {} + self.p_map = {} def add_thumbnail(self, photo): "should be overrridden" @@ -240,17 +240,17 @@ class Gallery(ImageSelect): def close(self): self.iconlist.hide() - for a in self.canvas_list: + for a in self.canvas_list.values(): a[0].destroy() a[1].destroy() a[2].destroy() - self.p_map = None self.canvas_list = None - self.iconlist.destroy() def on_canvas1_event(self,obj,event): - """Handle resize events over the canvas, redrawing if the size changes""" + """ + Handle resize events over the canvas, redrawing if the size changes + """ def item_event(self, widget, event=None): diff --git a/gramps2/src/ListModel.py b/gramps2/src/ListModel.py index 7ea06fc8c..118ee08c7 100644 --- a/gramps2/src/ListModel.py +++ b/gramps2/src/ListModel.py @@ -35,7 +35,7 @@ class ListModel: self.selection.set_mode(mode) self.mode = mode self.data_index = l - + self.count = 0 self.cids = [] cnum = 0 @@ -55,10 +55,10 @@ class ListModel: cnum = cnum + 1 self.cids.append(name[1]) - if name[1] != -1: + if name[0] != '': self.tree.append_column(column) - if self.cids[0] > 0: + if self.cids[0] != -1: self.model.set_sort_column_id(self.cids[0],gtk.SORT_ASCENDING) self.connect_model() @@ -72,6 +72,7 @@ class ListModel: self.tree.set_reorderable(order) def new_model(self): + self.count = 0 self.model = gtk.ListStore(*self.mylist) def connect_model(self): @@ -81,6 +82,8 @@ class ListModel: def sort(self): val = self.model.get_sort_column_id() col = val[0] + if col < 0: + return if col > 0: self.model.set_sort_column_id(col,val[1]) else: @@ -90,8 +93,25 @@ class ListModel: def get_selected(self): return self.selection.get_selected() + def get_row_at(self,x,y): + path = self.tree.get_path_at_pos(x,y) + if path == None: + return self.count -1 + else: + return path[0][0]-1 + + def get_selected_row(self): + store, iter = self.selection.get_selected() + if iter: + rows = store.get_path(iter) + return rows[0] + else: + return -1 + def get_selected_objects(self): - if self.mode == gtk.SELECTION_SINGLE: + if self.count == 0: + return [] + elif self.mode == gtk.SELECTION_SINGLE: store,iter = self.selection.get_selected() if iter: return [self.model.get_value(iter,self.data_index)] @@ -102,14 +122,26 @@ class ListModel: self.selection.selected_foreach(self.blist,mlist) return mlist + def get_icon(self): + if self.mode == gtk.SELECTION_SINGLE: + store,iter = self.selection.get_selected() + path = self.model.get_path(iter) + else: + mlist = [] + self.selection.selected_foreach(self.blist,mlist) + path = self.model.get_path(mlist[0]) + return self.tree.create_row_drag_icon(path) + def blist(self,store,path,iter,list): list.append(self.model.get_value(iter,self.data_index)) def clear(self): + self.count = 0 self.model.clear() def remove(self,iter): self.model.remove(iter) + self.count = self.count - 1 def get_row(self,iter): row = self.model.get_path(iter) @@ -122,6 +154,7 @@ class ListModel: return self.model.get_value(iter,self.data_index) def add(self,data,info=None,select=0): + self.count = self.count + 1 iter = self.model.append() col = 0 for object in data: @@ -133,6 +166,7 @@ class ListModel: return iter def add_and_select(self,data,info=None): + self.count = self.count + 1 iter = self.model.append() col = 0 for object in data: diff --git a/gramps2/src/Report.py b/gramps2/src/Report.py index 0aab2f439..c1588f009 100644 --- a/gramps2/src/Report.py +++ b/gramps2/src/Report.py @@ -1081,12 +1081,10 @@ try: parser = make_parser() path = const.template_dir parser.setContentHandler(TemplateParser(_template_map,path)) - parser.parse("%s/templates.xml" % path) + parser.parse("file://%s/templates.xml" % path) parser = make_parser() path = os.path.expanduser("~/.gramps/templates") parser.setContentHandler(TemplateParser(_template_map,path)) - parser.parse("%s/templates.xml" % path) + parser.parse("file://%s/templates.xml" % path) except (IOError,OSError,SAXParseException): pass - - diff --git a/gramps2/src/TextDoc.py b/gramps2/src/TextDoc.py index c6b50d4e9..5107af025 100644 --- a/gramps2/src/TextDoc.py +++ b/gramps2/src/TextDoc.py @@ -1,8 +1,39 @@ -# + # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2000 Donald N. Allingham # +# Modified September 2002 by Gary Shao +# +# Added line_break() method to TextDoc class to allow breaking a line +# in a paragraph (in those document generators that support it). +# +# Added start_listing() and end_listing() methods to TextDoc class to +# allow displaying text blocks without automatic filling and justification. +# Creating a new listing element seems called for because many document +# generator implementation have to use a different mechanism for text +# that is not going to be automatically filled and justified than that +# used for normal paragraphs. Examples are
 tags in HTML, using
+#   the Verbatim environment in LaTeX, and using the Preformatted class
+#   in reportlab for generating PDF.
+#
+#   Added another option, FONT_MONOSPACE, for use as a font face. This
+#   calls for a fixed-width font (e.g. Courier). It is intended primarily
+#   for supporting the display of text where alignment by character position
+#   may be important, such as in code source or column-aligned data.
+#   Especially useful in styles for the new listing element discussed above.
+#
+#   Added start_italic() and end_italic() methods to TextDoc class to
+#   complement the emphasis of text in a paragraph by bolding with the
+#   ability to italicize segments of text in a paragraph.
+#
+#   Added the show_link() method to TextDoc to enable the creation of
+#   hyperlinks in HTML output. Only produces active links in HTML, while
+#   link will be represented as text in other generator output. (active
+#   links are technically possible in PDF documents, but the reportlab
+#   modules the PDF generator is based on does not support them at this
+#   time)
+#
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
 # the Free Software Foundation; either version 2 of the License, or
@@ -51,6 +82,7 @@ except:
 #-------------------------------------------------------------------------
 FONT_SANS_SERIF = 0
 FONT_SERIF = 1
+FONT_MONOSPACE = 2
 
 PAPER_PORTRAIT  = 0
 PAPER_LANDSCAPE = 1
@@ -600,7 +632,7 @@ class ParagraphStyle:
 
     def set_alignment(self,align):
         """
-        Sets the pargraph alignment.
+        Sets the paragraph alignment.
 
         align - PARA_ALIGN_LEFT, PARA_ALIGN_RIGHT, PARA_ALIGN_CENTER, or
                 PARA_ALIGN_JUSTIFY
@@ -761,6 +793,8 @@ class StyleSheetList:
         try:
             parser = make_parser()
             parser.setContentHandler(SheetParser(self))
+            if self.file[0:7] != "file://":
+                self.file = "file://" + self.file
             parser.parse(self.file)
         except (IOError,OSError,SAXParseException):
             pass
@@ -797,7 +831,7 @@ class StyleSheet:
         Adds a paragraph style to the style sheet.
 
         name - name of the ParagraphStyle
-        style - PargraphStyle instance to be added.
+        style - ParagraphStyle instance to be added.
         """
         self.style_list[name] = ParagraphStyle(style)
 
@@ -1006,6 +1040,10 @@ class TextDoc:
         "Closes the document"
         pass
 
+    def line_break(self):
+        "Forces a line break within a paragraph"
+	pass
+
     def page_break(self):
         "Forces a page break, creating a new page"
         pass
@@ -1016,12 +1054,23 @@ class TextDoc:
     def end_bold(self):
         pass
 
+    def start_listing(self,style_name):
+        """
+	Starts a new listing block, using the specified style name.
+
+        style_name - name of the ParagraphStyle to use for the block.
+	"""
+        pass
+
+    def end_listing(self):
+        pass
+
     def start_paragraph(self,style_name,leader=None):
         """
-        Starts a new pargraph, using the specified style name.
+        Starts a new paragraph, using the specified style name.
 
-        style_name - name of the PargraphStyle to use for the paragraph.
-        leader     - Leading text for a pargraph. Typically ssed for numbering.
+        style_name - name of the ParagraphStyle to use for the paragraph.
+        leader     - Leading text for a paragraph. Typically used for numbering.
         """
         pass
 
diff --git a/gramps2/src/WriteXML.py b/gramps2/src/WriteXML.py
index bd5b076ae..f1b6e484d 100644
--- a/gramps2/src/WriteXML.py
+++ b/gramps2/src/WriteXML.py
@@ -454,8 +454,9 @@ class XmlWriter:
         if date.isEmpty():
             return
 
-        if cal != 0:
-            calstr = ' cformat="%s"' % date.get_calendar().NAME
+        name = date.get_calendar().NAME
+        if name != Calendar.Gregorian.NAME:
+            calstr = ' cformat="%s"' % name
         else:
             calstr = ''
 
diff --git a/gramps2/src/docgen/OpenDrawDoc.py b/gramps2/src/docgen/OpenDrawDoc.py
index 1699321dd..bf9cdca1e 100644
--- a/gramps2/src/docgen/OpenDrawDoc.py
+++ b/gramps2/src/docgen/OpenDrawDoc.py
@@ -27,15 +27,8 @@ from intl import gettext as _
 from TextDoc import *
 from DrawDoc import *
 
-from latin_utf8 import latin_to_utf8
 import const
 
-try:
-    from codecs import *
-except:
-    def EncodedFile(a,b,c):
-        return a
-    
 
 class OpenDrawDoc(DrawDoc):
 
@@ -66,7 +59,7 @@ class OpenDrawDoc(DrawDoc):
         os.mkdir(self.tempdir + os.sep + "META-INF")
 
         fname = self.tempdir + os.sep + "content.xml"
-        self.f = EncodedFile(open(fname,"wb"),'latin-1','utf-8')
+        self.f = open(fname,"wb")
         
         self.f.write('\n')
         self.f.write('\n')
         self.f.write('')
         text = string.replace(text,'\n','')
-	self.f.write(latin_to_utf8(text))
+	self.f.write(text)
 
     def _write_manifest(self):
 	file = self.tempdir + os.sep + "META-INF" + os.sep + "manifest.xml"
-	self.f = EncodedFile(open(file,"wb"),'latin-1','utf-8')
+	self.f = open(file,"wb")
 	self.f.write('\n')
 	self.f.write('')
@@ -369,8 +362,8 @@ class OpenDrawDoc(DrawDoc):
 
     def _write_meta_file(self):
 	file = self.tempdir + os.sep + "meta.xml"
-        name = latin_to_utf8(self.name)
-	self.f = EncodedFile(open(file,"wb"),'latin-1','utf-8')
+        name = self.name
+	self.f = open(file,"wb")
 	self.f.write('\n')
 	self.f.write('')
-            text = latin_to_utf8(string.replace(text,'\n',''))
+            text = string.replace(text,'\n','')
             self.f.write('>\n')
   	    self.f.write('')
 	    self.f.write('' % para_name)
diff --git a/gramps2/src/docgen/OpenOfficeDoc.py b/gramps2/src/docgen/OpenOfficeDoc.py
index 35d94bc54..0350f8e91 100644
--- a/gramps2/src/docgen/OpenOfficeDoc.py
+++ b/gramps2/src/docgen/OpenOfficeDoc.py
@@ -18,23 +18,39 @@
 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #
 
+#-------------------------------------------------------------------------
+#
+# Standard Python Modules 
+#
+#-------------------------------------------------------------------------
 import os
 import tempfile
 import string
+import zipfile
+import time
 
+#-------------------------------------------------------------------------
+#
+# Gramps modules
+#
+#-------------------------------------------------------------------------
 from TextDoc import *
-from latin_utf8 import latin_to_utf8
 import const
 import Plugins
-from intl import gettext as _
 import ImgManip
 
-try:
-    from codecs import *
-except:
-    def EncodedFile(a,b,c):
-        return a
+#-------------------------------------------------------------------------
+#
+# internationalization
+#
+#-------------------------------------------------------------------------
+from intl import gettext as _
 
+#-------------------------------------------------------------------------
+#
+# OpenOfficeDoc
+#
+#-------------------------------------------------------------------------
 class OpenOfficeDoc(TextDoc):
 
     def __init__(self,styles,type,template,orientation):
@@ -46,8 +62,6 @@ class OpenOfficeDoc(TextDoc):
         self.new_page = 0
 
     def open(self,filename):
-        import time
-
         t = time.localtime(time.time())
         self.time = "%04d-%02d-%02dT%02d:%02d:%02d" % \
                     (t[0],t[1],t[2],t[3],t[4],t[5])
@@ -58,13 +72,9 @@ class OpenOfficeDoc(TextDoc):
             self.filename = filename
             
         tempfile.tempdir = "/tmp"
-        self.tempdir = tempfile.mktemp()
-        os.mkdir(self.tempdir,0700)
-        os.mkdir(self.tempdir + os.sep + "Pictures")
-        os.mkdir(self.tempdir + os.sep + "META-INF")
-            
-        fname = self.tempdir + os.sep + "content.xml"
-        self.f = EncodedFile(open(fname,"wb"),'latin-1','utf-8')
+
+        self.content_xml = tempfile.mktemp()
+        self.f = open(self.content_xml,"wb")
 
         self.f.write('\n')
         self.f.write('\n')
+	self.f.write('" table:style-name="%s">\n' % style_name)
 	table = self.table_styles[style_name]
 	for col in range(0,table.get_columns()):
 	    self.f.write(' 1:
-            self.f.write(' table:number-columns-spanned="' + str(span) + '">\n')
+            self.f.write(' table:number-columns-spanned="%s">\n' % span)
 	else:	     
 	    self.f.write('>\n')
 
@@ -302,26 +311,25 @@ class OpenOfficeDoc(TextDoc):
 
     def _write_zip(self):
         
-        if os.path.isfile(self.filename):
-            os.unlink(self.filename)
-
-        os.system("cd %s; %s %s ." % (self.tempdir,const.zipcmd,self.filename))
-
-        os.unlink(self.tempdir + os.sep + "META-INF" + os.sep + "manifest.xml")
-        os.unlink(self.tempdir + os.sep + "content.xml")
-        os.unlink(self.tempdir + os.sep + "meta.xml")
-        os.unlink(self.tempdir + os.sep + "styles.xml")
+        file = zipfile.ZipFile(self.filename,"w",zipfile.ZIP_DEFLATED)
+        file.write(self.manifest_xml,"META-INF/manifest.xml")
+        file.write(self.content_xml,"content.xml")
+        file.write(self.meta_xml,"meta.xml")
+        file.write(self.styles_xml,"styles.xml")
+        
         for image in self.photo_list:
             base = os.path.basename(image[0])
-            os.unlink(self.tempdir + os.sep + "Pictures" + os.sep + base)
-        os.rmdir(self.tempdir + os.sep + "Pictures")
-        os.rmdir(self.tempdir + os.sep + "META-INF")
-        os.rmdir(self.tempdir)
+            file.write(image[0],"Pictures/%s" % base)
+        file.close()
+
+        os.unlink(self.manifest_xml)
+        os.unlink(self.content_xml)
+        os.unlink(self.meta_xml)
+        os.unlink(self.styles_xml)
         
     def _write_styles_file(self):
-	file = self.tempdir + os.sep + "styles.xml"
-
-	self.f = EncodedFile(open(file,"wb"),'latin-1','utf-8')
+        self.styles_xml = tempfile.mktemp()
+	self.f = open(self.styles_xml,"wb")
         
         self.f.write('\n')
         self.f.write('')
         if leader != None:
-            self.f.write(latin_to_utf8(leader))
+            self.f.write(leader)
             self.f.write('')
 
     def end_paragraph(self):
@@ -489,25 +497,11 @@ class OpenOfficeDoc(TextDoc):
 
     def write_text(self,text):
         text = string.replace(text,'\n','')
-	self.f.write(latin_to_utf8(text))
-
-    def _write_photos(self):
-        import shutil
-
-        for file_tuple in self.photo_list:
-            file = file_tuple[0]
-            base = os.path.basename(file)
-            image_name = self.tempdir + os.sep + "Pictures" + os.sep + base
-
-            try:
-                shutil.copy(file,image_name)
-            except IOError,msg:
-                import gnome.ui
-                gnome.ui.GnomeErrorDialog(_("Error copying %s") + "\n" + msg)
+	self.f.write(text)
 
     def _write_manifest(self):
-	file = self.tempdir + os.sep + "META-INF" + os.sep + "manifest.xml"
-	self.f = EncodedFile(open(file,"wb"),'latin-1','utf-8')
+        self.manifest_xml = tempfile.mktemp()
+	self.f = open(self.manifest_xml,"wb")
 	self.f.write('\n')
 	self.f.write('')
@@ -533,9 +527,9 @@ class OpenOfficeDoc(TextDoc):
 	self.f.close()
 
     def _write_meta_file(self):
-	file = self.tempdir + os.sep + "meta.xml"
-        name = latin_to_utf8(self.name)
-	self.f = EncodedFile(open(file,"wb"),'latin-1','utf-8')
+        name = self.name
+        self.meta_xml = tempfile.mktemp()
+	self.f = open(self.meta_xml,"wb")
 	self.f.write('\n')
 	self.f.write('