Merge changes done in the TOOL_OPT branch as follows:

* src/Tool.py: Add to CVS: Generic tool interface.
* src/ArgHandler.py: Support command line mode for tools.
* src/PluginMgr.py: New tool registration scheme.
* src/Plugins.py: Convert to tool registration scheme.
* src/const.py.in: Add tool categories.
* src/plugins/ChangeTypes.py: Convert to new scheme.
* src/Options.py: Add to CVS: generic options interface.
* src/ReportOptions.py: Keep only report-specific option
handling.
* src/Makefile.am: Ship new files.

* src/plugins/Checkpoint.py: Minor improvements for the RCS.
* src/plugins/Makefile.am: Ship Checkpoint.py.


svn: r5220
This commit is contained in:
Alex Roitman
2005-09-23 21:41:23 +00:00
parent 4f003d46b4
commit 374e117c17
11 changed files with 1078 additions and 438 deletions

View File

@@ -1,3 +1,20 @@
2005-09-23 Alex Roitman <shura@gramps-project.org>
Merge changes done in the TOOL_OPT branch as follows:
* src/Tool.py: Add to CVS: Generic tool interface.
* src/ArgHandler.py: Support command line mode for tools.
* src/PluginMgr.py: New tool registration scheme.
* src/Plugins.py: Convert to tool registration scheme.
* src/const.py.in: Add tool categories.
* src/plugins/ChangeTypes.py: Convert to new scheme.
* src/Options.py: Add to CVS: generic options interface.
* src/ReportOptions.py: Keep only report-specific option
handling.
* src/Makefile.am: Ship new files.
2005-09-23 Alex Roitman <shura@gramps-project.org>
* src/plugins/Checkpoint.py: Minor improvements for the RCS.
* src/plugins/Makefile.am: Ship Checkpoint.py.
2005-09-22 Don Allingham <don@gramps-project.org> 2005-09-22 Don Allingham <don@gramps-project.org>
* doc/gramps-manual/C/*.xml * doc/gramps-manual/C/*.xml

View File

@@ -50,6 +50,7 @@ import GrampsKeys
import RecentFiles import RecentFiles
import PluginMgr import PluginMgr
import Report import Report
import Tool
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@@ -211,7 +212,7 @@ class ArgHandler:
self.exports.append((outfname,outformat)) self.exports.append((outfname,outformat))
elif o in ( '-a', '--action' ): elif o in ( '-a', '--action' ):
action = v action = v
if action not in ( 'check', 'summary', 'report' ): if action not in ( 'check', 'summary', 'report', 'tool' ):
print "Unknown action: %s. Ignoring." % action print "Unknown action: %s. Ignoring." % action
continue continue
options_str = "" options_str = ""
@@ -619,6 +620,31 @@ class ArgHandler:
print "Unknown report name. Available names are:" print "Unknown report name. Available names are:"
for item in PluginMgr.cl_list: for item in PluginMgr.cl_list:
print " %s" % item[0] print " %s" % item[0]
elif action == "tool":
try:
options_str_dict = dict( [ tuple(chunk.split('=')) for
chunk in options_str.split(',') ] )
except:
options_str_dict = {}
print "Ignoring invalid options string."
name = options_str_dict.pop('name',None)
if not name:
print "Tool name not given. Please use name=toolname"
os._exit(1)
for item in PluginMgr.cli_tool_list:
if name == item[0]:
category = item[1]
tool_class = item[2]
options_class = item[3]
Tool.cli_tool(self.parent.db,name,category,
tool_class,options_class,options_str_dict)
return
print "Unknown tool name. Available names are:"
for item in PluginMgr.cli_tool_list:
print " %s" % item[0]
else: else:
print "Unknown action: %s." % action print "Unknown action: %s." % action
os._exit(1) os._exit(1)

View File

@@ -122,6 +122,8 @@ gdir_PYTHON = \
ReportOptions.py\ ReportOptions.py\
ReadGrdb.py\ ReadGrdb.py\
WriteGrdb.py\ WriteGrdb.py\
Options.py\
Tool.py\
Spell.py Spell.py
# Could use GNU make's ':=' syntax for nice wildcard use. # Could use GNU make's ':=' syntax for nice wildcard use.

514
gramps2/src/Options.py Normal file
View File

@@ -0,0 +1,514 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2004-2005 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$
# Written by Alex Roitman
"""
General option handling, including saving and parsing.
"""
#-------------------------------------------------------------------------
#
# Standard Python modules
#
#-------------------------------------------------------------------------
import os
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# SAX interface
#
#-------------------------------------------------------------------------
try:
from xml.sax import make_parser,handler,SAXParseException
except:
from _xmlplus.sax import make_parser,handler,SAXParseException
#-------------------------------------------------------------------------
#
# gramps modules
#
#-------------------------------------------------------------------------
import Utils
#-------------------------------------------------------------------------
#
# List of options for a single module
#
#-------------------------------------------------------------------------
class OptionList:
"""
Implements a set of options to parse and store for a given module.
"""
def __init__(self):
self.options = {}
def set_options(self,options):
"""
Sets the whole bunch of options for the OptionList.
@param options: list of options to set.
@type options: list
"""
self.options = options
def get_options(self):
"""
Returns the whole bunch of options for the OptionList.
@returns: list of options
@rtype: list
"""
return self.options
def set_option(self,name,value):
"""
Sets a particular option in the OptionList.
@param name: name of the option to set.
@type name: str
@param value: value of the option to set.
@type str
"""
self.options[name] = value
def remove_option(self,name):
"""
Removes a particular option from the OptionList.
@param name: name of the option to remove.
@type name: str
"""
if self.options.has_key(name):
del self.options[name]
def get_option(self,name):
"""
Returns the value of a particular option in the OptionList.
@param name: name of the option to retrieve
@type name: str
@returns: value associated with the passed option
@rtype: str
"""
return self.options.get(name,None)
#-------------------------------------------------------------------------
#
# Collection of option lists
#
#-------------------------------------------------------------------------
class OptionListCollection:
"""
Implements a collection of option lists.
"""
def __init__(self,filename):
"""
Creates an OptionListCollection instance from the list defined
in the specified file.
@param filename: XML file that contains option definitions
@type filename: str
"""
self.filename = os.path.expanduser(filename)
self.option_list_map = {}
self.init_common()
self.parse()
def init_common(self):
pass
def get_option_list_map(self):
"""
Returns the map of module names to option lists.
@returns: Returns the map of module names to option lists.
@rtype: dictionary
"""
return self.option_list_map
def get_option_list(self,name):
"""
Returns the option_list associated with the module name
@param name: name associated with the desired module.
@type name: str
@returns: returns the option list associated with the name,
or None of no such option exists
@rtype: str
"""
return self.option_list_map.get(name,None)
def get_module_names(self):
"""
Returns a list of all the module names in the OptionListCollection
@returns: returns the list of module names
@rtype: list
"""
return self.option_list_map.keys()
def set_option_list(self,name,option_list):
"""
Adds or replaces an option_list in the OptionListCollection.
@param name: name assocated with the module to add or replace.
@type name: str
@param option_list: list of options
@type option_list: str
"""
self.option_list_map[name] = option_list
def write_common(self,f):
"""
Stub function for common options. Overridden by reports.
"""
pass
def write_module_common(self,f,option_list):
"""
Stub function for common options. Overridden by reports.
"""
pass
def save(self):
"""
Saves the current OptionListCollection to the associated file.
"""
f = open(self.filename,"w")
f.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
f.write('<options>\n')
self.write_common(f)
for module_name in self.get_module_names():
option_list = self.get_option_list(module_name)
f.write('<module name="%s">\n' % module_name)
options = option_list.get_options()
for option_name in options.keys():
if type(options[option_name]) in (type(list()),type(tuple())):
f.write(' <option name="%s" value="" length="%d">\n' % (
option_name, len(options[option_name]) ) )
for list_index in range(len(options[option_name])):
f.write(' <listitem number="%d" value="%s"/>\n' % (
list_index, options[option_name][list_index]) )
f.write(' </option>\n')
else:
f.write(' <option name="%s" value="%s"/>\n' % (
option_name,options[option_name]) )
self.write_module_common(f,option_list)
f.write('</module>\n')
f.write('</options>\n')
f.close()
def parse(self):
"""
Loads the OptionList from the associated file, if it exists.
"""
try:
p = make_parser()
p.setContentHandler(OptionParser(self))
p.parse('file://' + self.filename)
except (IOError,OSError,SAXParseException):
pass
#-------------------------------------------------------------------------
#
# OptionParser
#
#-------------------------------------------------------------------------
class OptionParser(handler.ContentHandler):
"""
SAX parsing class for the OptionListCollection XML file.
"""
def __init__(self,collection):
"""
Creates a OptionParser class that populates the passed collection.
collection: OptionListCollection to be loaded from the file.
"""
handler.ContentHandler.__init__(self)
self.collection = collection
self.mname = None
self.option_list = None
self.oname = None
self.o = None
self.an_o = None
self.list_class = OptionList
def startElement(self,tag,attrs):
"""
Overridden class that handles the start of a XML element
"""
if tag in ("report","module"):
self.mname = attrs['name']
self.option_list = self.list_class()
self.o = {}
elif tag == "option":
self.oname = attrs['name']
if attrs.has_key('length'):
self.an_o = []
else:
self.an_o = attrs['value']
elif tag == "listitem":
self.an_o.append(attrs['value'])
def endElement(self,tag):
"Overridden class that handles the end of a XML element"
if tag == "option":
self.o[self.oname] = self.an_o
elif tag in ("report","module"):
self.option_list.set_options(self.o)
self.collection.set_option_list(self.mname,self.option_list)
#-------------------------------------------------------------------------
#
# Class handling options for plugins
#
#-------------------------------------------------------------------------
class OptionHandler:
"""
Implements handling of the options for the plugins.
"""
def __init__(self,module_name,options_dict,person_id=None):
self.module_name = module_name
self.default_options_dict = options_dict.copy()
self.options_dict = options_dict
# Retrieve our options from whole collection
self.init_subclass()
self.option_list_collection = self.collection_class(self.filename)
self.init_common()
self.saved_option_list = self.option_list_collection.get_option_list(module_name)
self.person_id = person_id
# Whatever was found should override the defaults
if self.saved_option_list:
self.set_options()
else:
# If nothing was found, set up the option list
self.saved_option_list = self.list_class()
self.option_list_collection.set_option_list(module_name,
self.saved_option_list)
def init_subclass(self):
self.collection_class = OptionListCollection
self.list_class = OptionList
self.filename = None
def init_common(self):
pass
def set_options(self):
"""
Sets options to be used in this plugin according to the passed
options dictionary.
Dictionary values are all strings, since they were read from XML.
Here we need to convert them to the needed types. We use default
values to determine the type.
"""
# First we set options_dict values based on the saved options
options = self.saved_option_list.get_options()
bad_opts = []
for option_name in options.keys():
if not self.options_dict.has_key(option_name):
print "Option %s is present in the %s but is not known "\
"to the module." % (option_name,
self.option_list_collection.filename)
print "Ignoring..."
bad_opts.append(option_name)
continue
try:
converter = Utils.get_type_converter(self.options_dict[option_name])
self.options_dict[option_name] = converter(options[option_name])
except ValueError:
pass
for option_name in bad_opts:
options.pop(option_name)
# Then we set common options from whatever was found
self.set_common_options()
def set_common_options(self):
pass
def save_options(self):
"""
Saves options to file.
We need to only store non-default options. Therefore, we remove all
options whose values are the defaults prior to saving.
"""
# First we save options from options_dict
for option_name in self.options_dict.keys():
if self.options_dict[option_name] == self.default_options_dict[option_name]:
self.saved_option_list.remove_option(option_name)
else:
self.saved_option_list.set_option(option_name,self.options_dict[option_name])
# Handle common options
self.save_common_options()
# Finally, save the whole collection into file
self.option_list_collection.save()
def save_common_options(self):
pass
def get_filter_number(self):
if self.default_options_dict.has_key('filter'):
return self.options_dict.get('filter',
self.default_options_dict['filter'])
else:
return None
def set_filter_number(self,val):
self.options_dict['filter'] = val
def get_person_id(self):
return self.person_id
def set_person_id(self,val):
self.person_id = val
#------------------------------------------------------------------------
#
# Base Options class
#
#------------------------------------------------------------------------
class Options:
"""
Defines options and provides handling interface.
This is a base Options class for the modules. All modules' options
classes should derive from it.
"""
def __init__(self,name,person_id=None):
"""
Initializes the class, performing usual house-keeping tasks.
Subclasses MUST call this in their __init__() method.
"""
self.set_new_options()
self.enable_options()
if self.enable_dict:
self.options_dict.update(self.enable_dict)
print name
self.handler = OptionHandler(name,self.options_dict,person_id)
def set_new_options(self):
"""
Sets options specific for this module.
Modules that need custom options need to override this method.
Two dictionaries MUST be defined here:
self.options_dict
This is a dictionary whose keys are option names
and values are the default option values.
self.options_help
This is a dictionary whose keys are option names
and values are 3- or 4- lists or tuples:
('=example','Short description',VALUES,DO_PREPEND)
The VALUES is either a single string (in that case
the DO_PREPEND does not matter) or a list/tuple of
strings to list. In that case, if DO_PREPEND evaluates
as True then each string will be preneded with the ordinal
number when help is printed on the command line.
NOTE: Both dictionaries must have identical keys.
NOTE: If a particular module does not use custom options,
then it should not override this method.
"""
self.options_dict = {}
self.options_help = {}
def enable_options(self):
"""
Enables semi-common options for this module.
The semi-common option is the option which GRAMPS is aware of,
but not common enough to be present in all modules. Here's the list
of possible keys for semi-commons:
'filter' - Filter number, selected among filters
available for this module. If defined,
get_module_filters() method must be defined
which returns the list of available filters.
A self.enable_dict dictionary MUST be defined here, whose keys
are the valid semi-common keys above, and whose values are the
desired default values for semi-commons.
NOTE: If a particular module does not use semi-common options,
then it should not override this method.
"""
self.enable_dict = {}
def add_user_options(self,dialog):
"""
Sets 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.
Any attribute of the dialog is available.
After the widgets are defined, they MUST be added to the dialog
using the following call:
dialog.add_options(LABEL,widget)
NOTE: To really have any effect besides looking pretty, each widget
set up here must be also parsed in the parse_user_options()
method below.
"""
pass
def parse_user_options(self,dialog):
"""
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.
Any attribute of the dialog is available.
After obtaining values from the widgets, they MUST be used to set the
appropriate options_dict values. Otherwise the values will not have
any user-visible effect.
NOTE: Any widget parsed here MUST be defined and added to the dialog
in the add_user_options() method above.
"""
pass
def get_filter_number(self):
"""
Return number of a filter to use.
This method MUST NOT be overridden by subclasses.
"""
return self.handler.get_filter_number()

View File

@@ -45,6 +45,7 @@ from gettext import gettext as _
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
import const import const
import Errors import Errors
import Tool
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@@ -64,6 +65,7 @@ drawdoc_list = []
failmsg_list = [] failmsg_list = []
bkitems_list = [] bkitems_list = []
cl_list = [] cl_list = []
cli_tool_list = []
_success_list = [] _success_list = []
@@ -77,6 +79,7 @@ _relcalc_class = Relationship.RelationshipCalculator
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# Constants
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
_unavailable = _("No description was provided"), _unavailable = _("No description was provided"),
@@ -154,16 +157,48 @@ def register_import(task, ffilter, mime=None, native_format=0, format_name=""):
import_list.append((task, ffilter, mime, native_format, format_name)) import_list.append((task, ffilter, mime, native_format, format_name))
#-------------------------------------------------------------------------
#
# Tool registration
#
#-------------------------------------------------------------------------
def register_tool( def register_tool(
task,
name, name,
category=_("Uncategorized"), category,
description=_unavailable, tool_class,
options_class,
modes,
translated_name,
status=_("Unknown"), status=_("Unknown"),
description=_unavailable,
author_name=_("Unknown"), author_name=_("Unknown"),
author_email=_("Unknown") author_email=_("Unknown")
): ):
"""Register a tool with the plugin system""" """
Register a tool with the plugin system.
This function should be used to register tool in GUI and/or
command-line mode. The low-level functions (starting with '_')
should not be used on their own. Instead, this functino will call
them as needed.
"""
(junk,gui_task) = divmod(modes,2**Tool.MODE_GUI)
if gui_task:
_register_gui_tool(tool_class,options_class,translated_name,
name,category,description,
status,author_name,author_email)
(junk,cli_task) = divmod(modes-gui_task,2**Tool.MODE_CLI)
if cli_task:
_register_cli_tool(name,category,tool_class,options_class)
def _register_gui_tool(tool_class,options_class,translated_name,
name,category,
description=_unavailable,
status=_("Unknown"),
author_name=_("Unknown"),
author_email=_("Unknown")):
del_index = -1 del_index = -1
for i in range(0,len(tool_list)): for i in range(0,len(tool_list)):
val = tool_list[i] val = tool_list[i]
@@ -171,8 +206,15 @@ def register_tool(
del_index = i del_index = i
if del_index != -1: if del_index != -1:
del tool_list[del_index] del tool_list[del_index]
tool_list.append((task, category, name, description, tool_list.append((tool_class,options_class,translated_name,
status, author_name, author_name)) category,name,description,status,
author_name,author_email))
def _register_cli_tool(name,category,tool_class,options_class):
for n in cli_tool_list:
if n[0] == name:
return
cli_tool_list.append((name,category,tool_class,options_class))
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@@ -194,7 +236,8 @@ def register_report(
""" """
Registers report for all possible flavors. Registers report for all possible flavors.
This function should be used to register report as a stand-alone, book item, or command-line flavor in any combination of those. This function should be used to register report as a stand-alone,
book item, or command-line flavor in any combination of those.
The low-level functions (starting with '_') should not be used The low-level functions (starting with '_') should not be used
on their own. Instead, this function will call them as needed. on their own. Instead, this function will call them as needed.
""" """

View File

@@ -1,7 +1,7 @@
# #
# Gramps - a GTK+/GNOME based genealogy program # Gramps - a GTK+/GNOME based genealogy program
# #
# Copyright (C) 2000-2004 Donald N. Allingham # Copyright (C) 2000-2005 Donald N. Allingham
# #
# This program is free software; you can redistribute it and/or modify # 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 # it under the terms of the GNU General Public License as published by
@@ -59,6 +59,7 @@ import Utils
import GrampsKeys import GrampsKeys
import Errors import Errors
import Report import Report
import Tool
import PluginMgr import PluginMgr
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@@ -421,16 +422,19 @@ class PluginStatus:
# Building pulldown menus # Building pulldown menus
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
def build_menu(top_menu,list,callback): def build_tools_menu(top_menu,callback):
report_menu = gtk.Menu() report_menu = gtk.Menu()
report_menu.show() report_menu.show()
hash_data = {} hash_data = {}
for report in list: for tool in PluginMgr.tool_list:
if hash_data.has_key(report[1]): tool_category = const.tool_categories[tool[3]]
hash_data[report[1]].append((report[2],report[0])) if hash_data.has_key(tool_category):
hash_data[tool_category].append(
(tool[0],tool[1],tool[2],tool[4],tool[3]))
else: else:
hash_data[report[1]] = [(report[2],report[0])] hash_data[tool_category] = [
(tool[0],tool[1],tool[2],tool[4],tool[3])]
catlist = hash_data.keys() catlist = hash_data.keys()
catlist.sort() catlist.sort()
@@ -442,11 +446,12 @@ def build_menu(top_menu,list,callback):
submenu.show() submenu.show()
entry.set_submenu(submenu) entry.set_submenu(submenu)
lst = hash_data[key] lst = hash_data[key]
lst.sort() lst.sort(by_menu_name)
for name in lst: for name in lst:
subentry = gtk.MenuItem("%s..." % name[0]) subentry = gtk.MenuItem("%s..." % name[2])
subentry.show() subentry.show()
subentry.connect("activate",callback,name[1]) subentry.connect("activate",callback,Tool.gui_tool,
name[0],name[1],name[2],name[3],name[4])
submenu.append(subentry) submenu.append(subentry)
top_menu.set_submenu(report_menu) top_menu.set_submenu(report_menu)
@@ -456,8 +461,6 @@ def build_menu(top_menu,list,callback):
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
def build_report_menu(top_menu,callback): def build_report_menu(top_menu,callback):
# build_menu(top_menu,_reports,callback)
#def build_menu(top_menu,list,callback):
report_menu = gtk.Menu() report_menu = gtk.Menu()
report_menu.show() report_menu.show()
@@ -488,7 +491,8 @@ def build_report_menu(top_menu,callback):
for name in lst: for name in lst:
subentry = gtk.MenuItem("%s..." % name[2]) subentry = gtk.MenuItem("%s..." % name[2])
subentry.show() subentry.show()
subentry.connect("activate",callback,Report.report,name[0],name[1],name[2],name[3],name[4]) subentry.connect("activate",callback,Report.report,
name[0],name[1],name[2],name[3],name[4])
submenu.append(subentry) submenu.append(subentry)
top_menu.set_submenu(report_menu) top_menu.set_submenu(report_menu)
@@ -501,8 +505,8 @@ def by_menu_name(a,b):
# build_tools_menu # build_tools_menu
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
def build_tools_menu(top_menu,callback): #def build_tools_menu(top_menu,callback):
build_menu(top_menu,PluginMgr.tool_list,callback) # build_menu(top_menu,PluginMgr.tool_list,callback)
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
@@ -724,9 +728,9 @@ def reload_plugins(obj=None,junk1=None,junk2=None,junk3=None):
# Register the plugin reloading tool # Register the plugin reloading tool
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
PluginMgr.register_tool( ## PluginMgr.register_tool(
reload_plugins, ## reload_plugins,
_("Reload plugins"), ## _("Reload plugins"),
category=_("Debug"), ## category=_("Debug"),
description=_("Attempt to reload plugins. Note: This tool itself is not reloaded!"), ## description=_("Attempt to reload plugins. Note: This tool itself is not reloaded!"),
) ## )

View File

@@ -52,70 +52,26 @@ import const
import GrampsKeys import GrampsKeys
import Utils import Utils
import BaseDoc import BaseDoc
import Options
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# List of options for a single report # List of options for a single report
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
class OptionList: class OptionList(Options.OptionList):
""" """
Implements a set of options to parse and store for a given report. Implements a set of options to parse and store for a given report.
""" """
def __init__(self): def __init__(self):
self.options = {} Options.OptionList.__init__(self)
self.style_name = None self.style_name = None
self.paper_name = None self.paper_name = None
self.orientation = None self.orientation = None
self.template_name = None self.template_name = None
self.format_name = None self.format_name = None
def set_options(self,options):
"""
Sets the whole bunch of options for the OptionList.
@param options: list of options to set.
@type options: list
"""
self.options = options
def get_options(self):
"""
Returns the whole bunch of options for the OptionList.
@returns: list of options
@rtype: list
"""
return self.options
def set_option(self,name,value):
"""
Sets a particular option in the OptionList.
@param name: name of the option to set.
@type name: str
@param value: value of the option to set.
@type str
"""
self.options[name] = value
def remove_option(self,name):
"""
Removes a particular option from the OptionList.
@param name: name of the option to remove.
@type name: str
"""
if self.options.has_key(name):
del self.options[name]
def get_option(self,name):
"""
Returns the value of a particular option in the OptionList.
@param name: name of the option to retrieve
@type name: str
@returns: value associated with the passed option
@rtype: str
"""
return self.options.get(name,None)
def set_style_name(self,style_name): def set_style_name(self,style_name):
""" """
Sets the style name for the OptionList. Sets the style name for the OptionList.
@@ -203,26 +159,20 @@ class OptionList:
# Collection of option lists # Collection of option lists
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
class OptionListCollection: class OptionListCollection(Options.OptionListCollection):
"""
Implements a collection of option lists.
"""
def __init__(self,filename):
Options.OptionListCollection.__init__(self,filename)
def init_common(self):
# Default values for common options # Default values for common options
default_style_name = "default" self.default_style_name = "default"
default_paper_name = GrampsKeys.get_paper_preference() self.default_paper_name = GrampsKeys.get_paper_preference()
default_template_name = "" self.default_template_name = ""
default_orientation = BaseDoc.PAPER_PORTRAIT self.default_orientation = BaseDoc.PAPER_PORTRAIT
default_format_name = 'print' self.default_format_name = 'print'
def __init__(self,filename=None):
"""
Creates an OptionListCollection instance from the list defined
in the specified file.
@param filename: XML file that contains option definitions
@type filename: str
"""
if not filename or not os.path.isfile(filename):
filename = const.report_options
self.filename = os.path.expanduser(filename)
self.last_paper_name = self.default_paper_name self.last_paper_name = self.default_paper_name
self.last_orientation = self.default_orientation self.last_orientation = self.default_orientation
@@ -230,45 +180,6 @@ class OptionListCollection:
self.last_format_name = self.default_format_name self.last_format_name = self.default_format_name
self.option_list_map = {} self.option_list_map = {}
self.parse()
def get_option_list_map(self):
"""
Returns the map of reports names to option lists.
@returns: Returns the map of reports names to option lists.
@rtype: dictionary
"""
return self.option_list_map
def get_option_list(self,name):
"""
Returns the option_list associated with the report name
@param name: name associated with the desired report.
@type name: str
@returns: returns the option list associated with the name,
or None of no such option exists
@rtype: str
"""
return self.option_list_map.get(name,None)
def get_report_names(self):
"""
Returns a list of all the report names in the OptionListCollection
@returns: returns the list of report names
@rtype: list
"""
return self.option_list_map.keys()
def set_option_list(self,name,option_list):
"""
Adds or replaces an option_list in the OptionListCollection.
@param name: name assocated with the report to add or replace.
@type name: str
@param option_list: list of options
@type option_list: str
"""
self.option_list_map[name] = option_list
def set_last_paper_name(self,paper_name): def set_last_paper_name(self,paper_name):
""" """
Sets the last paper name used for the any report in this collection. Sets the last paper name used for the any report in this collection.
@@ -330,14 +241,7 @@ class OptionListCollection:
""" """
return self.last_format_name return self.last_format_name
def save(self): def write_common(self,f):
"""
Saves the current OptionListCollection to the associated file.
"""
f = open(self.filename,"w")
f.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n")
f.write('<reportoptions>\n')
f.write('<last-common>\n') f.write('<last-common>\n')
if self.get_last_paper_name() != self.default_paper_name: if self.get_last_paper_name() != self.default_paper_name:
f.write(' <paper name="%s"/>\n' % self.get_last_paper_name() ) f.write(' <paper name="%s"/>\n' % self.get_last_paper_name() )
@@ -349,21 +253,7 @@ class OptionListCollection:
f.write(' <orientation value="%d"/>\n' % self.get_last_orientation() ) f.write(' <orientation value="%d"/>\n' % self.get_last_orientation() )
f.write('</last-common>\n') f.write('</last-common>\n')
for report_name in self.get_report_names(): def write_module_common(self,f,option_list):
option_list = self.get_option_list(report_name)
f.write('<report name="%s">\n' % report_name)
options = option_list.get_options()
for option_name in options.keys():
if type(options[option_name]) in (type(list()),type(tuple())):
f.write(' <option name="%s" value="" length="%d">\n' % (
option_name, len(options[option_name]) ) )
for list_index in range(len(options[option_name])):
f.write(' <listitem number="%d" value="%s"/>\n' % (
list_index, options[option_name][list_index]) )
f.write(' </option>\n')
else:
f.write(' <option name="%s" value="%s"/>\n' % (
option_name,options[option_name]) )
if option_list.get_style_name() \ if option_list.get_style_name() \
and option_list.get_style_name() != self.default_style_name: and option_list.get_style_name() != self.default_style_name:
f.write(' <style name="%s"/>\n' % option_list.get_style_name() ) f.write(' <style name="%s"/>\n' % option_list.get_style_name() )
@@ -379,10 +269,6 @@ class OptionListCollection:
if option_list.get_orientation() \ if option_list.get_orientation() \
and option_list.get_orientation() != self.default_orientation: and option_list.get_orientation() != self.default_orientation:
f.write(' <orientation value="%d"/>\n' % option_list.get_orientation() ) f.write(' <orientation value="%d"/>\n' % option_list.get_orientation() )
f.write('</report>\n')
f.write('</reportoptions>\n')
f.close()
def parse(self): def parse(self):
""" """
@@ -400,7 +286,7 @@ class OptionListCollection:
# OptionParser # OptionParser
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
class OptionParser(handler.ContentHandler): class OptionParser(Options.OptionParser):
""" """
SAX parsing class for the OptionListCollection XML file. SAX parsing class for the OptionListCollection XML file.
""" """
@@ -411,34 +297,17 @@ class OptionParser(handler.ContentHandler):
collection: BookList to be loaded from the file. collection: BookList to be loaded from the file.
""" """
handler.ContentHandler.__init__(self) Options.OptionParser.__init__(self,collection)
self.collection = collection
self.rname = None
self.option_list = None
self.oname = None
self.o = None
self.an_o = None
self.common = False self.common = False
self.list_class = OptionList
def startElement(self,tag,attrs): def startElement(self,tag,attrs):
""" """
Overridden class that handles the start of a XML element Overridden class that handles the start of a XML element
""" """
if tag == "report": # First we try report-specific tags
self.rname = attrs['name'] if tag == "last-common":
self.option_list = OptionList()
self.o = {}
elif tag == "last-common":
self.common = True self.common = True
elif tag == "option":
self.oname = attrs['name']
if attrs.has_key('length'):
self.an_o = []
else:
self.an_o = attrs['value']
elif tag == "listitem":
self.an_o.append(attrs['value'])
elif tag == "style": elif tag == "style":
self.option_list.set_style_name(attrs['name']) self.option_list.set_style_name(attrs['name'])
elif tag == "paper": elif tag == "paper":
@@ -461,32 +330,40 @@ class OptionParser(handler.ContentHandler):
self.collection.set_last_orientation(int(attrs['value'])) self.collection.set_last_orientation(int(attrs['value']))
else: else:
self.option_list.set_orientation(int(attrs['value'])) self.option_list.set_orientation(int(attrs['value']))
else:
# Tag is not report-specific, so we let the base class handle it.
Options.OptionParser.startElement(self,tag,attrs)
def endElement(self,tag): def endElement(self,tag):
"Overridden class that handles the end of a XML element" "Overridden class that handles the end of a XML element"
if tag == "option": # First we try report-specific tags
self.o[self.oname] = self.an_o if tag == "last-common":
elif tag == "report":
self.option_list.set_options(self.o)
self.collection.set_option_list(self.rname,self.option_list)
elif tag == "last-common":
self.common = False self.common = False
else:
# Tag is not report-specific, so we let the base class handle it.
Options.OptionParser.endElement(self,tag)
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# Class handling options for plugins # Class handling options for plugins
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
class OptionHandler: class OptionHandler(Options.OptionHandler):
""" """
Implements handling of the options for the plugins. Implements handling of the options for the plugins.
""" """
def __init__(self,module_name,options_dict,person_id=None):
Options.OptionHandler.__init__(self,module_name,options_dict,person_id)
def __init__(self,report_name,options_dict,person_id=None): def init_subclass(self):
self.report_name = report_name self.collection_class = OptionListCollection
self.default_options_dict = options_dict.copy() self.list_class = OptionList
self.options_dict = options_dict self.filename = const.report_options
def init_common(self):
"""
Specific initialization for reports.
"""
# These are needed for running reports. # These are needed for running reports.
# We will not need to save/retreive them, just keep around. # We will not need to save/retreive them, just keep around.
self.doc = None self.doc = None
@@ -494,50 +371,13 @@ class OptionHandler:
self.newpage = False self.newpage = False
# Retrieve our options from whole collection # Retrieve our options from whole collection
self.option_list_collection = OptionListCollection()
self.style_name = self.option_list_collection.default_style_name self.style_name = self.option_list_collection.default_style_name
self.paper_name = self.option_list_collection.get_last_paper_name() self.paper_name = self.option_list_collection.get_last_paper_name()
self.orientation = self.option_list_collection.get_last_orientation() self.orientation = self.option_list_collection.get_last_orientation()
self.template_name = self.option_list_collection.get_last_template_name() self.template_name = self.option_list_collection.get_last_template_name()
self.format_name = self.option_list_collection.get_last_format_name() self.format_name = self.option_list_collection.get_last_format_name()
self.saved_option_list = self.option_list_collection.get_option_list(report_name)
self.person_id = person_id
# Whatever was found should override the defaults def set_common_options(self):
if self.saved_option_list:
self.set_options()
else:
# If nothing was found, set up the option list
self.saved_option_list = OptionList()
self.option_list_collection.set_option_list(report_name,self.saved_option_list)
def set_options(self):
"""
Sets options to be used in this plugin according to the passed
options dictionary.
Dictionary values are all strings, since they were read from XML.
Here we need to convert them to the needed types. We use default
values to determine the type.
"""
# First we set options_dict values based on the saved options
options = self.saved_option_list.get_options()
bad_opts = []
for option_name in options.keys():
if not self.options_dict.has_key(option_name):
print "Option %s is present in the ~/.gramps/report_options.xml but is not known to the report." % option_name
print "Ignoring..."
bad_opts.append(option_name)
continue
try:
converter = Utils.get_type_converter(self.options_dict[option_name])
self.options_dict[option_name] = converter(options[option_name])
except ValueError:
pass
for option_name in bad_opts:
options.pop(option_name)
# Then we set common options from whatever was found
if self.saved_option_list.get_style_name(): if self.saved_option_list.get_style_name():
self.style_name = self.saved_option_list.get_style_name() self.style_name = self.saved_option_list.get_style_name()
if self.saved_option_list.get_orientation(): if self.saved_option_list.get_orientation():
@@ -549,29 +389,15 @@ class OptionHandler:
if self.saved_option_list.get_format_name(): if self.saved_option_list.get_format_name():
self.format_name = self.saved_option_list.get_format_name() self.format_name = self.saved_option_list.get_format_name()
def save_options(self): def save_common_options(self):
""" # First we save common options
Saves options to file.
We need to only store non-default options. Therefore, we remove all
options whose values are the defaults prior to saving. Also, we save
the present common options as the last-common for this collection.
"""
# First we save options from options_dict
for option_name in self.options_dict.keys():
if self.options_dict[option_name] == self.default_options_dict[option_name]:
self.saved_option_list.remove_option(option_name)
else:
self.saved_option_list.set_option(option_name,self.options_dict[option_name])
# Then we save common options
self.saved_option_list.set_style_name(self.style_name) self.saved_option_list.set_style_name(self.style_name)
self.saved_option_list.set_orientation(self.orientation) self.saved_option_list.set_orientation(self.orientation)
self.saved_option_list.set_template_name(self.template_name) self.saved_option_list.set_template_name(self.template_name)
self.saved_option_list.set_paper_name(self.paper_name) self.saved_option_list.set_paper_name(self.paper_name)
self.saved_option_list.set_format_name(self.format_name) self.saved_option_list.set_format_name(self.format_name)
self.option_list_collection.set_option_list(self.report_name,self.saved_option_list) self.option_list_collection.set_option_list(self.module_name,
self.saved_option_list)
# Then save last-common options from the current selection # Then save last-common options from the current selection
self.option_list_collection.set_last_orientation(self.orientation) self.option_list_collection.set_last_orientation(self.orientation)
@@ -579,9 +405,6 @@ class OptionHandler:
self.option_list_collection.set_last_paper_name(self.paper_name) self.option_list_collection.set_last_paper_name(self.paper_name)
self.option_list_collection.set_last_format_name(self.format_name) self.option_list_collection.set_last_format_name(self.format_name)
# Finally, save the whole collection into file
self.option_list_collection.save()
def get_report_generations(self): def get_report_generations(self):
if self.default_options_dict.has_key('gen'): if self.default_options_dict.has_key('gen'):
max_gen = self.options_dict.get('gen', max_gen = self.options_dict.get('gen',
@@ -598,7 +421,7 @@ class OptionHandler:
def get_stylesheet_savefile(self): def get_stylesheet_savefile(self):
"""Where to save user defined styles for this report.""" """Where to save user defined styles for this report."""
return "%s.xml" % self.report_name return "%s.xml" % self.module_name
def get_default_stylesheet_name(self): def get_default_stylesheet_name(self):
return self.style_name return self.style_name
@@ -606,16 +429,6 @@ class OptionHandler:
def set_default_stylesheet_name(self,style_name): def set_default_stylesheet_name(self,style_name):
self.style_name = style_name self.style_name = style_name
def get_filter_number(self):
if self.default_options_dict.has_key('filter'):
return self.options_dict.get('filter',
self.default_options_dict['filter'])
else:
return None
def set_filter_number(self,val):
self.options_dict['filter'] = val
def get_display_format(self): def get_display_format(self):
if self.default_options_dict.has_key('dispf'): if self.default_options_dict.has_key('dispf'):
return self.options_dict.get('dispf', return self.options_dict.get('dispf',
@@ -664,18 +477,12 @@ class OptionHandler:
def set_orientation(self,orientation): def set_orientation(self,orientation):
self.orientation = orientation self.orientation = orientation
def get_person_id(self):
return self.person_id
def set_person_id(self,val):
self.person_id = val
#------------------------------------------------------------------------ #------------------------------------------------------------------------
# #
# Base Options class # Base Options class
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
class ReportOptions: class ReportOptions(Options.Options):
""" """
Defines options and provides handling interface. Defines options and provides handling interface.
@@ -696,63 +503,6 @@ class ReportOptions:
self.options_dict.update(self.enable_dict) self.options_dict.update(self.enable_dict)
self.handler = OptionHandler(name,self.options_dict,person_id) self.handler = OptionHandler(name,self.options_dict,person_id)
def set_new_options(self):
"""
Sets options specific for this report.
Reports that need custom options need to override this method.
Two dictionaries MUST be defined here:
self.options_dict
This is a dictionary whose keys are option names
and values are the default option values.
self.options_help
This is a dictionary whose keys are option names
and values are 3- or 4- lists or tuples:
('=example",'Short description',VALUES,DO_PREPEND)
The VALUES is either a single string (in that case
the DO_PREPEND does not matter) or a list/tuple of
strings to list. In that case, if DO_PREPEND evaluates
as True then each string will be preneded with the ordinal
number when help is printed on the command line.
NOTE: Both dictionaries must have identical keys.
NOTE: If a particular report does not use custom options,
then it should not override this method.
"""
self.options_dict = {}
self.options_help = {}
def enable_options(self):
"""
Enables semi-common options for this report.
The semi-common option is the option which GRAMPS is aware of,
but not common enough to be present in all reports. Here's the list
of possible keys for semi-commons:
'filter' - Filter number, selected among filters
available for this report. If defined,
get_report_filters() method must be defined
which returns the list of available filters.
'gen' - Maximum number of generations to consider.
'pagebbg' - Whether or not make page breaks between generations.
'dispf' - Display format for the option box -- graphic reports.
A self.enable_dict dictionary MUST be defined here, whose keys
are the valid semi-common keys above, and whose values are the
desired default values for semi-commons.
NOTE: If a particular report does not use semi-common options,
then it should not override this method.
"""
self.enable_dict = {}
def make_default_style(self,default_style): def make_default_style(self,default_style):
""" """
Defines default style for this report. Defines default style for this report.
@@ -785,41 +535,6 @@ class ReportOptions:
""" """
pass pass
def add_user_options(self,dialog):
"""
Sets up UI controls (widgets) for the options specific for this report.
This method MUST be overridden by reports that define new options.
The single argument 'dialog' is the Report.BareReportDialog instance.
Any attribute of the dialog is available.
After the widgets are defined, they MUST be added to the dialog
using the following call:
dialog.add_options(LABEL,widget)
NOTE: To really have any effect besides looking pretty, each widget
set up here must be also parsed in the parse_user_options()
method below.
"""
pass
def parse_user_options(self,dialog):
"""
Parses UI controls (widgets) for the options specific for this report.
This method MUST be overridden by reports that define new options.
The single argument 'dialog' is the Report.BareReportDialog instance.
Any attribute of the dialog is available.
After obtaining values from the widgets, they MUST be used to set the
appropriate options_dict values. Otherwise the values will not have
any user-visible effect.
NOTE: Any widget parsed here MUST be defined and added to the dialog
in the add_user_options() method above.
"""
pass
def get_document(self): def get_document(self):
""" """
Return document instance. Return document instance.
@@ -876,14 +591,6 @@ class ReportOptions:
""" """
return self.handler.get_report_generations() return self.handler.get_report_generations()
def get_filter_number(self):
"""
Return number of a filter to use.
This method MUST NOT be overridden by subclasses.
"""
return self.handler.get_filter_number()
def get_display_format(self): def get_display_format(self):
""" """
Return display format for the option box of graphical report. Return display format for the option box of graphical report.

252
gramps2/src/Tool.py Normal file
View File

@@ -0,0 +1,252 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2005 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$
"ToolGeneration Framework"
__author__ = "Alex Roitman"
__version__ = "$Revision$"
from types import ClassType, InstanceType
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import const
import Utils
import GenericFilter
import NameDisplay
import Options
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
# Modes for running tools
MODE_GUI = 1 # Standrt tool using GUI
MODE_CLI = 2 # Command line interface (CLI)
#-------------------------------------------------------------------------
#
# Report
#
#-------------------------------------------------------------------------
class Tool:
"""
The Tool base class. This is a base class for generating
customized tools. It cannot be used as is, but it can be easily
sub-classed to create a functional tool.
"""
def __init__(self,database,person,options_class,name):
self.db = database
self.person = person
if type(options_class) == ClassType:
self.options = options_class(name)
elif type(options_class) == InstanceType:
self.options = options_class
def run_tool(self):
pass
#------------------------------------------------------------------------
#
# Command-line tool
#
#------------------------------------------------------------------------
class CommandLineTool:
"""
Provides a way to run tool from the command line.
"""
def __init__(self,database,name,category,option_class,options_str_dict):
self.database = database
self.category = category
self.option_class = option_class(name)
self.show = options_str_dict.pop('show',None)
self.options_str_dict = options_str_dict
self.init_options()
self.parse_option_str()
self.show_options()
def init_options(self):
self.options_dict = {
'id' : ''
}
self.options_help = {
'id' : ["=ID","Gramps ID of a central person. MANDATORY"],
'filter' : ["=num","Filter number."],
}
# Add tool-specific options
for key in self.option_class.handler.options_dict.keys():
if key not in self.options_dict.keys():
self.options_dict[key] = self.option_class.handler.options_dict[key]
# Add help for tool-specific options
for key in self.option_class.options_help.keys():
if key not in self.options_help.keys():
self.options_help[key] = self.option_class.options_help[key]
def parse_option_str(self):
for opt in self.options_str_dict.keys():
if opt in self.options_dict.keys():
converter = Utils.get_type_converter(self.options_dict[opt])
self.options_dict[opt] = converter(self.options_str_dict[opt])
self.option_class.handler.options_dict[opt] = self.options_dict[opt]
else:
print "Ignoring unknown option: %s" % opt
person_id = self.options_dict['id']
self.person = self.database.get_person_from_gramps_id(person_id)
id_list = []
for person_handle in self.database.get_person_handles():
person = self.database.get_person_from_handle(person_handle)
id_list.append("%s\t%s" % (
person.get_gramps_id(),
NameDisplay.displayer.display(person)))
self.options_help['id'].append(id_list)
self.options_help['id'].append(False)
if self.options_dict.has_key('filter'):
filter_num = self.options_dict['filter']
self.filters = self.option_class.get_report_filters(self.person)
self.option_class.handler.set_filter_number(filter_num)
filt_list = [ filt.get_name() for filt in self.filters ]
cust_filt_list = [ filt2.get_name() for filt2 in
GenericFilter.CustomFilters.get_filters() ]
filt_list.extend(cust_filt_list)
self.options_help['filter'].append(filt_list)
self.options_help['filter'].append(True)
def show_options(self):
if not self.show:
return
elif self.show == 'all':
print " Available options:"
for key in self.options_dict.keys():
print " %s" % key
print " Use 'show=option' to see description and acceptable values"
elif self.show in self.options_dict.keys():
print ' %s%s\t%s' % (self.show,
self.options_help[self.show][0],
self.options_help[self.show][1])
print " Available values are:"
vals = self.options_help[self.show][2]
if type(vals) in [list,tuple]:
if self.options_help[self.show][3]:
for num in range(len(vals)):
print " %d\t%s" % (num,vals[num])
else:
for val in vals:
print " %s" % val
else:
print " %s" % self.options_help[self.show][2]
else:
self.show = None
#------------------------------------------------------------------------
#
# Generic task functions for tools
#
#------------------------------------------------------------------------
# Standard GUI tool generic task
def gui_tool(database,person,tool_class,options_class,translated_name,
name,category,callback,parent):
"""
tool - 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
its arguments.
"""
try:
tool_class(database,person,options_class,name,callback,parent)
except:
import DisplayTrace
DisplayTrace.DisplayTrace()
# Command-line generic task
def cli_tool(database,name,category,tool_class,options_class,options_str_dict):
clt = CommandLineTool(database,name,category,
options_class,options_str_dict)
# Exit here if show option was given
if clt.show:
return
# run tool
try:
tool_class(database,clt.person,clt.option_class,name)
except:
import DisplayTrace
DisplayTrace.DisplayTrace()
#-------------------------------------------------------------------------
#
# Class handling options for plugins
#
#-------------------------------------------------------------------------
class OptionHandler(Options.OptionHandler):
"""
Implements handling of the options for the plugins.
"""
def __init__(self,module_name,options_dict,person_id=None):
Options.OptionHandler.__init__(self,module_name,options_dict,person_id)
def init_subclass(self):
self.collection_class = Options.OptionListCollection
self.list_class = Options.OptionList
self.filename = const.tool_options
#------------------------------------------------------------------------
#
# Tool Options class
#
#------------------------------------------------------------------------
class ToolOptions(Options.Options):
"""
Defines options and provides handling interface.
This is a base Options class for the tools. All tools' options
classes should derive from it.
"""
def __init__(self,name,person_id=None):
"""
Initializes the class, performing usual house-keeping tasks.
Subclasses MUST call this in their __init__() method.
"""
self.set_new_options()
self.enable_options()
if self.enable_dict:
self.options_dict.update(self.enable_dict)
self.handler = OptionHandler(name,self.options_dict,person_id)

View File

@@ -100,6 +100,7 @@ caution_xpm = "%s/caution.png" % rootDir
system_filters = "%s/system_filters.xml" % rootDir system_filters = "%s/system_filters.xml" % rootDir
custom_filters = "~/.gramps/custom_filters.xml" custom_filters = "~/.gramps/custom_filters.xml"
report_options = "~/.gramps/report_options.xml" report_options = "~/.gramps/report_options.xml"
tool_options = "~/.gramps/tool_options.xml"
icon = "%s/gramps.png" % rootDir icon = "%s/gramps.png" % rootDir
logo = "%s/logo.png" % rootDir logo = "%s/logo.png" % rootDir
gladeFile = "%s/gramps.glade" % rootDir gladeFile = "%s/gramps.glade" % rootDir
@@ -950,3 +951,19 @@ book_categories = {
CATEGORY_TEXT : _("Text"), CATEGORY_TEXT : _("Text"),
CATEGORY_DRAW : _("Graphics"), CATEGORY_DRAW : _("Graphics"),
} }
TOOL_DEBUG = -1
TOOL_ANAL = 0
TOOL_DBPROC = 1
TOOL_DBFIX = 2
TOOL_REVCTL = 3
TOOL_UTILS = 4
tool_categories = {
TOOL_DEBUG : _("Debug"),
TOOL_ANAL : _("Analysis and Exploration"),
TOOL_DBPROC : _("Database Processing"),
TOOL_DBFIX : _("Database Repair"),
TOOL_REVCTL : _("Revision Control"),
TOOL_UTILS : _("Utilities"),
}

View File

@@ -1963,10 +1963,13 @@ class Gramps(GrampsDBCallback.GrampsDBCallback):
task(self.db,self.active_person,report_class, task(self.db,self.active_person,report_class,
options_class,translated_name,name,category) options_class,translated_name,name,category)
def menu_tools(self,obj,task): def menu_tools(self,obj,task,tool_class,options_class,
translated_name,name,category):
"""Call the tool plugin selected from the menus""" """Call the tool plugin selected from the menus"""
if self.active_person: if self.active_person:
task(self.db,self.active_person,self.tool_callback,self) task(self.db,self.active_person,tool_class,options_class,
translated_name,name,category,
self.tool_callback,self)
def open_example(self,obj): def open_example(self,obj):
import shutil import shutil

View File

@@ -47,35 +47,30 @@ import const
import Utils import Utils
from QuestionDialog import OkDialog from QuestionDialog import OkDialog
import AutoComp import AutoComp
import Tool
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
# #
# #
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
def runTool(database,person,callback,parent=None): class ChangeTypes(Tool.Tool):
try: def __init__(self,db,person,options_class,name,callback=None,parent=None):
ChangeTypes(database,person,parent) Tool.Tool.__init__(self,db,person,options_class,name)
except:
import DisplayTrace
DisplayTrace.DisplayTrace()
#------------------------------------------------------------------------- if parent:
# self.init_gui(parent)
# else:
# self.run_tool(cli=True)
#-------------------------------------------------------------------------
class ChangeTypes: def init_gui(self,parent):
def __init__(self,db,person,parent): # Draw dialog and make it handle everything
self.person = person
self.db = db
self.parent = parent self.parent = parent
if self.parent.child_windows.has_key(self.__class__): if self.parent.child_windows.has_key(self.__class__):
self.parent.child_windows[self.__class__].present(None) self.parent.child_windows[self.__class__].present(None)
return return
self.win_key = self.__class__ self.win_key = self.__class__
self.trans = db.transaction_begin()
base = os.path.dirname(__file__) base = os.path.dirname(__file__)
glade_file = "%s/%s" % (base,"changetype.glade") glade_file = "%s/%s" % (base,"changetype.glade")
self.glade = gtk.glade.XML(glade_file,"top","gramps") self.glade = gtk.glade.XML(glade_file,"top","gramps")
@@ -85,6 +80,10 @@ class ChangeTypes:
AutoComp.fill_combo(self.auto1,const.personalEvents) AutoComp.fill_combo(self.auto1,const.personalEvents)
AutoComp.fill_combo(self.auto2,const.personalEvents) AutoComp.fill_combo(self.auto2,const.personalEvents)
self.auto1.child.set_text(
self.options.handler.options_dict['fromtype'])
self.auto2.child.set_text(
self.options.handler.options_dict['totype'])
self.title = _('Change Event Types') self.title = _('Change Event Types')
self.window = self.glade.get_widget('top') self.window = self.glade.get_widget('top')
@@ -102,6 +101,45 @@ class ChangeTypes:
self.add_itself_to_menu() self.add_itself_to_menu()
self.window.show() self.window.show()
def run_tool(self,cli=False):
# Run tool and return results
fromtype = self.options.handler.options_dict['fromtype']
totype = self.options.handler.options_dict['totype']
modified = 0
self.trans = self.db.transaction_begin()
if not cli:
progress = Utils.ProgressMeter(_('Analyzing events'),'')
progress.set_pass('',self.db.get_number_of_people())
for person_handle in self.db.get_person_handles(sort_handles=False):
person = self.db.get_person_from_handle(person_handle)
for event_handle in person.get_event_list():
if not event_handle:
continue
event = self.db.get_event_from_handle(event_handle)
if event.get_name() == fromtype:
event.set_name(totype)
modified = modified + 1
self.db.commit_event(event,self.trans)
if not cli:
progress.step()
if not cli:
progress.close()
self.db.transaction_commit(self.trans,_('Change types'))
if modified == 0:
msg = _("No event record was modified.")
elif modified == 1:
msg = _("1 event record was modified.")
else:
msg = _("%d event records were modified.") % modified
if cli:
print "Done: ", msg
return (bool(modified),msg)
def on_delete_event(self,obj,b): def on_delete_event(self,obj,b):
self.remove_itself_from_menu() self.remove_itself_from_menu()
@@ -124,32 +162,17 @@ class ChangeTypes:
self.window.present() self.window.present()
def on_apply_clicked(self,obj): def on_apply_clicked(self,obj):
modified = 0 self.options.handler.options_dict['fromtype'] = unicode(
original = unicode(self.auto1.child.get_text()) self.auto1.child.get_text())
new = unicode(self.auto2.child.get_text()) self.options.handler.options_dict['totype'] = unicode(
self.auto2.child.get_text())
progress = Utils.ProgressMeter(_('Analyzing events'),'')
progress.set_pass('',self.db.get_number_of_people())
for person_handle in self.db.get_person_handles(sort_handles=False):
person = self.db.get_person_from_handle(person_handle)
for event_handle in person.get_event_list():
if not event_handle:
continue
event = self.db.get_event_from_handle(event_handle)
if event.get_name() == original:
event.set_name(new)
modified = modified + 1
self.db.commit_event(event,self.trans)
progress.step()
progress.close()
if modified == 1:
msg = _("1 event record was modified")
else:
msg = _("%d event records were modified") % modified
modified,msg = self.run_tool(cli=False)
OkDialog(_('Change types'),msg,self.parent.topWindow) OkDialog(_('Change types'),msg,self.parent.topWindow)
self.db.transaction_commit(self.trans,_('Change types'))
# Save options
self.options.handler.save_options()
self.close(None) self.close(None)
#------------------------------------------------------------------------ #------------------------------------------------------------------------
@@ -157,11 +180,43 @@ class ChangeTypes:
# #
# #
#------------------------------------------------------------------------ #------------------------------------------------------------------------
from PluginMgr import register_tool class ChangeTypesOptions(Tool.ToolOptions):
"""
Defines options and provides handling interface.
"""
def __init__(self,name,person_id=None):
Tool.ToolOptions.__init__(self,name,person_id)
def set_new_options(self):
# Options specific for this report
self.options_dict = {
'fromtype' : '',
'totype' : '',
}
self.options_help = {
'fromtype' : ("=str","Type of events to replace",
"Event type string"),
'totype' : ("=str","New type replacing the old one",
"Event type string"),
}
#------------------------------------------------------------------------
#
#
#
#------------------------------------------------------------------------
from PluginMgr import register_tool
register_tool( register_tool(
runTool, name = 'chtype',
_("Rename personal event types"), category = const.TOOL_DBPROC,
category=_("Database Processing"), tool_class = ChangeTypes,
description=_("Allows all the events of a certain name to be renamed to a new name") options_class = ChangeTypesOptions,
modes = Tool.MODE_GUI | Tool.MODE_CLI,
translated_name = _("Rename personal event types"),
status = _("Beta"),
author_name = "Donald N. Allingham",
author_email = "dallingham@users.sourceforge.net",
description = _("Allows all the events of a certain name "
"to be renamed to a new name.")
) )