[z3-checkins] r14801 - in z3/zopejam/trunk/src: zcmledit zopejam

hathawsh at codespeak.net hathawsh at codespeak.net
Wed Jul 20 09:09:26 CEST 2005


Author: hathawsh
Date: Wed Jul 20 09:09:21 2005
New Revision: 14801

Modified:
   z3/zopejam/trunk/src/zcmledit/configfile.py
   z3/zopejam/trunk/src/zcmledit/directives.py
   z3/zopejam/trunk/src/zcmledit/inspector.py
   z3/zopejam/trunk/src/zcmledit/project.py
   z3/zopejam/trunk/src/zopejam/columns.py
   z3/zopejam/trunk/src/zopejam/main.py
   z3/zopejam/trunk/src/zopejam/propbook.py
Log:
When multiple directives are selected, show an editable grid widget.

Also reformatted some code in the zcmledit package.


Modified: z3/zopejam/trunk/src/zcmledit/configfile.py
==============================================================================
--- z3/zopejam/trunk/src/zcmledit/configfile.py	(original)
+++ z3/zopejam/trunk/src/zcmledit/configfile.py	Wed Jul 20 09:09:21 2005
@@ -18,8 +18,8 @@
 from zcmledit import interfaces
 
 
-ZCML_CONDITION = (u"http://namespaces.zope.org/zcml", u"condition")
-XMLNS_NS = u"http://www.w3.org/2000/xmlns/" # URI for XML NS declarations
+zcml_condition = (u"http://namespaces.zope.org/zcml", u"condition")
+xmlns_ns = u"http://www.w3.org/2000/xmlns/" # URI for XML NS declarations
 
 
 class ConfigurationFile:
@@ -81,18 +81,19 @@
     def createDirective(self, element):
         """Returns an IDirective to fit an XML element"""
         ns, localname = element.name
-        if localname == 'configure':
-            return directives.ConfigureDirective(element, self.package_name)
-
-        if localname in ('include', 'includeOverrides'):
-            return directives.IncludeDirective(element, self.project)
 
-        if ns == directives.META_NS and localname in (
+        if localname == 'configure':
+            t = directives.ConfigureDirective
+        elif localname in ('include', 'includeOverrides'):
+            t = directives.IncludeDirective
+        elif ns == directives.meta_ns and localname in (
             'directive', 'groupingDirective',
             'complexDirective', 'simpleDirective'):
-            return directives.DefinitionDirective(element)
+            t = directives.DefinitionDirective
+        else:
+            t = directives.CommonDirective
 
-        return directives.CommonDirective(element)
+        return t(element)
 
 
     def generateXML(self):
@@ -140,35 +141,6 @@
         self.directive = None
 
 
-##        # Collect information from certain XML attributes
-##        self._generic_ns = False
-##        ns, localname = name
-##        if localname == 'configure':
-##            # This directive can modify the context package name
-##            self._generic_ns = True
-##            p = data.get('package')
-##            if p:
-##                p = p.strip()
-##        else:
-##            p = None
-##        self._package_name = p
-
-##        if localname in ('include', 'includeOverrides'):
-##            self._generic_ns = True
-##            self._is_include = True
-##        else:
-##            self._is_include = False
-
-##        if ns == META_NS and localname in (
-##            'directive', 'groupingDirective',
-##            'complexDirective', 'simpleDirective'):
-##            self._is_definition = True
-##        else:
-##            self._is_definition = False
-
-##    def setPackageName(self, package_name):
-##        self._package_name = package_name
-
     def flattened(self):
         """Returns a list containing this directive and all descendants.
         """
@@ -177,47 +149,11 @@
             res.extend(e.flattened())
         return res
 
-##    def getAbsolutePackageName(self):
-##        """Returns the absolute package name in context of this directive.
-
-##        Used for resolving relative package names.
-##        """
-##        my_pn = self._package_name
-##        if not my_pn:
-##            # inherit
-##            elem = self.parent
-##            while elem is not None:
-##                if elem._package_name:
-##                    return elem.getAbsolutePackageName()
-##                elem = elem.parent
-##            raise NoPackageError("No absolute package has been set")
-##        elif not my_pn.startswith('.'):
-##            return my_pn
-
-##        # my_pn is relative, so resolve it.
-##        if self.parent is not None:
-##            parent_pn = self.parent.getAbsolutePackageName()
-##        else:
-##            raise NoPackageError("No absolute package has been set")
-##        return join_package(parent_pn, my_pn)
-
-##    def isInGenericNamespace(self):
-##        """Returns True if this directive is in the generic (*) namespace"""
-##        return self._generic_ns
-
-##    def isInclude(self):
-##        """Returns True if this is an include directive"""
-##        return self._is_include
-
-##    def isDefinition(self):
-##        """Returns True if this directive defines a directive type"""
-##        return self._is_definition
-
     def getXMLName(self, ns, localname):
         """Returns the tag or attribute for a given namespace and localname"""
         if not ns:
             return localname
-        if ns == XMLNS_NS:
+        if ns == xmlns_ns:
             if localname:
                 return u'xmlns:%s' % localname
             else:
@@ -254,12 +190,12 @@
             out_attrs[(u'', key)] = value
         for prefix, uri in self.prefix_uri.items():
             if not prefix:
-                key = XMLNS_NS, ''
+                key = xmlns_ns, ''
             else:
-                key = XMLNS_NS, prefix
+                key = xmlns_ns, prefix
             out_attrs[key] = uri
         if self.condition:
-            out_attrs[ZCML_CONDITION] = self.condition
+            out_attrs[zcml_condition] = self.condition
 
         if not out_attrs:
             line = u'%s<%s%s' % (indent, tag_name, tag_end)
@@ -359,7 +295,7 @@
         items = pm.items()
         items.sort()
         for prefix, uri in items:
-            attr_order.append((XMLNS_NS, prefix))
+            attr_order.append((xmlns_ns, prefix))
 
         # attrs is a list of alternating names and values.
         # gather its contents, preserving the attribute order.
@@ -373,7 +309,7 @@
             attr_order.append(key)
 
             ns, localname = key
-            if key == ZCML_CONDITION:
+            if key == zcml_condition:
                 condition = value
             elif not ns or ns == name[0]:
                 data[localname] = value

Modified: z3/zopejam/trunk/src/zcmledit/directives.py
==============================================================================
--- z3/zopejam/trunk/src/zcmledit/directives.py	(original)
+++ z3/zopejam/trunk/src/zcmledit/directives.py	Wed Jul 20 09:09:21 2005
@@ -1,4 +1,9 @@
 
+# (c) 2005 Shane Hathaway
+# License: ZPL 2.1
+
+"""Partially interpreted configuration directives"""
+
 from glob import glob
 import os
 
@@ -8,7 +13,7 @@
 from zcmledit.exceptions import NameResolutionError, NoPackageError
 from zcmledit.exceptions import InvalidRelativeNameError, MissingPackageError
 
-META_NS = u"http://namespaces.zope.org/meta"
+meta_ns = u"http://namespaces.zope.org/meta"
 
 
 class Directive(object):
@@ -17,6 +22,10 @@
         self.element = element
         self.errors = []
         self._abs_package = None
+        self.readElement()
+
+    def readElement(self):
+        pass
 
     def getInheritedPackageName(self):
         ancestor = self.element.parent
@@ -53,23 +62,27 @@
             return self._abs_package
         return self.getInheritedPackageName()
 
+    def getType(self):
+        """Returns an IDefinitionDirective or None"""
+        project = self.element.config_file.project
+        if interfaces.IGenericNamespaceDirective.providedBy(self):
+            ns, localname = self.element.name
+            return project.definitions.get(('*', localname))
+        else:
+            return project.definitions.get(self.element.name)
+
 
 class ConfigureDirective(Directive):
     implements(interfaces.IConfigureDirective)
 
-    def __init__(self, element, config_file_package=None):
-        Directive.__init__(self, element)
-        self.config_file_package = config_file_package
-        self.update()
-
-    def update(self):
+    def readElement(self):
         self.errors = []
         self.package = self.element.data.get('package')
         self.setAbsolutePackage(self.package)
 
     def getInheritedPackageName(self):
         if self.element.parent is None:
-            return self.config_file_package
+            return self.element.config_file.package_name
         else:
             return Directive.getInheritedPackageName(self)
 
@@ -81,12 +94,7 @@
     """
     implements(interfaces.IIncludeDirective)
 
-    def __init__(self, element, project):
-        Directive.__init__(self, element)
-        self.project = project
-        self.update()
-
-    def update(self):
+    def readElement(self):
         """Read the directive element and prepare the filename pattern.
 
         The constructor calls this method, but it can be called again
@@ -118,9 +126,9 @@
             # convert to an absolute path
             abs_package = self.getAbsolutePackageName()
             if abs_package:
+                pythonpath = element.config_file.project.pythonpath
                 try:
-                    basepath = find_package(
-                        abs_package, self.project.pythonpath)
+                    basepath = find_package(abs_package, pythonpath)
                 except NameResolutionError, e:
                     basepath = None
                     self.errors.append(
@@ -153,11 +161,7 @@
     """A directive that defines other directives"""
     implements(interfaces.IDefinitionDirective)
 
-    def __init__(self, element):
-        Directive.__init__(self, element)
-        self.update()
-
-    def update(self):
+    def readElement(self):
         self.errors = []
         self.name = self.element.data.get('name')
         self.schema = self.element.data.get('schema')
@@ -165,7 +169,7 @@
         ns = None
         parent = self.element.parent
         while parent is not None:
-            if parent.name == (META_NS, 'directives'):
+            if parent.name == (meta_ns, 'directives'):
                 # use the namespace inherited from a 'directives' directive
                 ns = parent.data['namespace']
                 break
@@ -189,6 +193,34 @@
             self.errors.append("Missing 'schema' attribute")
         self.abs_schema = abs_schema
 
+    def getSchemaInfo(self):
+        project = self.element.config_file.project
+        return project.interfaces[self.abs_schema]
+
+
+class BootstrapDirective(Directive):
+    """A bootstrap definition directive.
+
+    Not defined in any configuration file.
+    """
+    implements(interfaces.IDefinitionDirective)
+
+    def __init__(self, project, ns, name, abs_schema):
+        self.project = project
+        self.element = None
+        self.errors = ()
+
+        self.name = name
+        self.fullname = (ns, name)
+        self.schema = abs_schema
+        self.abs_schema = abs_schema
+
+    def getAbsolutePackageName(self):
+        return None
+
+    def getSchemaInfo(self):
+        return self.project.interfaces[self.abs_schema]
+
 
 class CommonDirective(Directive):
     implements(interfaces.IDirective)
@@ -253,49 +285,3 @@
         msg += ("  (Directory '%s' is a candidate, but one "
                 "or more '__init__.py' files are required.)" % candidate)
     raise MissingPackageError(msg)
-
-
-class BootstrapDirective(Directive):
-    """A bootstrap definition directive.
-
-    Not defined in any configuration file.
-    """
-    implements(interfaces.IDefinitionDirective)
-
-    def __init__(self, ns, name, abs_schema):
-        self.element = None
-        self.errors = ()
-
-        self.name = name
-        self.fullname = (ns, name)
-        self.schema = abs_schema
-        self.abs_schema = abs_schema
-
-    def getAbsolutePackageName(self):
-        return None
-
-
-def createBootstrapDirectives():
-    """Returns a dictionary containing the bootstrap directive definitions"""
-    res = {}
-    for ns, name, schema in [
-        ('*', 'configure', "zope.configuration.zopeconfigure.IZopeConfigure"),
-        ('*', 'include', "zope.configuration.xmlconfig.IInclude"),
-        ('*', 'includeOverride', "zope.configuration.xmlconfig.IInclude"),
-        (META_NS, 'directive',
-         "zope.configuration.config.IFullInfo"),
-        (META_NS, 'groupingDirective',
-         "zope.configuration.config.IFullInfo"),
-        (META_NS, 'directives',
-         "zope.configuration.config.IDirectivesInfo"),
-        (META_NS, 'complexDirective',
-         "zope.configuration.config.IFullInfo"),
-        (META_NS, 'subdirective',
-         "zope.configuration.config.IDirectiveInfo"),
-        (META_NS, 'provides',
-         "zope.configuration.config.IProvidesDirectiveInfo"),
-        ]:
-        res[(ns, name)] = BootstrapDirective(ns, name, schema)
-    return res
-
-

Modified: z3/zopejam/trunk/src/zcmledit/inspector.py
==============================================================================
--- z3/zopejam/trunk/src/zcmledit/inspector.py	(original)
+++ z3/zopejam/trunk/src/zcmledit/inspector.py	Wed Jul 20 09:09:21 2005
@@ -20,7 +20,7 @@
 
 
 def inspect_interfaces(names):
-    """Returns {name: {'doc', 'bases', 'attrs' | 'error'}}"""
+    """Returns {name: {'doc', 'bases', 'sro', 'attrs' | 'error'}}"""
     res = {}
     # the names are absolute.
     todo = list(names)
@@ -48,6 +48,8 @@
 
         if IInterface.providedBy(obj):
             info['doc'] = getattr(obj, '__doc__', None)
+
+            # report base interfaces
             bases = []
             for base in getattr(obj, '__bases__', ()):
                 m = getattr(base, '__module__', None)
@@ -58,6 +60,17 @@
                     if not res.has_key(fullname):
                         todo.append(fullname)
             info['bases'] = bases
+
+            # report specification resolution order
+            sro = []
+            for base in getattr(obj, '__sro__', ()):
+                m = getattr(base, '__module__', None)
+                n = getattr(base, '__name__', None)
+                if m and n:
+                    fullname = '%s.%s' % (m, n)
+                    sro.append(fullname)
+            info['sro'] = sro
+
             attrs = {}
             for n in obj.names(False):
                 attrs[n] = obj[n]

Modified: z3/zopejam/trunk/src/zcmledit/project.py
==============================================================================
--- z3/zopejam/trunk/src/zcmledit/project.py	(original)
+++ z3/zopejam/trunk/src/zcmledit/project.py	Wed Jul 20 09:09:21 2005
@@ -11,6 +11,7 @@
 import sys
 
 from zope.interface import implements
+from zope.schema.interfaces import IField
 
 from zcmledit import interfaces
 from zcmledit.configfile import ConfigurationFile
@@ -32,11 +33,37 @@
             pythonpath = [os.path.join(self.base, 'src')] + sys.path
         self.pythonpath = pythonpath
 
+    def createBootstrapDirectives(self):
+        """Returns a dictionary containing the bootstrap definitions"""
+        res = {}
+        meta_ns = directives.meta_ns
+        for ns, name, schema in [
+            ('*', 'configure',
+             "zope.configuration.zopeconfigure.IZopeConfigure"),
+            ('*', 'include', "zope.configuration.xmlconfig.IInclude"),
+            ('*', 'includeOverride', "zope.configuration.xmlconfig.IInclude"),
+            (meta_ns, 'directive',
+             "zope.configuration.config.IFullInfo"),
+            (meta_ns, 'groupingDirective',
+             "zope.configuration.config.IFullInfo"),
+            (meta_ns, 'directives',
+             "zope.configuration.config.IDirectivesInfo"),
+            (meta_ns, 'complexDirective',
+             "zope.configuration.config.IFullInfo"),
+            (meta_ns, 'subdirective',
+             "zope.configuration.config.IDirectiveInfo"),
+            (meta_ns, 'provides',
+             "zope.configuration.config.IProvidesDirectiveInfo"),
+            ]:
+            res[(ns, name)] = directives.BootstrapDirective(
+                self, ns, name, schema)
+        return res
+
     def load(self):
         self.packages = {}  # {package name: [filename]}
         self.files = {}     # {filename: config_file}
         # self.definitions contains {(ns, localname): IDirectiveDefinition}
-        self.definitions = directives.createBootstrapDirectives()
+        self.definitions = self.createBootstrapDirectives()
         self.root_config = ConfigurationFile(self, self.root_filename)
         self.files[self.root_filename] = self.root_config
 
@@ -68,9 +95,16 @@
                                        "directive %s" % repr(dfn.fullname))
                 self.definitions[dfn.fullname] = dfn
 
-        # load schemas
+        self.load_schemas()
+
+    def load_schemas(self):
         names = [dfn.abs_schema for dfn in self.definitions.values()]
-        self.schemas = self.call_inspector('inspect_interfaces', names)
+        d = self.call_inspector('inspect_interfaces', names)
+        self.interfaces = {}
+        for name, info in d.items():
+            self.interfaces[name] = InterfaceInfo(name, info)
+        for info in self.interfaces.values():
+            info.initBases(self.interfaces)
 
     def call_inspector(self, funcname, *args, **kw):
         inspector_py = os.path.join(here, 'inspector.py')
@@ -93,10 +127,8 @@
     def print_fields(self):
         """Shows reuse of fields by different directive types."""
         fields = {}  # {(field_name, field_type) -> [schema_name]}
-        for schema_name, info in self.schemas.items():
-            if not info.has_key('attributes'):
-                continue
-            for attr_name, obj in info['attributes'].items():
+        for schema_name, info in self.interfaces.items():
+            for attr_name, obj in info.attributes.items():
                 if not IField.providedBy(obj):
                     continue
                 key = (attr_name, type(obj))
@@ -114,3 +146,37 @@
             if len(p) > len_base and p[len_base] == os.sep:
                 return p[len_base + 1:]
         return p
+
+
+class InterfaceInfo:
+    """Contains info received from inspector.inspect_interfaces()."""
+
+    def __init__(self, name, info):
+        self.name = name
+        self.error = info.get('error', '')
+        self.doc = info.get('doc', '')
+        self.base_names = info.get('bases', ())
+        self.sro_names = info.get('sro', ())
+        self.attributes = info.get('attributes')
+        if self.attributes is None:
+            self.attributes = {}
+        self.fields = {}
+        for k, v in self.attributes.items():
+            if IField.providedBy(v):
+                self.fields[k] = v
+
+    def initBases(self, all_interfaces):
+        """As part of construction, link with base InterfaceInfo objects."""
+        self.bases = [all_interfaces[name] for name in self.base_names]
+        self.sro = [all_interfaces[name] for name in self.sro_names]
+
+    def getField(self, k):
+        v = self.fields.get(k)
+        if v is not None:
+            return v
+        for info in self.sro:
+            v = info.fields.get(k)
+            if v is not None:
+                return v
+        return None
+

Modified: z3/zopejam/trunk/src/zopejam/columns.py
==============================================================================
--- z3/zopejam/trunk/src/zopejam/columns.py	(original)
+++ z3/zopejam/trunk/src/zopejam/columns.py	Wed Jul 20 09:09:21 2005
@@ -18,8 +18,11 @@
     default_width = 100
     indent = False
 
-    def setProject(self, project):
-        self.project = project
+    def getLabel(self):
+        return self.label
+
+    def getDefaultWidth(self):
+        return self.default_width
 
     def getText(self, d):
         return ''
@@ -27,6 +30,10 @@
     def getSortKey(self, d):
         return self.getText(d)
 
+    def getFlags(self, d):
+        """Returns (valid, editable, has_error)."""
+        return (True, False, False)
+
     def resolve(self, d, name):
         """Tries to resolve a package name,
 
@@ -58,8 +65,8 @@
                 text = cfg.package_name
             else:
                 text = '%s "%s"' % (cfg.package_name, basename)
-        elif self.project is not None:
-            text = '"%s"' % self.project.shortenPath(cfg.filename)
+        elif cfg.project is not None:
+            text = '"%s"' % cfg.project.shortenPath(cfg.filename)
         else:
             text = '"%s"' % cfg.filename
         return text
@@ -94,23 +101,6 @@
 
     def getText(self, d):
         data = d.element.data
-
-##        if interfaces.IIncludeDirective.providedBy(d):
-##            fn = data.get('files') or data.get('file') or 'configure.zcml'
-##            package = data.get('package') or '.'
-##            if package:
-##                abs_package, error = self.resolve(d, package)
-##                if error:
-##                    abs_package = '??? %s' % package
-##            if abs_package:
-##                if fn == 'configure.zcml':
-##                    label = abs_package
-##                else:
-##                    label = '%s "%s"' % (abs_package, fn)
-##            else:
-##                label = '"%s"' % fn
-##            return label
-
         res = data.get('name')
         if res is None:
             res = data.get('id', '')
@@ -145,18 +135,33 @@
         return self.getText(d, mark_inherited=False)
 
 
-class File(Column):
-    label = 'File'
-    default_width = 80
+class SchemaAttribute(Column):
+    default_width = 100
+
+    def __init__(self, schema_attr):
+        self.schema_attr = schema_attr
+        if self.schema_attr.endswith('_'):
+            self.xml_attr = self.schema_attr[:-1]
+        else:
+            self.xml_attr = self.schema_attr
+
+    def getLabel(self):
+        return self.xml_attr
 
     def getText(self, d):
         data = d.element.data
-        name = data.get('file')
-        if name is None:
-            name = data.get('template')
-            if name is None:
-                name = data.get('page')
-        return name or ''
+        return data.get(self.xml_attr, '')
+
+    def getFlags(self, d):
+        """Returns (valid, editable, has_error)."""
+        t = d.getType()
+        valid = False
+        if t is not None:
+            info = t.getSchemaInfo()
+            f = info.getField(self.schema_attr)
+            if f is not None:
+                valid = True
+        return (valid, valid, False)
 
 
 def create_default_columns():
@@ -166,9 +171,3 @@
         NameOrId(),
         FactoryClassOrObject(),
         ]
-##        For(),
-##        Provides(),
-##        Permission(),
-##        InterfaceColumn(),
-##        File(),
-##        ]

Modified: z3/zopejam/trunk/src/zopejam/main.py
==============================================================================
--- z3/zopejam/trunk/src/zopejam/main.py	(original)
+++ z3/zopejam/trunk/src/zopejam/main.py	Wed Jul 20 09:09:21 2005
@@ -362,13 +362,13 @@
             return
 
         dfn = self.project.definitions[fullname]
-        schema_info = self.project.schemas.get(dfn.abs_schema)
-        if schema_info.get('error'):
+        info = dfn.getSchemaInfo()
+        if info.error:
             doc = ('An error occurred while loading the '
-                   'schema for this directive: %s' % schema_info['error'])
+                   'schema for this directive: %s' % info.error)
             body_color = wx.RED
         else:
-            doc = self.join_lines(schema_info.get('doc', ''))
+            doc = self.join_lines(info.doc)
             body_color = wx.BLACK
         if not doc:
             doc = 'No documentation available.'
@@ -441,8 +441,8 @@
         wx.ListCtrl.__init__(
             self, parent, id, style=wx.LC_REPORT | wx.LC_VIRTUAL)
         self.gui = gui
-        self.elements = []
-        self.indexes = []  # list of element indexes (shuffled by sorting)
+        self.directives = []  # list of directives, not reordered by sorting
+        self.indexes = []  # list of directive indexes, reordered by sorting
 
         self.filter = Filter(gui, xrc.XRCCTRL(self.gui.frame, 'filter_panel'))
         self.columns = columns.create_default_columns()
@@ -452,7 +452,7 @@
         self.initColumnSorter(len(self.columns))
 
         for i, c in enumerate(self.columns):
-            self.InsertColumn(i, c.label, width=c.default_width)
+            self.InsertColumn(i, c.getLabel(), width=c.getDefaultWidth())
 
         self.SortListItems(0, 1)
 
@@ -474,23 +474,22 @@
         selected = []
         item = self.GetFirstSelected()
         while item >= 0:
-            selected.append(self.elements[item])
+            index = self.indexes[item]
+            selected.append(self.directives[index])
             item = self.GetNextSelected(item)
         self.gui.book.onSelect(selected)
 
     def populate(self):
         self.itemDataMap = {}
-        for c in self.columns:
-            c.setProject(self.gui.project)
 
         if self.gui.project is None:
             self.SetItemCount(0)
             return
 
-        self.elements = []
+        self.directives = []
         files = []
-        # Order the elements by filename.  The original order is not
-        # used directly for display order, but when two elements have
+        # Order the directives by filename.  The original order is not
+        # used directly for display order, but when two directives have
         # the same sort key, sorting will fall back to the original
         # order.
         for cfg in self.gui.project.files.values():
@@ -498,8 +497,9 @@
         files.sort()
         for sort_key, cfg in files:
             if cfg.root is not None:
-                self.elements.extend(cfg.root.flattened())
-        self.SetItemCount(len(self.elements))
+                self.directives.extend(
+                    [e.directive for e in cfg.root.flattened()])
+        self.SetItemCount(len(self.directives))
         self._doResize()
         try:
             self.SortItems()
@@ -510,7 +510,7 @@
 
     def OnGetItemText(self, item, col):
         index = self.indexes[item]
-        d = self.elements[index].directive
+        d = self.directives[index]
         col_obj = self.columns[col]
         text = col_obj.getText(d)
         if col == self._col and col_obj.indent and d.element.depth:
@@ -537,10 +537,10 @@
         # gather the focus and selection flags
         flags = {}
         mask = wx.LIST_STATE_SELECTED | wx.LIST_STATE_FOCUSED
-        for i, element_index in enumerate(self.indexes):
+        for i, directive_index in enumerate(self.indexes):
             state = self.GetItemState(i, mask)
             if state:
-                flags[element_index] = state
+                flags[directive_index] = state
         
         # _col and _colSortFlag are defined in ColumnSorterMixin.
         # col is the column which was clicked on and
@@ -550,34 +550,34 @@
         col = self._col
         sf = self._colSortFlag[col]
 
-        # create pairs [(element_sort_key, element_index)]
+        # create pairs [(directive_sort_key, directive_index)]
         items = []
         col_obj = self.columns[col]
-        for i, e in enumerate(self.elements):
-            sort_key = col_obj.getSortKey(e.directive)
+        for i, d in enumerate(self.directives):
+            sort_key = col_obj.getSortKey(d)
             items.append((sort_key, i))
 
-        # sort the pairs by value (first element), then by original
-        # order (second element).  Multiple same values are okay,
+        # sort the pairs by value (first sort key), then by original
+        # order (second sort key).  Multiple same values are okay,
         # because the keys are unique.
         items.sort()
 
-        # get the element index for each sorted item
+        # get the directive index for each sorted item
         k = [key for value, key in items]
 
         # False is descending (starting from last)
         if sf == False:
             k.reverse()
 
-        # store the element indexes as self.indexes.
+        # store the directive indexes as self.indexes.
         self.indexes = k
 
         # clear state for all rows (undocumented API?)
         self.SetItemState(-1, 0, mask)
 
         # reapply the selection and focus flags
-        for i, element_index in enumerate(self.indexes):
-            state = flags.get(element_index)
+        for i, directive_index in enumerate(self.indexes):
+            state = flags.get(directive_index)
             if state:
                 self.SetItemState(i, state, mask)
                 if state & wx.LIST_STATE_FOCUSED:

Modified: z3/zopejam/trunk/src/zopejam/propbook.py
==============================================================================
--- z3/zopejam/trunk/src/zopejam/propbook.py	(original)
+++ z3/zopejam/trunk/src/zopejam/propbook.py	Wed Jul 20 09:09:21 2005
@@ -6,6 +6,9 @@
 """
 
 import wx
+import wx.grid
+
+from zopejam import columns
 
 
 class PropertiesNotebook:
@@ -13,11 +16,88 @@
     def __init__(self, gui, notebook):
         self.gui = gui
         self.notebook = notebook
+##        self.props_page = wx.ScrolledWindow(self.notebook)
+##        self.props_page.SetSizer(wx.BoxSizer(wx.VERTICAL))
+##        self.props_page.SetScrollRate(0, 20)
         self.props_page = wx.Panel(self.notebook)
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        self.props_page.SetSizer(sizer)
         self.notebook.AddPage(self.props_page, "Properties")
         self.source_page = wx.Panel(self.notebook)
         self.notebook.AddPage(self.source_page, "Source")
 
-    def onSelect(self, elements):
-        pass
-
+    def onSelect(self, directives):
+        self.props_page.DestroyChildren()
+        sizer = self.props_page.GetSizer()
+        if not directives:
+            return
+        if len(directives) > 1:
+            grid = wx.grid.Grid(self.props_page, -1)
+            sizer = self.props_page.GetSizer()
+            sizer.Add(grid, proportion=1, flag=wx.EXPAND)
+            grid.SetTable(PropertyTable(directives))
+            self.props_page.Layout()
+        # else show a friendly property editor with documentation
+
+
+class PropertyTable(wx.grid.PyGridTableBase):
+
+    def __init__(self, directives):
+        wx.grid.PyGridTableBase.__init__(self)
+        self.directives = directives
+        attrs = {}
+        for d in directives:
+            t = d.getType()
+            if t is not None:
+                info = t.getSchemaInfo()
+                attrs.update(info.attributes)
+        attrs = attrs.keys()
+        attrs.sort()
+        self.columns = [
+            columns.SourceFile(),
+            columns.DirectiveType(),
+            ]
+        for a in attrs:
+            self.columns.append(columns.SchemaAttribute(a))
+
+        # prepare self.cell_attrs
+        self.cell_attrs = {}  # {(valid, editable, has_error): GridCellAttr}
+        for valid in (False, True):
+            for editable in (False, True):
+                for has_error in (False, True):
+                    gca = wx.grid.GridCellAttr()
+                    if not valid:
+                        gca.SetBackgroundColour(wx.Colour(127, 127, 127))
+                    elif has_error:
+                        gca.SetBackgroundColour(wx.Colour(255, 127, 127))
+                    gca.SetReadOnly(not valid or not editable)
+                    self.cell_attrs[(valid, editable, has_error)] = gca
+
+    def GetNumberCols(self):
+        return len(self.columns)
+
+    def GetNumberRows(self):
+        return len(self.directives)
+
+    def GetColLabelValue(self, col):
+        return self.columns[col].getLabel()
+
+    def GetRowLabelValue(self, row):
+        return '%d' % (row + 1)
+
+    def GetValue(self, row, col):
+        d = self.directives[row]
+        return self.columns[col].getText(d)
+
+    def GetRawValue(self, row, col):
+        return self.GetValue(row, col)
+
+    def SetValue(self, row, col, value):
+        raise NotImplementedError
+
+    def GetAttr(self, row, col, kind):
+        d = self.directives[row]
+        flags = self.columns[col].getFlags(d)
+        a = self.cell_attrs[flags]
+        a.IncRef()
+        return a


More information about the z3-checkins mailing list