I'm all confused now. What are the use cases for this order support again? For me, ordered support is useful in two cases: 1. For people want to make menues or lists of document/objects, and want them to be in a specific order. This requires ordering of the objects, and to display that ordering. 2. When you make objects and services that rely on an ordered list of subobjects. For example, say that you have a service of some kind that uses several plugins to perform functions, and it has to call these plugins in a particular order. Is there anything I have missed? When it comes to UI, you need to have a way of ordering and sorting the objects, and of course displaying the cureent order. There are two ways to do that as I can see it. 1. Use the currentZMI object listing, "main.dtml". That saves you from having two user interfaces. It would be nice to have a sorting function too, to sort on id, title and date, and this is alredy availiable in the ZMI, and that means it doesn't have to be duplicated it. 2 Having two separate interfaces, one being the normal ZMI view, and the second being a ZMI tab where you order and sort the objects. There are benefits to this, for example it means that you can sort the ZMI object list without changing the ordering. It also keeps the main.dtml exactly as it is today, since the ordered support would instead add a separate tab, and it would keep the main display less cluttered. I do not as of today have an opinion on this last matter. When it comes to API, I would expect an API with two methods. One to move to a particular position, where 0 is first and -1 is last, as per normal Python standard, and the other where you move relatively, where negative numbers move you towards the front and positive towards the back. As an example of this I give you my OrderedDictionary.py, which have: def order(self, key, order) and def move(self, key, distance) There would also be functions to move a set of keys one step forward, one step backwards, first and last that are callable through the ZMI with a list of ids, to make it easier to do web user interfaces. I do have ONE opinion (wow!): I personally preferr the type of UI where you check the boxes of the objects you want to move, and then click a button to move all of them up/down/first/last as opposed to the UI that has one up/down/first/last button per object. Well, that's my take on all this. I'm sure I've missed some important stuff, but as I said, I got all confused by the discussion. ;) # (c) 2003 Nuxeo SARL <http://nuxeo.com> # An Ordered, Persistent dictionary. # Some code from David Benjamins odict # $Id: OrderedDictionary.py,v 1.3 2003/02/21 17:14:30 regebro Exp $ from types import ListType, TupleType from ZODB.PersistentMapping import PersistentMapping from ZODB.PersistentList import PersistentList class OrderedDictionary(PersistentMapping): def __init__(self, dict = None): if dict: self._keys = PersistentList(dict.keys()) else: self._keys = PersistentList() PersistentMapping.__init__(self, dict) def __delitem__(self, key): PersistentMapping.__delitem__(self, key) self._keys.remove(key) def __setitem__(self, key, item): PersistentMapping.__setitem__(self, key, item) if key not in self._keys: self._keys.append(key) def __cmp__(self, dict): if isinstance(dict, OrderedDictionary): return cmp(self.data, dict.data) and cmp(self._keys, dict._keys) else: return 0 def clear(self): PersistentMapping.clear(self) self._keys = PersistentList() def copy(self): mcopy = OrderedDictionary() mcopy.data = self.data.copy() mcopy._keys = self._keys[:] return mcopy def items(self): return zip(self._keys, self.values()) def keys(self): return self._keys[:] # This returns a non-persistent copy of self._keys, # so you can manipulate the copy without manipulating self._keys def popitem(self): try: key = self._keys[-1] except IndexError: raise KeyError('dictionary is empty') val = self[key] del self[key] return (key, val) def index(self, key): return self._keys.index(key) def setdefault(self, key, failobj = None): if key not in self._keys: self._keys.append(key) return PersistentMapping.setdefault(self, key, failobj) def update(self, dict): for (key,val) in dict.items(): self.__setitem__(key,val) def values(self): return map(self.get, self._keys) def order(self, key, order ): """Moves the specified item to the specifed position 0 is first, 1 is second, -1 is last, -1 second from last, and so on. """ if order < 0: order = len(self) + order # Negative numbers are counted from behind if order < 0: order = 0 # It's still negative: move first self._keys.remove(key) if order >= len(self._keys): self._keys.append(key) else: self._keys.insert(order, key) def move(self, key, distance): """Moves the specified item a number of positions Positive numbers move to higher index numbers, negavtive to lower index numbers""" oldpos = self.index(key) newpos = oldpos + distance if newpos < 0: newpos = 0 self.order(key, newpos)