diff --git a/src/PluginUtils/_PluginWindows.py b/src/PluginUtils/_PluginWindows.py
index f101195dd..cb172ae64 100644
--- a/src/PluginUtils/_PluginWindows.py
+++ b/src/PluginUtils/_PluginWindows.py
@@ -45,8 +45,10 @@ import gobject
#-------------------------------------------------------------------------
import ManagedWindow
import Errors
-from gen.plug import PluginManager
+from gen.plug import PluginManager, PluginRegister, PTYPE_STR
import _Tool as Tool
+from QuestionDialog import InfoDialog
+import config
#-------------------------------------------------------------------------
#
@@ -55,6 +57,9 @@ import _Tool as Tool
#-------------------------------------------------------------------------
class PluginStatus(ManagedWindow.ManagedWindow):
"""Displays a dialog showing the status of loaded plugins"""
+ HIDDEN = '%s' % _('Hidden')
+ AVAILABLE = '%s'\
+ % _('Visible')
def __init__(self, uistate, track=[]):
self.__uistate = uistate
@@ -63,6 +68,7 @@ class PluginStatus(ManagedWindow.ManagedWindow):
self.__class__)
self.__pmgr = PluginManager.get_instance()
+ self.__preg = PluginRegister.get_instance()
self.set_window(gtk.Dialog("", uistate.window,
gtk.DIALOG_DESTROY_WITH_PARENT,
(gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE)),
@@ -70,6 +76,52 @@ class PluginStatus(ManagedWindow.ManagedWindow):
self.window.set_size_request(600, 400)
self.window.connect('response', self.close)
+ notebook = gtk.Notebook()
+
+ #first page with all registered plugins
+ vbox_reg = gtk.VBox()
+ scrolled_window_reg = gtk.ScrolledWindow()
+ self.list_reg = gtk.TreeView()
+ # model: plugintype, hidden, pluginname, plugindescr, pluginid
+ self.model_reg = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
+ gobject.TYPE_STRING, gobject.TYPE_STRING, gobject.TYPE_STRING)
+ self.selection_reg = self.list_reg.get_selection()
+ self.list_reg.set_model(self.model_reg)
+ self.list_reg.set_rules_hint(True)
+ self.list_reg.connect('button-press-event', self.button_press_reg)
+ col0_reg = gtk.TreeViewColumn(_('Type'), gtk.CellRendererText(), text=0)
+ col0_reg.set_sort_column_id(0)
+ self.list_reg.append_column(col0_reg)
+ self.list_reg.append_column(
+ gtk.TreeViewColumn(_('Hidden'), gtk.CellRendererText(), markup=1))
+ col2_reg = gtk.TreeViewColumn(_('Name'), gtk.CellRendererText(), text=2)
+ col2_reg.set_sort_column_id(2)
+ self.list_reg.append_column(col2_reg)
+ self.list_reg.append_column(
+ gtk.TreeViewColumn(_('Description'), gtk.CellRendererText(), text=3))
+ self.list_reg.set_search_column(2)
+
+ scrolled_window_reg.add(self.list_reg)
+ vbox_reg.pack_start(scrolled_window_reg)
+ hbutbox = gtk.HButtonBox()
+ hbutbox.set_layout(gtk.BUTTONBOX_SPREAD)
+ self.__info_btn = gtk.Button(_("Info"))
+ hbutbox.add(self.__info_btn)
+ self.__info_btn.connect('clicked', self.__info)
+ self.__hide_btn = gtk.Button(_("Hide/Unhide"))
+ hbutbox.add(self.__hide_btn)
+ self.__hide_btn.connect('clicked', self.__hide)
+ if __debug__:
+ self.__load_btn = gtk.Button(_("Load"))
+ hbutbox.add(self.__load_btn)
+ self.__load_btn.connect('clicked', self.__load)
+ vbox_reg.pack_start(hbutbox, expand=False, padding=5)
+
+ notebook.append_page(vbox_reg,
+ tab_label=gtk.Label(_('Registered plugins')))
+
+
+ #second page with loaded plugins
scrolled_window = gtk.ScrolledWindow()
self.list = gtk.TreeView()
self.model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_STRING,
@@ -91,7 +143,9 @@ class PluginStatus(ManagedWindow.ManagedWindow):
self.list.set_search_column(1)
scrolled_window.add(self.list)
- self.window.vbox.add(scrolled_window)
+ notebook.append_page(scrolled_window,
+ tab_label=gtk.Label(_('Loaded plugins')))
+ self.window.vbox.add(notebook)
if __debug__:
# Only show the "Reload" button when in debug mode
@@ -100,11 +154,19 @@ class PluginStatus(ManagedWindow.ManagedWindow):
self.window.action_area.add(self.__reload_btn)
self.__reload_btn.connect('clicked', self.__reload)
+ #obtain hidden plugins from the pluginmanager
+ self.hidden = self.__pmgr.get_hidden_plugin_ids()
+
self.window.show_all()
- self.__populate_list()
+ self.__populate_lists()
- def __populate_list(self):
- """ Build the list of plugins """
+ def __populate_lists(self):
+ """ Build the lists of plugins """
+ self.__populate_load_list()
+ self.__populate_reg_list()
+
+ def __populate_load_list(self):
+ """ Build list of loaded plugins"""
fail_list = self.__pmgr.get_fail_list()
for i in fail_list:
@@ -126,6 +188,28 @@ class PluginStatus(ManagedWindow.ManagedWindow):
self.model.append(row=[
'%s' % _("OK"),
i[0], descr, None])
+
+ def __populate_reg_list(self):
+ """ Build list of registered plugins"""
+ for (type, typestr) in PTYPE_STR.iteritems():
+ for pdata in self.__preg.type_plugins(type):
+ # model: plugintype, hidden, pluginname, plugindescr, pluginid
+ hidden = pdata.id in self.hidden
+ if hidden:
+ hiddenstr = self.HIDDEN
+ else:
+ hiddenstr = self.AVAILABLE
+ self.model_reg.append(row=[
+ typestr, hiddenstr, pdata.name, pdata.description,
+ pdata.id])
+
+ def __rebuild_load_list(self):
+ self.model.clear()
+ self.__populate_load_list()
+
+ def __rebuild_reg_list(self):
+ self.model_reg.clear()
+ self.__populate_reg_list()
def button_press(self, obj, event):
""" Callback function from the user clicking on a line """
@@ -142,9 +226,76 @@ class PluginStatus(ManagedWindow.ManagedWindow):
def __reload(self, obj):
""" Callback function from the "Reload" button """
self.__pmgr.reload_plugins()
- self.model.clear()
- self.__populate_list()
-
+ self.__rebuild_load_list()
+ self.__rebuild_reg_list()
+
+ def button_press_reg(self, obj, event):
+ """ Callback function from the user clicking on a line in reg plugin
+ """
+ if event.type == gtk.gdk._2BUTTON_PRESS and event.button == 1:
+ self.__info(None)
+
+ def __info(self, obj):
+ """ Callback function from the "Info" button
+ """
+ model, node = self.selection_reg.get_selected()
+ if not node:
+ return
+ id = model.get_value(node, 4)
+ typestr = model.get_value(node, 0)
+ pdata = self.__preg.get_plugin(id)
+ auth = ' - '.join(pdata.authors)
+ email = ' - '.join(pdata.authors_email)
+ if len(auth) > 60:
+ auth = auth[:60] + '...'
+ if len(email) > 60:
+ email = email[:60] + '...'
+ if pdata:
+ infotxt = """Plugin name: %(name)s [%(typestr)s]
+
+Description: %(descr)s
+Authors: %(authors)s
+Email: %(email)s
+Filename: %(fname)s
+ """ % {
+ 'name': pdata.name,
+ 'typestr': typestr,
+ 'descr': pdata.description,
+ 'authors': auth,
+ 'email': email,
+ 'fname': pdata.fname
+ }
+ InfoDialog('Detailed Info', infotxt, parent=self.window)
+
+ def __hide(self, obj):
+ """ Callback function from the "Hide" button
+ """
+ model, node = self.selection_reg.get_selected()
+ if not node:
+ return
+ id = model.get_value(node, 4)
+ if id in self.hidden:
+ #unhide
+ self.hidden.remove(id)
+ model.set_value(node, 1, self.AVAILABLE)
+ self.__pmgr.unhide_plugin(id)
+ else:
+ #hide
+ self.hidden.add(id)
+ model.set_value(node, 1, self.HIDDEN)
+ self.__pmgr.hide_plugin(id)
+
+ def __load(self, obj):
+ """ Callback function from the "Load" button
+ """
+ model, node = self.selection_reg.get_selected()
+ if not node:
+ return
+ id = model.get_value(node, 4)
+ pdata = self.__preg.get_plugin(id)
+ self.__pmgr.load_plugin(pdata)
+ self.__rebuild_load_list()
+
#-------------------------------------------------------------------------
#
# Details for an individual plugin that failed
diff --git a/src/config.py b/src/config.py
index 775419ddf..61850efe1 100644
--- a/src/config.py
+++ b/src/config.py
@@ -643,6 +643,8 @@ register('researcher.researcher-phone', '')
register('researcher.researcher-postal', '')
register('researcher.researcher-state', '')
+register('plugin.hiddenplugins', [])
+
#---------------------------------------------------------------
#
# Upgrade Conversions go here.
diff --git a/src/gen/plug/__init__.py b/src/gen/plug/__init__.py
index aaf65fa58..685b0a61e 100644
--- a/src/gen/plug/__init__.py
+++ b/src/gen/plug/__init__.py
@@ -29,7 +29,7 @@ from _pluginreg import (PluginData, PluginRegister, REPORT, TOOL,
TOOL_UTILS, CATEGORY_QR_MISC, CATEGORY_QR_PERSON,
CATEGORY_QR_FAMILY, CATEGORY_QR_EVENT, CATEGORY_QR_SOURCE,
CATEGORY_QR_PLACE, CATEGORY_QR_REPOSITORY, CATEGORY_QR_NOTE,
- CATEGORY_QR_DATE )
+ CATEGORY_QR_DATE, PTYPE_STR )
from _manager import PluginManager
from _import import ImportPlugin
from _export import ExportPlugin
@@ -45,4 +45,4 @@ __all__ = [ "docbackend", "docgen", "menu", Plugin, PluginData,
TOOL_UTILS, CATEGORY_QR_MISC, CATEGORY_QR_PERSON,
CATEGORY_QR_FAMILY, CATEGORY_QR_EVENT, CATEGORY_QR_SOURCE,
CATEGORY_QR_PLACE, CATEGORY_QR_REPOSITORY, CATEGORY_QR_NOTE,
- CATEGORY_QR_DATE]
+ CATEGORY_QR_DATE, PTYPE_STR]
diff --git a/src/gen/plug/_manager.py b/src/gen/plug/_manager.py
index 838584460..bc1a4f112 100644
--- a/src/gen/plug/_manager.py
+++ b/src/gen/plug/_manager.py
@@ -47,6 +47,7 @@ from gettext import gettext as _
import gen.utils
import Relationship
from gen.plug import PluginRegister
+import config
#-------------------------------------------------------------------------
#
@@ -97,6 +98,21 @@ class PluginManager(gen.utils.Callback):
self.__pgr = PluginRegister.get_instance()
self.__registereddir_set = set()
self.__loaded_plugins = {}
+ self.__hidden_plugins = set([])
+ for id in config.get('plugin.hiddenplugins'):
+ self.__hidden_plugins.add(id)
+ self.__hidden_changed()
+
+ def __hidden_changed(self, *args):
+ #if hidden changed, stored data must be emptied as it could contain
+ #something that now must be hidden
+ self.__import_plugins = []
+ self.__export_plugins = []
+ self.__docgen_plugins = []
+ #objects that need to know if the plugins available changed, are
+ #listening to this signal to update themselves. If a plugin becomes
+ #(un)hidden, this should happen, so we emit.
+ self.emit('plugins-reloaded')
def reg_plugins(self, direct):
"""
@@ -197,6 +213,33 @@ class PluginManager(gen.utils.Callback):
self.emit('plugins-reloaded')
+ def get_hidden_plugin_ids(self):
+ """
+ Returns copy of the set hidden plugin ids
+ """
+ return self.__hidden_plugins.copy()
+
+ def hide_plugin(self, id):
+ """ Hide plugin with given id. This will hide the plugin so queries do
+ not return it anymore, and write this change to the config.
+ Note that config will then emit a signal
+ """
+ self.__hidden_plugins.add(id)
+ hideset = [x for x in self.__hidden_plugins]
+ config.set('plugin.hiddenplugins', hideset)
+ config.save()
+ self.__hidden_changed()
+
+ def unhide_plugin(self, id):
+ """ Unhide plugin with given id. This will unhide the plugin so queries
+ return it again, and write this change to the config
+ """
+ self.__hidden_plugins.remove(id)
+ hideset = [x for x in self.__hidden_plugins]
+ config.set('plugin.hiddenplugins', hideset)
+ config.save()
+ self.__hidden_changed()
+
def get_fail_list(self):
""" Return the list of failed plugins. """
return self.__failmsg_list
@@ -206,33 +249,38 @@ class PluginManager(gen.utils.Callback):
return self.__success_list
def get_reg_reports(self, gui=True):
- """ Return list of registered reports
+ """ Return list of non hidden registered reports
:Param gui: bool indicating if GUI reports or CLI reports must be
returned
"""
- return self.__pgr.report_plugins(gui)
+ return [plg for plg in self.__pgr.report_plugins(gui) if plg.id not in
+ self.__hidden_plugins]
def get_reg_tools(self, gui=True):
- """ Return list of registered tools
+ """ Return list of non hidden registered tools
:Param gui: bool indicating if GUI reports or CLI reports must be
returned
"""
- return self.__pgr.tool_plugins(gui)
+ return [plg for plg in self.__pgr.tool_plugins(gui) if plg.id not in
+ self.__hidden_plugins]
def get_reg_quick_reports(self):
- """ Return list of registered quick reports
+ """ Return list of non hidden registered quick reports
"""
- return self.__pgr.quickreport_plugins()
+ return [plg for plg in self.__pgr.quickreport_plugins() if plg.id not in
+ self.__hidden_plugins]
def get_reg_mapservices(self):
- """ Return list of registered mapservices
+ """ Return list of non hidden registered mapservices
"""
- return self.__pgr.mapservice_plugins()
+ return [plg for plg in self.__pgr.mapservice_plugins() if plg.id not in
+ self.__hidden_plugins]
def get_reg_bookitems(self):
- """ Return list of reports registered as bookitem
+ """ Return list of non hidden reports registered as bookitem
"""
- return self.__pgr.bookitem_plugins()
+ return [plg for plg in self.__pgr.bookitem_plugins() if plg.id not in
+ self.__hidden_plugins]
def get_external_opt_dict(self):
""" Return the dictionary of external options. """
@@ -252,7 +300,8 @@ class PluginManager(gen.utils.Callback):
## only PluginData, loading from module when importfunction needed?
if self.__import_plugins == []:
#The module still needs to be imported
- imps = self.__pgr.import_plugins()
+ imps = [pdata for pdata in self.__pgr.import_plugins() if pdata.id
+ not in self.__hidden_plugins]
for pdata in imps:
mod = self.load_plugin(pdata)
if mod:
@@ -274,7 +323,8 @@ class PluginManager(gen.utils.Callback):
## only PluginData, loading from module when export/options needed?
if self.__export_plugins == []:
#The modules still need to be imported
- exps = self.__pgr.export_plugins()
+ exps = [pdata for pdata in self.__pgr.export_plugins() if pdata.id
+ not in self.__hidden_plugins]
for pdata in exps:
mod = self.load_plugin(pdata)
if mod:
@@ -299,7 +349,8 @@ class PluginManager(gen.utils.Callback):
## So, only do import when docgen.get_basedoc() is requested
if self.__docgen_plugins == []:
#The modules still need to be imported
- dgdps = self.__pgr.docgen_plugins()
+ dgdps = [pdata for pdata in self.__pgr.docgen_plugins() if pdata.id
+ not in self.__hidden_plugins]
for pdata in dgdps:
mod = self.load_plugin(pdata)
if mod:
diff --git a/src/gen/plug/_pluginreg.py b/src/gen/plug/_pluginreg.py
index a39d6823b..14e89ddf9 100644
--- a/src/gen/plug/_pluginreg.py
+++ b/src/gen/plug/_pluginreg.py
@@ -67,6 +67,19 @@ RELCALC = 9
GRAMPLET = 10
PTYPE = [ REPORT , QUICKREPORT, TOOL, IMPORT,
EXPORT, DOCGEN, GENERAL, MAPSERVICE, VIEW, RELCALC, GRAMPLET]
+PTYPE_STR = {
+ REPORT: _('Report') ,
+ QUICKREPORT: _('Quickreport'),
+ TOOL: _('Tool'),
+ IMPORT: _('Importer'),
+ EXPORT: _('Exporter'),
+ DOCGEN: _('Doc creator'),
+ GENERAL: _('Plugin lib'),
+ MAPSERVICE: _('Map service'),
+ VIEW: _('GRAMPS View'),
+ RELCALC: _('Relationships'),
+ GRAMPLET: _('Gramplet'),
+ }
#possible report categories
CATEGORY_TEXT = 0
@@ -834,7 +847,14 @@ class PluginRegister(object):
for ind in rmlist:
del self.__plugindata[ind]
- def __type_plugins(self, ptype):
+ def get_plugin(self, id):
+ """Return the PluginData for the plugin with id"""
+ for x in self.__plugindata:
+ if x.id == id:
+ return x
+ return None
+
+ def type_plugins(self, ptype):
"""Return a list of PluginData that are of type ptype
"""
return [x for x in self.__plugindata if x.ptype == ptype]
@@ -844,68 +864,68 @@ class PluginRegister(object):
:param gui: bool, if True then gui plugin, otherwise cli plugin
"""
if gui:
- return [x for x in self.__type_plugins(REPORT) if REPORT_MODE_GUI
+ return [x for x in self.type_plugins(REPORT) if REPORT_MODE_GUI
in x.report_modes]
else:
- return [x for x in self.__type_plugins(REPORT) if REPORT_MODE_CLI
+ return [x for x in self.type_plugins(REPORT) if REPORT_MODE_CLI
in x.report_modes]
def tool_plugins(self, gui=True):
"""Return a list of PluginData that are of type TOOL
"""
if gui:
- return [x for x in self.__type_plugins(TOOL) if TOOL_MODE_GUI
+ return [x for x in self.type_plugins(TOOL) if TOOL_MODE_GUI
in x.tool_modes]
else:
- return [x for x in self.__type_plugins(TOOL) if TOOL_MODE_CLI
+ return [x for x in self.type_plugins(TOOL) if TOOL_MODE_CLI
in x.tool_modes]
def bookitem_plugins(self):
"""Return a list of REPORT PluginData that are can be used as bookitem
"""
- return [x for x in self.__type_plugins(REPORT) if REPORT_MODE_BKI
+ return [x for x in self.type_plugins(REPORT) if REPORT_MODE_BKI
in x.report_modes]
def quickreport_plugins(self):
"""Return a list of PluginData that are of type QUICKREPORT
"""
- return self.__type_plugins(QUICKREPORT)
+ return self.type_plugins(QUICKREPORT)
def import_plugins(self):
"""Return a list of PluginData that are of type IMPORT
"""
- return self.__type_plugins(IMPORT)
+ return self.type_plugins(IMPORT)
def export_plugins(self):
"""Return a list of PluginData that are of type EXPORT
"""
- return self.__type_plugins(EXPORT)
+ return self.type_plugins(EXPORT)
def docgen_plugins(self):
"""Return a list of PluginData that are of type DOCGEN
"""
- return self.__type_plugins(DOCGEN)
+ return self.type_plugins(DOCGEN)
def general_plugins(self):
"""Return a list of PluginData that are of type GENERAL
"""
- return self.__type_plugins(GENERAL)
+ return self.type_plugins(GENERAL)
def mapservice_plugins(self):
"""Return a list of PluginData that are of type MAPSERVICE
"""
- return self.__type_plugins(MAPSERVICE)
+ return self.type_plugins(MAPSERVICE)
def view_plugins(self):
"""Return a list of PluginData that are of type VIEW
"""
- return self.__type_plugins(RELCALC)
+ return self.type_plugins(VIEW)
def relcalc_plugins(self):
"""Return a list of PluginData that are of type RELCALC
"""
- return self.__type_plugins(RELCALC)
+ return self.type_plugins(RELCALC)
def filter_load_on_reg(self):
"""Return a list of PluginData that have load_on_reg == True
diff --git a/src/gui/viewmanager.py b/src/gui/viewmanager.py
index b595fe5be..3892ac709 100644
--- a/src/gui/viewmanager.py
+++ b/src/gui/viewmanager.py
@@ -223,6 +223,10 @@ class ViewManager(CLIManager):
self.buttons = []
self.merge_ids = []
self._key = None
+ self.toolactions = None
+ self.tool_menu_ui_id = None
+ self.reportactions = None
+ self.report_menu_ui_id = None
self.show_sidebar = config.get('interface.view')
self.show_toolbar = config.get('interface.toolbar-on')
@@ -1290,12 +1294,15 @@ class ViewManager(CLIManager):
"""
Builds a new tools menu
"""
+ if self.toolactions:
+ self.uistate.uimanager.remove_action_group(self.toolactions)
+ self.uistate.uimanager.remove_ui(self.tool_menu_ui_id)
self.toolactions = gtk.ActionGroup('ToolWindow')
(uidef, actions) = self.build_plugin_menu(
'ToolsMenu', tool_menu_list, Tool.tool_categories,
make_plugin_callback)
self.toolactions.add_actions(actions)
- self.uistate.uimanager.add_ui_from_string(uidef)
+ self.tool_menu_ui_id = self.uistate.uimanager.add_ui_from_string(uidef)
self.uimanager.insert_action_group(self.toolactions, 1)
self.uistate.uimanager.ensure_update()
@@ -1303,12 +1310,15 @@ class ViewManager(CLIManager):
"""
Builds a new reports menu
"""
+ if self.reportactions:
+ self.uistate.uimanager.remove_action_group(self.reportactions)
+ self.uistate.uimanager.remove_ui(self.report_menu_ui_id)
self.reportactions = gtk.ActionGroup('ReportWindow')
(uidef, actions) = self.build_plugin_menu(
'ReportsMenu', report_menu_list, ReportBase.standalone_categories,
make_plugin_callback)
self.reportactions.add_actions(actions)
- self.uistate.uimanager.add_ui_from_string(uidef)
+ self.report_menu_ui_id = self.uistate.uimanager.add_ui_from_string(uidef)
self.uimanager.insert_action_group(self.reportactions, 1)
self.uistate.uimanager.ensure_update()
diff --git a/src/plugins/webreport/WebCal.py b/src/plugins/webreport/WebCal.py
index 5308300d4..56e353bcd 100644
--- a/src/plugins/webreport/WebCal.py
+++ b/src/plugins/webreport/WebCal.py
@@ -28,7 +28,7 @@ Web Calendar generator.
Refactoring. This is an ongoing job until this plugin is in a better shape.
"""
-
+from __future__ import with_statement
#------------------------------------------------------------------------
#
# python modules