[kupfer: 1/51] grouping: Add grouping support as obj.grouping



commit 691d1a35f4085bf3d1cb0104a973fde86bf7bc41
Author: Ulrik Sverdrup <ulrik sverdrup gmail com>
Date:   Sun Jan 3 21:26:50 2010 +0100

    grouping: Add grouping support as obj.grouping

 kupfer/obj/grouping.py |  165 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 165 insertions(+), 0 deletions(-)
---
diff --git a/kupfer/obj/__init__.py b/kupfer/obj/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/kupfer/obj/grouping.py b/kupfer/obj/grouping.py
new file mode 100644
index 0000000..8059b66
--- /dev/null
+++ b/kupfer/obj/grouping.py
@@ -0,0 +1,165 @@
+# -*- encoding: UTF-8 -*-
+"""
+Classes used to provide grouping leaves mechanism.
+"""
+import copy
+import time
+import weakref
+
+from kupfer.objects import Leaf, Source
+
+__author__ = ("Karol BÄ?dkowski <karol bedkowsk+gh gmail com>, "
+              "Ulrik Sverdrup <ulrik sverdrup gmail com>" )
+
+
+EMAIL_KEY = "EMAIL"
+NAME_KEY = "NAME"
+
+CONTACTS_CATEGORY = "Contacts"
+HOSTS_CATEGORY = "Hosts"
+
+class GroupingLeaf (Leaf):
+	"""
+	A Leaf that groups with other leaves inside Grouping Sources
+
+	The represented object of a GroupedLeaf is a
+	dictionary of (slot, value) pairs, where
+	slot identifies the slot, and the value is something that
+	must be equal to be grouped.
+	"""
+	def __init__(self, obj, name):
+		Leaf.__init__(self, obj, name)
+		self.links = [self]
+
+	def slots(self):
+		return self.object
+
+	def has_content(self):
+		return len(self.links) > 1
+
+	def content_source(self, alternate=False):
+		return _GroupedItemsSource(self)
+
+	def __len__(self):
+		return len(self.links)
+
+	def __contains__(self, key):
+		"Return True if GroupedLeaf has value for @key"
+		return any(key in leaf.object for leaf in self.links)
+
+	def __getitem__(self, key):
+		"Return iterator of all values for @key"
+		return [leaf.object[key] for leaf in self.links if key in leaf.object]
+
+class GroupingSource (Source):
+	grouping_keys = [EMAIL_KEY, NAME_KEY]
+
+	def __init__(self, name, sources):
+		Source.__init__(self, name)
+		self.sources = sources
+		print "making", self
+
+	def get_leaves(self, force_update=False):
+		st = time.time()
+		self.output_debug("START")
+
+		# map (slot, value) -> group
+		groups = {}
+		for src in self.sources:
+			self.output_debug("Merging", src)
+			leaves = Source.get_leaves(src, force_update)
+			for leaf in leaves:
+				try:
+					slots = leaf.slots()
+				except AttributeError:
+					# Let through Non-grouping leaves
+					yield leaf
+					continue
+				for slot in self.grouping_keys:
+					slots = leaf.slots()
+					if slot not in slots:
+						continue
+					groups.setdefault((slot, slots[slot]), set()).add(leaf)
+
+		def merge_groups(key1, key2):
+			if groups[key1] is groups[key2]:
+				return
+			print "Merging", key1, "and", key2
+			groups[key1].update(groups[key2])
+			groups[key2] = groups[key1]
+
+		# Find all values that have more than one value
+		# and we merge those groups
+		for (slot, value), leaves in groups.iteritems():
+			#leaves = slotdicts[slot][value]
+			if len(leaves) <= 1:
+				continue
+			for leaf in list(leaves):
+				for slot2 in self.grouping_keys:
+					for value2 in leaf[slot2]:
+						merge_groups((slot, value), (slot2, value2))
+
+		idset = set()
+		for group in groups.itervalues():
+			if id(group) in idset:
+				continue
+			idset.add(id(group))
+			leaf = self._make_group_leader(group)
+			yield leaf
+		self.output_debug("END", time.time() - st)
+
+	@classmethod
+	def _make_group_leader(cls, leaves):
+		obj = copy.copy(iter(leaves).next())
+		obj.links = list(leaves)
+		obj.name_aliases = set(obj.name_aliases)
+		for other in leaves:
+			if other is not obj:
+				obj.name_aliases.add(unicode(other))
+				# adding the other's aliases can be misleading
+				# since the matched email address might not be
+				# what we are e-mailing
+				# obj.name_aliases.update(other.name_aliases)
+		obj.name_aliases.discard(unicode(obj))
+		return obj
+
+class ToplevelGroupingSource (GroupingSource):
+	"""
+	Sources of this type group their leaves with others in the toplevel
+	of the catalog.
+	"""
+	_sources = {}
+
+	def __init__(self, name, category):
+		GroupingSource.__init__(self, name, [self])
+		self.category = category
+
+	def toplevel_source(self):
+		sources = self._sources[self.category].keys()
+		return GroupingSource(self.category, sources)
+
+	def initialize(self):
+		if not self.category in self._sources:
+			self._sources[self.category] = weakref.WeakKeyDictionary()
+		self._sources[self.category][self] = 1
+		self.output_debug("Register %s source %s" % (self.category, self))
+
+class _GroupedItemsSource(Source):
+	def __init__(self, leaf):
+		Source.__init__(self, unicode(leaf))
+		self._leaf = leaf
+
+	def get_items(self):
+		for leaf in self._leaf.links:
+			yield leaf
+
+class ContactLeaf(GroupingLeaf):
+	def get_icon_name(self):
+		return "stock_person"
+
+
+class HostLeaf(GroupingLeaf):
+	def get_icon_name(self):
+		return "stock_host"
+
+



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