diff --git a/po/POTFILES.in b/po/POTFILES.in index 62c53ba7f..dd1a2db3a 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -341,7 +341,6 @@ src/PluginUtils/_PluginWindows.py src/PluginUtils/_MenuOptions.py # ReportBase package -src/ReportBase/_BareReportDialog.py src/ReportBase/_BookFormatComboBox.py src/ReportBase/_CommandLineReport.py src/ReportBase/_Constants.py diff --git a/src/ManagedWindow.py b/src/ManagedWindow.py index 4994f3680..cf2d52630 100644 --- a/src/ManagedWindow.py +++ b/src/ManagedWindow.py @@ -425,7 +425,7 @@ class ManagedWindow: Connect the OK button to a method that checks if all is ok, Do not call close, close is called here. (if not ok, do self.window.run() to obtain new response ) - TODO: remove close here and do close in BareReportDialog, + TODO: remove close here and do close in ReportDialog, this can only be done, once all methods use modal_call() instead of their own implementation Connect Cancel to do close, delete event is connected to close diff --git a/src/PluginUtils/_Options.py b/src/PluginUtils/_Options.py index fb74f6cc3..8afb59a6c 100644 --- a/src/PluginUtils/_Options.py +++ b/src/PluginUtils/_Options.py @@ -445,7 +445,7 @@ class Options: Set up UI controls (widgets) for the options specific for this modul. This method MUST be overridden by modules that define new options. - The single argument 'dialog' is the Report.BareReportDialog instance. + The single argument 'dialog' is the Report.ReportDialog instance. Any attribute of the dialog is available. After the widgets are defined, they MUST be added to the dialog @@ -463,7 +463,7 @@ class Options: Parses UI controls (widgets) for the options specific for this module. This method MUST be overridden by modules that define new options. - The single argument 'dialog' is the Report.BareReportDialog instance. + The single argument 'dialog' is the Report.ReportDialog instance. Any attribute of the dialog is available. After obtaining values from the widgets, they MUST be used to set the diff --git a/src/PluginUtils/_PluginWindows.py b/src/PluginUtils/_PluginWindows.py index 0ffc732b6..f86c5c306 100644 --- a/src/PluginUtils/_PluginWindows.py +++ b/src/PluginUtils/_PluginWindows.py @@ -195,7 +195,6 @@ class ToolManagedWindowBase(ManagedWindow.ManagedWindow): """ Copied from src/ReportBase/_BareReportDialog.py BareReportDialog """ - frame_pad = 5 border_pad = 6 HELP_TOPIC = None def __init__(self, dbstate, uistate, option_class, name, callback=None): diff --git a/src/ReportBase/Makefile.am b/src/ReportBase/Makefile.am index 82a67b861..762ee899d 100644 --- a/src/ReportBase/Makefile.am +++ b/src/ReportBase/Makefile.am @@ -4,7 +4,6 @@ pkgdatadir = $(datadir)/@PACKAGE@/ReportBase pkgdata_PYTHON = \ __init__.py\ - _BareReportDialog.py\ _Bibliography.py\ _BookFormatComboBox.py\ _CommandLineReport.py\ diff --git a/src/ReportBase/_BareReportDialog.py b/src/ReportBase/_BareReportDialog.py deleted file mode 100644 index 47b31e686..000000000 --- a/src/ReportBase/_BareReportDialog.py +++ /dev/null @@ -1,490 +0,0 @@ -# -# Gramps - a GTK+/GNOME based genealogy program -# -# Copyright (C) 2001-2007 Donald N. Allingham -# -# 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$ - -#------------------------------------------------------------------------- -# -# Python modules -# -#------------------------------------------------------------------------- -from types import ClassType, InstanceType -from gettext import gettext as _ - -#------------------------------------------------------------------------- -# -# GTK/Gnome modules -# -#------------------------------------------------------------------------- -import gtk - -#------------------------------------------------------------------------- -# -# gramps modules -# -#------------------------------------------------------------------------- -from BasicUtils import name_displayer -import BaseDoc - -import ManagedWindow -from _StyleComboBox import StyleComboBox -from _StyleEditor import StyleListDisplay - -import logging - -log = logging.getLogger(".") - -#------------------------------------------------------------------------- -# -# Private Constants -# -#------------------------------------------------------------------------- -URL_REPORT_PAGE = "Gramps_3.0_Wiki_Manual_-_Reports" - -#------------------------------------------------------------------------- -# -# BareReportDialog class -# -#------------------------------------------------------------------------- -class BareReportDialog(ManagedWindow.ManagedWindow): - """ - The BareReportDialog base class. This is a base class for generating - customized dialogs to solicit some options for a report. This class - cannot be meaningfully used on its own since normally more options will - have to be solicited. The ReportDialog class adds this functionality. - The intended use of this class is either for ReportDialog or for being - subclassed by Bare Reports that are part of the Book. - """ - - frame_pad = 5 - border_pad = 6 - - def __init__(self, dbstate, uistate, option_class, - name, translated_name, track=[]): - """Initialize a dialog to request that the user select options - for a basic *bare* report.""" - self.raw_name = name - self.dbstate = dbstate - self.db = dbstate.db - self.report_name = translated_name - - ManagedWindow.ManagedWindow.__init__(self, uistate, track, self) - - self.init_options(option_class) - self.init_interface() - - def init_options(self, option_class): - if type(option_class) == ClassType: - self.options = option_class(self.raw_name, self.db) - elif type(option_class) == InstanceType: - self.options = option_class - - self.options.load_previous_values() - - def build_window_key(self, obj): - key = self.raw_name - return key - - def build_menu_names(self, obj): - return (_("Configuration"),self.report_name) - - def init_interface(self): - self.widgets = [] - self.frame_names = [] - self.frames = {} - self.format_menu = None - self.style_button = None - - self.style_name = self.options.handler.get_default_stylesheet_name() - - window = gtk.Dialog('GRAMPS') - self.set_window(window,None,self.get_title()) - self.window.set_has_separator(False) - self.window.set_modal(True) - - self.help = self.window.add_button(gtk.STOCK_HELP, gtk.RESPONSE_HELP) - self.help.connect('clicked',self.on_help_clicked) - - self.cancel = self.window.add_button(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL) - self.cancel.connect('clicked',self.on_cancel) - - self.ok = self.window.add_button(gtk.STOCK_OK,gtk.RESPONSE_OK) - self.ok.connect('clicked',self.on_ok_clicked) - - self.window.set_default_size(600,-1) - - # Set up and run the dialog. These calls are not in top down - # order when looking at the dialog box as there is some - # interaction between the various frames. - - self.setup_title() - self.setup_header() - self.tbl = gtk.Table(4,4,False) - self.tbl.set_col_spacings(12) - self.tbl.set_row_spacings(6) - self.tbl.set_border_width(6) - self.row = 0 - - # Build the list of widgets that are used to extend the Options - # frame and to create other frames - self.add_user_options() - - self.setup_main_options() - self.setup_init() - self.setup_format_frame() - self.setup_target_frame() - self.setup_style_frame() - - self.notebook = gtk.Notebook() - self.notebook.set_scrollable(True) - self.notebook.set_border_width(6) - self.window.vbox.add(self.notebook) - - self.setup_report_options_frame() - self.setup_other_frames() - self.notebook.set_current_page(0) - - self.window.vbox.add(self.tbl) - self.show() - - def get_title(self): - """The window title for this dialog""" - return "%s - GRAMPS Book" % self.report_name - - def get_header(self, name): - """The header line to put at the top of the contents of the - dialog box. By default this will just be the name of the - selected person. Most subclasses will customize this to give - some indication of what the report will be, i.e. 'Descendant - Report for %s'.""" - return _("%(report_name)s for GRAMPS Book") % { - 'report_name' : self.report_name} - - #------------------------------------------------------------------------ - # - # Customization hooks for subclasses - # - #------------------------------------------------------------------------ - def get_stylesheet_savefile(self): - """Where should new styles for this report be saved? This is - the name of an XML file that will be located in the ~/.gramps - directory. This file does not have to exist; it will be - created when needed. All subclasses should probably override - this function.""" - return "basic_report.xml" - - #------------------------------------------------------------------------ - # - # Functions related to extending the options - # - #------------------------------------------------------------------------ - def add_user_options(self): - """Called to allow subclasses add widgets to the dialog form. - It is called immediately before the window is displayed. All - calls to add_option or add_frame_option should be called in - this task.""" - self.options.add_user_options(self) - - def parse_user_options(self): - """Called to allow parsing of added widgets. - It is called when OK is pressed in a dialog. - All custom widgets should provide a parsing code here.""" - try: - self.options.parse_user_options(self) - except: - log.error("Failed to parse user options.", exc_info=True) - - - def add_option(self, label_text, widget): - """Takes a text string and a Gtk Widget, and stores them to be - appended to the Options section of the dialog. The text string - is used to create a label for the passed widget. This allows the - subclass to extend the Options section with its own widgets. The - subclass is reponsible for all managing of the widgets, including - extracting the final value before the report executes. This task - should only be called in the add_user_options task.""" - self.widgets.append((label_text, widget)) - - def add_frame_option(self, frame_name, label_text, widget): - """Similar to add_option this method takes a frame_name, a - text string and a Gtk Widget. When the interface is built, - all widgets with the same frame_name are grouped into a - GtkFrame. This allows the subclass to create its own sections, - filling them with its own widgets. The subclass is reponsible for - all managing of the widgets, including extracting the final value - before the report executes. This task should only be called in - the add_user_options task.""" - - if self.frames.has_key(frame_name): - self.frames[frame_name].append((label_text,widget)) - else: - self.frames[frame_name] = [(label_text,widget)] - self.frame_names.append(frame_name) - - #------------------------------------------------------------------------ - # - # Functions to create a default output style. - # - #------------------------------------------------------------------------ - - def build_style_menu(self,default=None): - """Build a menu of style sets that are available for use in - this report. This menu will always have a default style - available, and will have any other style set name that the - user has previously created for this report. This menu is - created here instead of inline with the rest of the style - frame, because it must be recreated to reflect any changes - whenever the user closes the style editor dialog.""" - - if default is None: - default = self.style_name - - style_sheet_map = self.style_sheet_list.get_style_sheet_map() - self.style_menu.set(style_sheet_map,default) - - #------------------------------------------------------------------------ - # - # Functions related to setting up the dialog window. - # - #------------------------------------------------------------------------ - def setup_title(self): - """Set up the title bar of the dialog. This function relies - on the get_title() customization function for what the title - should be.""" - self.name = '' - self.window.set_title(self.get_title()) - - def setup_header(self): - """Set up the header line bar of the dialog. This function - relies on the get_header() customization function for what the - header line should read. If no customization function is - supplied by the subclass, the default is to use the full name - of the currently selected person.""" - - title = self.get_header(self.name) - label = gtk.Label('%s' % title) - label.set_use_markup(True) - self.window.vbox.pack_start(label, True, True, - BareReportDialog.border_pad) - - def setup_target_frame(self): - """Bare report dialog only uses Doc Options header.""" - - label = gtk.Label("%s" % _('Document Options')) - label.set_use_markup(1) - label.set_alignment(0.0,0.5) - self.tbl.set_border_width(12) - self.tbl.attach(label, 0, 4, self.row, self.row+1, gtk.FILL|gtk.EXPAND) - self.row += 1 - - def setup_style_frame(self): - """Set up the style frame of the dialog. This function relies - on other routines create the default style for this report, - and to read in any user defined styles for this report. It - the builds a menu of all the available styles for the user to - choose from.""" - # Build the default style set for this report. - self.default_style = BaseDoc.StyleSheet() - self.options.make_default_style(self.default_style) - - if self.default_style.is_empty(): - # Don't display the option of no styles are used - return - - # Styles Frame - label = gtk.Label("%s:" % _("Style")) - label.set_alignment(0.0,0.5) - - self.style_menu = StyleComboBox() - self.style_button = gtk.Button("%s..." % _("Style Editor")) - self.style_button.connect('clicked',self.on_style_edit_clicked) - - self.tbl.attach(label,1,2,self.row,self.row+1,gtk.SHRINK|gtk.FILL) - self.tbl.attach(self.style_menu,2,3,self.row,self.row+1, - yoptions=gtk.SHRINK) - self.tbl.attach(self.style_button,3,4,self.row,self.row+1, - xoptions=gtk.SHRINK|gtk.FILL,yoptions=gtk.SHRINK) - self.row += 1 - - # Build the initial list of available styles sets. This - # includes the default style set and any style sets saved from - # previous invocations of gramps. - self.style_sheet_list = BaseDoc.StyleSheetList( - self.options.handler.get_stylesheet_savefile(), - self.default_style) - - # Now build the actual menu. - style = self.options.handler.get_default_stylesheet_name() - self.build_style_menu(style) - - def setup_report_options_frame(self): - """Set up the report options frame of the dialog. This - function relies on several report_xxx() customization - functions to determine which of the items should be present in - this box. *All* of these items are optional, although the - generations fields is used in most - (but not all) dialog boxes.""" - - row = 0 - max_rows = len(self.widgets) - - if max_rows == 0: - return - - table = gtk.Table(3,max_rows+1) - table.set_col_spacings(12) - table.set_row_spacings(6) - - label = gtk.Label("%s" % _("Report Options")) - label.set_alignment(0.0,0.5) - label.set_use_markup(True) - - table.set_border_width(6) - self.notebook.append_page(table,label) - row += 1 - - # Setup requested widgets - for (text,widget) in self.widgets: - if text: - text_widget = gtk.Label("%s:" % text) - text_widget.set_alignment(0.0,0.0) - table.attach(text_widget, 1, 2, row, row+1, - gtk.SHRINK|gtk.FILL, gtk.SHRINK) - table.attach(widget, 2, 3, row, row+1, - yoptions=gtk.SHRINK) - else: - table.attach(widget, 2, 3, row, row+1, - yoptions=gtk.SHRINK) - row += 1 - - def setup_other_frames(self): - for key in self.frame_names: - if key == "": - continue - flist = self.frames[key] - table = gtk.Table(3,len(flist)) - table.set_col_spacings(12) - table.set_row_spacings(6) - table.set_border_width(6) - l = gtk.Label("%s" % _(key)) - l.set_use_markup(True) - self.notebook.append_page(table,l) - - row = 0 - for (text,widget) in flist: - if text: - text_widget = gtk.Label('%s:' % text) - text_widget.set_alignment(0.0,0.5) - table.attach(text_widget, 1, 2, row, row+1, - gtk.SHRINK|gtk.FILL, gtk.SHRINK) - table.attach(widget, 2, 3, row, row+1, - yoptions=gtk.SHRINK) - else: - table.attach(widget, 2, 3, row, row+1, - yoptions=gtk.SHRINK) - row = row + 1 - - def setup_init(self): - pass - - def setup_main_options(self): - if self.frames.has_key(""): - flist = self.frames[""] - for (text,widget) in flist: - label = gtk.Label("%s" % text) - label.set_use_markup(True) - label.set_alignment(0.0,0.5) - - self.tbl.set_border_width(12) - self.tbl.attach(label,0,4,self.row,self.row+1) - self.row += 1 - - self.tbl.attach(widget,2,4,self.row,self.row+1) - self.row += 1 - - - #------------------------------------------------------------------------ - # - # Customization hooks for stand-alone reports (subclass ReportDialog) - # - #------------------------------------------------------------------------ - def setup_format_frame(self): - """Not used in bare report dialogs. Override in the subclass.""" - pass - - #------------------------------------------------------------------------ - # - # Functions related to retrieving data from the dialog window - # - #------------------------------------------------------------------------ - def parse_style_frame(self): - """Parse the style frame of the dialog. Save the user - selected output style for later use. Note that this routine - retrieves a value whether or not the menu is displayed on the - screen. The subclass will know whether this menu was enabled. - This is for simplicity of programming.""" - if not self.default_style.is_empty(): - (style_name, self.selected_style) = self.style_menu.get_value() - self.options.handler.set_default_stylesheet_name(style_name) - - #------------------------------------------------------------------------ - # - # Callback functions from the dialog - # - #------------------------------------------------------------------------ - def on_cancel(self,*obj): - pass - - def on_help_clicked(self, *obj): - import GrampsDisplay - GrampsDisplay.help(URL_REPORT_PAGE, self.report_name.replace(" ", "_")) - - def on_ok_clicked(self, obj): - """The user is satisfied with the dialog choices. Parse all options - and close the window.""" - - # Preparation - self.parse_style_frame() - self.parse_user_options() - - # Save options - self.options.handler.save_options() - - def on_style_edit_clicked(self, *obj): - """The user has clicked on the 'Edit Styles' button. Create a - style sheet editor object and let them play. When they are - done, the previous routine will be called to update the dialog - menu for selecting a style.""" - StyleListDisplay(self.style_sheet_list,self.build_style_menu, - self.window) - - #------------------------------------------------------------------------ - # - # Functions related to creating the actual report document. - # - #------------------------------------------------------------------------ - def make_report(self): - """Create the contents of the report. This is the meat and - potatoes of reports. The whole purpose of the dialog is to - get to this routine so that data is written to a file. This - routine should either write the data directly to the file, or - better yet, should create a subclass of a Report that will - write the data to a file.""" - pass diff --git a/src/ReportBase/_DocReportDialog.py b/src/ReportBase/_DocReportDialog.py index 559e7b3a4..11f53769b 100644 --- a/src/ReportBase/_DocReportDialog.py +++ b/src/ReportBase/_DocReportDialog.py @@ -129,16 +129,15 @@ class DocReportDialog(ReportDialog): self.notebook.insert_page(self.html_table,self.html_label,0) self.html_table.show_all() - if not self.get_target_is_directory(): - fname = self.target_fileentry.get_full_path(0) - (spath,ext) = os.path.splitext(fname) + fname = self.target_fileentry.get_full_path(0) + (spath,ext) = os.path.splitext(fname) - ext_val = obj.get_ext() - if ext_val: - fname = spath + ext_val - else: - fname = spath - self.target_fileentry.set_filename(fname) + ext_val = obj.get_ext() + if ext_val: + fname = spath + ext_val + else: + fname = spath + self.target_fileentry.set_filename(fname) # Does this report format use styles? if self.style_button: @@ -170,12 +169,9 @@ class DocReportDialog(ReportDialog): ext = "" else: spath = self.get_default_directory() - if self.get_target_is_directory(): - self.target_fileentry.set_filename(spath) - else: - base = self.get_default_basename() - spath = os.path.normpath("%s/%s%s" % (spath,base,ext)) - self.target_fileentry.set_filename(spath) + base = self.get_default_basename() + spath = os.path.normpath("%s/%s%s" % (spath, base, ext)) + self.target_fileentry.set_filename(spath) def setup_report_options_frame(self): self.paper_frame = PaperFrame(self.options.handler.get_paper_metric(), diff --git a/src/ReportBase/_GraphvizReportDialog.py b/src/ReportBase/_GraphvizReportDialog.py index 5726bae47..b576bdd8c 100644 --- a/src/ReportBase/_GraphvizReportDialog.py +++ b/src/ReportBase/_GraphvizReportDialog.py @@ -887,12 +887,9 @@ class GraphvizReportDialog(ReportDialog): ext = "" else: spath = self.get_default_directory() - if self.get_target_is_directory(): - self.target_fileentry.set_filename(spath) - else: - base = self.get_default_basename() - spath = os.path.normpath("%s/%s%s" % (spath,base,ext)) - self.target_fileentry.set_filename(spath) + base = self.get_default_basename() + spath = os.path.normpath("%s/%s%s" % (spath, base, ext)) + self.target_fileentry.set_filename(spath) def setup_report_options_frame(self): self.paper_label = gtk.Label('%s'%_("Paper Options")) @@ -980,5 +977,5 @@ class GraphvizReportDialog(ReportDialog): self.options.handler.set_format_name(format_name) def setup_style_frame(self): - """Required by ReportDialog:BareReportDialog""" + """Required by ReportDialog""" pass diff --git a/src/ReportBase/_ReportDialog.py b/src/ReportBase/_ReportDialog.py index 8810d1c97..2489cff10 100644 --- a/src/ReportBase/_ReportDialog.py +++ b/src/ReportBase/_ReportDialog.py @@ -2,6 +2,7 @@ # Gramps - a GTK+/GNOME based genealogy program # # Copyright (C) 2001-2006 Donald N. Allingham +# Copyright (C) 2008 Brian G. Matherly # # 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 @@ -26,11 +27,11 @@ # #------------------------------------------------------------------------- import os +from types import ClassType, InstanceType from gettext import gettext as _ import logging - -log = logging.getLogger(".") +LOG = logging.getLogger(".") #------------------------------------------------------------------------- # @@ -47,24 +48,35 @@ import gtk import Config import Errors from QuestionDialog import ErrorDialog, OptionDialog -from _Constants import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK, +from ReportBase import (CATEGORY_TEXT, CATEGORY_DRAW, CATEGORY_BOOK, CATEGORY_CODE, CATEGORY_WEB, CATEGORY_GRAPHVIZ, standalone_categories) -from _BareReportDialog import BareReportDialog +import BaseDoc +import ManagedWindow +from _StyleComboBox import StyleComboBox +from _StyleEditor import StyleListDisplay from _FileEntry import FileEntry +#------------------------------------------------------------------------- +# +# Private Constants +# +#------------------------------------------------------------------------- +URL_REPORT_PAGE = "Gramps_3.0_Wiki_Manual_-_Reports" + #------------------------------------------------------------------------- # # ReportDialog class # #------------------------------------------------------------------------- -class ReportDialog(BareReportDialog): +class ReportDialog(ManagedWindow.ManagedWindow): """ The ReportDialog base class. This is a base class for generating customized dialogs to solicit options for a report. It cannot be used as is, but it can be easily sub-classed to create a functional dialog for a stand-alone report. """ + border_pad = 6 def __init__(self, dbstate, uistate, option_class, name, trans_name, track=[]): @@ -73,45 +85,332 @@ class ReportDialog(BareReportDialog): self.style_name = "default" self.page_html_added = False - BareReportDialog.__init__(self, dbstate, uistate, option_class, - name, trans_name, track) + self.raw_name = name + self.dbstate = dbstate + self.db = dbstate.db + self.report_name = trans_name + + ManagedWindow.ManagedWindow.__init__(self, uistate, track, self) - # Allow for post processing of the format frame, since the - # show_all task calls events that may reset values + self.init_options(option_class) + self.init_interface() + + def init_options(self, option_class): + if type(option_class) == ClassType: + self.options = option_class(self.raw_name, self.db) + elif type(option_class) == InstanceType: + self.options = option_class + + self.options.load_previous_values() + + def build_window_key(self, obj): + key = self.raw_name + return key + + def build_menu_names(self, obj): + return (_("Configuration"), self.report_name) def init_interface(self): - BareReportDialog.init_interface(self) + self.widgets = [] + self.frame_names = [] + self.frames = {} + self.format_menu = None + self.style_button = None + + self.style_name = self.options.handler.get_default_stylesheet_name() + + window = gtk.Dialog('GRAMPS') + self.set_window(window, None, self.get_title()) + self.window.set_has_separator(False) + self.window.set_modal(True) + + self.help = self.window.add_button(gtk.STOCK_HELP, gtk.RESPONSE_HELP) + self.help.connect('clicked', self.on_help_clicked) + + self.cancel = self.window.add_button(gtk.STOCK_CANCEL, + gtk.RESPONSE_CANCEL) + self.cancel.connect('clicked', self.on_cancel) + + self.ok = self.window.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK) + self.ok.connect('clicked', self.on_ok_clicked) + + self.window.set_default_size(600, -1) + + # Set up and run the dialog. These calls are not in top down + # order when looking at the dialog box as there is some + # interaction between the various frames. + + self.setup_title() + self.setup_header() + self.tbl = gtk.Table(4, 4, False) + self.tbl.set_col_spacings(12) + self.tbl.set_row_spacings(6) + self.tbl.set_border_width(6) + self.row = 0 + + # Build the list of widgets that are used to extend the Options + # frame and to create other frames + self.add_user_options() + + self.setup_main_options() + self.setup_init() + self.setup_format_frame() + self.setup_target_frame() + self.setup_style_frame() + + self.notebook = gtk.Notebook() + self.notebook.set_scrollable(True) + self.notebook.set_border_width(6) + self.window.vbox.add(self.notebook) + + self.setup_report_options_frame() + self.setup_other_frames() + self.notebook.set_current_page(0) + + self.window.vbox.add(self.tbl) + self.show() def get_title(self): """The window title for this dialog""" name = self.report_name category = standalone_categories[self.category] - return "%s - %s - GRAMPS" % (name,category) - - def get_header(self, name): - """The header line to put at the top of the contents of the - dialog box. By default this will just be the name of the - report for the selected person. """ - return self.report_name - + return "%s - %s - GRAMPS" % (name, category) + #------------------------------------------------------------------------ # # Customization hooks for subclasses # #------------------------------------------------------------------------ - def get_target_is_directory(self): - """Is the user being asked to input the name of a file or a - directory in the 'Save As' File Entry widget. This item - currently only selects the Filename/Directory prompt, and - whether or not the browser accepts filenames. In the future it - may also control checking of the selected filename.""" - return None + def get_stylesheet_savefile(self): + """Where should new styles for this report be saved? This is + the name of an XML file that will be located in the ~/.gramps + directory. This file does not have to exist; it will be + created when needed. All subclasses should probably override + this function.""" + return "basic_report.xml" def get_default_basename(self): """What should the default name be? """ spath = self.options.handler.get_stylesheet_savefile() return spath.split('.')[0] + + #------------------------------------------------------------------------ + # + # Functions related to extending the options + # + #------------------------------------------------------------------------ + def add_user_options(self): + """Called to allow subclasses add widgets to the dialog form. + It is called immediately before the window is displayed. All + calls to add_option or add_frame_option should be called in + this task.""" + self.options.add_user_options(self) + + def parse_user_options(self): + """Called to allow parsing of added widgets. + It is called when OK is pressed in a dialog. + All custom widgets should provide a parsing code here.""" + try: + self.options.parse_user_options(self) + except: + LOG.error("Failed to parse user options.", exc_info=True) + + def add_option(self, label_text, widget): + """Takes a text string and a Gtk Widget, and stores them to be + appended to the Options section of the dialog. The text string + is used to create a label for the passed widget. This allows the + subclass to extend the Options section with its own widgets. The + subclass is reponsible for all managing of the widgets, including + extracting the final value before the report executes. This task + should only be called in the add_user_options task.""" + self.widgets.append((label_text, widget)) + + def add_frame_option(self, frame_name, label_text, widget): + """Similar to add_option this method takes a frame_name, a + text string and a Gtk Widget. When the interface is built, + all widgets with the same frame_name are grouped into a + GtkFrame. This allows the subclass to create its own sections, + filling them with its own widgets. The subclass is reponsible for + all managing of the widgets, including extracting the final value + before the report executes. This task should only be called in + the add_user_options task.""" + + if self.frames.has_key(frame_name): + self.frames[frame_name].append((label_text, widget)) + else: + self.frames[frame_name] = [(label_text, widget)] + self.frame_names.append(frame_name) + + #------------------------------------------------------------------------ + # + # Functions to create a default output style. + # + #------------------------------------------------------------------------ + + def build_style_menu(self, default=None): + """Build a menu of style sets that are available for use in + this report. This menu will always have a default style + available, and will have any other style set name that the + user has previously created for this report. This menu is + created here instead of inline with the rest of the style + frame, because it must be recreated to reflect any changes + whenever the user closes the style editor dialog.""" + + if default is None: + default = self.style_name + + style_sheet_map = self.style_sheet_list.get_style_sheet_map() + self.style_menu.set(style_sheet_map, default) + + #------------------------------------------------------------------------ + # + # Functions related to setting up the dialog window. + # + #------------------------------------------------------------------------ + def setup_title(self): + """Set up the title bar of the dialog. This function relies + on the get_title() customization function for what the title + should be.""" + self.window.set_title(self.get_title()) + + def setup_header(self): + """Set up the header line bar of the dialog.""" + label = gtk.Label('%s' % + self.report_name) + label.set_use_markup(True) + self.window.vbox.pack_start(label, True, True, self.border_pad) + + def setup_style_frame(self): + """Set up the style frame of the dialog. This function relies + on other routines create the default style for this report, + and to read in any user defined styles for this report. It + the builds a menu of all the available styles for the user to + choose from.""" + # Build the default style set for this report. + self.default_style = BaseDoc.StyleSheet() + self.options.make_default_style(self.default_style) + + if self.default_style.is_empty(): + # Don't display the option of no styles are used + return + + # Styles Frame + label = gtk.Label("%s:" % _("Style")) + label.set_alignment(0.0, 0.5) + + self.style_menu = StyleComboBox() + self.style_button = gtk.Button("%s..." % _("Style Editor")) + self.style_button.connect('clicked', self.on_style_edit_clicked) + + self.tbl.attach(label, 1, 2, self.row, self.row+1, gtk.SHRINK|gtk.FILL) + self.tbl.attach(self.style_menu, 2, 3, self.row, self.row+1, + yoptions=gtk.SHRINK) + self.tbl.attach(self.style_button, 3, 4, self.row, self.row+1, + xoptions=gtk.SHRINK|gtk.FILL, yoptions=gtk.SHRINK) + self.row += 1 + + # Build the initial list of available styles sets. This + # includes the default style set and any style sets saved from + # previous invocations of gramps. + self.style_sheet_list = BaseDoc.StyleSheetList( + self.options.handler.get_stylesheet_savefile(), + self.default_style) + + # Now build the actual menu. + style = self.options.handler.get_default_stylesheet_name() + self.build_style_menu(style) + + def setup_report_options_frame(self): + """Set up the report options frame of the dialog. This + function relies on several report_xxx() customization + functions to determine which of the items should be present in + this box. *All* of these items are optional, although the + generations fields is used in most + (but not all) dialog boxes.""" + + row = 0 + max_rows = len(self.widgets) + + if max_rows == 0: + return + + table = gtk.Table(3, max_rows+1) + table.set_col_spacings(12) + table.set_row_spacings(6) + + label = gtk.Label("%s" % _("Report Options")) + label.set_alignment(0.0, 0.5) + label.set_use_markup(True) + + table.set_border_width(6) + self.notebook.append_page(table, label) + row += 1 + + # Setup requested widgets + for (text, widget) in self.widgets: + if text: + text_widget = gtk.Label("%s:" % text) + text_widget.set_alignment(0.0, 0.0) + table.attach(text_widget, 1, 2, row, row+1, + gtk.SHRINK|gtk.FILL, gtk.SHRINK) + table.attach(widget, 2, 3, row, row+1, + yoptions=gtk.SHRINK) + else: + table.attach(widget, 2, 3, row, row+1, + yoptions=gtk.SHRINK) + row += 1 + + def setup_other_frames(self): + for key in self.frame_names: + if key == "": + continue + flist = self.frames[key] + table = gtk.Table(3, len(flist)) + table.set_col_spacings(12) + table.set_row_spacings(6) + table.set_border_width(6) + l = gtk.Label("%s" % _(key)) + l.set_use_markup(True) + self.notebook.append_page(table, l) + + row = 0 + for (text, widget) in flist: + if text: + text_widget = gtk.Label('%s:' % text) + text_widget.set_alignment(0.0, 0.5) + table.attach(text_widget, 1, 2, row, row+1, + gtk.SHRINK|gtk.FILL, gtk.SHRINK) + table.attach(widget, 2, 3, row, row+1, + yoptions=gtk.SHRINK) + else: + table.attach(widget, 2, 3, row, row+1, + yoptions=gtk.SHRINK) + row = row + 1 + + def setup_main_options(self): + if self.frames.has_key(""): + flist = self.frames[""] + for (text, widget) in flist: + label = gtk.Label("%s" % text) + label.set_use_markup(True) + label.set_alignment(0.0, 0.5) + + self.tbl.set_border_width(12) + self.tbl.attach(label, 0, 4, self.row, self.row+1) + self.row += 1 + + self.tbl.attach(widget, 2, 4, self.row, self.row+1) + self.row += 1 + + #------------------------------------------------------------------------ + # + # Customization hooks for stand-alone reports (subclass ReportDialog) + # + #------------------------------------------------------------------------ + def setup_format_frame(self): + """Not used in bare report dialogs. Override in the subclass.""" + pass #------------------------------------------------------------------------ # @@ -132,7 +431,7 @@ class ReportDialog(BareReportDialog): This means that the last directory used will only be remembered for this session of gramps unless the user saves his/her preferences.""" - Config.set(Config.REPORT_DIRECTORY,value) + Config.set(Config.REPORT_DIRECTORY, value) #------------------------------------------------------------------------ # @@ -142,16 +441,16 @@ class ReportDialog(BareReportDialog): def setup_init(self): # add any elements that we are going to need: hid = self.get_stylesheet_savefile() - if hid[-4:]==".xml": + if hid[-4:] == ".xml": hid = hid[0:-4] - self.target_fileentry = FileEntry(hid,_("Save As")) + self.target_fileentry = FileEntry(hid, _("Save As")) spath = self.get_default_directory() self.target_fileentry.set_filename(spath) self.target_fileentry.gtk_entry().set_position(len(spath)) # need any labels at top: label = gtk.Label("%s" % _('Document Options')) label.set_use_markup(1) - label.set_alignment(0.0,0.5) + label.set_alignment(0.0, 0.5) self.tbl.set_border_width(12) self.tbl.attach(label, 0, 4, self.row, self.row+1, gtk.FILL) self.row += 1 @@ -164,12 +463,8 @@ class ReportDialog(BareReportDialog): directory should be used.""" # Save Frame - if self.get_target_is_directory(): - self.target_fileentry.set_directory_entry(1) - self.doc_label = gtk.Label("%s:" % _("Directory")) - else: - self.doc_label = gtk.Label("%s:" % _("Filename")) - self.doc_label.set_alignment(0.0,0.5) + self.doc_label = gtk.Label("%s:" % _("Filename")) + self.doc_label.set_alignment(0.0, 0.5) self.tbl.attach(self.doc_label, 1, 2, self.row, self.row+1, xoptions=gtk.SHRINK|gtk.FILL,yoptions=gtk.SHRINK) @@ -196,8 +491,7 @@ class ReportDialog(BareReportDialog): if os.path.exists(self.target_path): # selected path is an existing dir and we need a dir - if os.path.isdir(self.target_path) \ - and self.get_target_is_directory(): + if os.path.isdir(self.target_path): # check whether the dir has rwx permissions if not os.access(self.target_path, os.R_OK|os.W_OK|os.X_OK): @@ -210,13 +504,12 @@ class ReportDialog(BareReportDialog): return None # selected path is an exsting file and we need a file - if os.path.isfile(self.target_path) \ - and not self.get_target_is_directory(): + if os.path.isfile(self.target_path): a = OptionDialog(_('File already exists'), _('You can choose to either overwrite the ' 'file, or change the selected filename.'), - _('_Overwrite'),None, - _('_Change filename'),None) + _('_Overwrite'), None, + _('_Change filename'), None) if a.get_response() == gtk.RESPONSE_YES: return None @@ -238,7 +531,22 @@ class ReportDialog(BareReportDialog): self.set_default_directory(os.path.dirname(self.target_path) + os.sep) self.options.handler.output = self.target_path return 1 + + def parse_style_frame(self): + """Parse the style frame of the dialog. Save the user + selected output style for later use. Note that this routine + retrieves a value whether or not the menu is displayed on the + screen. The subclass will know whether this menu was enabled. + This is for simplicity of programming.""" + if not self.default_style.is_empty(): + (style_name, self.selected_style) = self.style_menu.get_value() + self.options.handler.set_default_stylesheet_name(style_name) + #------------------------------------------------------------------------ + # + # Callback functions from the dialog + # + #------------------------------------------------------------------------ def on_ok_clicked(self, obj): """The user is satisfied with the dialog choices. Validate the output file name before doing anything else. If there is @@ -254,14 +562,29 @@ class ReportDialog(BareReportDialog): # Save options self.options.handler.save_options() + + def on_cancel(self, *obj): + pass + + def on_help_clicked(self, *obj): + import GrampsDisplay + GrampsDisplay.help(URL_REPORT_PAGE, self.report_name.replace(" ", "_")) + + def on_style_edit_clicked(self, *obj): + """The user has clicked on the 'Edit Styles' button. Create a + style sheet editor object and let them play. When they are + done, the previous routine will be called to update the dialog + menu for selecting a style.""" + StyleListDisplay(self.style_sheet_list, self.build_style_menu, + self.window) #------------------------------------------------------------------------ # # Generic task function a standalone GUI report # #------------------------------------------------------------------------ -def report(dbstate,uistate,person,report_class, options_class, - trans_name, name,category, require_active): +def report(dbstate, uistate, person, report_class, options_class, + trans_name, name, category, require_active): """ report - task starts the report. The plugin system requires that the task be in the format of task that takes a database and a person as @@ -289,7 +612,7 @@ def report(dbstate,uistate,person,report_class, options_class, dialog_class = WebReportDialog elif category in (CATEGORY_BOOK, CATEGORY_CODE): try: - report_class(dbstate,uistate) + report_class(dbstate, uistate) except Errors.WindowActiveError: pass return @@ -309,15 +632,15 @@ def report(dbstate,uistate,person,report_class, options_class, MyReport.write_report() MyReport.end_report() except Errors.FilterError, msg: - (m1,m2) = msg.messages() - ErrorDialog(m1,m2) + (m1, m2) = msg.messages() + ErrorDialog(m1, m2) except IOError, msg: ErrorDialog(_("Report could not be created"),str(msg)) except Errors.ReportError, msg: - (m1,m2) = msg.messages() - ErrorDialog(m1,m2) + (m1, m2) = msg.messages() + ErrorDialog(m1, m2) except Errors.DatabaseError,msg: - ErrorDialog(_("Report could not be created"),str(msg)) + ErrorDialog(_("Report could not be created"), str(msg)) # The following except statement will catch all "NoneType" exceptions. # This is useful for released code where the exception is most likely # a corrupt database. But it is less useful for developing new reports @@ -331,7 +654,7 @@ def report(dbstate,uistate,person,report_class, options_class, # raise raise except: - log.error("Failed to run report.", exc_info=True) + LOG.error("Failed to run report.", exc_info=True) break elif (response == gtk.RESPONSE_DELETE_EVENT or response == gtk.RESPONSE_CANCEL):