diff --git a/src/plugins/drawreport/TimeLine.py b/src/plugins/drawreport/TimeLine.py index 60b93ebc1..642bb567f 100644 --- a/src/plugins/drawreport/TimeLine.py +++ b/src/plugins/drawreport/TimeLine.py @@ -99,57 +99,57 @@ class TimeLine(Report): menu = options.menu self.filter = menu.get_option_by_name('filter').get_filter() - self.title = _("Timeline Graph for %s") % self.filter.get_name() - sort_func_num = menu.get_option_by_name('sortby').get_value() sort_functions = _get_sort_functions(Sort.Sort(database)) self.sort_name = sort_functions[sort_func_num][0] self.sort_func = sort_functions[sort_func_num][1] - self.calendar = 0 + self.calendar = config.get('preferences.calendar-format-report') def write_report(self): + # Apply the filter + self._user.begin_progress(_('Timeline'), + _('Applying filter...'), + self.database.get_number_of_people()) + self.plist = self.filter.apply(self.database, + self.database.iter_person_handles(), + self._user.step_progress) + self._user.end_progress() + + # Find the range of dates to include (low, high) = self.find_year_range() + + # Generate the actual timeline + self.generate_timeline(low, high) - if low == high: - if self.standalone: - self.doc.close() - ErrorDialog(_("Report could not be created"), - _("The range of dates chosen was not valid")) - return - + def generate_timeline(self, low, high): st_size = self.name_size() - style_sheet = self.doc.get_style_sheet() font = style_sheet.get_paragraph_style('TLG-Name').get_font() - incr = pt2cm(font.get_size()) - pad = incr*.75 - - x1,x2,y1,y2 = (0,0,0,0) - - start = st_size+0.5 - stop = self.doc.get_usable_width()-0.5 - size = (stop-start) + pad = incr * 0.75 + x1,x2,y1,y2 = (0, 0, 0, 0) + start = st_size + 0.5 + stop = self.doc.get_usable_width() - 0.5 + size = (stop - start) self.header = 2.0 - self.doc.start_page() - - index = 1 - current = 1; - - length = len(self.plist) - - self._user.begin_progress(_('Timeline'), _('Sorting dates...'), 1) + # Sort the people as requested + self._user.begin_progress(_('Timeline'), _('Sorting dates...'), 0) self.plist.sort(key=self.sort_func) self._user.end_progress() + self.doc.start_page() + self.build_grid(low, high, start, stop) + + index = 1 + current = 1; + + length = len(self.plist) + self._user.begin_progress(_('Timeline'), - _('Calculating timeline...'), len(self.plist)) - - self.calendar = config.get('preferences.calendar-format-report') - + _('Calculating timeline...'), length) + for p_id in self.plist: - self._user.step_progress() p = self.database.get_person_from_handle(p_id) birth = get_birth_or_fallback(self.database, p) if birth: @@ -194,7 +194,6 @@ class TimeLine(Report): if (y2 + incr) >= self.doc.get_usable_height(): if current != length: - self.build_grid(low, high,start,stop) self.doc.end_page() self.doc.start_page() self.build_grid(low, high,start,stop) @@ -203,11 +202,11 @@ class TimeLine(Report): else: index += 1; current += 1 - self._user.end_progress() - self.build_grid(low, high,start,stop) - self.doc.end_page() + self._user.step_progress() + self.doc.end_page() + self._user.end_progress() - def build_grid(self,year_low,year_high,start_pos,stop_pos): + def build_grid(self, year_low, year_high, start_pos, stop_pos): """ Draws the grid outline for the chart. Sets the document label, draws the vertical lines, and adds the year labels. Arguments @@ -218,75 +217,119 @@ class TimeLine(Report): start_pos - x position of the lowest leftmost grid line stop_pos - x position of the rightmost grid line """ - width = self.doc.get_usable_width() + self.draw_title() + self.draw_columns(start_pos, stop_pos) + if year_high is not None and year_low is not None: + self.draw_year_headings(year_low, year_high, start_pos, stop_pos) + else: + self.draw_no_date_heading() - style_sheet = self.doc.get_style_sheet() - title_font = style_sheet.get_paragraph_style('TLG-Title').get_font() - normal_font = style_sheet.get_paragraph_style('TLG-Name').get_font() - label_font = style_sheet.get_paragraph_style('TLG-Label').get_font() + def draw_columns(self, start_pos, stop_pos): + """ + Draws the columns out of vertical lines. - byline = _("Sorted by %s") % self.sort_name - - self.doc.center_text('TLG-title',self.title + "\n" + byline,width/2.0,0) - - label_y = self.header - (pt2cm(normal_font.get_size())*1.2) + start_pos - x position of the lowest leftmost grid line + stop_pos - x position of the rightmost grid line + """ top_y = self.header bottom_y = self.doc.get_usable_height() + delta = (stop_pos - start_pos)/ 5 + for val in range(0,6): + xpos = start_pos + (val * delta) + self.doc.draw_line('TLG-grid', xpos, top_y, xpos, bottom_y) + + def draw_title(self): + """ + Draws the title for the page. + """ + width = self.doc.get_usable_width() + byline = _("Sorted by %s") % self.sort_name + title = _("Timeline Graph for %s") % self.filter.get_name() + self.doc.center_text('TLG-title', title + "\n" + byline, width / 2.0, 0) + def draw_year_headings(self, year_low, year_high, start_pos, stop_pos): + """ + Draws the column headings (years) for the page. + """ + style_sheet = self.doc.get_style_sheet() + label_font = style_sheet.get_paragraph_style('TLG-Label').get_font() + label_y = self.header - (pt2cm(label_font.get_size()) * 1.2) + top_y = self.header + bottom_y = self.doc.get_usable_height() incr = (year_high - year_low)/5 delta = (stop_pos - start_pos)/ 5 - for val in range(0,6): - year_str = str(year_low + (incr*val)) - xpos = start_pos+(val*delta) + year_str = str(year_low + (incr*val)) self.doc.center_text('TLG-label', year_str, xpos, label_y) - self.doc.draw_line('TLG-grid', xpos, top_y, xpos, bottom_y) + + def draw_no_date_heading(self): + """ + Draws a single heading that says "No Date Information" + """ + width = self.doc.get_usable_width() + style_sheet = self.doc.get_style_sheet() + label_font = style_sheet.get_paragraph_style('TLG-Label').get_font() + label_y = self.header - (pt2cm(label_font.get_size()) * 1.2) + self.doc.center_text('TLG-label', _("No Date Information"), + width / 2.0, label_y) def find_year_range(self): - low = 999999 - high = -999999 + """ + Finds the range of years that will be displayed on the chart. + + Returns a tuple of low and high years. If no dates are found, the + function returns (None, None). + """ + low = None + high = None + + def min_max_year(low, high, year): + if year is not None and year != 0: + if low is not None: + low = min(low, year) + else: + low = year + if high is not None: + high = max(high, year) + else: + high = year + return (low, high) - self.plist = self.filter.apply(self.database, - self.database.iter_person_handles()) - - self.calendar = config.get('preferences.calendar-format-report') + self._user.begin_progress(_('Timeline'), + _('Finding date range...'), + len(self.plist)) for p_id in self.plist: p = self.database.get_person_from_handle(p_id) birth = get_birth_or_fallback(self.database, p) if birth: b = birth.get_date_object().to_calendar(self.calendar).get_year() - else: - b = None + (low, high) = min_max_year(low, high, b) death = get_death_or_fallback(self.database, p) if death: d = death.get_date_object().to_calendar(self.calendar).get_year() - else: - d = None - - if b: - low = min(low,b) - high = max(high,b) - - if d: - low = min(low,d) - high = max(high,d) + (low, high) = min_max_year(low, high, d) + self._user.step_progress() # round the dates to the nearest decade - low = int((low/10))*10 - high = int(((high+9)/10))*10 + if low is not None: + low = int((low/10))*10 + else: + low = high + + if high is not None: + high = int(((high+9)/10))*10 + else: + high = low # Make sure the difference is a multiple of 50 so all year ranges land # on a decade. - low -= 50 - ((high-low) % 50) - - if low is None: - low = high - if high is None: - high = low + if low is not None and high is not None: + low -= 50 - ((high-low) % 50) + self._user.end_progress() return (low, high) def name_size(self):