* src/Plugins.py, src/PluginMgr.py: Move to ReportUtils.

svn: r6133
This commit is contained in:
Alex Roitman
2006-03-11 01:12:06 +00:00
parent 9d086fd022
commit 6b9d4207ce
91 changed files with 321 additions and 375 deletions

View File

@@ -11,7 +11,9 @@ pkgdata_PYTHON = \
_ReportOptions.py\
_Report.py\
_ReportUtils.py\
_Tool.py
_Tool.py\
_PluginMgr.py\
_Plugins.py
pkgpyexecdir = @pkgpyexecdir@/PluginUtils
pkgpythondir = @pkgpythondir@/PluginUtils

View File

@@ -0,0 +1,470 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-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$
"""
The core of the GRAMPS plugin system. This module provides tasks to load
plugins from specfied directories, build menus for the different categories,
and provide dialog to select and execute plugins.
Plugins are divided into several categories. This are: reports, tools,
importers, exporters, and document generators.
"""
#-------------------------------------------------------------------------
#
# Standard Python modules
#
#-------------------------------------------------------------------------
import os
import sys
import re
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import Errors
#-------------------------------------------------------------------------
#
# Global lists
#
#-------------------------------------------------------------------------
report_list = []
tool_list = []
import_list = []
export_list = []
expect_list = []
attempt_list = []
loaddir_list = []
textdoc_list = []
bookdoc_list = []
drawdoc_list = []
failmsg_list = []
bkitems_list = []
cl_list = []
cli_tool_list = []
_success_list = []
#-------------------------------------------------------------------------
#
# Default relationship calculator
#
#-------------------------------------------------------------------------
import Relationship
_relcalc_class = Relationship.RelationshipCalculator
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
_unavailable = _("No description was provided"),
#-------------------------------------------------------------------------
#
# load_plugins
#
#-------------------------------------------------------------------------
def load_plugins(direct):
"""Searches the specified directory, and attempts to load any python
modules that it finds, adding name to the attempt_lists list. If the module
successfully loads, it is added to the _success_list list. Each plugin is
responsible for registering itself in the correct manner. No attempt
is done in this routine to register the tasks."""
global _success_list,attempt_list,loaddir_list,failmsg_list
# if the directory does not exist, do nothing
if not os.path.isdir(direct):
return True
# if the path has not already been loaded, save it in the loaddir_list
# list for use on reloading
if direct not in loaddir_list:
loaddir_list.append(direct)
# add the directory to the python search path
sys.path.append(direct)
pymod = re.compile(r"^(.*)\.py$")
# loop through each file in the directory, looking for files that
# have a .py extention, and attempt to load the file. If it succeeds,
# add it to the _success_list list. If it fails, add it to the _failure
# list
for filename in os.listdir(direct):
name = os.path.split(filename)
match = pymod.match(name[1])
if not match:
continue
attempt_list.append(filename)
plugin = match.groups()[0]
try:
a = __import__(plugin)
_success_list.append(a)
except Errors.PluginError, msg:
expect_list.append((filename,str(msg)))
except:
failmsg_list.append((filename,sys.exc_info()))
if len(expect_list)+len(failmsg_list):
return False
else:
return True
#-------------------------------------------------------------------------
#
# Plugin registering
#
#-------------------------------------------------------------------------
def register_export(exportData,title,description='',config=None,filename=''):
"""
Register an export filter, taking the task, file filter,
and the list of patterns for the filename matching.
"""
if description and filename:
del_index = -1
for i in range(0,len(export_list)):
if export_list[i][1] == title:
del_index = i
if del_index != -1:
del export_list[del_index]
export_list.append((exportData,title,description,config,filename))
def register_import(task, ffilter, mime=None, native_format=0, format_name=""):
"""Register an import filter, taking the task and file filter"""
if mime:
del_index = -1
for i in range(0,len(import_list)):
if import_list[i][2] == mime:
del_index = i
if del_index != -1:
del import_list[del_index]
import_list.append((task, ffilter, mime, native_format, format_name))
#-------------------------------------------------------------------------
#
# Tool registration
#
#-------------------------------------------------------------------------
def register_tool(
name,
category,
tool_class,
options_class,
modes,
translated_name,
status=_("Unknown"),
description=_unavailable,
author_name=_("Unknown"),
author_email=_("Unknown"),
unsupported=False
):
"""
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.
"""
import _Tool
(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,unsupported)
(junk,cli_task) = divmod(modes-gui_task,2**_Tool.MODE_CLI)
if cli_task:
_register_cli_tool(name,category,tool_class,options_class,
translated_name,unsupported)
def _register_gui_tool(tool_class,options_class,translated_name,
name,category,
description=_unavailable,
status=_("Unknown"),
author_name=_("Unknown"),
author_email=_("Unknown"),
unsupported=False):
del_index = -1
for i in range(0,len(tool_list)):
val = tool_list[i]
if val[4] == name:
del_index = i
if del_index != -1:
del tool_list[del_index]
tool_list.append((tool_class,options_class,translated_name,
category,name,description,status,
author_name,author_email,unsupported))
def _register_cli_tool(name,category,tool_class,options_class,
translated_name,unsupported=False):
del_index = -1
for i in range(0,len(cli_tool_list)):
val = cli_tool_list[i]
if val[0] == name:
del_index = i
if del_index != -1:
del cli_tool_list[del_index]
cli_tool_list.append((name,category,tool_class,options_class,
translated_name,unsupported))
#-------------------------------------------------------------------------
#
# Report registration
#
#-------------------------------------------------------------------------
def register_report(
name,
category,
report_class,
options_class,
modes,
translated_name,
status=_("Unknown"),
description=_unavailable,
author_name=_("Unknown"),
author_email=_("Unknown"),
unsupported=False
):
"""
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.
The low-level functions (starting with '_') should not be used
on their own. Instead, this function will call them as needed.
"""
import _Report
(junk,standalone_task) = divmod(modes,2**_Report.MODE_GUI)
if standalone_task:
_register_standalone(report_class,options_class,translated_name,
name,category,description,
status,author_name,author_email,unsupported)
(junk,book_item_task) = divmod(modes-standalone_task,2**_Report.MODE_BKI)
if book_item_task:
book_item_category = _Report.book_categories[category]
register_book_item(translated_name,book_item_category,
report_class,options_class,name,unsupported)
(junk,command_line_task) = divmod(modes-standalone_task-book_item_task,
2**_Report.MODE_CLI)
if command_line_task:
_register_cl_report(name,category,report_class,options_class,
translated_name,unsupported)
def _register_standalone(report_class, options_class, translated_name,
name, category,
description=_unavailable,
status=_("Unknown"),
author_name=_("Unknown"),
author_email=_("Unknown"),
unsupported=False
):
"""Register a report with the plugin system"""
from PluginUtils import Report
del_index = -1
for i in range(0,len(report_list)):
val = report_list[i]
if val[4] == name:
del_index = i
if del_index != -1:
del report_list[del_index]
report_list.append((report_class, options_class, translated_name,
category, name, description, status,
author_name, author_email, unsupported))
def register_book_item(translated_name, category, report_class,
option_class, name, unsupported):
"""Register a book item"""
del_index = -1
for i in range(0,len(bkitems_list)):
val = bkitems_list[i]
if val[4] == name:
del_index = i
if del_index != -1:
del bkitems_list[del_index]
bkitems_list.append((translated_name, category, report_class,
option_class, name, unsupported))
def _register_cl_report(name,category,report_class,options_class,
translated_name,unsupported):
del_index = -1
for i in range(0,len(cl_list)):
val = cl_list[i]
if val[0] == name:
del_index = i
if del_index != -1:
del cl_list[del_index]
cl_list.append((name,category,report_class,options_class,
translated_name,unsupported))
#-------------------------------------------------------------------------
#
# Text document generator registration
#
#-------------------------------------------------------------------------
def register_text_doc(name,classref, table, paper, style, ext,
print_report_label=None,clname=''):
"""Register a text document generator"""
del_index = -1
for i in range(0,len(textdoc_list)):
val = textdoc_list[i]
if val[0] == name:
del_index = i
if del_index != -1:
del textdoc_list[del_index]
if not clname:
clname = ext[1:]
textdoc_list.append(
(name, classref, table, paper, style,
ext, print_report_label, clname))
#-------------------------------------------------------------------------
#
# Book document generator registration
#
#-------------------------------------------------------------------------
def register_book_doc(name,classref, table, paper, style, ext, clname=''):
"""Register a text document generator"""
del_index = -1
for i in range(0,len(bookdoc_list)):
val = bookdoc_list[i]
if val[0] == name:
del_index = i
if del_index != -1:
del bookdoc_list[del_index]
if not clname:
clname = ext[1:]
bookdoc_list.append((name,classref,table,paper,style,ext,None,clname))
#-------------------------------------------------------------------------
#
# Drawing document generator registration
#
#-------------------------------------------------------------------------
def register_draw_doc(name,classref,paper,style, ext,
print_report_label=None,clname=''):
"""Register a drawing document generator"""
del_index = -1
for i in range(0,len(drawdoc_list)):
val = drawdoc_list[i]
if val[0] == name:
del_index = i
if del_index != -1:
del drawdoc_list[del_index]
if not clname:
clname = ext[1:]
drawdoc_list.append((name, classref, paper,style, ext,
print_report_label, clname))
#-------------------------------------------------------------------------
#
# Remove plugins whose reloading failed from the already-registered lists
#
#-------------------------------------------------------------------------
def purge_failed(failed_list,export_list,import_list,tool_list,cli_tool_list,
report_list,bkitems_list,cl_list,textdoc_list,bookdoc_list,
drawdoc_list):
failed_module_names = [
os.path.splitext(os.path.basename(filename))[0]
for filename,junk in failed_list
]
export_list = [ item for item in export_list
if item[0].__module__ not in failed_module_names ]
import_list = [ item for item in import_list
if item[0].__module__ not in failed_module_names ]
tool_list = [ item for item in tool_list
if item[0].__module__ not in failed_module_names ]
cli_tool_list = [ item for item in cli_tool_list
if item[2].__module__ not in failed_module_names ]
report_list = [ item for item in report_list
if item[0].__module__ not in failed_module_names ]
bkitems_list = [ item for item in bkitems_list
if item[2].__module__ not in failed_module_names ]
cl_list = [ item for item in cl_list
if item[2].__module__ not in failed_module_names ]
textdoc_list = [ item for item in textdoc_list
if item[1].__module__ not in failed_module_names ]
bookdoc_list = [ item for item in bookdoc_list
if item[1].__module__ not in failed_module_names ]
drawdoc_list = [ item for item in drawdoc_list
if item[1].__module__ not in failed_module_names ]
# For some funky reason this module's global variables
# are not seen inside this function. But they are seen
# from other modules, so we pass them back and forth.
# Sucks, but I don't know why this happens :-(
return (export_list,import_list,tool_list,cli_tool_list,
report_list,bkitems_list,cl_list,textdoc_list,bookdoc_list,
drawdoc_list)
#-------------------------------------------------------------------------
#
# Relationship calculator registration
#
#-------------------------------------------------------------------------
def register_relcalc(relclass, languages):
"""Register a relationshp calculator"""
global _relcalc_class
try:
if os.environ["LANG"] in languages:
_relcalc_class = relclass
except:
pass
def relationship_class(db):
global _relcalc_class
return _relcalc_class(db)
#-------------------------------------------------------------------------
#
# Image attributes
#
#-------------------------------------------------------------------------
_image_attributes = []
def register_image_attribute(name):
if name not in _image_attributes:
_image_attributes.append(name)
def get_image_attributes():
return _image_attributes

575
src/PluginUtils/_Plugins.py Normal file
View File

@@ -0,0 +1,575 @@
#
# Gramps - a GTK+/GNOME based genealogy program
#
# Copyright (C) 2000-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$
"""
The core of the GRAMPS plugin system. This module provides tasks to load
plugins from specfied directories, build menus for the different categories,
and provide dialog to select and execute plugins.
Plugins are divided into several categories. This are: reports, tools,
importers, exporters, and document generators.
"""
#-------------------------------------------------------------------------
#
# GTK libraries
#
#-------------------------------------------------------------------------
import gobject
import gtk
import gtk.glade
#-------------------------------------------------------------------------
#
# Standard Python modules
#
#-------------------------------------------------------------------------
import traceback
import os
import sys
import re
from gettext import gettext as _
#-------------------------------------------------------------------------
#
# GRAMPS modules
#
#-------------------------------------------------------------------------
import const
import Utils
import Config
import Errors
import _Report
import _Tool
import _PluginMgr
import GrampsDisplay
import DisplayState
#-------------------------------------------------------------------------
#
# Constants
#
#-------------------------------------------------------------------------
REPORTS = 0
TOOLS = 1
UNSUPPORTED = _("Unsupported")
#-------------------------------------------------------------------------
#
# PluginDialog interface class
#
#-------------------------------------------------------------------------
class PluginDialog(DisplayState.ManagedWindow):
"""Displays the dialog box that allows the user to select the
report that is desired."""
def __init__(self,state, uistate, track, item_list,categories,msg,label=None,
button_label=None,tool_tip=None,content=REPORTS):
"""Display the dialog box, and build up the list of available
reports. This is used to build the selection tree on the left
hand side of the dailog box."""
self.active = state.active
self.imap = {}
self.msg = msg
self.content = content
DisplayState.ManagedWindow.__init__(self, uistate, [], None)
self.state = state
self.uistate = uistate
self.dialog = gtk.glade.XML(const.plugins_glade,"report","gramps")
self.dialog.signal_autoconnect({
"on_report_apply_clicked" : self.on_apply_clicked,
"destroy_passed_object" : self.close,
"on_delete_event" : self.on_delete_event,
})
self.tree = self.dialog.get_widget("tree")
self.window = self.dialog.get_widget("report")
self.title = self.dialog.get_widget("title")
Utils.set_titles(self.window, self.title, msg )
self.store = gtk.TreeStore(gobject.TYPE_STRING)
self.selection = self.tree.get_selection()
self.selection.connect('changed', self.on_node_selected)
col = gtk.TreeViewColumn('',gtk.CellRendererText(),text=0)
self.tree.append_column(col)
self.tree.set_model(self.store)
self.description = self.dialog.get_widget("description")
if label:
self.description.set_text(label)
self.status = self.dialog.get_widget("report_status")
Utils.set_title_label(self.dialog,msg)
self.author_name = self.dialog.get_widget("author_name")
self.author_email = self.dialog.get_widget("author_email")
self.statbox = self.dialog.get_widget("statbox")
self.apply_button = self.dialog.get_widget("apply")
if button_label:
self.apply_button.set_label(button_label)
else:
self.apply_button.set_label(_("_Apply"))
self.apply_button.set_use_underline(True)
if tool_tip:
try:
tt = gtk.tooltips_data_get(self.apply_button)
if tt:
tt[0].set_tip(self.apply_button,tool_tip)
except AttributeError:
pass
self.item = None
self.build_plugin_tree(item_list,categories)
self.window.show()
def on_delete_event(self,obj,b):
pass
def close(self,ok=0):
self.window.destroy()
def on_apply_clicked(self,obj):
"""Execute the selected report"""
(item_class,options_class,title,category,name) = self.item
if self.content == REPORTS:
_Report.report(self.state.db,self.state.active,
item_class,options_class,title,name,category)
else:
_Tool.gui_tool(self.state.db,self.state.active,
item_class,options_class,title,name,category,
self.state.db.request_rebuild,self.parent)
def on_node_selected(self,obj):
"""Updates the informational display on the right hand side of
the dialog box with the description of the selected report"""
store,node = self.selection.get_selected()
if node:
path = store.get_path(node)
if not node or not self.imap.has_key(path):
self.statbox.hide()
return
self.statbox.show()
data = self.imap[path]
(report_class,options_class,title,category,name,
doc,status,author,email,unsupported) = data
self.description.set_text(doc)
if unsupported:
status = UNSUPPORTED
self.status.set_text(status)
self.title.set_text('<span weight="bold" size="larger">%s</span>' % title)
self.title.set_use_markup(1)
self.author_name.set_text(author)
self.author_email.set_text(email)
self.item = (report_class,options_class,title,category,name)
def build_plugin_tree(self,item_list,categories):
"""Populates a GtkTree with each menu item assocated with a entry
in the lists. The list must consist of a tuples with the following
format:
(item_class,options_class,title,category,name,
doc,status,author,email)
Items in the same category are grouped under the same submenu.
The categories must be dicts from integer to string.
"""
ilist = []
# build the tree items and group together based on the category name
item_hash = {}
for plugin in item_list:
if plugin[9]:
category = UNSUPPORTED
else:
category = categories[plugin[3]]
if item_hash.has_key(category):
item_hash[category].append(plugin)
else:
item_hash[category] = [plugin]
# add a submenu for each category, and populate it with the
# GtkTreeItems that are associated with it.
key_list = [ item for item in item_hash.keys() if item != UNSUPPORTED]
key_list.sort()
key_list.reverse()
prev = None
if item_hash.has_key(UNSUPPORTED):
key = UNSUPPORTED
data = item_hash[key]
node = self.store.insert_after(None,prev)
self.store.set(node,0,key)
next = None
data.sort(lambda x,y: cmp(x[2],y[2]))
for item in data:
next = self.store.insert_after(node,next)
ilist.append((next,item))
self.store.set(next,0,item[2])
for key in key_list:
data = item_hash[key]
node = self.store.insert_after(None,prev)
self.store.set(node,0,key)
next = None
data.sort(lambda x,y: cmp(x[2],y[2]))
for item in data:
next = self.store.insert_after(node,next)
ilist.append((next,item))
self.store.set(next,0,item[2])
for next,tab in ilist:
path = self.store.get_path(next)
self.imap[path] = tab
#-------------------------------------------------------------------------
#
# ReportPlugins interface class
#
#-------------------------------------------------------------------------
class ReportPlugins(PluginDialog):
"""Displays the dialog box that allows the user to select the
report that is desired."""
def __init__(self,dbstate,uistate,track):
"""Display the dialog box, and build up the list of available
reports. This is used to build the selection tree on the left
hand side of the dailog box."""
PluginDialog.__init__(
self,
dbstate,
uistate,
track,
_PluginMgr.report_list,
_Report.standalone_categories,
_("Report Selection"),
_("Select a report from those available on the left."),
_("_Generate"), _("Generate selected report"),
REPORTS)
#-------------------------------------------------------------------------
#
# ToolPlugins interface class
#
#-------------------------------------------------------------------------
class ToolPlugins(PluginDialog):
"""Displays the dialog box that allows the user to select the tool
that is desired."""
def __init__(self,dbstate,uistate,track):
"""Display the dialog box, and build up the list of available
reports. This is used to build the selection tree on the left
hand side of the dailog box."""
PluginDialog.__init__(
self,
dbstate,
uistate,
track,
_PluginMgr.tool_list,
_Tool.tool_categories,
_("Tool Selection"),
_("Select a tool from those available on the left."),
_("_Run"),
_("Run selected tool"),
TOOLS)
#-------------------------------------------------------------------------
#
# PluginStatus
#
#-------------------------------------------------------------------------
class PluginStatus(DisplayState.ManagedWindow):
"""Displays a dialog showing the status of loaded plugins"""
def __init__(self,state,uistate,track):
import cStringIO
DisplayState.ManagedWindow.__init__(self, uistate, [], None)
self.state = state
self.uistate = uistate
self.glade = gtk.glade.XML(const.pluginsFile,"plugstat","gramps")
self.window = self.glade.get_widget("plugstat")
self.window.set_title("%s - GRAMPS" % _('Plugin status'))
window = self.glade.get_widget("text")
self.pop_button = self.glade.get_widget("pop_button")
self.pop_button.set_active(Config.get_pop_plugin_status())
self.pop_button.connect('toggled',
lambda obj: Config.save_pop_plugin_status(self.pop_button.get_active()))
Config.client.notify_add("/apps/gramps/behavior/pop-plugin-status",
self.pop_button_update)
self.glade.signal_autoconnect({
'on_close_clicked' : self.close,
'on_help_clicked' : self.help,
'on_plugstat_delete_event' : self.on_delete,
})
info = cStringIO.StringIO()
if len(_PluginMgr.expect_list) + len(_PluginMgr.failmsg_list) == 0:
window.get_buffer().set_text(_('All modules were successfully loaded.'))
else:
info.write(_("The following modules could not be loaded:"))
info.write("\n\n")
for (filename,msg) in _PluginMgr.expect_list:
info.write("%s: %s\n\n" % (filename,msg))
for (filename,msgs) in _PluginMgr.failmsg_list:
error = str(msgs[0])
if error[0:11] == "exceptions.":
error = error[11:]
info.write("%s: %s\n" % (filename,error) )
traceback.print_exception(msgs[0],msgs[1],msgs[2],None,info)
info.write('\n')
info.seek(0)
window.get_buffer().set_text(info.read())
def on_delete(self,obj1,obj2):
pass
def close(self,obj):
self.window.destroy()
def help(self,obj):
"""Display the GRAMPS manual"""
GrampsDisplay.help('gramps-getting-started')
def pop_button_update(self, client,cnxn_id,entry,data):
self.pop_button.set_active(Config.get_pop_plugin_status())
#-------------------------------------------------------------------------
#
# Building pulldown menus
#
#-------------------------------------------------------------------------
def build_tools_menu(top_menu,callback):
build_plugin_menu(_PluginMgr.tool_list,
_Tool.tool_categories,
_Tool.gui_tool,
top_menu,callback)
def build_report_menu(top_menu,callback):
build_plugin_menu(_PluginMgr.report_list,
_Report.standalone_categories,
_Report.report,
top_menu,callback)
def build_plugin_menu(item_list,categories,func,top_menu,callback):
menu = gtk.Menu()
menu.show()
hash_data = {}
for item in item_list:
if item[9]:
category = UNSUPPORTED
else:
category = categories[item[3]]
if hash_data.has_key(category):
hash_data[category].append(
(item[0],item[1],item[2],item[4],item[3]))
else:
hash_data[category] = [
(item[0],item[1],item[2],item[4],item[3])]
# Sort categories, skipping the unsupported
catlist = [item for item in hash_data.keys() if item != UNSUPPORTED]
catlist.sort()
for key in catlist:
entry = gtk.MenuItem(key)
entry.show()
menu.append(entry)
submenu = gtk.Menu()
submenu.show()
entry.set_submenu(submenu)
lst = hash_data[key]
lst.sort(by_menu_name)
for name in lst:
subentry = gtk.MenuItem("%s..." % name[2])
subentry.show()
subentry.connect("activate",callback,func,
name[0],name[1],name[2],name[3],name[4])
submenu.append(subentry)
# If there are any unsupported items we add separator
# and the unsupported category at the end of the menu
if hash_data.has_key(UNSUPPORTED):
entry = gtk.MenuItem(None)
entry.show()
menu.append(entry)
key = UNSUPPORTED
entry = gtk.MenuItem(key)
entry.show()
menu.append(entry)
submenu = gtk.Menu()
submenu.show()
entry.set_submenu(submenu)
lst = hash_data[key]
lst.sort(by_menu_name)
for name in lst:
subentry = gtk.MenuItem("%s..." % name[2])
subentry.show()
subentry.connect("activate",callback,func,
name[0],name[1],name[2],name[3],name[4])
submenu.append(subentry)
top_menu.set_submenu(menu)
def by_menu_name(a,b):
return cmp(a[2],b[2])
#-------------------------------------------------------------------------
#
# Reload plugins
#
#-------------------------------------------------------------------------
class Reload(_Tool.Tool):
def __init__(self,db,person,options_class,name,callback=None,parent=None):
_Tool.Tool.__init__(self,db,person,options_class,name)
"""
Treated as a callback, causes all plugins to get reloaded.
This is useful when writing and debugging a plugin.
"""
pymod = re.compile(r"^(.*)\.py$")
oldfailmsg = _PluginMgr.failmsg_list[:]
_PluginMgr.failmsg_list = []
# attempt to reload all plugins that have succeeded in the past
for plugin in _PluginMgr._success_list:
filename = os.path.basename(plugin.__file__)
filename = filename.replace('pyc','py')
filename = filename.replace('pyo','py')
try:
reload(plugin)
except:
_PluginMgr.failmsg_list.append((filename,sys.exc_info()))
# Remove previously good plugins that are now bad
# from the registered lists
(_PluginMgr.export_list,
_PluginMgr.import_list,
_PluginMgr.tool_list,
_PluginMgr.cli_tool_list,
_PluginMgr.report_list,
_PluginMgr.bkitems_list,
_PluginMgr.cl_list,
_PluginMgr.textdoc_list,
_PluginMgr.bookdoc_list,
_PluginMgr.drawdoc_list) = _PluginMgr.purge_failed(
_PluginMgr.failmsg_list,
_PluginMgr.export_list,
_PluginMgr.import_list,
_PluginMgr.tool_list,
_PluginMgr.cli_tool_list,
_PluginMgr.report_list,
_PluginMgr.bkitems_list,
_PluginMgr.cl_list,
_PluginMgr.textdoc_list,
_PluginMgr.bookdoc_list,
_PluginMgr.drawdoc_list)
# attempt to load the plugins that have failed in the past
for (filename,message) in oldfailmsg:
name = os.path.split(filename)
match = pymod.match(name[1])
if not match:
continue
_PluginMgr.attempt_list.append(filename)
plugin = match.groups()[0]
try:
# For some strange reason second importing of a failed plugin
# results in success. Then reload reveals the actual error.
# Looks like a bug in Python.
a = __import__(plugin)
reload(a)
_PluginMgr._success_list.append(a)
except:
_PluginMgr.failmsg_list.append((filename,sys.exc_info()))
# attempt to load any new files found
for directory in _PluginMgr.loaddir_list:
for filename in os.listdir(directory):
name = os.path.split(filename)
match = pymod.match(name[1])
if not match:
continue
if filename in _PluginMgr.attempt_list:
continue
_PluginMgr.attempt_list.append(filename)
plugin = match.groups()[0]
try:
a = __import__(plugin)
if a not in _PluginMgr._success_list:
_PluginMgr._success_list.append(a)
except:
_PluginMgr.failmsg_list.append((filename,sys.exc_info()))
if Config.get_pop_plugin_status() and len(_PluginMgr.failmsg_list):
PluginStatus()
else:
global status_up
if status_up:
status_up.close(None)
status_up = None
# Re-generate tool and report menus
parent.build_plugin_menus(rebuild=True)
class ReloadOptions(_Tool.ToolOptions):
"""
Defines options and provides handling interface.
"""
def __init__(self,name,person_id=None):
_Tool.ToolOptions.__init__(self,name,person_id)
#-------------------------------------------------------------------------
#
# Register the plugin reloading tool
#
#-------------------------------------------------------------------------
if __debug__:
_PluginMgr.register_tool(
name = 'reload',
category = _Tool.TOOL_DEBUG,
tool_class = Reload,
options_class = ReloadOptions,
modes = _Tool.MODE_GUI,
translated_name = _("Reload plugins"),
description=_("Attempt to reload plugins. "
"Note: This tool itself is not reloaded!"),
)

View File

@@ -52,7 +52,7 @@ import gtk
#-------------------------------------------------------------------------
import const
import Utils
import PluginMgr
import _PluginMgr
import BaseDoc
from _StyleEditor import StyleListDisplay
import Config
@@ -1769,27 +1769,27 @@ class CommandLineReport:
self.options_help['of'].append(os.path.expanduser("~/whatever_name"))
if self.category == CATEGORY_TEXT:
for item in PluginMgr.textdoc_list:
for item in _PluginMgr.textdoc_list:
if item[7] == self.options_dict['off']:
self.format = item[1]
self.options_help['off'].append(
[ item[7] for item in PluginMgr.textdoc_list ]
[ item[7] for item in _PluginMgr.textdoc_list ]
)
self.options_help['off'].append(False)
elif self.category == CATEGORY_DRAW:
for item in PluginMgr.drawdoc_list:
for item in _PluginMgr.drawdoc_list:
if item[6] == self.options_dict['off']:
self.format = item[1]
self.options_help['off'].append(
[ item[6] for item in PluginMgr.drawdoc_list ]
[ item[6] for item in _PluginMgr.drawdoc_list ]
)
self.options_help['off'].append(False)
elif self.category == CATEGORY_BOOK:
for item in PluginMgr.bookdoc_list:
for item in _PluginMgr.bookdoc_list:
if item[6] == self.options_dict['off']:
self.format = item[1]
self.options_help['off'].append(
[ item[6] for item in PluginMgr.bookdoc_list ]
[ item[6] for item in _PluginMgr.bookdoc_list ]
)
self.options_help['off'].append(False)
else:
@@ -1956,9 +1956,9 @@ class GrampsTextFormatComboBox(gtk.ComboBox):
out_pref = Config.get_output_preference()
index = 0
PluginMgr.textdoc_list.sort()
_PluginMgr.textdoc_list.sort()
active_index = 0
for item in PluginMgr.textdoc_list:
for item in _PluginMgr.textdoc_list:
if tables and item[2] == 0:
continue
name = item[0]
@@ -1973,25 +1973,25 @@ class GrampsTextFormatComboBox(gtk.ComboBox):
self.set_active(active_index)
def get_label(self):
return PluginMgr.textdoc_list[self.get_active()][0]
return _PluginMgr.textdoc_list[self.get_active()][0]
def get_reference(self):
return PluginMgr.textdoc_list[self.get_active()][1]
return _PluginMgr.textdoc_list[self.get_active()][1]
def get_paper(self):
return PluginMgr.textdoc_list[self.get_active()][3]
return _PluginMgr.textdoc_list[self.get_active()][3]
def get_styles(self):
return PluginMgr.textdoc_list[self.get_active()][4]
return _PluginMgr.textdoc_list[self.get_active()][4]
def get_ext(self):
return PluginMgr.textdoc_list[self.get_active()][5]
return _PluginMgr.textdoc_list[self.get_active()][5]
def get_printable(self):
return PluginMgr.textdoc_list[self.get_active()][6]
return _PluginMgr.textdoc_list[self.get_active()][6]
def get_clname(self):
return PluginMgr.textdoc_list[self.get_active()][7]
return _PluginMgr.textdoc_list[self.get_active()][7]
class GrampsDrawFormatComboBox(gtk.ComboBox):
@@ -2004,9 +2004,9 @@ class GrampsDrawFormatComboBox(gtk.ComboBox):
out_pref = Config.get_output_preference()
index = 0
PluginMgr.drawdoc_list.sort()
_PluginMgr.drawdoc_list.sort()
active_index = 0
for item in PluginMgr.drawdoc_list:
for item in _PluginMgr.drawdoc_list:
if tables and item[2] == 0:
continue
name = item[0]
@@ -2021,25 +2021,25 @@ class GrampsDrawFormatComboBox(gtk.ComboBox):
self.set_active(active_index)
def get_reference(self):
return PluginMgr.drawdoc_list[self.get_active()][1]
return _PluginMgr.drawdoc_list[self.get_active()][1]
def get_label(self):
return PluginMgr.drawdoc_list[self.get_active()][0]
return _PluginMgr.drawdoc_list[self.get_active()][0]
def get_paper(self):
return PluginMgr.drawdoc_list[self.get_active()][2]
return _PluginMgr.drawdoc_list[self.get_active()][2]
def get_styles(self):
return PluginMgr.drawdoc_list[self.get_active()][3]
return _PluginMgr.drawdoc_list[self.get_active()][3]
def get_ext(self):
return PluginMgr.drawdoc_list[self.get_active()][4]
return _PluginMgr.drawdoc_list[self.get_active()][4]
def get_printable(self):
return PluginMgr.drawdoc_list[self.get_active()][5]
return _PluginMgr.drawdoc_list[self.get_active()][5]
def get_clname(self):
return PluginMgr.drawdoc_list[self.get_active()][6]
return _PluginMgr.drawdoc_list[self.get_active()][6]
class GrampsBookFormatComboBox(gtk.ComboBox):
@@ -2052,10 +2052,10 @@ class GrampsBookFormatComboBox(gtk.ComboBox):
out_pref = Config.get_output_preference()
index = 0
PluginMgr.drawdoc_list.sort()
_PluginMgr.drawdoc_list.sort()
active_index = 0
self.data = []
for item in PluginMgr.bookdoc_list:
for item in _PluginMgr.bookdoc_list:
if tables and item[2] == 0:
continue
self.data.append(item)

View File

@@ -20,7 +20,16 @@
# $Id: Report.py 6044 2006-03-03 00:10:52Z rshura $
from _PluginMgr import \
register_export, register_import, \
register_tool, register_report, \
register_relcalc, relationship_class, \
textdoc_list, drawdoc_list, bookdoc_list, \
bkitems_list, cl_list, cli_tool_list, \
load_plugins
import _Report as Report
import _ReportOptions as ReportOptions
import _ReportUtils as ReportUtils
import _Tool as Tool
import _Plugins as Plugins