[kupfer] core: Keep track of where plugin objects come from



commit 33e2e965f269e1d2f244e08025ba72267634a583
Author: Ulrik Sverdrup <ulrik sverdrup gmail com>
Date:   Sun May 9 16:25:25 2010 +0100

    core: Keep track of where plugin objects come from

 kupfer/core/data.py    |   77 +++++++++++++----------------------------
 kupfer/core/sources.py |   90 ++++++++++++++++++++++++++++++++++++++++++------
 2 files changed, 103 insertions(+), 64 deletions(-)
---
diff --git a/kupfer/core/data.py b/kupfer/core/data.py
index 10ecb18..9fe1f2a 100644
--- a/kupfer/core/data.py
+++ b/kupfer/core/data.py
@@ -437,14 +437,14 @@ class DataController (gobject.GObject, pretty.OutputMixin):
 		sch.connect("load", self._load)
 		sch.connect("finish", self._finish)
 
-	def register_text_sources(self, srcs):
+	def register_text_sources(self, plugin_id, srcs):
 		"""Pass in text sources as @srcs
 
 		we register text sources """
 		sc = GetSourceController()
-		sc.add_text_sources(srcs)
+		sc.add_text_sources(plugin_id, srcs)
 	
-	def register_action_decorators(self, actions):
+	def register_action_decorators(self, plugin_id, actions):
 		# Keep a mapping: Decorated Leaf Type -> List of actions
 		decorate_types = {}
 		for action in actions:
@@ -453,13 +453,9 @@ class DataController (gobject.GObject, pretty.OutputMixin):
 		if not decorate_types:
 			return
 		sc = GetSourceController()
-		sc.add_action_decorators(decorate_types)
-		self.output_debug("Actions:")
-		for typ in decorate_types:
-			self.output_debug(typ.__name__)
-			self._list_plugin_objects(decorate_types[typ])
+		sc.add_action_decorators(plugin_id, decorate_types)
 
-	def register_content_decorators(self, contents):
+	def register_content_decorators(self, plugin_id, contents):
 		"""
 		Register the sequence of classes @contents as
 		potential content decorators. Classes not conforming to
@@ -478,31 +474,23 @@ class DataController (gobject.GObject, pretty.OutputMixin):
 		if not decorate_item_types:
 			return
 		sc = GetSourceController()
-		sc.add_content_decorators(decorate_item_types)
-		self.output_debug("Content decorators:")
-		for typ in decorate_item_types:
-			self.output_debug(typ.__name__)
-			self._list_plugin_objects(decorate_item_types[typ])
+		sc.add_content_decorators(plugin_id, decorate_item_types)
 
-	def register_action_generators(self, generators):
+	def register_action_generators(self, plugin_id, generators):
 		sc = GetSourceController()
 		for generator in generators:
-			sc.add_action_generator(generator)
-
-	def _list_plugin_objects(self, objs):
-		"Print a list of plugin objects to debug output"
-		for o in objs:
-			typ = type(o) if hasattr(o, "__class__") else o
-			self.output_debug(" ", typ.__module__, ".", typ.__name__, sep="")
+			sc.add_action_generator(plugin_id, generator)
 
 	def _load(self, sched):
 		"""Load data from persistent store"""
-		S_s, s_s = self._setup_plugins()
+		setctl = settings.GetSettingsController()
+		setctl.connect("plugin-enabled-changed", self._plugin_enabled)
+
+		self._load_all_plugins()
+		D_s, d_s = self._get_directory_sources()
 		sc = GetSourceController()
-		direct_sources = set(S_s)
-		other_sources = set(s_s) - direct_sources
-		sc.add(direct_sources, toplevel=True)
-		sc.add(other_sources, toplevel=False)
+		sc.add(None, D_s, toplevel=True)
+		sc.add(None, d_s, toplevel=False)
 		sc.initialize()
 		self.source_pane.source_rebase(sc.root)
 		learn.load()
@@ -540,35 +528,18 @@ class DataController (gobject.GObject, pretty.OutputMixin):
 
 		return S_sources, s_sources
 
-	def _setup_plugins(self):
+	def _load_all_plugins(self):
 		"""
-		@S_sources are to be included directly in the catalog,
-		@s_souces as just as subitems
+		Insert all plugin sources into the catalog
 		"""
 		from kupfer.core import plugins
 
-		s_sources = []
-		S_sources = []
-
 		setctl = settings.GetSettingsController()
-		setctl.connect("plugin-enabled-changed", self._plugin_enabled)
-
 		for item in plugins.get_plugin_ids():
 			if not setctl.get_plugin_enabled(item):
 				continue
 			sources = self._load_plugin(item)
-			if setctl.get_plugin_is_toplevel(item):
-				S_sources.extend(sources)
-			else:
-				s_sources.extend(sources)
-
-		D_dirs, d_dirs = self._get_directory_sources()
-		S_sources.extend(D_dirs)
-		s_sources.extend(d_dirs)
-
-		if not S_sources and not s_sources:
-			pretty.print_info(__name__, "No sources found!")
-		return S_sources, s_sources
+			self._insert_sources(item, sources, initialize=False)
 
 	def _load_plugin(self, plugin_id):
 		"""
@@ -577,10 +548,10 @@ class DataController (gobject.GObject, pretty.OutputMixin):
 		"""
 		with pluginload.exception_guard(plugin_id):
 			plugin = pluginload.load_plugin(plugin_id)
-			self.register_text_sources(plugin.text_sources)
-			self.register_action_decorators(plugin.action_decorators)
-			self.register_content_decorators(plugin.content_decorators)
-			self.register_action_generators(plugin.action_generators)
+			self.register_text_sources(plugin_id, plugin.text_sources)
+			self.register_action_decorators(plugin_id, plugin.action_decorators)
+			self.register_content_decorators(plugin_id, plugin.content_decorators)
+			self.register_action_generators(plugin_id, plugin.action_generators)
 			return set(plugin.sources)
 		return set()
 
@@ -590,13 +561,13 @@ class DataController (gobject.GObject, pretty.OutputMixin):
 			sources = self._load_plugin(plugin_id)
 			self._insert_sources(plugin_id, sources)
 
-	def _insert_sources(self, plugin_id, sources):
+	def _insert_sources(self, plugin_id, sources, initialize=True):
 		if not sources:
 			return
 		setctl = settings.GetSettingsController()
 		is_toplevel = setctl.get_plugin_is_toplevel(plugin_id)
 		sc = GetSourceController()
-		sc.add(sources, toplevel=is_toplevel, initialize=True)
+		sc.add(plugin_id, sources, toplevel=is_toplevel, initialize=initialize)
 		self.source_pane.source_rebase(sc.root)
 
 	def _finish(self, sched):
diff --git a/kupfer/core/sources.py b/kupfer/core/sources.py
index 8c71294..590e828 100644
--- a/kupfer/core/sources.py
+++ b/kupfer/core/sources.py
@@ -8,6 +8,7 @@ import cPickle as pickle
 import os
 import threading
 import time
+import weakref
 
 from kupfer import config, pretty, scheduler
 from kupfer import conspickle
@@ -254,14 +255,13 @@ class SourceController (pretty.OutputMixin):
 		self.content_decorators = {}
 		self.action_decorators = {}
 		self.action_generators = []
+		self.plugin_object_map = weakref.WeakKeyDictionary()
 		self.loaded_successfully = False
-		self._restored_sources = set()
 		self._pre_root = None
 
-	def add(self, srcs, toplevel=False, initialize=False):
-		self._pre_root = None
+	def add(self, plugin_id, srcs, toplevel=False, initialize=False):
+		self._invalidate_root()
 		sources = set(self._try_restore(srcs))
-		self._restored_sources.update(sources)
 		sources.update(srcs)
 
 		self.sources.update(sources)
@@ -270,21 +270,88 @@ class SourceController (pretty.OutputMixin):
 		if initialize:
 			self._initialize_sources(sources)
 			self._cache_sources(sources)
+		if plugin_id:
+			self._register_plugin_objects(plugin_id, *sources)
+		self.rescanner.set_catalog(self.sources)
+
+	def _register_plugin_objects(self, plugin_id, *objects):
+		"Register a plugin id mapping for @objects"
+		for obj in objects:
+			self.plugin_object_map[obj] = plugin_id
+			pretty.print_debug(__name__, "Add", repr(obj))
+
+	def _remove(self, src):
+		self._invalidate_root()
+		self.toplevel_sources.discard(src)
+		self.sources.discard(src)
 		self.rescanner.set_catalog(self.sources)
-	def add_text_sources(self, srcs):
+		self._finalize_source(src)
+		pretty.print_debug(__name__, "Remove", repr(src))
+
+	def get_plugin_id_for_object(self, obj):
+		id_ = self.plugin_object_map.get(obj)
+		#self.output_debug("Object", repr(obj), "has id", id_, id(obj))
+		return id_
+
+	def remove_objects_for_plugin_id(self, plugin_id):
+		"""Remove all objects for @plugin_id
+
+		Return True if the catalog configuration changed
+		"""
+		removed_source = False
+		self.output_debug("Removing objects for plugin:", plugin_id)
+
+		# sources
+		for src in list(self.sources):
+			if self.get_plugin_id_for_object(src) == plugin_id:
+				self._remove(src)
+				removed_source = True
+
+		# all other objects
+		def remove_matching_objects(collection, plugin_id):
+			for obj in list(collection):
+				if self.get_plugin_id_for_object(obj) == plugin_id:
+					collection.remove(obj)
+					pretty.print_debug(__name__, "Remove", repr(obj))
+
+		remove_matching_objects(self.text_sources, plugin_id)
+
+		for typ in self.content_decorators:
+			remove_matching_objects(self.content_decorators[typ], plugin_id)
+
+		for typ in self.action_decorators:
+			remove_matching_objects(self.action_decorators[typ], plugin_id)
+
+		remove_matching_objects(self.action_generators[typ], plugin_id)
+
+		return removed_source
+
+	def get_sources(self):
+		return self.sources
+
+	def add_text_sources(self, plugin_id, srcs):
 		self.text_sources.update(srcs)
+		self._register_plugin_objects(plugin_id, *srcs)
+
 	def get_text_sources(self):
 		return self.text_sources
-	def add_content_decorators(self, decos):
+
+	def add_content_decorators(self, plugin_id, decos):
 		for typ in decos:
 			self.content_decorators.setdefault(typ, set()).update(decos[typ])
-	def add_action_decorators(self, decos):
+			self._register_plugin_objects(plugin_id, *decos[typ])
+
+	def add_action_decorators(self, plugin_id, decos):
 		for typ in decos:
 			self.action_decorators.setdefault(typ, set()).update(decos[typ])
+			self._register_plugin_objects(plugin_id, *decos[typ])
 		for typ in self.action_decorators:
 			self._disambiguate_actions(self.action_decorators[typ])
-	def add_action_generator(self, agenerator):
+
+	def add_action_generator(self, plugin_id, agenerator):
 		self.action_generators.append(agenerator)
+		self._register_plugin_objects(plugin_id, agenerator)
+
 	def _disambiguate_actions(self, actions):
 		"""Rename actions by the same name (adding a suffix)"""
 		# FIXME: Disambiguate by plugin name, not python module name
@@ -301,8 +368,6 @@ class SourceController (pretty.OutputMixin):
 			self.output_debug("Disambiguate Action %s" % (action, ))
 			action.name += " (%s)" % (type(action).__module__.split(".")[-1],)
 
-	def clear_sources(self):
-		pass
 	def __contains__(self, src):
 		return src in self.sources
 	def __getitem__(self, src):
@@ -323,6 +388,10 @@ class SourceController (pretty.OutputMixin):
 			root_catalog = None
 		return root_catalog
 
+	def _invalidate_root(self):
+		"The source root needs to be recalculated"
+		self._pre_root = None
+
 	@property
 	def _firstlevel(self):
 		if self._pre_root:
@@ -481,7 +550,6 @@ class SourceController (pretty.OutputMixin):
 		self._initialize_sources(self.sources)
 		self._cache_sources(self.toplevel_sources)
 		self.loaded_successfully = True
-		self._restored_sources.clear()
 
 	def _initialize_sources(self, sources):
 		for src in set(sources):



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]