From c39b6ba091d0463da89c118103824ea776fd51f5 Mon Sep 17 00:00:00 2001 From: Don Allingham Date: Thu, 20 Jan 2005 04:11:13 +0000 Subject: [PATCH] * src/ReportUtils.py: added estimate_age and sanitize_person * src/BaseDoc.py: Add checks attempting to add styles after initializing the document * src/docgen/OpenOfficeDoc.py: add init assertions * src/docgen/PSDrawDoc.py: fix line style in boxes * src/docgen/SvgDrawDoc.py: fix line style in boxes * src/ReportUtils.py: added documentation svn: r3942 --- ChangeLog | 11 +++ src/BaseDoc.py | 7 +- src/ReportUtils.py | 184 ++++++++++++++++++++++++++++++++++-- src/docgen/OpenOfficeDoc.py | 3 + src/docgen/PSDrawDoc.py | 15 +-- src/docgen/SvgDrawDoc.py | 25 ++--- 6 files changed, 220 insertions(+), 25 deletions(-) diff --git a/ChangeLog b/ChangeLog index 590cc75b0..9a17fccdb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2005-01-19 Don Allingham + * src/ReportUtils.py: added estimate_age and sanitize_person + * src/BaseDoc.py: Add checks attempting to add styles after initializing + the document + * src/docgen/OpenOfficeDoc.py: add init assertions + * src/docgen/PSDrawDoc.py: fix line style in boxes + * src/docgen/SvgDrawDoc.py: fix line style in boxes + +2005-01-18 Don Allingham + * src/ReportUtils.py: added documentation + 2005-01-18 Martin Hawlisch * src/NameEdit.py: Fix patronymic show/save. diff --git a/src/BaseDoc.py b/src/BaseDoc.py index 4be252f9f..d0cc51c83 100644 --- a/src/BaseDoc.py +++ b/src/BaseDoc.py @@ -1114,9 +1114,10 @@ class BaseDoc: self.media_list = [] self.print_req = 0 self.mode = TEXT_MODE + self.init_called = False def init(self): - pass + self.init_called = True def set_mode(self, mode): self.mode = mode @@ -1189,6 +1190,7 @@ class BaseDoc: self.title = name def add_draw_style(self,name,style): + assert(self.init_called==False) self.draw_styles[name] = GraphicsStyle(style) def get_draw_style(self,name): @@ -1204,6 +1206,7 @@ class BaseDoc: @param name: name of the table style @param style: TableStyle instance to be added """ + assert(self.init_called==False) self.table_styles[name] = TableStyle(style) def add_cell_style(self,name,style): @@ -1213,6 +1216,7 @@ class BaseDoc: @param name: name of the table cell style @param style: TableCellStyle instance to be added """ + assert(self.init_called==False) self.cell_styles[name] = TableCellStyle(style) def open(self,filename): @@ -1374,6 +1378,7 @@ class BaseDoc: def draw_wedge(self, style, centerx, centery, radius, start_angle, end_angle, short_radius=0): + assert(self.init_called) while end_angle < start_angle: end_angle += 360 diff --git a/src/ReportUtils.py b/src/ReportUtils.py index ab6e98c1e..6ddf7f041 100644 --- a/src/ReportUtils.py +++ b/src/ReportUtils.py @@ -21,6 +21,9 @@ # $Id$ +import Date +import RelLib + #------------------------------------------------------------------------- # # Convert points to cm and back @@ -116,7 +119,31 @@ def draw_legend(doc, start_x, start_y, data): start_y += size * 1.3 def draw_vertical_bar_graph(doc, format, start_x, start_y, height, width, data): - doc.draw_line(format,start_x,start_y,start_x,start_y+height) + """ + Draws a vertical bar chart in the specified document. The data passed + should consist of the actual data. The bars are scaled appropriately by + the routine. + + @param doc: Document to which the bar chart should be added + @type doc: BaseDoc derived class + @param start_x: x coordinate in centimeters where the left hand side of the + chart should be. 0 is the left hand edge of the document. + @type start_x: float + @param start_y: y coordinate in centimeters where the top of the chart + should be. 0 is the top edge of the document + @param start_y: float + @param height: height of the graph in centimeters + @type height: float + @param width: width of the graph in centimeters + @type width: float + @param data: List of tuples containing the data to be plotted. The values + are (graphics_format, value), where graphics_format is a BaseDoc + GraphicsStyle, and value is a floating point number. Any other items in + the tuple are ignored. This allows you to share the same data list with + the L{draw_legend} function. + @type data: list + """ + doc.draw_line(format,start_x,start_y+height,start_x,start_y) doc.draw_line(format,start_x,start_y+height,start_x+width,start_y+height) largest = 0.0 @@ -131,13 +158,158 @@ def draw_vertical_bar_graph(doc, format, start_x, start_y, height, width, data): start = 0.5*box_width + start_x for index in range(units): - print height, float(data[index][1]) * scale size = float(data[index][1]) * scale doc.draw_bar(data[index][0],start,bottom-size,start+box_width,bottom) start += box_width * 1.5 -def age_of(person): - pass +def estimate_age(db, person): + """ + Estimates the age of a person based off the birth and death + dates of the person. A tuple containing the estimated upper + and lower bounds of the person's age is returned. If either + the birth or death date is missing, a (-1,-1) is returned. + + @param db: GRAMPS database to which the Person object belongs + @type db: GrampsDbBase + @param person: Person object to calculate the age of + @type db: Person + @returns: tuple containing the lower and upper bounds of the + person's age, or (-1,-1) if it could not be determined. + @rtype: tuple + """ + bhandle = person.get_birth_handle() + dhandle = person.get_death_handle() + + # if either of the events is not defined, return an error message + if not bhandle or not dhandle: + return (-1,-1) + + bdata = db.get_event_from_handle(bhandle).get_date_object() + ddata = db.get_event_from_handle(dhandle).get_date_object() + + # if the date is not valid, return an error message + if not bdata.get_valid() or not ddata.get_valid(): + return (-1,-1) + + # if a year is not valid, return an error message + if not bdata.get_year_valid() or not ddata.get_year_valid(): + return (-1,-1) + + bstart = bdata.get_start_date() + bstop = bdata.get_stop_date() + + dstart = ddata.get_start_date() + dstop = ddata.get_stop_date() + + def _calc_diff(low,high): + if (low[1],low[0]) > (high[1],high[0]): + return high[2] - low[2] - 1 + else: + return high[2] - low[2] + + if bstop == Date.EMPTY and dstop == Date.EMPTY: + lower = _calc_diff(bstart,dstart) + age = (lower, lower) + elif bstop == Date.EMPTY: + lower = _calc_diff(bstart,dstart) + upper = _calc_diff(bstart,dstop) + age = (lower,upper) + elif dstop == Date.EMPTY: + lower = _calc_diff(bstop,dstart) + upper = _calc_diff(bstart,dstart) + age = (lower,upper) + else: + lower = _calc_diff(bstop,dstart) + upper = _calc_diff(bstart,dstop) + age = (lower,upper) + return age + +def sanitize_person(db,person): + """ + Creates a new Person instance based off the passed Person + instance. The returned instance has all private records + removed from it. + + @param db: GRAMPS database to which the Person object belongs + @type db: GrampsDbBase + @param person: source Person object that will be copied with + privacy records removed + @type db: Person + @returns: 'cleansed' Person object + @rtype: Person + """ + new_person = RelLib.Person() + name = person.get_primary_name() + + # copy gender + new_person.set_gender(person.get_gender()) + + # copy names if not private + if not name.get_privacy(): + new_person.set_primary_name(name) + new_person.set_nick_name(person.get_nick_name()) + for name in person.get_alternate_names(): + if not name.get_privacy(): + new_person.add_alternate_name(name) + + # set complete flag + new_person.set_complete_flag(person.get_complete_flag()) + + # copy birth event + event_handle = person.get_birth_handle() + event = db.get_event_from_handle(event_handle) + if event and not event.get_privacy(): + new_person.set_birth_handle(event_handle) + + # copy death event + event_handle = person.get_death_handle() + event = db.get_event_from_handle(event_handle) + if event and not event.get_privacy(): + new_person.set_death_handle(event_handle) + + # copy event list + for event_handle in person.get_event_list(): + event = db.get_event_from_handle(event_handle) + if event and not event.get_privacy(): + new_person.add_event_handle(event_handle) + + # copy address list + for address in person.get_address_list(): + if not address.get_privacy(): + new_person.add_address(RelLib.Address(address)) + + # copy attribute list + for attribute in person.get_attribute_list(): + if not attribute.get_privacy(): + new_person.add_attribute(RelLib.Attribute(attribute)) + + # copy URL list + for url in person.get_url_list(): + if not url.get_privacy(): + new_person.add_url(url) + + # copy Media reference list + for obj in person.get_media_list(): + new_person.add_media_reference(RelLib.MediaRef(obj)) + + # copy Family reference list + for handle in person.get_family_handle_list(): + new_person.add_family_handle(handle) + + # LDS ordinances + ord = person.get_lds_baptism() + if ord: + new_person.set_lds_baptism(ord) + + ord = person.get_lds_endowment() + if ord: + new_person.set_lds_endowment(ord) + + ord = person.get_lds_sealing() + if ord: + new_person.set_lds_sealing(ord) + + return new_person #------------------------------------------------------------------------- # @@ -146,7 +318,7 @@ def age_of(person): #------------------------------------------------------------------------- def roman(num): """ Integer to Roman numeral converter for 0 < num < 4000 """ - if type(num) != type(0): + if type(num) != int: return "?" if not 0 < num < 4000: return "?" @@ -198,7 +370,7 @@ if __name__ == "__main__": doc.add_draw_style("blue",g) g = BaseDoc.GraphicsStyle() - g.set_fill_color((0,255,255)) + g.set_fill_color((255,255,0)) g.set_paragraph_style('Normal') g.set_line_width(1) doc.add_draw_style("yellow",g) diff --git a/src/docgen/OpenOfficeDoc.py b/src/docgen/OpenOfficeDoc.py index e32cb76d7..9bc4d31a0 100644 --- a/src/docgen/OpenOfficeDoc.py +++ b/src/docgen/OpenOfficeDoc.py @@ -92,6 +92,9 @@ class OpenOfficeDoc(BaseDoc.BaseDoc): def init(self): + assert(self.init_called==False) + self.init_called = True + current_locale = locale.getlocale() self.lang = current_locale[0] if self.lang: diff --git a/src/docgen/PSDrawDoc.py b/src/docgen/PSDrawDoc.py index 07668a1e4..d85b236e6 100644 --- a/src/docgen/PSDrawDoc.py +++ b/src/docgen/PSDrawDoc.py @@ -362,13 +362,14 @@ class PSDrawDoc(BaseDoc.BaseDoc): self.f.write('1 setgray\n') self.f.write('fill\n') self.f.write('newpath\n') - self.f.write('%f cm %f cm moveto\n' % self.translate(x,y)) - self.f.write('0 -%f cm rlineto\n' % bh) - self.f.write('%f cm 0 rlineto\n' % bw) - self.f.write('0 %f cm rlineto\n' % bh) - self.f.write('closepath\n') - self.f.write('%.4f setlinewidth\n' % box_style.get_line_width()) - self.f.write('%.4f %.4f %.4f setrgbcolor stroke\n' % rgb_color(box_style.get_color())) + if box_style.get_line_width(): + self.f.write('%f cm %f cm moveto\n' % self.translate(x,y)) + self.f.write('0 -%f cm rlineto\n' % bh) + self.f.write('%f cm 0 rlineto\n' % bw) + self.f.write('0 %f cm rlineto\n' % bh) + self.f.write('closepath\n') + self.f.write('%.4f setlinewidth\n' % box_style.get_line_width()) + self.f.write('%.4f %.4f %.4f setrgbcolor stroke\n' % rgb_color(box_style.get_color())) if text != "": (text,fdef) = self.encode_text(p,text) self.f.write(fdef) diff --git a/src/docgen/SvgDrawDoc.py b/src/docgen/SvgDrawDoc.py index 83f0a0fa8..0ef145767 100644 --- a/src/docgen/SvgDrawDoc.py +++ b/src/docgen/SvgDrawDoc.py @@ -141,9 +141,8 @@ class SvgDrawDoc(BaseDoc.BaseDoc): self.f.write('\n' % - (color[0],color[1],color[2],s.get_line_width())) + self.f.write('style="stroke:#%02x%02x%02x; ' % s.get_color()) + self.f.write('stroke-width:%.2fpt;"/>\n' % s.get_line_width()) def draw_path(self,style,path): stype = self.draw_styles[style] @@ -169,7 +168,8 @@ class SvgDrawDoc(BaseDoc.BaseDoc): self.f.write('y="%4.2fcm" ' % y1) self.f.write('width="%4.2fcm" ' % (x2-x1)) self.f.write('height="%4.2fcm" ' % (y2-y1)) - self.f.write('style="fill:#ffffff; stroke:#000000; ') + self.f.write('style="fill:##%02x%02x%02x; ' % s.get_fill_color()) + self.f.write('stroke:#%02x%02x%02x; ' % s.get_color()) self.f.write('stroke-width:%.2f;"/>\n' % s.get_line_width()) def draw_box(self,style,text,x,y): @@ -182,18 +182,21 @@ class SvgDrawDoc(BaseDoc.BaseDoc): bh = box_style.get_height() bw = box_style.get_width() - self.f.write('\n') + if box_style.get_shadow(): + self.f.write('\n') self.f.write('\n' % box_style.get_fill_color()) + self.f.write('style="fill:#%02x%02x%02x; ' % box_style.get_fill_color()) + self.f.write('stroke:#%02x%02x%02x; ' % box_style.get_color()) + self.f.write('stroke-width:%f;"/>\n' % box_style.get_line_width()) if text != "": font = p.get_font() font_size = font.get_size()