# # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2003-2007 Donald N. Allingham # Copyright (C) 2007-2008 Brian G. Matherly # Copyright (C) 2010 Jakim Friant # # 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 # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # $Id$ # Written by Alex Roitman, # largely based on the BaseDoc classes by Don Allingham #------------------------------------------------------------------------- # # Standard Python modules # #------------------------------------------------------------------------- from gen.ggettext import gettext as _ #------------------------------------------------------------------------ # # Set up logging # #------------------------------------------------------------------------ import logging log = logging.getLogger(".BookReport") import os #------------------------------------------------------------------------- # # SAX interface # #------------------------------------------------------------------------- try: from xml.sax import make_parser, handler, SAXParseException from xml.sax.saxutils import escape except: from _xmlplus.sax import make_parser, handler, SAXParseException from _xmlplus.sax.saxutils import escape #------------------------------------------------------------------------- # # GTK/Gnome modules # #------------------------------------------------------------------------- import gtk import gobject #------------------------------------------------------------------------- # # gramps modules # #------------------------------------------------------------------------- import const import Utils import ListModel import Errors from gui.pluginmanager import GuiPluginManager from gen.plug.docgen import StyleSheet, StyleSheetList from QuestionDialog import WarningDialog, ErrorDialog from gen.plug.menu import PersonOption, FilterOption, FamilyOption import ManagedWindow from glade import Glade from gui.utils import open_file_with_default_application # Import from specific modules in ReportBase from gen.plug.report import CATEGORY_BOOK, book_categories from gui.plug.report._reportdialog import ReportDialog from gui.plug.report._docreportdialog import DocReportDialog from gen.plug.report._options import ReportOptions from cli.plug import CommandLineReport from gen.display.name import displayer as _nd #------------------------------------------------------------------------ # # Private Constants # #------------------------------------------------------------------------ _UNSUPPORTED = _("Unsupported") #------------------------------------------------------------------------ # # Private Functions # #------------------------------------------------------------------------ def _initialize_options(options, dbstate, uistate): """ Validates all options by making sure that their values are consistent with the database. menu: The Menu class dbase: the database the options will be applied to """ if not hasattr(options, "menu"): return dbase = dbstate.get_database() menu = options.menu for name in menu.get_all_option_names(): option = menu.get_option_by_name(name) value = option.get_value() if isinstance(option, PersonOption): if not dbase.get_person_from_gramps_id(value): person_handle = uistate.get_active('Person') person = dbase.get_person_from_handle(person_handle) option.set_value(person.get_gramps_id()) elif isinstance(option, FamilyOption): if not dbase.get_family_from_gramps_id(value): person_handle = uistate.get_active('Person') person = dbase.get_person_from_handle(person_handle) family_list = person.get_family_handle_list() if family_list: family_handle = family_list[0] else: family_handle = dbase.iter_family_handles().next() family = dbase.get_family_from_handle(family_handle) option.set_value(family.get_gramps_id()) def _get_subject(options, dbase): """ Attempts to determine the subject of a set of options. The subject would likely be a person (using a PersonOption) or a filter (using a FilterOption) options: The ReportOptions class dbase: the database for which it corresponds """ if not hasattr(options, "menu"): return _("Not Applicable") menu = options.menu option_names = menu.get_all_option_names() for name in option_names: option = menu.get_option_by_name(name) if isinstance(option, FilterOption): return option.get_filter().get_name() elif isinstance(option, PersonOption): gid = option.get_value() person = dbase.get_person_from_gramps_id(gid) return _nd.display(person) elif isinstance(option, FamilyOption): family = dbase.get_family_from_gramps_id(option.get_value()) family_id = family.get_gramps_id() fhandle = family.get_father_handle() mhandle = family.get_mother_handle() if fhandle: father = dbase.get_person_from_handle(fhandle) father_name = _nd.display(father) else: father_name = _("unknown father") if mhandle: mother = dbase.get_person_from_handle(mhandle) mother_name = _nd.display(mother) else: mother_name = _("unknown mother") name = _("%(father)s and %(mother)s (%(id)s)") % { 'father' : father_name, 'mother' : mother_name, 'id' : family_id } return name return _("Not Applicable") #------------------------------------------------------------------------ # # Book Item class # #------------------------------------------------------------------------ class BookItem(object): """ Interface into the book item -- a smallest element of the book. """ def __init__(self, dbase, name): """ Create a new empty BookItem. name: the book item is retrieved from the book item registry using name for lookup """ self.dbase = dbase self.style_name = "default" pmgr = GuiPluginManager.get_instance() for pdata in pmgr.get_reg_bookitems(): if pdata.id == name: self.translated_name = pdata.name if not pdata.supported: self.category = _UNSUPPORTED else: self.category = book_categories[pdata.category] mod = pmgr.load_plugin(pdata) self.write_item = eval('mod.' + pdata.reportclass) self.name = pdata.id oclass = eval('mod.' + pdata.optionclass) self.option_class = oclass(self.name, self.dbase) self.option_class.load_previous_values() def get_name(self): """ Return the name of the item. """ return self.name def get_translated_name(self): """ Return the translated name of the item. """ return self.translated_name def get_category(self): """ Return the category of the item. """ return self.category def get_write_item(self): """ Return the report-writing function of the item. """ return self.write_item def set_style_name(self, style_name): """ Set the style name for the item. style_name: name of the style to set. """ self.style_name = style_name def get_style_name(self): """ Return the style name of the item. """ return self.style_name #------------------------------------------------------------------------ # # Book class # #------------------------------------------------------------------------ class Book(object): """ Interface into the user-defined book -- a collection of book items. """ def __init__(self, obj=None): """ Create a new empty Book. obj: if not None, creates the Book from the values in obj, instead of creating an empty Book. """ self.name = "" self.dbname = "" if obj: self.item_list = obj.item_list else: self.item_list = [] def set_name(self, name): """ Set the name of the book. name: the name to set. """ self.name = name def get_name(self): """ Return the name of the book. """ return self.name def get_dbname(self): """ Return the name of the database file used for the book. """ return self.dbname def set_dbname(self, name): """ Set the name of the database file used for the book. name: a filename to set. """ self.dbname = name def clear(self): """ Clears the contents of the book. """ self.item_list = [] def append_item(self, item): """ Add an item to the book. item: an item to append. """ self.item_list.append(item) def insert_item(self, index, item): """ Inserts an item into the given position in the book. index: a position index. item: an item to append. """ self.item_list.insert(index, item) def pop_item(self, index): """ Pop an item from given position in the book. index: a position index. """ return self.item_list.pop(index) def get_item(self, index): """ Return an item at a given position in the book. index: a position index. """ return self.item_list[index] def set_item(self, index, item): """ Set an item at a given position in the book. index: a position index. item: an item to set. """ self.item_list[index] = item def get_item_list(self): """ Return list of items in the current book. """ return self.item_list #------------------------------------------------------------------------ # # BookList class # #------------------------------------------------------------------------ class BookList(object): """ Interface into the user-defined list of books. BookList is loaded from a specified XML file if it exists. """ def __init__(self, filename, dbase): """ Create a new BookList from the books that may be defined in the specified file. file: XML file that contains book items definitions """ self.dbase = dbase self.bookmap = {} self.file = os.path.join(const.HOME_DIR, filename) self.parse() def delete_book(self, name): """ Remove a book from the list. Since each book must have a unique name, the name is used to delete the book. name: name of the book to delete """ del self.bookmap[name] def get_book_map(self): """ Return the map of names to books. """ return self.bookmap def get_book(self, name): """ Return the Book associated with the name name: name associated with the desired Book. """ return self.bookmap[name] def get_book_names(self): "Return a list of all the book names in the BookList" return self.bookmap.keys() def set_book(self, name, book): """ Add or replaces a Book in the BookList. name: name associated with the Book to add or replace. book: definition of the Book """ self.bookmap[name] = book def save(self): """ Saves the current BookList to the associated file. """ f = open(self.file, "w") f.write("\n") f.write('\n') for name in self.bookmap: book = self.get_book(name) dbname = book.get_dbname() f.write('\n' % (name, dbname) ) for item in book.get_item_list(): f.write(' \n' % (item.get_name(),item.get_translated_name() ) ) options = item.option_class.handler.options_dict for option_name, option_value in options.iteritems(): if isinstance(option_value, (list, tuple)): f.write(' \n') else: option_type = Utils.type_name(option_value) value = escape(unicode(option_value)) value = value.replace('"', '"') f.write('