[z3-checkins] r14459 - in z3/zopejam/trunk/src/zopejam: . icons/palette/16x16

hathawsh at codespeak.net hathawsh at codespeak.net
Sun Jul 10 01:01:19 CEST 2005


Author: hathawsh
Date: Sun Jul 10 01:01:14 2005
New Revision: 14459

Added:
   z3/zopejam/trunk/src/zopejam/icons/palette/16x16/sort_down.png   (contents, props changed)
   z3/zopejam/trunk/src/zopejam/icons/palette/16x16/sort_up.png   (contents, props changed)
Modified:
   z3/zopejam/trunk/src/zopejam/columns.py
   z3/zopejam/trunk/src/zopejam/main.py
Log:
Sortable directives list


Modified: z3/zopejam/trunk/src/zopejam/columns.py
==============================================================================
--- z3/zopejam/trunk/src/zopejam/columns.py	(original)
+++ z3/zopejam/trunk/src/zopejam/columns.py	Sun Jul 10 01:01:14 2005
@@ -16,6 +16,7 @@
 class Column:
     label = ''
     default_width = 100
+    indent = False
 
     def setProject(self, project):
         self.project = project
@@ -23,6 +24,9 @@
     def getText(self, d):
         return ''
 
+    def getSortKey(self, d):
+        return self.getText(d)
+
     def resolve(self, d, name):
         """Tries to resolve a package name,
 
@@ -44,6 +48,7 @@
 class SourceFile(Column):
     label = 'Source File'
     default_width = 350
+    indent = True
 
     def getText(self, d):
         cfg = d.element.config_file
@@ -57,10 +62,11 @@
             text = '"%s"' % self.project.shortenPath(cfg.filename)
         else:
             text = '"%s"' % cfg.filename
-        if d.element.depth:
-            return '    ' * (d.element.depth) + text
-        else:
-            return text
+        return text
+
+    def getSortKey(self, d):
+        cfg = d.element.config_file
+        return (cfg.package_name, cfg.filename)
 
 
 class DirectiveType(Column):
@@ -75,6 +81,12 @@
             ns = ns[len(nzo_prefix):]
         return '%s:%s' % (ns, localname)
 
+    def getSortKey(self, d):
+        ns, localname = d.element.name
+        if interfaces.IGenericNamespaceDirective.providedBy(d):
+            ns = '*'
+        return (ns, localname)
+
 
 class NameOrId(Column):
     label = 'Name / Id'
@@ -82,22 +94,23 @@
 
     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
-            
+
+##        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', '')
@@ -106,9 +119,9 @@
 
 class FactoryClassOrObject(Column):
     label = 'Factory / Class / Object'
-    default_width = 210
+    default_width = 150
 
-    def getText(self, d):
+    def getText(self, d, mark_inherited=True):
         # Search for an object in the directive or any parent
         src = d.element
         while src is not None:
@@ -122,12 +135,15 @@
             src = src.parent
         if name:
             text, error = self.resolve(d, name)
-            if src is not d.element:
+            if mark_inherited and src is not d.element:
                 # inherited
                 text = '^ ' + text
             return text
         return ''
 
+    def getSortKey(self, d):
+        return self.getText(d, mark_inherited=False)
+
 
 class File(Column):
     label = 'File'

Added: z3/zopejam/trunk/src/zopejam/icons/palette/16x16/sort_down.png
==============================================================================
Binary file. No diff available.

Added: z3/zopejam/trunk/src/zopejam/icons/palette/16x16/sort_up.png
==============================================================================
Binary file. No diff available.

Modified: z3/zopejam/trunk/src/zopejam/main.py
==============================================================================
--- z3/zopejam/trunk/src/zopejam/main.py	(original)
+++ z3/zopejam/trunk/src/zopejam/main.py	Sun Jul 10 01:01:14 2005
@@ -13,6 +13,7 @@
 import sys
 import wx
 from wx import xrc
+from wx.lib.mixins import listctrl
 
 from zcmledit.project import Project
 from zopejam import columns
@@ -231,7 +232,7 @@
         menubar = self.frame.GetMenuBar()
         addmenu = menubar.GetMenu(2)
         for item in addmenu.GetMenuItems():
-            addmenu.Destroy(item)
+            addmenu.DestroyItem(item)
 
         if self.project is None:
             return
@@ -399,21 +400,40 @@
         return p
 
 
-class DirectiveList(wx.ListCtrl):
+class DirectiveList(wx.ListCtrl, listctrl.ListCtrlAutoWidthMixin,
+                    listctrl.ColumnSorterMixin):
 
     def __init__(self, gui, parent, id):
         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.focus = -1    # element index or -1
 
         self.filter = Filter(gui, xrc.XRCCTRL(self.gui.frame, 'filter_panel'))
         self.columns = columns.create_default_columns()
+        self.SetImageList(self.gui.small_palette_images, wx.IMAGE_LIST_SMALL)
+
+        listctrl.ListCtrlAutoWidthMixin.__init__(self)
+        self.initColumnSorter(len(self.columns))
 
         for i, c in enumerate(self.columns):
             self.InsertColumn(i, c.label, width=c.default_width)
 
+        self.SortListItems(0, 1)
+
+        self.Bind(wx.EVT_LIST_ITEM_FOCUSED, self.onFocusItem)
+
+    def onFocusItem(self, event):
+        item = event.GetIndex()
+        if item < 0:
+            self.focus = -1
+        else:
+            self.focus = self.indexes[item]
+
     def populate(self):
+        self.itemDataMap = {}
         for c in self.columns:
             c.setProject(self.gui.project)
 
@@ -423,19 +443,106 @@
 
         self.elements = []
         files = []
+        # Order the elements by filename.  The original order is not
+        # used directly for display order, but when two elements have
+        # the same sort key, sorting will fall back to the original
+        # order.
         for cfg in self.gui.project.files.values():
-            # sort by source file
             files.append(((cfg.package_name or '', cfg.filename), cfg))
         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._doResize()
+        try:
+            self.SortItems()
+        except:
+            self.SetItemCount(0)
+            raise
+        self.Refresh()
+
+    def OnGetItemText(self, item, col):
+        index = self.indexes[item]
+        d = self.elements[index].directive
+        col_obj = self.columns[col]
+        text = col_obj.getText(d)
+        if col == self._col and col_obj.indent and d.element.depth:
+            # indent when sorting on an indentable column
+            return '    ' * (d.element.depth) + text
+        else:
+            return text
+
+    def GetListCtrl(self):
+        return self
+
+    def GetSortImages(self):
+        return (self.gui.small_palette_images['sort_up'],
+                self.gui.small_palette_images['sort_down'])
+
+    def SortItems(self, sorter=None):
+        """A SortItem implementation that works with virtual lists.
+
+        The sorter is not used.
+
+        Based on code by Egor Zindy
+        http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/426407
+        """
+        # _col and _colSortFlag are defined in ColumnSorterMixin.
+        # col is the column which was clicked on and
+        # sf, the sort flag, is False for descending (Z->A)
+        # and True for ascending (A->Z).
+
+        col = self._col
+        sf = self._colSortFlag[col]
+
+        # create pairs [(element_sort_key, element_index)]
+        items = []
+        col_obj = self.columns[col]
+        for i, e in enumerate(self.elements):
+            sort_key = col_obj.getSortKey(e.directive)
+            items.append((sort_key, i))
+
+        # sort the pairs by value (first element), then by original
+        # order (second element).  Multiple same values are okay,
+        # because the keys are unique.
+        items.sort()
+
+        # get the element index for each sorted item
+        k = [key for value, key in items]
 
-    def OnGetItemText(self, item, column):
-        d = self.elements[item].directive
-        c = self.columns[column]
-        return c.getText(d)
+        # False is descending (starting from last)
+        if sf == False:
+            k.reverse()
+
+        # store the element indexes as self.indexes.
+        self.indexes = k
+
+        # restore the focus to the element that had focus
+        if self.focus >= 0:
+            i = self.indexes.index(self.focus)
+            self.EnsureVisible(i)
+            # XXX need a way to change which item is focused (focus is
+            # independent of selection)
+
+        # redraw the list
+        self.Refresh()
+
+    def initColumnSorter(self, numColumns):
+        self._colSortFlag = [True] * numColumns
+        self._col = -1
+        self.Bind(wx.EVT_LIST_COL_CLICK, self.__OnColClick, self)
+
+    def __OnColClick(self, evt):
+        oldCol = self._col
+        self._col = col = evt.GetColumn()
+        # Toggle forward/reverse when clicking a column more than once,
+        # but not when switching columns
+        if col == oldCol:
+            self._colSortFlag[col] = not self._colSortFlag[col]
+        self.GetListCtrl().SortItems(self.GetColumnSorter())
+        self._ColumnSorterMixin__updateImages(oldCol)
+        evt.Skip()
 
 
 class Filter:


More information about the z3-checkins mailing list