GEPS 008: Move book code

svn: r20524
This commit is contained in:
Nick Hall 2012-10-05 14:58:20 +00:00
parent c8baa0fcb6
commit 289689ffa8
10 changed files with 631 additions and 599 deletions

View File

@ -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)

View File

@ -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 = ""

View File

@ -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

View File

@ -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

View File

@ -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("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
f.write('<booklist>\n')
for name in sorted(self.bookmap): # enable a diff of archived copies
book = self.get_book(name)
dbname = book.get_dbname()
f.write('<book name="%s" database="%s">\n' % (name, dbname) )
for item in book.get_item_list():
f.write(' <item name="%s" trans_name="%s">\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(' <option name="%s" value="" '
'length="%d">\n' % (
escape(option_name),
len(options[option_name]) ) )
for list_index in range(len(option_value)):
option_type = type_name(option_value[list_index])
value = escape(unicode(option_value[list_index]))
value = value.replace('"', '&quot;')
f.write(' <listitem number="%d" type="%s" '
'value="%s"/>\n' % (
list_index,
option_type,
value ) )
f.write(' </option>\n')
else:
option_type = type_name(option_value)
value = escape(unicode(option_value))
value = value.replace('"', '&quot;')
f.write(' <option name="%s" type="%s" '
'value="%s"/>\n' % (
escape(option_name),
option_type,
value) )
f.write(' <style name="%s"/>\n' % item.get_style_name() )
f.write(' </item>\n')
f.write('</book>\n')
f.write('</booklist>\n')
f.close()
def parse(self):
"""
Loads the BookList from the associated file, if it exists.
"""
try:
p = make_parser()
p.setContentHandler(BookParser(self, self.dbase))
the_file = open(self.file)
p.parse(the_file)
the_file.close()
except (IOError, OSError, ValueError, SAXParseException, KeyError,
AttributeError):
pass
#-------------------------------------------------------------------------
#
# BookParser
#
#-------------------------------------------------------------------------
class BookParser(handler.ContentHandler):
"""
SAX parsing class for the Books XML file.
"""
def __init__(self, booklist, dbase):
"""
Create a BookParser class that populates the passed booklist.
booklist: BookList to be loaded from the file.
"""
handler.ContentHandler.__init__(self)
self.dbase = dbase
self.booklist = booklist
self.b = None
self.i = None
self.o = None
self.an_o_name = None
self.an_o_value = None
self.s = None
self.bname = None
self.iname = None
def startElement(self, tag, attrs):
"""
Overridden class that handles the start of a XML element
"""
if tag == "book":
self.b = Book()
self.bname = attrs['name']
self.b.set_name(self.bname)
self.dbname = attrs['database']
self.b.set_dbname(self.dbname)
elif tag == "item":
self.i = BookItem(self.dbase, attrs['name'])
self.o = {}
elif tag == "option":
self.an_o_name = attrs['name']
if attrs.has_key('length'):
self.an_o_value = []
else:
converter = get_type_converter_by_name(attrs['type'])
self.an_o_value = converter(attrs['value'])
elif tag == "listitem":
converter = get_type_converter_by_name(attrs['type'])
self.an_o_value.append(converter(attrs['value']))
elif tag == "style":
self.s = attrs['name']
else:
pass
def endElement(self, tag):
"Overridden class that handles the end of a XML element"
if tag == "option":
self.o[self.an_o_name] = self.an_o_value
elif tag == "item":
self.i.option_class.handler.options_dict.update(self.o)
self.i.set_style_name(self.s)
self.b.append_item(self.i)
elif tag == "book":
self.booklist.set_book(self.bname, self.b)

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<object class="GtkDialog" id="bookreport">
<object class="GtkDialog" id="book">
<property name="height_request">300</property>
<property name="can_focus">False</property>
<property name="type_hint">normal</property>
@ -17,12 +17,10 @@
<child>
<object class="GtkButton" id="delete_button">
<property name="label">gtk-delete</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_booklist_delete_clicked" object="top" swapped="yes"/>
</object>
@ -35,12 +33,10 @@
<child>
<object class="GtkButton" id="close_button">
<property name="label">gtk-close</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_booklist_cancel_clicked" object="top" swapped="yes"/>
</object>
@ -53,12 +49,10 @@
<child>
<object class="GtkButton" id="ok_button">
<property name="label">gtk-ok</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_booklist_ok_clicked" object="top" swapped="yes"/>
</object>
@ -209,13 +203,11 @@
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="button61">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Clear the book</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_clear_clicked" swapped="no"/>
<child>
<object class="GtkImage" id="image33">
@ -233,13 +225,11 @@
</child>
<child>
<object class="GtkButton" id="button62">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Save current set of configured selections</property>
<property name="use_action_appearance">False</property>
<accelerator key="r" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<signal name="clicked" handler="on_save_clicked" swapped="no"/>
<child>
@ -258,13 +248,11 @@
</child>
<child>
<object class="GtkButton" id="button63">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Open previously created book</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_open_clicked" swapped="no"/>
<child>
<object class="GtkImage" id="image35">
@ -282,13 +270,11 @@
</child>
<child>
<object class="GtkButton" id="button64">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Manage previously created books</property>
<property name="use_action_appearance">False</property>
<accelerator key="s" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<signal name="clicked" handler="on_edit_clicked" swapped="no"/>
<child>
@ -444,13 +430,11 @@
<property name="spacing">2</property>
<child>
<object class="GtkButton" id="button52">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Add an item to the book</property>
<property name="use_action_appearance">False</property>
<accelerator key="a" signal="activate" modifiers="GDK_CONTROL_MASK"/>
<signal name="clicked" handler="on_add_clicked" swapped="no"/>
<child>
@ -469,13 +453,11 @@
</child>
<child>
<object class="GtkButton" id="button53">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Remove currently selected item from the book</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_remove_clicked" swapped="no"/>
<child>
<object class="GtkImage" id="image25">
@ -493,13 +475,11 @@
</child>
<child>
<object class="GtkButton" id="button54">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Move current selection one step up in the book</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_up_clicked" swapped="no"/>
<child>
<object class="GtkImage" id="image26">
@ -517,13 +497,11 @@
</child>
<child>
<object class="GtkButton" id="button55">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Move current selection one step down in the book</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_down_clicked" swapped="no"/>
<child>
<object class="GtkImage" id="image27">
@ -541,13 +519,11 @@
</child>
<child>
<object class="GtkButton" id="button56">
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="tooltip_text" translatable="yes">Configure currently selected item</property>
<property name="use_action_appearance">False</property>
<signal name="clicked" handler="on_setup_clicked" swapped="no"/>
<child>
<object class="GtkImage" id="image28">
@ -598,12 +574,10 @@
<child>
<object class="GtkButton" id="button12">
<property name="label">gtk-close</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="destroy_passed_object" object="top" swapped="yes"/>
</object>
@ -616,12 +590,10 @@
<child>
<object class="GtkButton" id="button13">
<property name="label">gtk-ok</property>
<property name="use_action_appearance">False</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="receives_default">False</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
<signal name="clicked" handler="on_book_ok_clicked" swapped="no"/>
</object>

View File

@ -30,3 +30,4 @@
from _reportdialog import report
from _drawreportdialog import DrawReportDialog
from _textreportdialog import TextReportDialog
from _bookdialog import BookSelector

View File

@ -39,20 +39,7 @@ from gramps.gen.ggettext import gettext as _
#
#------------------------------------------------------------------------
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
log = logging.getLogger(".Book")
#-------------------------------------------------------------------------
#
@ -68,28 +55,25 @@ from gi.repository import GObject
# gramps modules
#
#-------------------------------------------------------------------------
from gramps.gen.const import HOME_DIR
from gramps.gen.utils.cast import get_type_converter_by_name, type_name
from gramps.gui.listmodel import ListModel
from ...listmodel import ListModel
from gramps.gen.errors import FilterError, ReportError
from gramps.gui.pluginmanager import GuiPluginManager
from gramps.gen.plug.docgen import StyleSheet, StyleSheetList, PaperStyle
from gramps.gui.dialog import WarningDialog, ErrorDialog
from ...pluginmanager import GuiPluginManager
from gramps.gen.plug.docgen import StyleSheet, StyleSheetList
from ...dialog import WarningDialog, ErrorDialog
from gramps.gen.plug.menu import PersonOption, FilterOption, FamilyOption
from gramps.gui.managedwindow import ManagedWindow, set_titles
from gramps.gui.glade import Glade
from gramps.gui.utils import is_right_click, open_file_with_default_application
from gramps.gui.user import User
from gramps.gui.plug import make_gui_option
from ...managedwindow import ManagedWindow, set_titles
from ...glade import Glade
from ...utils import is_right_click, open_file_with_default_application
from ...user import User
from .. import make_gui_option
from types import ClassType
# Import from specific modules in ReportBase
from gramps.gen.plug.report import BookList, Book, BookItem
from gramps.gen.plug.report import CATEGORY_BOOK, book_categories
from gramps.gui.plug.report._reportdialog import ReportDialog
from gramps.gui.plug.report._docreportdialog import DocReportDialog
from gramps.gen.plug.report._options import ReportOptions
from gramps.cli.plug import CommandLineReport
from gramps.cli.user import User
from _reportdialog import ReportDialog
from _docreportdialog import DocReportDialog
from gramps.gen.display.name import displayer as _nd
@ -202,376 +186,6 @@ def _get_subject(options, dbase):
return ""
#------------------------------------------------------------------------
#
# 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(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("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
f.write('<booklist>\n')
for name in sorted(self.bookmap): # enable a diff of archived copies
book = self.get_book(name)
dbname = book.get_dbname()
f.write('<book name="%s" database="%s">\n' % (name, dbname) )
for item in book.get_item_list():
f.write(' <item name="%s" trans_name="%s">\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(' <option name="%s" value="" '
'length="%d">\n' % (
escape(option_name),
len(options[option_name]) ) )
for list_index in range(len(option_value)):
option_type = type_name(option_value[list_index])
value = escape(unicode(option_value[list_index]))
value = value.replace('"', '&quot;')
f.write(' <listitem number="%d" type="%s" '
'value="%s"/>\n' % (
list_index,
option_type,
value ) )
f.write(' </option>\n')
else:
option_type = type_name(option_value)
value = escape(unicode(option_value))
value = value.replace('"', '&quot;')
f.write(' <option name="%s" type="%s" '
'value="%s"/>\n' % (
escape(option_name),
option_type,
value) )
f.write(' <style name="%s"/>\n' % item.get_style_name() )
f.write(' </item>\n')
f.write('</book>\n')
f.write('</booklist>\n')
f.close()
def parse(self):
"""
Loads the BookList from the associated file, if it exists.
"""
try:
p = make_parser()
p.setContentHandler(BookParser(self, self.dbase))
the_file = open(self.file)
p.parse(the_file)
the_file.close()
except (IOError, OSError, ValueError, SAXParseException, KeyError,
AttributeError):
pass
#-------------------------------------------------------------------------
#
# BookParser
#
#-------------------------------------------------------------------------
class BookParser(handler.ContentHandler):
"""
SAX parsing class for the Books XML file.
"""
def __init__(self, booklist, dbase):
"""
Create a BookParser class that populates the passed booklist.
booklist: BookList to be loaded from the file.
"""
handler.ContentHandler.__init__(self)
self.dbase = dbase
self.booklist = booklist
self.b = None
self.i = None
self.o = None
self.an_o_name = None
self.an_o_value = None
self.s = None
self.bname = None
self.iname = None
def startElement(self, tag, attrs):
"""
Overridden class that handles the start of a XML element
"""
if tag == "book":
self.b = Book()
self.bname = attrs['name']
self.b.set_name(self.bname)
self.dbname = attrs['database']
self.b.set_dbname(self.dbname)
elif tag == "item":
self.i = BookItem(self.dbase, attrs['name'])
self.o = {}
elif tag == "option":
self.an_o_name = attrs['name']
if attrs.has_key('length'):
self.an_o_value = []
else:
converter = get_type_converter_by_name(attrs['type'])
self.an_o_value = converter(attrs['value'])
elif tag == "listitem":
converter = get_type_converter_by_name(attrs['type'])
self.an_o_value.append(converter(attrs['value']))
elif tag == "style":
self.s = attrs['name']
else:
pass
def endElement(self, tag):
"Overridden class that handles the end of a XML element"
if tag == "option":
self.o[self.an_o_name] = self.an_o_value
elif tag == "item":
self.i.option_class.handler.options_dict.update(self.o)
self.i.set_style_name(self.s)
self.b.append_item(self.i)
elif tag == "book":
self.booklist.set_book(self.bname, self.b)
#------------------------------------------------------------------------
#
# BookList Display class
@ -595,7 +209,7 @@ class BookListDisplay(object):
self.booklist = booklist
self.dosave = dosave
self.xml = Glade()
self.xml = Glade('book.glade')
self.top = self.xml.toplevel
self.unsaved_changes = False
@ -666,7 +280,7 @@ class BookListDisplay(object):
def on_booklist_cancel_clicked(self, obj):
if self.unsaved_changes:
from gramps.gui.dialog import QuestionDialog2
from ...dialog import QuestionDialog2
q = QuestionDialog2(
_('Discard Unsaved Changes'),
_('You have made changes which have not been saved.'),
@ -682,7 +296,7 @@ class BookListDisplay(object):
#------------------------------------------------------------------------
#
#
# Book Options
#
#------------------------------------------------------------------------
class BookOptions(ReportOptions):
@ -709,7 +323,7 @@ class BookOptions(ReportOptions):
# Book creation dialog
#
#-------------------------------------------------------------------------
class BookReportSelector(ManagedWindow):
class BookSelector(ManagedWindow):
"""
Interface into a dialog setting up the book.
@ -721,12 +335,12 @@ class BookReportSelector(ManagedWindow):
self.db = dbstate.db
self.dbstate = dbstate
self.uistate = uistate
self.title = _('Book Report')
self.title = _('Book')
self.file = "books.xml"
ManagedWindow.__init__(self, uistate, [], self.__class__)
self.xml = Glade(toplevel="top")
self.xml = Glade('book.glade', toplevel="top")
window = self.xml.toplevel
title_label = self.xml.get_object('title')
@ -1002,7 +616,7 @@ class BookReportSelector(ManagedWindow):
(Gtk.STOCK_CLEAR, self.on_clear_clicked, 1),
(Gtk.STOCK_SAVE, self.on_save_clicked, 1),
(Gtk.STOCK_OPEN, self.on_open_clicked, 1),
(_("Edit"), self.on_edit_clicked,1 ),
(_("Edit"), self.on_edit_clicked, 1),
]
menu = Gtk.Menu()
@ -1041,10 +655,10 @@ class BookReportSelector(ManagedWindow):
def on_book_ok_clicked(self, obj):
"""
Run final BookReportDialog with the current book.
Run final BookDialog with the current book.
"""
if self.book.item_list:
BookReportDialog(self.dbstate, self.uistate,
BookDialog(self.dbstate, self.uistate,
self.book, BookOptions)
else:
WarningDialog(_('No items'), _('This book has no items.'))
@ -1064,7 +678,7 @@ class BookReportSelector(ManagedWindow):
)
return
if name in self.book_list.get_book_names():
from gramps.gui.dialog import QuestionDialog2
from ...dialog import QuestionDialog2
q = QuestionDialog2(
_('Book name already exists'),
_('You are about to save away a '
@ -1230,7 +844,7 @@ class _BookFormatComboBox(Gtk.ComboBox):
# The final dialog - paper, format, target, etc.
#
#------------------------------------------------------------------------
class BookReportDialog(DocReportDialog):
class BookDialog(DocReportDialog):
"""
A usual Report.Dialog subclass.
@ -1244,7 +858,7 @@ class BookReportDialog(DocReportDialog):
self.page_html_added = False
self.book = book
DocReportDialog.__init__(self, dbstate, uistate, options,
'book', _("Book Report"))
'book', _("Book"))
self.options.options_dict['bookname'] = self.book.name
self.database = dbstate.db
self.selected_style = StyleSheet()
@ -1285,8 +899,8 @@ class BookReportDialog(DocReportDialog):
response = self.window.run()
if response == Gtk.ResponseType.OK:
try:
self.make_report()
except (IOError,OSError),msg:
self.make_book()
except (IOError, OSError),msg:
ErrorDialog(str(msg))
self.close()
@ -1295,7 +909,7 @@ class BookReportDialog(DocReportDialog):
def parse_style_frame(self): pass
def get_title(self):
return _("Book Report")
return _("Book")
def get_header(self, name):
return _("Gramps Book")
@ -1320,8 +934,8 @@ class BookReportDialog(DocReportDialog):
self.rptlist.append(obj)
self.doc.open(self.target_path)
def make_report(self):
"""The actual book report. Start it out, then go through the item list
def make_book(self):
"""The actual book. Start it out, then go through the item list
and call each item's write_book_item method."""
self.doc.init()
@ -1350,107 +964,7 @@ class BookReportDialog(DocReportDialog):
#------------------------------------------------------------------------
#
# Function to write books from command line
#
#------------------------------------------------------------------------
def cl_report(database, name, category, options_str_dict):
clr = CommandLineReport(database, name, category,
BookOptions, options_str_dict)
# Exit here if show option was given
if clr.show:
return
if 'bookname' not in clr.options_dict or not clr.options_dict['bookname']:
print _("Please specify a book name")
return
book_list = BookList('books.xml', database)
book_name = clr.options_dict['bookname']
if book_name:
if book_name not in book_list.get_book_names():
print _("No such book '%s'") % book_name
return
book = book_list.get_book(book_name)
else:
print _("Please specify a book name")
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 report
# Generic task function for book
#
#------------------------------------------------------------------------
def write_book_item(database, report_class, options, user):

View File

@ -72,7 +72,7 @@ from gramps.gen.plug import (START, END)
from gramps.gen.plug import REPORT
from gramps.gen.plug.report._constants import standalone_categories
from .plug import (PluginWindows, ReportPluginDialog, ToolPluginDialog)
from .plug.report import report
from .plug.report import report, BookSelector
from gramps.gen.plug.utils import version_str_to_tup, load_addon_file
from .pluginmanager import GuiPluginManager
from gramps.gen.relationship import get_relationship_calculator
@ -165,8 +165,12 @@ UIDEFAULT = '''<ui>
<placeholder name="GoToBook"/>
</menu>
<menu action="ReportsMenu">
<menuitem action="Books"/>
<separator/>
<placeholder name="P_ReportsMenu"/>
</menu>
<menu action="ToolsMenu">
<placeholder name="P_ToolsMenu"/>
</menu>
<menu action="WindowsMenu">
<placeholder name="WinMenu"/>
@ -781,6 +785,7 @@ class ViewManager(CLIManager):
_("Open the reports dialog"), self.reports_clicked),
('GoMenu', None, _('_Go')),
('ReportsMenu', None, _('_Reports')),
('Books', None, _('Books...'), None, None, self.run_book),
('WindowsMenu', None, _('_Windows')),
('F2', None, 'F2', "F2", None, self.__keypress),
('F3', None, 'F3', "F3", None, self.__keypress),
@ -855,6 +860,12 @@ class ViewManager(CLIManager):
_('Undo History...'), "<PRIMARY>H", None, self.undo_history),
]
def run_book(self, action):
"""
Run a book.
"""
BookSelector(self.dbstate, self.uistate)
def __keypress(self, action):
"""
Callback that is called on a keypress. It works by extracting the
@ -1757,7 +1768,8 @@ class ViewManager(CLIManager):
"""
actions = []
ofile = StringIO()
ofile.write('<ui><menubar name="MenuBar"><menu action="%s">' % text)
ofile.write('<ui><menubar name="MenuBar"><menu action="%s">'
'<placeholder name="%s">' % (text, 'P_'+ text))
menu = Gtk.Menu()
menu.show()
@ -1804,7 +1816,7 @@ class ViewManager(CLIManager):
func(pdata, self.dbstate, self.uistate)))
ofile.write('</menu>')
ofile.write('</menu></menubar></ui>')
ofile.write('</placeholder></menu></menubar></ui>')
return (ofile.getvalue(), actions)
def display_about_box(self, obj):

View File

@ -1,43 +0,0 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2009 Benny Malengier
#
# 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$
#------------------------------------------------------------------------
#
# Book plugin
#
#------------------------------------------------------------------------
register(REPORT,
id = 'book',
name = _("Book Report"),
description = _("Produces a book containing several reports."),
version = '1.0',
gramps_target_version = '4.0',
status = STABLE,
fname = 'bookreport.py',
authors = ["Alex Roitman"],
authors_email = ["shura@gramps-project.org"],
category = CATEGORY_BOOK,
reportclass = 'BookReportSelector',
optionclass = 'cl_report',
report_modes = [REPORT_MODE_GUI, REPORT_MODE_CLI]
)