eggification
[GroupUserFolder.git] / Products / GroupUserFolder / class_utility.py
diff --git a/Products/GroupUserFolder/class_utility.py b/Products/GroupUserFolder/class_utility.py
new file mode 100644 (file)
index 0000000..79357bd
--- /dev/null
@@ -0,0 +1,197 @@
+# -*- coding: utf-8 -*-
+## GroupUserFolder
+## Copyright (C)2006 Ingeniweb
+
+## 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; see the file COPYING. If not, write to the
+## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+"""
+
+"""
+__version__ = "$Revision:  $"
+# $Source:  $
+# $Id: class_utility.py 30098 2006-09-08 12:35:01Z encolpe $
+__docformat__ = 'restructuredtext'
+
+import string
+import re
+import threading
+import string
+
+# Base classes global vars management
+_BASECLASSESLOCK = threading.RLock()
+_BASECLASSES = {}
+_BASEMETALOCK = threading.RLock()
+_BASEMETA = {}
+
+def showaq(self, indent=''):
+    "showaq"
+    rval = ""
+    obj = self
+    base = getattr(obj, 'aq_base', obj)
+    try: id = base.id
+    except: id = str(base)
+    try: id = id()
+    except: pass
+
+    if hasattr(obj, 'aq_self'):
+        if hasattr(obj.aq_self, 'aq_self'):
+            rval = rval + indent + "(" + id + ")\n"
+            rval = rval + indent + "|  \\\n"
+            rval = rval + showaq(obj.aq_self, '|   ' + indent)
+            rval = rval + indent + "|\n"
+        if hasattr(obj, 'aq_parent'):
+            rval = rval + indent + id + "\n"
+            rval = rval + indent + "|\n"
+            rval = rval + showaq(obj.aq_parent, indent)
+    else:
+        rval = rval + indent + id + "\n"
+    return rval
+
+
+def listBaseMetaTypes(cl, reverse = 0):
+    """
+    listBaseMetaTypes(cl, reverse = 0) => list of strings
+
+    List all base meta types for this class.
+    """
+    # Look for the class in _BASEMETA cache
+    try:
+        return _BASEMETA[cl][reverse]
+
+    except KeyError:
+        _populateBaseMetaTypes(cl)
+        return listBaseMetaTypes(cl, reverse)
+
+def isBaseMetaType(meta, cl):
+    try:
+        return _BASEMETA[cl][2].has_key(meta)
+
+    except KeyError:
+        _populateBaseMetaTypes(cl)
+        return isBaseMetaType(meta, cl)
+
+def _populateBaseMetaTypes(cl):
+    """Fill the base classes structure"""
+    # Fill the base classes list
+    try:
+        ret = [cl.meta_type]
+    except AttributeError:
+        ret = []
+
+    for b in cl.__bases__:
+        ret = list(listBaseMetaTypes(b, 1)) + ret
+
+    # Fill the base classes dict
+    bases = {}
+    for b in ret:
+        bases[b] = 1
+
+    _BASEMETALOCK.acquire()
+    try:
+        rev = ret[:]
+        rev.reverse()
+        _BASEMETA[cl] = (tuple(rev), tuple(ret), bases)
+    finally:
+        _BASEMETALOCK.release()
+
+def objectIds(container, meta_types = []):
+    """
+    """
+    return map(lambda x: x[0], objectItems(container, meta_types))
+
+def objectValues(container, meta_types = []):
+    """
+    """
+    return map(lambda x: x[1], objectItems(container, meta_types))
+
+def objectItems(container, meta_types = []):
+    """
+    objectItems(container, meta_types = [])
+    Same as a container's objectItem method, meta_types are scanned in the base classes too.
+    Ie. all objects derivated from Folder will be returned by objectItem(x, ['Folder'])
+    """
+    # Convert input type
+    if type(meta_types) not in (type(()), type([])):
+        meta_types = [meta_types]
+
+    # Special case where meta_types is empty
+    if not meta_types:
+        return container.objectItems()
+
+    # Otherwise : check parent for each meta_type
+    ret = []
+    for (id, obj) in container.objectItems():
+        for mt in meta_types:
+            if isBaseMetaType(mt, obj.__class__):
+                ret.append((id, obj))
+                break
+
+    return ret
+
+
+
+def listBaseClasses(cl, reverse = 0):
+    """
+    listBaseClasses(cl, reverse = 0) => list of classes
+
+    List all the base classes of an object.
+    When reverse is 0, return the self class first.
+    When reverse is 1, return the self class last.
+
+    WARNING : reverse is 0 or 1, it is an integer, NOT A BOOLEAN ! (optim issue)
+
+    CACHE RESULTS
+
+    WARNING : for optimization issues, the ORIGINAL tuple is returned : please do not change it !
+    """
+    # Look for the class in _BASECLASSES cache
+    try:
+        return _BASECLASSES[cl][reverse]
+
+    except:
+        _populateBaseClasses(cl)
+        return listBaseClasses(cl, reverse)
+
+
+def isBaseClass(base, cl):
+    """
+    isBaseClass(base, cl) => Boolean
+    Return true if base is a base class of cl
+    """
+    try:
+        return _BASECLASSES[cl][2].has_key(base)
+    except:
+        _populateBaseClasses(cl)
+        return isBaseClass(base, cl)
+
+
+def _populateBaseClasses(cl):
+    """Fill the base classes structure"""
+    # Fill the base classes list
+    ret = [cl]
+    for b in cl.__bases__:
+        ret = list(listBaseClasses(b, 1)) + ret
+
+    # Fill the base classes dict
+    bases = {}
+    for b in ret:
+        bases[b] = 1
+
+    _BASECLASSESLOCK.acquire()
+    try:
+        rev = ret[:]
+        rev.reverse()
+        _BASECLASSES[cl] = (tuple(rev), tuple(ret), bases)
+    finally:
+        _BASECLASSESLOCK.release()