From 289689ffa8b4b1e25c22d51ca80cbfe8f4f5986e Mon Sep 17 00:00:00 2001 From: Nick Hall Date: Fri, 5 Oct 2012 14:58:20 +0000 Subject: [PATCH] GEPS 008: Move book code svn: r20524 --- gramps/cli/arghandler.py | 31 +- gramps/cli/argparser.py | 2 +- gramps/cli/plug/__init__.py | 111 +++- gramps/gen/plug/report/__init__.py | 4 +- gramps/gen/plug/report/_book.py | 442 ++++++++++++++ .../bookreport.glade => gui/glade/book.glade} | 30 +- gramps/gui/plug/report/__init__.py | 1 + .../plug/report/_bookdialog.py} | 548 +----------------- gramps/gui/viewmanager.py | 18 +- gramps/plugins/bookreport.gpr.py | 43 -- 10 files changed, 631 insertions(+), 599 deletions(-) create mode 100644 gramps/gen/plug/report/_book.py rename gramps/{plugins/bookreport.glade => gui/glade/book.glade} (93%) rename gramps/{plugins/bookreport.py => gui/plug/report/_bookdialog.py} (67%) delete mode 100644 gramps/plugins/bookreport.gpr.py diff --git a/gramps/cli/arghandler.py b/gramps/cli/arghandler.py index c4b6309c4..3e2b290e3 100644 --- a/gramps/cli/arghandler.py +++ b/gramps/cli/arghandler.py @@ -47,13 +47,13 @@ from gramps.gen.ggettext import gettext as _ #------------------------------------------------------------------------- from gramps.gen.recentfiles import recent_files from gramps.gen.utils.file import (rm_tempdir, get_empty_tempdir, - get_unicode_path_from_env_var) + get_unicode_path_from_env_var) from gramps.gen.db import DbBsddb from clidbman import CLIDbManager, NAME_FILE, find_locker_name from gramps.gen.plug import BasePluginManager -from gramps.gen.plug.report import CATEGORY_BOOK, CATEGORY_CODE -from plug import cl_report +from gramps.gen.plug.report import CATEGORY_BOOK, CATEGORY_CODE, BookList +from plug import cl_report, cl_book from user import User #------------------------------------------------------------------------- @@ -665,6 +665,31 @@ class ArgHandler(object): else: print >> sys.stderr, " %s\t- %s" % (pdata.id, pdata.name.encode(sys.getfilesystemencoding())) + + elif action == "book": + try: + options_str_dict = _split_options(options_str) + except: + options_str_dict = {} + print >> sys.stderr, _("Ignoring invalid options string.") + + name = options_str_dict.pop('name', None) + book_list = BookList('books.xml', self.dbstate.db) + if name: + if name in book_list.get_book_names(): + cl_book(self.dbstate.db, name, book_list.get_book(name), + options_str_dict) + return + msg = _("Unknown book name.") + else: + msg = _("Book name not given. " + "Please use one of %(donottranslate)s=bookname.") % \ + {'donottranslate' : '[-p|--options] name'} + + print >> sys.stderr, _("%s\n Available names are:") % msg + for name in sorted(book_list.get_book_names()): + print >> sys.stderr, " %s" % name + else: print >> sys.stderr, _("Unknown action: %s.") % action sys.exit(0) diff --git a/gramps/cli/argparser.py b/gramps/cli/argparser.py index ef08b6d33..0b169df04 100644 --- a/gramps/cli/argparser.py +++ b/gramps/cli/argparser.py @@ -272,7 +272,7 @@ class ArgParser(object): self.exports.append((value, family_tree_format)) elif option in ( '-a', '--action' ): action = value - if action not in ( 'report', 'tool' ): + if action not in ('report', 'tool', 'book'): print >> sys.stderr, "Unknown action: %s. Ignoring." % action continue options_str = "" diff --git a/gramps/cli/plug/__init__.py b/gramps/cli/plug/__init__.py index ec43416f2..3c98d200a 100644 --- a/gramps/cli/plug/__init__.py +++ b/gramps/cli/plug/__init__.py @@ -54,9 +54,10 @@ from gramps.gen.plug.menu import (FamilyOption, PersonOption, NoteOption, BooleanOption, DestinationOption, StringOption, TextOption, EnumeratedListOption, Option) from gramps.gen.display.name import displayer as name_displayer -from gramps.gen.errors import ReportError +from gramps.gen.errors import ReportError, FilterError from gramps.gen.plug.report import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK, - CATEGORY_GRAPHVIZ, CATEGORY_CODE) + CATEGORY_GRAPHVIZ, CATEGORY_CODE, + ReportOptions) from gramps.gen.plug.report._paper import paper_sizes from gramps.gen.const import USER_HOME from gramps.gen.dbstate import DbState @@ -650,3 +651,109 @@ def run_report(db, name, **options_str_dict): options_str_dict) return clr return clr + +#------------------------------------------------------------------------ +# +# Function to write books from command line +# +#------------------------------------------------------------------------ +def cl_book(database, name, book, options_str_dict): + + clr = CommandLineReport(database, name, CATEGORY_BOOK, + ReportOptions, options_str_dict) + + # Exit here if show option was given + if clr.show: + return + + selected_style = StyleSheet() + + for item in book.get_item_list(): + handler = item.option_class.handler + + # Set up default style + handler.set_default_stylesheet_name(item.get_style_name()) + default_style = StyleSheet() + make_default_style = item.option_class.make_default_style + make_default_style(default_style) + + # Read all style sheets available for this item + style_file = handler.get_stylesheet_savefile() + style_list = StyleSheetList(style_file, default_style) + + # Get the selected stylesheet + style_name = handler.get_default_stylesheet_name() + style_sheet = style_list.get_style_sheet(style_name) + + for this_style_name in style_sheet.get_paragraph_style_names(): + selected_style.add_paragraph_style( + this_style_name, + style_sheet.get_paragraph_style(this_style_name)) + + for this_style_name in style_sheet.get_draw_style_names(): + selected_style.add_draw_style( + this_style_name, + style_sheet.get_draw_style(this_style_name)) + + for this_style_name in style_sheet.get_table_style_names(): + selected_style.add_table_style( + this_style_name, + style_sheet.get_table_style(this_style_name)) + + for this_style_name in style_sheet.get_cell_style_names(): + selected_style.add_cell_style( + this_style_name, + style_sheet.get_cell_style(this_style_name)) + + # The option values were loaded magically by the book parser. + # But they still need to be applied to the menu options. + opt_dict = item.option_class.options_dict + menu = item.option_class.menu + for optname in opt_dict: + menu_option = menu.get_option_by_name(optname) + if menu_option: + menu_option.set_value(opt_dict[optname]) + + # write report + doc = clr.format(selected_style, + PaperStyle(clr.paper, clr.orien, clr.marginl, + clr.marginr, clr.margint, clr.marginb)) + user = User() + rptlist = [] + for item in book.get_item_list(): + item.option_class.set_document(doc) + report_class = item.get_write_item() + obj = write_book_item(database, + report_class, item.option_class, user) + rptlist.append(obj) + + doc.open(clr.option_class.get_output()) + doc.init() + newpage = 0 + for item in rptlist: + if newpage: + doc.page_break() + newpage = 1 + item.begin_report() + item.write_report() + doc.close() + +#------------------------------------------------------------------------ +# +# Generic task function for book +# +#------------------------------------------------------------------------ +def write_book_item(database, report_class, options, user): + """Write the report using options set. + All user dialog has already been handled and the output file opened.""" + try: + return report_class(database, options, user) + except ReportError, msg: + (m1, m2) = msg.messages() + print "ReportError", m1, m2 + except FilterError, msg: + (m1, m2) = msg.messages() + print "FilterError", m1, m2 + except: + log.error("Failed to write book item.", exc_info=True) + return None diff --git a/gramps/gen/plug/report/__init__.py b/gramps/gen/plug/report/__init__.py index 1c5c5ae76..a83124d43 100644 --- a/gramps/gen/plug/report/__init__.py +++ b/gramps/gen/plug/report/__init__.py @@ -32,4 +32,6 @@ from _reportbase import Report from _bibliography import Bibliography, Citation -from _options import MenuReportOptions +from _options import MenuReportOptions, ReportOptions + +from _book import BookList, Book, BookItem diff --git a/gramps/gen/plug/report/_book.py b/gramps/gen/plug/report/_book.py new file mode 100644 index 000000000..645b58252 --- /dev/null +++ b/gramps/gen/plug/report/_book.py @@ -0,0 +1,442 @@ +# +# 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 +# Copyright (C) 2011-2012 Paul Franklin +# +# 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 ...ggettext import gettext as _ + +#------------------------------------------------------------------------ +# +# Set up logging +# +#------------------------------------------------------------------------ +import logging +log = logging.getLogger(".Book") +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 + +#------------------------------------------------------------------------- +# +# gramps modules +# +#------------------------------------------------------------------------- +from ...const import HOME_DIR +from ...utils.cast import get_type_converter_by_name, type_name +from .. import BasePluginManager +from . import book_categories + +#------------------------------------------------------------------------ +# +# Private Constants +# +#------------------------------------------------------------------------ +_UNSUPPORTED = _("Unsupported") + +#------------------------------------------------------------------------ +# +# 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 = BasePluginManager.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(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, sorted" + return sorted(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 sorted(self.bookmap): # enable a diff of archived copies + 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 = type_name(option_value) + value = escape(unicode(option_value)) + value = value.replace('"', '"') + f.write('