From waterbug at step.nasa.gov  Sun May  1 02:22:38 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sun May  1 02:22:39 2005
Subject: [pangalactic-commits] localdb clean-ups; more needed!!
Message-ID: <200505010622.j416Mcs7001296@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/utils/datamanager.py 1.172 1.173
PanGalactic/pangalactic/utils/localdb.py 1.127 1.128

Log message:
localdb clean-ups; more needed!!

Index: PanGalactic/pangalactic/utils/localdb.py
diff -u PanGalactic/pangalactic/utils/localdb.py:1.127 PanGalactic/pangalactic/utils/localdb.py:1.128
--- PanGalactic/pangalactic/utils/localdb.py:1.127	Sat Apr 30 14:45:25 2005
+++ PanGalactic/pangalactic/utils/localdb.py	Sun May  1 02:22:36 2005
@@ -1,9 +1,9 @@
 """
 Local object cache manager
 
-@version: $Revision: 1.127 $
+@version: $Revision: 1.128 $
 """
-__version__ = "$Revision: 1.127 $"[11:-2]
+__version__ = "$Revision: 1.128 $"[11:-2]
 
 import os
 import glob
@@ -33,56 +33,35 @@
 
 
 class LocalStorage:
-
-    ACU = "Acu"
-    DCU = "Dcu"
-    CATEGORY = "ObjectSchema"
-    DISPLAY_CONFIG = "DisplayConfig"
-    DOCUMENT = "Document"
-    # GIDEPALERT = "GidepAlert"
-    # GIDEPPROBLEMADVISORY = "GidepProblemAdvisory"
-    # GIDEPDMSMSNOTICE = "GidepDmsmsNotice"
-    # GIDEPAGENCYACTIONNOTICE = "GidepAgencyActionNotice"
-    # GIDEPPRODUCTCHANGENOTICE = "GidepProductChangeNotice"
-    # NASAADVISORY = "NasaAdvisory"
-    MODEL = "Model"
     OIDLOOKUP = "OidLookup"
     ORGANIZATION = "Organization"
-    PART = "Part"
-    PARTSLIST = "PartsList"
     PASSWD = "Passwd"
-    FILELINK = "FileLink"
     PROJECT = "Project"
     PROJECTOBJECTS = "ProjectObjects"
-    UNCOMMITTEDDOCUMENTIDS = "UncommittedDocumentIDs"
-    UNCOMMITTEDOBJECTS = "UncommittedObjects"
     USER = "User"
     WFACTIVITY = "WfActivity"
     WFEVENTAUDIT = "WfEventAudit" 
     WFPROCESSINSTANCE = "WfProcessInstance"
     WFTRANSITION = "WfTransition"
-
     # tuple fields:
     # first field  - the dict name
     # second field - does this dict persist after clearing localdb?
     # third field  - who sees the dict displayed in the dbbrowser?
-
-    dictlist = [(ACU, 1, user),
-                (CATEGORY, 0, user),
-                (DISPLAY_CONFIG, 1, admin),
-                (DCU, 1, admin),
-                (DOCUMENT, 1, user), 
-                (MODEL, 1, user), 
-                (OIDLOOKUP, 1, god),
+    dictlist = [('Acu', 1, user),
+                ('DisplayConfig', 1, admin),
+                ('Dcu', 1, admin),
+                ('Document', 1, user), 
+                ('Model', 1, user), 
+                ('ObjectSchema', 0, user),
+                (OIDLOOKUP, 1, admin),
                 (ORGANIZATION, 0, user),
-                (PART, 1, user), 
-                (PARTSLIST, 1, user),
+                ('Part', 1, user), 
+                ('PartsList', 1, user),
                 (PASSWD, 0, admin),
-                (FILELINK, 1, god),
+                ('FileLink', 1, user),
                 (PROJECT, 0, admin),
-                (PROJECTOBJECTS, 0, god),
-                (UNCOMMITTEDDOCUMENTIDS, 1, god), 
-                (UNCOMMITTEDOBJECTS, 1, user), 
+                (PROJECTOBJECTS, 0, user),
+                ("Uncommitted", 1, user), 
                 (USER, 0, admin),
                 (WFACTIVITY, 1, user),
                 (WFEVENTAUDIT, 1, admin),
@@ -91,13 +70,13 @@
 
     DictListNames = [x for x, y, z in dictlist]
 
-    CommittedDicts = [ACU,
-                      DCU,
-                      DOCUMENT,
-                      MODEL,
-                      PART,
-                      PARTSLIST,
-                      FILELINK,
+    CommittedDicts = ['Acu',
+                      'Dcu',
+                      'Document',
+                      'Model',
+                      'Part',
+                      'PartsList',
+                      'FileLink',
                       PROJECT,
                       WFACTIVITY,
                       WFEVENTAUDIT,
@@ -127,7 +106,6 @@
         self.dbroot = self.dbconnection.root()
         self.Setup()
 
-
     def Pack(self):
         """
         Removes old entries from and cleans a PersistentStorage object
@@ -167,7 +145,7 @@
             pass
         self.dbroot[dictname][obj.pgef_oid] = obj
 
-    def SaveUser(self, user = None):
+    def SaveUser(self, user=None):
 #        print "localdb.saveuser"
         if user:
             self.saveDict(self.USER, user)
@@ -188,6 +166,7 @@
         return pwd_dict[passwd_id]
 
     ######### TODO: define ObjectSchema instances for the Wf classes!!
+
     def defaultDisplayConfig(self):
         print "localdb.defaultDisplayConfig"
         current_config = {}
@@ -201,45 +180,33 @@
 
     def getDisplayConfig(self):
         print "localdb.getDisplayConfig"
-        foo = self.getDict(self.DISPLAY_CONFIG)
+        foo = self.getDict('DisplayConfig')
         print "localdb.config.keys", foo.keys()
         if not foo:
             foo = self.defaultDisplayConfig()
         return foo
 
     def setDisplayConfig(self, config):
-        self.dbroot[self.DISPLAY_CONFIG] = config
+        self.dbroot['DisplayConfig'] = config
         self.Commit()
 
     def getLookupObject(self, pgef_oid):
         dict = self.lookupOid(pgef_oid)
         return self.getLocalObject(dict, pgef_oid)
 
-    def updateACU(self, acu_obj):
-        print "localdb.updateacu is deprecated."
-        return acu_obj
-
     def SavePartsList(self, partslist_list):
         for obj in partslist_list:
-            self.saveItWithLookup(self.PARTSLIST, obj, True)
-        self.Commit()
-
-    def AddDocumentIDandTypeToUncommittedList(self, idtypelist):
-        for docid, doctype in idtypelist:
-            self.dbroot[self.UNCOMMITTEDDOCUMENTIDS][docid] = doctype
+            self.saveItWithLookup('PartsList', obj, True)
         self.Commit()
 
-    def GetACUDict(self):
-        return self.dbroot[self.ACU]
-
     def GetLocalAcus(self, project=None):
         #print "getlocalacus", project
-        acu_dict = self.GetACUDict()
-        uncommitted_dict = self.GetUncommittedDict()
+        acu_dict = self.dbroot['Acu']
+        uncommitted_dict = self.dbroot["Uncommitted"]
 
         objdict = {}
         for nid, nobj in acu_dict.items():
-            if nobj.state: # <> 'DELETE':
+            if nobj.state: # != 'DELETE':
                 pass
             else:
                 childobj = self.getLookupObject(nobj.component)
@@ -247,15 +214,15 @@
                     if project and getattr(childobj, 'project', None) == project:
                         objdict[nid] = nobj
         for nid, nobj in uncommitted_dict.items():
-            if nobj.__class__.__name__ == "Acu":
+            if nobj._schema.id == "Acu":
                 if objdict.has_key(nid):
-                    if nobj.state <> 'DELETE':
+                    if nobj.state != 'DELETE':
                         childobj = self.getLookupObject(nobj.component)
                         objdict[nid] = nobj
                     else:
                         del objdict[nid]
                 else:
-                    if nobj.state <> 'DELETE':
+                    if nobj.state != 'DELETE':
                         childobj = self.getLookupObject(nobj.component)
                         objdict[nid] = nobj
                     #else:
@@ -264,10 +231,6 @@
             #    print "skipping nonacu", nobj.name
         return objdict
 
-    def GetNauoByComponentID(self, component, project = None):
-        #print "localdb.getnauobycomponentid"
-        return self.GetAcuByComponent(component, project)
-
     def GetAcuByComponent(self, component, project = None):
         #print "localdb.getacubycomponentid"
         acudict = self.GetLocalAcus(project)
@@ -279,12 +242,12 @@
 
     def GetLocalPartDocLinks(self, project = None):
         #print "getlocalpartdoclinks"
-        pdr_dict = self.dbroot[self.DCU]
-        uncommitted_dict = self.GetUncommittedDict()
+        pdr_dict = self.dbroot['Dcu']
+        uncommitted_dict = self.dbroot["Uncommitted"]
 
         objdict = {}
         for pdrid, pdrobj in pdr_dict.items():
-            if pdrobj.state: # <> 'DELETE':
+            if pdrobj.state: # != 'DELETE':
                 pass
                 #print "skipping deleted pdr", pdrid
             else:
@@ -293,9 +256,9 @@
                     objdict[pdrid] = pdrobj
 
         for pdrid, pdrobj in uncommitted_dict.items():
-            if pdrobj.__class__.__name__ == "ProductDocumentRelationship":
+            if pdrobj._schema.id == "ProductDocumentRelationship":
                 if objdict.has_key(pdrid):
-                    if pdrobj.state <> 'DELETE':
+                    if pdrobj.state != 'DELETE':
                         parentobj = self.getLookupObject(pdrobj.product)
                         if project and parentobj.project == project:
                             objdict[pdrid] = pdrobj
@@ -306,7 +269,7 @@
                         #print "removing deleted pdr", pdrid
                         del objdict[pdrid]
                 else:
-                    if pdrobj.state <> 'DELETE':
+                    if pdrobj.state != 'DELETE':
                         parentobj = self.getLookupObject(pdrobj.product)
                         if project and parentobj.project == project:
                             objdict[pdrid] = pdrobj
@@ -317,71 +280,53 @@
         return objdict
 
     def getLocalObjectsOfTypes(self, dictnamelist, project):
-        #print "localdb.getlocalobjectsoftype"
+        print "localdb.getlocalobjectsoftype"
         dict_list = []
         for dictname in dictnamelist:
-            #print "dictname", dictname
+            print "dictname", dictname
             dict_list.append((self.getDict(dictname), dictname))
-
-        uncommitted_dict = self.GetUncommittedDict()
-
+        uncommitted_dict = self.dbroot["Uncommitted"]
         objdict = {}
         for localdict, objclass in dict_list:
-            product_dict = localdict
-            for nid, nobj in product_dict.items():
-                tmpobj = None
-                if nobj.state <> 'DELETE':
-                    tmpobj = self.getLookupObject(nobj.pgef_oid)
-                elif tmpobj.state == None:
-                    tmpobj = self.getLookupObject(nobj.pgef_oid)
-
-                if tmpobj:
-                    if hasattr(tmpobj, "project"):
-                        if project and tmpobj.project == project:
-#                            tmpobj.project = tmpobj.project
-                            objdict[nid] = tmpobj
-                    elif hasattr(tmpobj, "_project"):
-                        if project and tmpobj._project.id == project:
-                            tmpobj.project = tmpobj._project.id
+            if localdict:
+                for nid, nobj in localdict.items():
+                    tmpobj = None
+                    if nobj.state != 'DELETE':
+                        tmpobj = self.getLookupObject(nobj.pgef_oid)
+                    elif tmpobj.state == None:
+                        tmpobj = self.getLookupObject(nobj.pgef_oid)
+                    if tmpobj:
+                        if hasattr(tmpobj, "project"):
+                            if project and tmpobj.project == project:
+    #                            tmpobj.project = tmpobj.project
+                                objdict[nid] = tmpobj
+                        else:
                             objdict[nid] = tmpobj
-                    else:
-                        objdict[nid] = tmpobj
-
         for nid, nobj in uncommitted_dict.items():
-            classname = nobj.__class__.__name__
+            classname = nobj._schema.id
             #print nid, nobj.id, classname
             for localdict, objclass in dict_list:
                 if classname == objclass:
                     if objdict.has_key(nid):
                         #print classname, "exists"
-                        if nobj.state <> 'DELETE':
+                        if nobj.state != 'DELETE':
                             #tmpobj = self.getLookupObject(nobj.pgef_oid)
                             if hasattr(nobj, "project"):
                                 if project and nobj.project == project:
 #                                    nobj.project = nobj.project
                                     objdict[nid] = nobj
-                            elif hasattr(nobj, "_project"):
-                                if project and nobj._project.id == project:
-                                    nobj.project = nobj._project.id
-                                    objdict[nid] = nobj
                             else:
                                 objdict[nid] = nobj
                         else:
                             del objdict[nid]
                     else:
                         #print classname, "new", nobj.id
-                        if nobj.state <> 'DELETE':
+                        if nobj.state != 'DELETE':
                             #tmpobj = self.getLookupObject(nobj.pgef_oid)
                             if hasattr(nobj, "project"):
                                 if project and nobj.project == project:
 #                                    nobj.project = nobj.project
                                     objdict[nid] = nobj
-
-                            elif hasattr(nobj, "_project"):
-                                if project and nobj._project.id == project:
-                                    nobj.project = nobj._project.id
-                                    objdict[nid] = nobj
-
                             else:
                                 objdict[nid] = nobj
 
@@ -406,61 +351,59 @@
             pass
         return dictname
 
-    def GetGeneralDocuments(self):
+    def getDocuments(self):
         # so far, the only documents with specialized editors are Alerts and Parts Lists.
         # Thus we only ignore these types.
         # isinstance is specifically used here for groups of classes
-
-        #print "localdb.getgeneraldocuments"
+        # print "localdb.getgeneraldocuments"
         tmpdict = {}
-        for docid, doc in self.dbroot[self.DOCUMENT].items():
-            if isinstance(doc, Document) and not \
-               isinstance(doc, PartsList):
-                if doc.state <> None:
-                    tmpdict[docid] = doc
-        for docid, doc in self.dbroot[self.UNCOMMITTEDOBJECTS].items():
+        for docoid, doc in self.dbroot['Document'].items():
+            if doc._schema.id == 'Document':
+                if doc.state is not None:
+                    tmpdict[docoid] = doc
+        for docid, doc in self.dbroot["Uncommitted"].items():
             if isinstance(doc, Document) and not \
                isinstance(doc, PartsList):
-                if doc.state <> 'DELETE':
+                if doc.state != 'DELETE':
                     tmpdict[docid] = doc
         #print "# documents", len(tmpdict)
         return tmpdict
 
     def GetPartsLists(self):
         tmpdict = {}
-        for docid, doc in self.dbroot[self.DOCUMENT].items():
-            if doc.__class__.__name__ == "PartsList":
-                if doc.state <> None:
+        for docid, doc in self.dbroot['Document'].items():
+            if doc._schema.id == "PartsList":
+                if doc.state is not None:
                     tmpdict[docid] = doc
-        for docid, doc in self.dbroot[self.UNCOMMITTEDOBJECTS].items():
-            if doc.__class__.__name__ == "PartsList":
-                if doc.state <> 'DELETE':
+        for docid, doc in self.dbroot["Uncommitted"].items():
+            if doc._schema.id == "PartsList":
+                if doc.state != 'DELETE':
                     tmpdict[docid] = doc
         return tmpdict
 
     def ClearUncommittedObjects(self, committedobjs):
         #print "localdb.clearuncommittedobjects", committedobjs
         try:
-            uncommittedobjs = self.dbroot[self.UNCOMMITTEDOBJECTS]
+            uncommittedobjs = self.dbroot["Uncommitted"]
             for obj in committedobjs:
                 #print "checking", obj.id
                 if uncommittedobjs.has_key(obj.pgef_oid):
                     del uncommittedobjs[obj.pgef_oid]
                     #print "deleting", obj.id
-            self.dbroot[self.UNCOMMITTEDOBJECTS] = uncommittedobjs
+            self.dbroot["Uncommitted"] = uncommittedobjs
 
         except Exception, e:
             print "exception: unable to clear uncommitted objects"
         self.Commit()
 
     def GetUncommittedDict(self):
-        uncommittedobjs = self.dbroot[self.UNCOMMITTEDOBJECTS]
+        uncommittedobjs = self.dbroot["Uncommitted"]
         return uncommittedobjs
 
     def GetUncommittedObjects(self, projectobjs):
         #print "localdb.getuncommittedobjects"
         try:
-            uncommittedobjs = self.dbroot[self.UNCOMMITTEDOBJECTS] 
+            uncommittedobjs = self.dbroot["Uncommitted"] 
             objlist = []
             objkeys = projectobjs.keys()
             for objid, obj in uncommittedobjs.items():
@@ -475,7 +418,7 @@
     def getLocalObject(self, searchdict, pgef_oid):
         #print "localdb.getlocalobject", searchdict, pgef_oid
         try:
-            retobj = self.dbroot[self.UNCOMMITTEDOBJECTS][pgef_oid]
+            retobj = self.dbroot["Uncommitted"][pgef_oid]
         except:
             try:
                 retobj = self.dbroot[searchdict][pgef_oid]
@@ -483,12 +426,6 @@
                 retobj = None
         return retobj
 
-    def GetUncommittedItemIDs(self):
-        return self.dbroot[self.UNCOMMITTEDITEMIDS]
-
-    def GetUncommittedDocumentIDs(self):
-        return self.dbroot[self.UNCOMMITTEDDOCUMENTIDS]
-
     def GetUncommittedPartsListIDs(self):
         return self.dbroot[self.UNCOMMITTEDPARTSLISTIDS]
 
@@ -496,7 +433,7 @@
         # print "localdb.addprojectobjects", currproject, len(objlist)
         objdict = {}
         for obj in objlist:
-            objdict[obj.pgef_oid] = obj.__class__.__name__
+            objdict[obj.pgef_oid] = obj._schema.id
         allobjects = self.GetProjectObjects()
         if allobjects.has_key(currproject):
             projobjs = allobjects[currproject]
@@ -588,7 +525,7 @@
         retlist = []
         if unsavedlist:
             for obj in unsavedlist:
-                classname = obj.__class__.__name__
+                classname = obj._schema.id
                 if classname == "WfProcessInstance":
                     # saving a wfprocess is not typical, hence the specific save method
                     if self.dbroot[self.WFPROCESSINSTANCE].has_key(obj.pgef_oid):
@@ -601,7 +538,7 @@
                         self.SaveWfProcessInstance([obj])
 
                 elif classname == "Acu":
-                    self.saveItWithLookup(self.ACU, obj, override)
+                    self.saveItWithLookup('Acu', obj, override)
                     retlist.append(obj)
 
                 elif classname == "Person":
@@ -647,28 +584,28 @@
 
     def add(self, unsavedlist):
         #print "localdb.add"
-        self.saveObjectWithLookup(self.UNCOMMITTEDOBJECTS, unsavedlist)
+        self.saveObjectWithLookup("Uncommitted", unsavedlist)
         self.Commit()
 
     def RemoveACU(self, acuobj):
-        if acuobj.__class__.__name__ == "Acu":
-            if self.dbroot[self.ACU].has_key(acuobj.pgef_oid):
-                del self.dbroot[self.ACU][acuobj.pgef_oid]
+        if acuobj._schema.id == "Acu":
+            if self.dbroot['Acu'].has_key(acuobj.pgef_oid):
+                del self.dbroot['Acu'][acuobj.pgef_oid]
         elif type(acuobj) is str:
-            if self.dbroot[self.ACU].has_key(acuobj):
-                del self.dbroot[self.ACU][acuobj]
+            if self.dbroot['Acu'].has_key(acuobj):
+                del self.dbroot['Acu'][acuobj]
         self.Commit()
 
     def getUncommittedWfObjects(self):
         try:
-            uncommittedobjs = self.dbroot[self.UNCOMMITTEDOBJECTS]
+            uncommittedobjs = self.dbroot["Uncommitted"]
             objlist = []
             wfobj_types = ["WfProcessInstance",
                            "WfActivity",
                            "WfEventAudit"]
 
             for objid, obj in uncommittedobjs.items():
-                if obj.__class__.__name__ in wfobj_types:
+                if obj._schema.id in wfobj_types:
                     objlist.append(obj)
             return objlist
         except:
@@ -677,10 +614,10 @@
 
     def getUncommittedWorkflows(self):
         try:
-            uncommittedobjs = self.dbroot[self.UNCOMMITTEDOBJECTS]
+            uncommittedobjs = self.dbroot["Uncommitted"]
             objlist = []
             for objid, obj in uncommittedobjs.items():
-                if obj.__class__.__name__ == "WfProcessInstance":
+                if obj._schema.id == "WfProcessInstance":
 #                    if obj.wfdata == None:
                     objlist.append(obj)
             return objlist
@@ -698,7 +635,7 @@
 
         objdict = {}
         for wfid, wfobj in wf_dict.items():
-            if wfobj.state <> 'DELETE':
+            if wfobj.state != 'DELETE':
                 tmpobj = self.getLocalObject(self.WFPROCESSINSTANCE, wfobj.pgef_oid)
             elif tmpobj.state == None:
                 tmpobj = self.getLocalObject(self.WFPROCESSINSTANCE, wfobj.pgef_oid)
@@ -710,13 +647,13 @@
             if wfobj.__class__.__name__ == "WfProcessInstance":
                 #print "wfobj.name", wfobj.name
                 if objdict.has_key(wfid):
-                    if wfobj.state <> 'DELETE':
+                    if wfobj.state != 'DELETE':
                         tmpobj = self.getLocalObject(self.WFPROCESSINSTANCE, wfobj.pgef_oid)
                         objdict[wfid] = tmpobj
                     else:
                         del objdict[wfid]
                 else:
-                    if wfobj.state <> 'DELETE':
+                    if wfobj.state != 'DELETE':
                         tmpobj = self.getLocalObject(self.WFPROCESSINSTANCE, wfobj.pgef_oid)
                         objdict[wfid] = tmpobj
 
@@ -747,16 +684,16 @@
     def addWfProcessInstance(self, wflist, recurse = False):
         #print "localdb.addWfProcessInstance"
         for wfobj in wflist:
-            self.saveItWithLookup(self.UNCOMMITTEDOBJECTS, wfobj, True)
+            self.saveItWithLookup("Uncommitted", wfobj, True)
             for entry in wfobj.history:
-                self.saveItWithLookup(self.UNCOMMITTEDOBJECTS, entry, True)
+                self.saveItWithLookup("Uncommitted", entry, True)
 
             if recurse:
                 for akey, avalue in wfobj.activities.items():
                     #print "activity", akey, avalue.id, avalue.name, avalue.fields
-                    self.saveItWithLookup(self.UNCOMMITTEDOBJECTS, avalue, True)
+                    self.saveItWithLookup("Uncommitted", avalue, True)
                 for tkey, tvalue in wfobj.transitions_dict.items():
-                    self.saveItWithLookup(self.UNCOMMITTEDOBJECTS, tvalue, True)
+                    self.saveItWithLookup("Uncommitted", tvalue, True)
         self.Commit()
 
 
@@ -773,7 +710,7 @@
     def getCategories(self, context):
         #print "localdb.getcategories", context
         cats = {}
-        catdict = self.getDict(self.CATEGORY)
+        catdict = self.getDict('ObjectSchema')
         if catdict.has_key(context):
             cats = catdict[context]
         return cats
@@ -781,32 +718,29 @@
 
     def saveCategories(self, context, values, override = False):
         #print "localdb.savecategories.values", context
-        if self.dbroot[self.CATEGORY].has_key(context):
+        if self.dbroot['ObjectSchema'].has_key(context):
             #print "have dict", context
             if override:
-                for entry in self.dbroot[self.CATEGORY][context].keys():
-                    del self.dbroot[self.CATEGORY][context][entry]
+                for entry in self.dbroot['ObjectSchema'][context].keys():
+                    del self.dbroot['ObjectSchema'][context][entry]
                 return
         else:
             #print "make dict", context
-            self.dbroot[self.CATEGORY][context] = PersistentMapping()  
-
-        #print "dict", self.CATEGORY, context, len(values)
+            self.dbroot['ObjectSchema'][context] = PersistentMapping()  
+        #print "dict", 'ObjectSchema', context, len(values)
         tmpdict = PersistentMapping()  
         for obj in values:
             #print obj.id, obj.name
             tmpdict[obj.id] = obj
-        self.dbroot[self.CATEGORY][context] = tmpdict
+        self.dbroot['ObjectSchema'][context] = tmpdict
         self.Commit()
 
-
     def getFiles(self, attrlist = None):
         #print "localdb.getfiles", attrlist
-
         if attrlist:
             tmpdict = {}
-            for docid, doc in self.dbroot[self.FILELINK].items():
-                #print "checking", doc.__class__.__name__, doc.id
+            for docid, doc in self.dbroot['FileLink'].items():
+                #print "checking", doc._schema.id, doc.id
                 retval_list = []
                 for attrname, op, attrvalue in attrlist:
                     left = getattr(doc, attrname)
@@ -816,7 +750,6 @@
                         retval_list.append(tmpval)
                     #else:
                     #    print "  missing attribute", attrname
-
                 tmpdict[docid] = doc
                 for retval in retval_list:
                     if not retval:
@@ -824,8 +757,7 @@
                         break
             return tmpdict
         else:
-            return self.dbroot[self.FILELINK]
-
+            return self.dbroot['FileLink']
 
     def evalAttrExp(self, left, op, right):
         #print "  eval", left, op, right
@@ -834,7 +766,7 @@
                 left = left.date
 
             qleft = '"' + str(left) + '"'
-            if op <> "in":
+            if op != "in":
                 qright = '"' + str(right) + '"'
             else:
                 qright = str(right)

Index: PanGalactic/pangalactic/utils/datamanager.py
diff -u PanGalactic/pangalactic/utils/datamanager.py:1.172 PanGalactic/pangalactic/utils/datamanager.py:1.173
--- PanGalactic/pangalactic/utils/datamanager.py:1.172	Wed Apr 27 15:05:15 2005
+++ PanGalactic/pangalactic/utils/datamanager.py	Sun May  1 02:22:36 2005
@@ -1,10 +1,10 @@
-# $Id: datamanager.py,v 1.172 2005/04/27 19:05:15 waterbug Exp $
+# $Id: datamanager.py,v 1.173 2005/05/01 06:22:36 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_datamanager -*-
 
 """
 PanGalaxian's local workspace manager.
 
-@version: $Revision: 1.172 $
+@version: $Revision: 1.173 $
 """
 # TODO:  move the transaction/interface stuff, like XmlrpcInterface, into a
 # separate module -- InterfaceManager, which will handle all client
@@ -15,7 +15,7 @@
 # came from (repository, file import, etc.) and what their state is
 # (committed/uncommitted, etc.)
 
-__version__ = "$Revision: 1.172 $"[11:-2]
+__version__ = "$Revision: 1.173 $"[11:-2]
 
 import time
 import mx.DateTime
@@ -493,9 +493,6 @@
     def getLocalObjectsOfTypes(self, classnamelist, project=None):
         return self.localdb.getLocalObjectsOfTypes(classnamelist, project)
 
-    def getGeneralDocuments(self):
-        return self.localdb.GetGeneralDocuments()
-
     def getDocPartLinks(self):
         return self.localdb.getDict(self.localdb.DOCPTREL)
 

From waterbug at step.nasa.gov  Tue May  3 03:09:04 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May  3 03:09:08 2005
Subject: [pangalactic-commits] Extensive rewrites to DM and LocalStore ...
	more needed.
Message-ID: <200505030709.j43794el030437@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/core/workflow/wfactivity_implementation.py 1.4 1.5
PanGalactic/pangalactic/core/workflow/wfprocessoverview.py 1.4 1.5
PanGalactic/pangalactic/core/workflow/workflow_wizard.py 1.4 1.5
PanGalactic/pangalactic/node/pangalaxian.py 1.53 1.54
PanGalactic/pangalactic/node/gui/dialogs/searchframe.py 1.3 1.4
PanGalactic/pangalactic/node/gui/psm/docdroptarget.py 1.1 1.2
PanGalactic/pangalactic/node/gui/psm/docform.py 1.3 1.4
PanGalactic/pangalactic/node/gui/psm/doctreeframe.py 1.8 1.9
PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py 1.7 1.8
PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py 1.5 1.6
PanGalactic/pangalactic/node/gui/psm/itemeditframe.py 1.11 1.12
PanGalactic/pangalactic/node/gui/psm/modelform.py 1.2 1.3
PanGalactic/pangalactic/node/gui/psm/otherdocform.py 1.2 1.3
PanGalactic/pangalactic/node/gui/psm/partslistform.py 1.1 1.2
PanGalactic/pangalactic/node/gui/psm/partslisttreeframe.py 1.5 1.6
PanGalactic/pangalactic/node/gui/psm/partslistview.py 1.5 1.6
PanGalactic/pangalactic/node/gui/psm/pgefdoctree.py 1.3 1.4
PanGalactic/pangalactic/node/gui/psm/pgefedittree.py 1.3 1.4
PanGalactic/pangalactic/node/gui/psm/pgeftree.py 1.7 1.8
PanGalactic/pangalactic/node/gui/psm/pgefversiontree.py 1.4 1.5
PanGalactic/pangalactic/node/gui/psm/psmtool.py 1.29 1.30
PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py 1.1 1.2
PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py 1.1 1.2
PanGalactic/pangalactic/node/gui/widgets/pgeftree.py 1.4 1.5
PanGalactic/pangalactic/node/tests/test_login.py None 1.1
PanGalactic/pangalactic/node/tests/runall.py 1.11 1.12
PanGalactic/pangalactic/node/tests/test_itemeditframe.py 1.29 1.30
PanGalactic/pangalactic/node/tests/test_localdb.py 1.4 1.5
PanGalactic/pangalactic/node/tests/test_partslist.py 1.15 1.16
PanGalactic/pangalactic/node/tests/test_searchframe.py 1.4 1.5
PanGalactic/pangalactic/node/tests/test_loginform.py 1.4 None
PanGalactic/pangalactic/test/IDTEST 1.110 1.111
PanGalactic/pangalactic/test/test_datamanager.py 1.3 1.4
PanGalactic/pangalactic/utils/basegrid.py 1.43 1.44
PanGalactic/pangalactic/utils/cagesearchframe.py 1.7 1.8
PanGalactic/pangalactic/utils/datamanager.py 1.173 1.174
PanGalactic/pangalactic/utils/httpupload.py 1.11 1.12
PanGalactic/pangalactic/utils/localdb.py 1.128 1.129
PanGalactic/pangalactic/utils/usersearchframe.py 1.11 1.12
PanGalactic/pangalactic/utils/xmlrpcinterface.py 1.78 1.79

Log message:
Extensive rewrites to DM and LocalStore ... more needed.
Touched *many* files, excised much horrible stuff;
lots of simplifications; more passes are needed.

Index: PanGalactic/pangalactic/node/tests/test_searchframe.py
diff -u PanGalactic/pangalactic/node/tests/test_searchframe.py:1.4 PanGalactic/pangalactic/node/tests/test_searchframe.py:1.5
--- PanGalactic/pangalactic/node/tests/test_searchframe.py:1.4	Fri Mar  5 16:18:12 2004
+++ PanGalactic/pangalactic/node/tests/test_searchframe.py	Tue May  3 03:08:30 2005
@@ -1,20 +1,19 @@
 import unittest
-import modules.psm.searchframe
+from pangalactic.node.gui.dialogs.searchframe import SearchFrame
 from pangalactic.utils import datamanager
-#import support.psmstate
-import pgefstate
-from wxPython.wx import *
+import wx
 
 class TestSearchFrame(unittest.TestCase):
+
     def Title(self):
         print '\nSearchFrame suite'
+
     def testCreateSearchFrame(self):
-        state = pgefstate.PgefState()
-        testframe = wxFrame(None, -1, 'Test Frame')
+        testframe = wx.Frame(None, -1, 'Test Frame')
         dm = datamanager.DataManager(testframe, true)
-        searchframe = None
-        searchframe = modules.psm.searchframe.SearchFrame(testframe, -1, 'Search', dm)
-        assert searchframe != None, 'Couldnt create AboutBox'
+        sf = None
+        sf = SearchFrame(testframe, -1, 'Search', dm)
+        assert sf != None, 'Couldnt create AboutBox'
 
 def suite():
     searchframe_suite = unittest.TestSuite()
@@ -22,11 +21,9 @@
     searchframe_suite.addTest(TestSearchFrame("testCreateSearchFrame"))
     return searchframe_suite
 
-
 def main():
     runner = unittest.TextTestRunner()
     runner.run(suite())
 
-
 if __name__ == '__main__':
     main()        

Index: PanGalactic/pangalactic/utils/cagesearchframe.py
diff -u PanGalactic/pangalactic/utils/cagesearchframe.py:1.7 PanGalactic/pangalactic/utils/cagesearchframe.py:1.8
--- PanGalactic/pangalactic/utils/cagesearchframe.py:1.7	Mon Feb 14 11:46:43 2005
+++ PanGalactic/pangalactic/utils/cagesearchframe.py	Tue May  3 03:08:31 2005
@@ -91,7 +91,7 @@
         #print "cagesearchframe.oncloseuserframe"
         self.org_frame.Show(False)
         self.org_frame = None
-#        self.dm.saveUser(self.curr_user)
+#        self.dm.save(self.curr_user)
 
         
     def onClose(self, event):

Index: PanGalactic/pangalactic/utils/usersearchframe.py
diff -u PanGalactic/pangalactic/utils/usersearchframe.py:1.11 PanGalactic/pangalactic/utils/usersearchframe.py:1.12
--- PanGalactic/pangalactic/utils/usersearchframe.py:1.11	Mon Feb 14 11:46:44 2005
+++ PanGalactic/pangalactic/utils/usersearchframe.py	Tue May  3 03:08:31 2005
@@ -1,10 +1,10 @@
-# $Id: usersearchframe.py,v 1.11 2005/02/14 16:46:44 waterbug Exp $
+# $Id: usersearchframe.py,v 1.12 2005/05/03 07:08:31 waterbug Exp $
 """
 wx frame for doing searches for users.
 
-@version: $Revision: 1.11 $
+@version: $Revision: 1.12 $
 """
-__version__ = "$Revision: 1.11 $"[11:-2]
+__version__ = "$Revision: 1.12 $"[11:-2]
 
 from wxPython.wx import *
 
@@ -68,7 +68,6 @@
         EVT_MENU(self.resultsgrid, usergrid.USER_ENABLE, self.onEnableUser)
         EVT_MENU(self.resultsgrid, usergrid.USER_APPROVE, self.onApproveUser)
 
-
     def onEditUser(self, event):
         print "usersearchframe.edituser"
         curr_user = self.resultsgrid.getObject(self.resultsgrid.SelectedRow)
@@ -76,7 +75,6 @@
         self.showUser(mode = userinfo.EDIT_MODE, user_info = curr_user)
         self.dm.add([curr_user])
 
-
     def onEnableUser(self, event):
         print "usersearchframe.enableuser"
         curr_user = self.resultsgrid.getObject(self.resultsgrid.SelectedRow)
@@ -85,7 +83,6 @@
         self.resultsgrid.Refresh(True)
         self.dm.add([curr_user])
 
-
     def onApproveUser(self, event):
         print "usersearchframe.approveuser"
         curr_user = self.resultsgrid.getObject(self.resultsgrid.SelectedRow)
@@ -95,7 +92,6 @@
         self.dm.add([curr_user])
         self.dm.approveUser(curr_user)
 
-
     def onDisableUser(self, event):
         print "usersearchframe.disableuser"
         curr_user = self.resultsgrid.getObject(self.resultsgrid.SelectedRow)
@@ -104,7 +100,6 @@
         self.resultsgrid.Refresh(True)
         self.dm.add([curr_user])
 
-
     def showUser(self, mode, user_info):
         self.curr_user = user_info
         if self.user_frame:
@@ -132,13 +127,11 @@
                    self.user_info.getCloseWgt().GetId(),
                    self.onCloseUserFrame)
 
-
     def onCloseUserFrame(self, event):
         #print "usersearchframe.oncloseuserframe"
         self.user_frame.Show(False)
         self.user_frame = None
-        self.dm.saveUser(self.curr_user)
-
+        self.dm.save(self.curr_user)
 
     def onClose(self, event):
         self.Show(False)
@@ -184,7 +177,6 @@
                 noresultsdlg.ShowModal() 
                 noresultsdlg.Destroy()
 
-
     def onClear(self, event):
         self.searchgui.clearForm()
         self.resultsgrid.ClearGrid()

Index: PanGalactic/pangalactic/node/gui/psm/modelform.py
diff -u PanGalactic/pangalactic/node/gui/psm/modelform.py:1.2 PanGalactic/pangalactic/node/gui/psm/modelform.py:1.3
--- PanGalactic/pangalactic/node/gui/psm/modelform.py:1.2	Wed Oct 20 02:32:18 2004
+++ PanGalactic/pangalactic/node/gui/psm/modelform.py	Tue May  3 03:08:29 2005
@@ -176,7 +176,7 @@
         modelobj.creator = self.GetPoc().GetValue()
         modelobj.description = self.GetNomenclature().GetValue()
         modelobj.comment = self.GetDesc().GetValue()
-        modelobj._upload_file_name = self.getFilename()
+        modelobj.local_file_path = self.getFilename()
         return modelobj
 
 

Index: PanGalactic/pangalactic/node/tests/test_partslist.py
diff -u PanGalactic/pangalactic/node/tests/test_partslist.py:1.15 PanGalactic/pangalactic/node/tests/test_partslist.py:1.16
--- PanGalactic/pangalactic/node/tests/test_partslist.py:1.15	Sat Jan 29 16:52:47 2005
+++ PanGalactic/pangalactic/node/tests/test_partslist.py	Tue May  3 03:08:30 2005
@@ -26,7 +26,7 @@
         #assert len(self.obj1.PartsListFilenames) == 0, 'Bad initial value for PartsListFilenames'
 ##==> (postgres) removed from schema        assert self.obj1.Modified == false, 'Bad initial value for Modified'
         #assert self.obj1.Delete == false, 'Bad initial value for Delete'
-        assert self.obj1._upload_file_name == '', 'Bad initial value for ServerFileName '
+        assert self.obj1.local_file_path == '', 'Bad initial value for ServerFileName '
         #assert self.obj1.CommitToServerDate == '', 'Bad initial value for CommitToServerDate'
         assert len(self.obj1._ColumnMapping.keys()) == 0, 'Bad initial value for ColumnMapping'
         assert self.obj1._ColumnMappingID == -1, 'Bad initial value for ColumnMappingID'

Index: PanGalactic/pangalactic/node/tests/test_localdb.py
diff -u PanGalactic/pangalactic/node/tests/test_localdb.py:1.4 PanGalactic/pangalactic/node/tests/test_localdb.py:1.5
--- PanGalactic/pangalactic/node/tests/test_localdb.py:1.4	Fri Mar  5 16:18:12 2004
+++ PanGalactic/pangalactic/node/tests/test_localdb.py	Tue May  3 03:08:30 2005
@@ -1,36 +1,28 @@
 import unittest
 import pangalactic.utils.localdb
 
-false = None
-true = not None
-
 class ZODBImportTest(unittest.TestCase):
     def testImport(self):
         try:
             import ZODB
             from ZODB import FileStorage, DB
-            #following line commented out as it causes a warning from python 2.2
-            #from ZODB import *
         except ImportError:
             self.fail('ZODB could not be imported')
-            
+
 class ZODBTestCase(unittest.TestCase):
     def Title(self):
         print '\nLocalDB suite'
         
     def testCreateLocalStorage(self):
         self.ldb = None
-        self.ldb = pangalactic.utils.localdb.LocalStorage(true)
+        self.ldb = pangalactic.utils.localdb.LocalStorage(True)
         assert self.ldb != None , "Couldnt create localstorage"
-        #self.ldb.db.close()
-        
+
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(ZODBTestCase("Title"))
     suite.addTest(ZODBImportTest("testImport"))
     suite.addTest(ZODBTestCase("testCreateLocalStorage"))
-    
-    
     return suite
 
 def main():

Index: PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py:1.7 PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py:1.8
--- PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py:1.7	Thu Mar 24 02:18:26 2005
+++ PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py	Tue May  3 03:08:29 2005
@@ -9,7 +9,7 @@
 from pangalactic.utils.pgefstate import state
 from pangalactic.utils.preferences import prefs, writePrefs
 
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 
 class DocumentTreeFrame(doctreeframe.DocTreeFrame):
@@ -41,11 +41,11 @@
 
     def Setup(self):
         self.currentdocument = self.dm.newObject("Document")
-        self.currentdocument._upload_file_name = ""
+        self.currentdocument.local_file_path = ""
 
         rootobj = self.tree.GetPyData(self.tree.GetRootItem())
         nodeid = rootobj[1]
-        nodeobj = self.dm.getLookupObject(nodeid)
+        nodeobj = self.dm.getLocalObject(nodeid)
         if nodeobj:
             self.currentdocument(**nodeobj.__dict__)
             self.docform.FillForm(self.currentdocument)
@@ -93,12 +93,9 @@
             except:
                 self.docform.EditingMode()
                 return
-            dfile = self.dm.newFileLink(newdoc)
+            dfile = self.dm.newFileLink()
             dfile.state = 'ADD'
             self.dm.save([newdoc, dfile])
-
-            self.dm.addProjectObjects(state['project'],
-                                      [newdoc, dfile])
             if self.EditMode:
                 self.EditMode = False
                 self.currentdocument(**newdoc.__dict__)
@@ -186,7 +183,7 @@
 
         self.tree.LoadGeneralDocuments(self.dm, "Documents")
         treeitemdata = self.tree.GetPyData(self.tree.GetRootItem())
-        self.rootobject = self.dm.getLookupObject(treeitemdata[1])
+        self.rootobject = self.dm.getLocalObject(treeitemdata[1])
         treedlg.Destroy()
         print "end buildtree"
 
@@ -222,9 +219,9 @@
             self.docform.Save(doc)
             doc.state = 'ADD'
 
-            dfile = self.dm.newFileLink(doc)#, doc._upload_file_name)
+            dfile = self.dm.newFileLink()
 #            dfile.parent = doc.pgef_oid
-#            dfile.setLocalFilename(doc._upload_file_name)
+#            dfile.setLocalFilename(doc.local_file_path)
 #            dfile.mime_type_oid = "text/plain"
             dfile.state = 'ADD'
             self.dm.add([dfile])

Index: PanGalactic/pangalactic/node/gui/psm/pgefdoctree.py
diff -u PanGalactic/pangalactic/node/gui/psm/pgefdoctree.py:1.3 PanGalactic/pangalactic/node/gui/psm/pgefdoctree.py:1.4
--- PanGalactic/pangalactic/node/gui/psm/pgefdoctree.py:1.3	Thu Mar 24 02:18:26 2005
+++ PanGalactic/pangalactic/node/gui/psm/pgefdoctree.py	Tue May  3 03:08:29 2005
@@ -20,11 +20,11 @@
         docid = self.GetPyData(selectednode)
 
         if docid:
-            doc = self.dm.getLookupObject(docid[1])
+            doc = self.dm.getLocalObject(docid[1])
             if doc:
                 print "Document:", doc.id, doc.version, "(" + doc.pgef_oid + ")"
             else:
-                pl = self.dm.getLookupObject(docid[1])
+                pl = self.dm.getLocalObject(docid[1])
                 if pl:
                     print "Parts List:", pl.id, "(" + pl.pgef_oid + ")"
 
@@ -56,7 +56,7 @@
         """Loads the tree from the dicts in the DataManager"""
         #print "pgefdoctree: loadtreefrompls"
         self.DeleteAllItems()
-        rootitem = datamanager.getLookupObject(rootitemid)
+        rootitem = datamanager.getLocalObject(rootitemid)
 
         foo = self.getTreeLabelForProduct(rootitem)
         self.nodeStack.append(self.AddRoot(foo))
@@ -94,7 +94,7 @@
 
         childcount = 0
         for id in PdrNodes:
-            pdrobj = datamanager.getLookupObject(id)
+            pdrobj = datamanager.getLocalObject(id)
             if pdrobj.name == "parts_list":
                 if pdrobj.state:
                     if pdrobj.state == 'DELETE':
@@ -105,7 +105,7 @@
                 continue
 
             #print "pdrobj", pdrobj
-            plobj = datamanager.getLookupObject(pdrobj.document)
+            plobj = datamanager.getLocalObject(pdrobj.document)
 
             if plobj:
                 treeid = self.AppendItem(rootnode, plobj.id)
@@ -137,7 +137,7 @@
         #print "pgefdoctree: loadtreefromotherdocs"
 
         self.DeleteAllItems()
-        rootitem = datamanager.getLookupObject(rootitemid)
+        rootitem = datamanager.getLocalObject(rootitemid)
         foo = self.getTreeLabelForProduct(rootitem)
         #foo = rootitem.of_pm_id + "." + rootitem.of_pv_id
         self.nodeStack.append(self.AddRoot(foo))
@@ -184,7 +184,7 @@
         childcount = 0
         #print "numnodes: " + str(len(PdrNodes))
         for id in PdrNodes:
-            pdrobj = datamanager.getLookupObject(id)
+            pdrobj = datamanager.getLocalObject(id)
             #print "id", id, "pdrobj", pdrobj
             if pdrobj.name == "document":
                 if pdrobj.state:
@@ -198,7 +198,7 @@
                 continue
 
             #print "call getdocument"
-            docobj = datamanager.getLookupObject(pdrobj.document)
+            docobj = datamanager.getLocalObject(pdrobj.document)
             #print "back from getdocument"
 
             if docobj:
@@ -246,7 +246,7 @@
         self.SelectItem(rootnode)
 
         for docid, doc in docdict.items():
-            docobj = datamanager.getLookupObject(docid)
+            docobj = datamanager.getLocalObject(docid)
             if docobj:
                treeid = self.AppendItem(rootnode, docobj.id + " " + docobj.version)
                #print "doc id", docobj.id
@@ -289,7 +289,7 @@
         self.SelectItem(rootnode)
 
         for docid, doc in docdict.items():
-            docobj = datamanager.getLookupObject(docid)
+            docobj = datamanager.getLocalObject(docid)
             if docobj:
                treeid = self.AppendItem(rootnode, docobj.id)
                self.SetPyData(treeid, ["None", docobj.pgef_oid])

Index: PanGalactic/pangalactic/node/gui/psm/doctreeframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/doctreeframe.py:1.8 PanGalactic/pangalactic/node/gui/psm/doctreeframe.py:1.9
--- PanGalactic/pangalactic/node/gui/psm/doctreeframe.py:1.8	Thu Mar 24 01:51:39 2005
+++ PanGalactic/pangalactic/node/gui/psm/doctreeframe.py	Tue May  3 03:08:29 2005
@@ -1,4 +1,4 @@
-# $Id: doctreeframe.py,v 1.8 2005/03/24 06:51:39 waterbug Exp $
+# $Id: doctreeframe.py,v 1.9 2005/05/03 07:08:29 waterbug Exp $
 
 import wx
 from wx import grid
@@ -10,7 +10,7 @@
 from pangalactic.utils.pgefstate import state
 from pangalactic.utils import basegrid
 
-__version__ = "$Revision: 1.8 $"[11:-2]
+__version__ = "$Revision: 1.9 $"[11:-2]
 
 
 NEW_MODE = 1
@@ -115,7 +115,7 @@
                 else:
                     obj = self.tree.GetPyData(node)
                     if obj:
-                        doc = self.dm.getLookupObject(obj[2])
+                        doc = self.dm.getLocalObject(obj[2])
                         self.docform.ResetForm(doc)
                     else:
                         self.docform.ClearForm()
@@ -206,7 +206,7 @@
 
                 self.docform.ClearForm()
                 if nodeid:
-                    docobj = self.dm.getLookupObject(nodeid)
+                    docobj = self.dm.getLocalObject(nodeid)
                     if docobj:
                         if docobj.__class__.__name__ in ["PartsList", "Document"]:
                             self.docform.fillForm(docobj, versionobj)
@@ -214,7 +214,7 @@
 # old way                    
 #                if nodetype == "Document" or nodetype == "PartsList":
 #                    print "look for a", nodetype
-#                    docobj = self.dm.getLookupObject(nodeid)
+#                    docobj = self.dm.getLocalObject(nodeid)
 #
 #                elif nodetype == "FileLink":
 #                    print "look for a FileLink"

Index: PanGalactic/pangalactic/node/gui/psm/partslistform.py
diff -u PanGalactic/pangalactic/node/gui/psm/partslistform.py:1.1 PanGalactic/pangalactic/node/gui/psm/partslistform.py:1.2
--- PanGalactic/pangalactic/node/gui/psm/partslistform.py:1.1	Wed Oct 20 02:20:37 2004
+++ PanGalactic/pangalactic/node/gui/psm/partslistform.py	Tue May  3 03:08:29 2005
@@ -1,6 +1,6 @@
-# $Id: partslistform.py,v 1.1 2004/10/20 06:20:37 waterbug Exp $
+# $Id: partslistform.py,v 1.2 2005/05/03 07:08:29 waterbug Exp $
 
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.2 $"[11:-2]
 
 from wxPython.wx import wxPanel, wxTAB_TRAVERSAL, wxPyTypeCast, wxPyDefaultPosition, wxPyDefaultSize
 from wxPython.wx import wxFileDialog
@@ -102,7 +102,7 @@
         PartsListObject.Type = self.GetChoiceType().GetStringSelection()
         PartsListObject.id = self.GetTextctrlPartslistid().GetValue()
         PartsListObject.base_id = PartsListObject.id
-        PartsListObject._upload_file_name = PartsListObject.pgef_oid + ".tsv"
+        PartsListObject.local_file_path = PartsListObject.pgef_oid + ".tsv"
 
 
     def ClearForm(self):

Index: PanGalactic/pangalactic/utils/httpupload.py
diff -u PanGalactic/pangalactic/utils/httpupload.py:1.11 PanGalactic/pangalactic/utils/httpupload.py:1.12
--- PanGalactic/pangalactic/utils/httpupload.py:1.11	Thu Mar 24 02:18:28 2005
+++ PanGalactic/pangalactic/utils/httpupload.py	Tue May  3 03:08:31 2005
@@ -1,5 +1,5 @@
 #!/usr/bin/env python
-# $Id: httpupload.py,v 1.11 2005/03/24 07:18:28 waterbug Exp $
+# $Id: httpupload.py,v 1.12 2005/05/03 07:08:31 waterbug Exp $
 """
 Upload from the local path either the specified file, or all
 files in the specified directory, as MIME multipart/form-data
@@ -14,9 +14,9 @@
     -h / --help
         Print this message and exit.
 
-@version: $Revision: 1.11 $
+@version: $Revision: 1.12 $
 """
-__version__ = "$Revision: 1.11 $"[11:-2]
+__version__ = "$Revision: 1.12 $"[11:-2]
 
 import base64
 import getopt
@@ -44,7 +44,6 @@
         print >> sys.stderr, msg
     sys.exit(code)
 
-
 def enclose(lpath):
     """
     Create a part for a MIME multipart message
@@ -91,7 +90,6 @@
                    name='file', filename=filename)
     return msg, filename, ctype
 
-
 def upload(localpath='', host='', port='', srvpath='/', userid='',
            passwd='', secure=0, useragent='PanGalaxian [en]',
            oid='', mimetype=''):
@@ -200,7 +198,6 @@
         raise HTTPException, msg
     return response.read()
 
-
 if __name__ == '__main__':
     try:
         opts, args = getopt.getopt(sys.argv[1:], 'h:', ['help'])

Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.53 PanGalactic/pangalactic/node/pangalaxian.py:1.54
--- PanGalactic/pangalactic/node/pangalaxian.py:1.53	Tue Mar 22 11:11:00 2005
+++ PanGalactic/pangalactic/node/pangalaxian.py	Tue May  3 03:08:28 2005
@@ -1,13 +1,13 @@
 #!/usr/bin/env python 
 
-# $Id: pangalaxian.py,v 1.53 2005/03/22 16:11:00 waterbug Exp $
+# $Id: pangalaxian.py,v 1.54 2005/05/03 07:08:28 waterbug Exp $
 
 """
 Main application module for the PGEF desktop client.
 
-@version: $Revision: 1.53 $
+@version: $Revision: 1.54 $
 """
-__version__ = "$Revision: 1.53 $"[11:-2]
+__version__ = "$Revision: 1.54 $"[11:-2]
 
 import sys
 import os
@@ -255,11 +255,11 @@
                 if srv not in serverlist:
                     serverlist.append(srv)
         state['serverlist'] = serverlist
-        state['project'] = state.get('lastproject',
+        state['project'] = state.get('project',
                                      None) or prefs.get(
                                      'defaultproject',
                                      'NoProject')
-        state['id_ns'] = state.get('lastproject',
+        state['id_ns'] = state.get('project',
                                    None) or prefs.get(
                                    'defaultproject',
                                    'NoProject')
@@ -563,8 +563,7 @@
                               wx.YES_NO | wx.YES_DEFAULT | wx.ICON_EXCLAMATION)
         dlg.CentreOnParent()
         if dlg.ShowModal() == wx.ID_YES:
-            self.dm.clearLocalDB()
-            self.dm.packLocalDB()
+            self.dm.clearCache()
             self.psmgui.ClearTreeAndGrid()
 
 
@@ -783,8 +782,8 @@
 
     def commit(self, event):
         print "PanGalaxian.commit()"
-        objlist = self.dm.getUncommittedObjs()
-        self.psmgui.commit(closing=False, objectlist=objlist, dont_ask=False)
+        objs = self.dm.getUncommittedObjs()
+        self.psmgui.commit(closing=False, objectlist=objs, dont_ask=False)
 
 
     def CloseActiveTool(self, event):

Index: PanGalactic/pangalactic/node/tests/test_itemeditframe.py
diff -u PanGalactic/pangalactic/node/tests/test_itemeditframe.py:1.29 PanGalactic/pangalactic/node/tests/test_itemeditframe.py:1.30
--- PanGalactic/pangalactic/node/tests/test_itemeditframe.py:1.29	Tue Apr 26 00:53:51 2005
+++ PanGalactic/pangalactic/node/tests/test_itemeditframe.py	Tue May  3 03:08:30 2005
@@ -156,7 +156,7 @@
         partslist.FillSamplePartsList(temppl)
         temppl.owner = 'me'
         temppl.id = '1111'
-        temppl._upload_file_name = 'sample.xls'
+        temppl.local_file_path = 'sample.xls'
         temppl.PLM_Converted = 1
         self.DisplayWgts = wxFrame(None, -1, 'Display Widget')
         testframe = wxFrame(None, -1, 'Test Frame')

Index: PanGalactic/pangalactic/test/test_datamanager.py
diff -u PanGalactic/pangalactic/test/test_datamanager.py:1.3 PanGalactic/pangalactic/test/test_datamanager.py:1.4
--- PanGalactic/pangalactic/test/test_datamanager.py:1.3	Thu Mar 24 02:18:27 2005
+++ PanGalactic/pangalactic/test/test_datamanager.py	Tue May  3 03:08:31 2005
@@ -1,4 +1,4 @@
-# $Id: test_datamanager.py,v 1.3 2005/03/24 07:18:27 waterbug Exp $
+# $Id: test_datamanager.py,v 1.4 2005/05/03 07:08:31 waterbug Exp $
 
 """
 Unit tests for pangalactic.utils.datamanager
@@ -69,9 +69,9 @@
         pass
     test_packLocalDB.todo = 'not done.'
 
-    def test_getLookupObject(self, pgef_oid):
+    def test_getLocalObject(self, pgef_oid):
         pass
-    test_getLookupObject.todo = 'not done.'
+    test_getLocalObject.todo = 'not done.'
 
     def test_getObject(self, dict, oid):
         pass

Index: PanGalactic/pangalactic/utils/basegrid.py
diff -u PanGalactic/pangalactic/utils/basegrid.py:1.43 PanGalactic/pangalactic/utils/basegrid.py:1.44
--- PanGalactic/pangalactic/utils/basegrid.py:1.43	Sat Apr 30 14:45:25 2005
+++ PanGalactic/pangalactic/utils/basegrid.py	Tue May  3 03:08:31 2005
@@ -1,13 +1,13 @@
-# $Id: basegrid.py,v 1.43 2005/04/30 18:45:25 waterbug Exp $
+# $Id: basegrid.py,v 1.44 2005/05/03 07:08:31 waterbug Exp $
 
 """
 Wrapper for the grid that adds the drag and drop functionality to the base
 grid class.  Also adds the ability to set the labels for the grid columns
 and to fill a row of data given the data in a list format
 
-@version: $Revision: 1.43 $
+@version: $Revision: 1.44 $
 """
-__version__ = "$Revision: 1.43 $"[11:-2]
+__version__ = "$Revision: 1.44 $"[11:-2]
 
 import cPickle
 import os
@@ -183,7 +183,7 @@
         itemoid = self.GetObjectOid(selectedrow) 
         if itemoid == "":
             return False
-        data = [None, itemid, "GRID", self.GetId()]
+        data = [None, itemoid, "GRID", self.GetId()]
         datapickle = cPickle.dumps(data, 1)
         dragitem = wx.CustomDataObject(wx.CustomDataFormat("PGEF_Item"))
         dragitem.SetData(datapickle)

Index: PanGalactic/pangalactic/node/gui/widgets/pgeftree.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgeftree.py:1.4 PanGalactic/pangalactic/node/gui/widgets/pgeftree.py:1.5
--- PanGalactic/pangalactic/node/gui/widgets/pgeftree.py:1.4	Thu Feb 17 16:19:57 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgeftree.py	Tue May  3 03:08:30 2005
@@ -1,10 +1,10 @@
-# $Id: pgeftree.py,v 1.4 2005/02/17 21:19:57 waterbug Exp $
+# $Id: pgeftree.py,v 1.5 2005/05/03 07:08:30 waterbug Exp $
 """
 Base class for PanGalaxian's trees
 
-@version: $Revision: 1.4 $
+@version: $Revision: 1.5 $
 """
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 import wx
 import cPickle, types
@@ -16,7 +16,7 @@
 from pangalactic.node.gui.psm     import itemdroptarget
 from pangalactic.node.io          import treereport
 
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 
 class PgefTree(wx.TreeCtrl):
@@ -98,7 +98,7 @@
         # being dragged.  quite useful, on occasion
         selectednode = self.GetSelection()
         nauo_item = self.GetPyData(selectednode)
-        item = self.dm.getLookupObject(nauo_item[1])
+        item = self.dm.getLocalObject(nauo_item[1])
         if item:
             print "item: " + item.name # + "; parts: " + str(item.has_parts_flag) + \
                   #"; plflag: " + str(item.has_parts_lists_flag) + \
@@ -135,16 +135,15 @@
         self.SetPyData(rootnode,[acu_id, rootobj.pgef_oid])
         if state['loggedin']:
             print "  - getting more acus from server ..."
-            dm.getNAUOByAssemblyID([rootobj.pgef_oid])
-                
-        localacus = dm.getLocalAcus(state['project'])
+            dm.getAcusByAssemblyOid(rootobj.pgef_oid)
+        localacus = dm.getLocalObjects('Acu', state['project'])
         for acuid, acuobj in localacus.items():
             if acuobj.assembly == rootobj.pgef_oid and acuobj.state <> 'DELETE':
                 AcuIds.append(acuid)
         print '  - AcuIds: ', AcuIds
         for acuid in AcuIds:
-            acuobj = dm.getLookupObject(acuid)
-            itemobj = dm.getLookupObject(acuobj.component)
+            acuobj = dm.getLocalObject(acuid)
+            itemobj = dm.getLocalObject(acuobj.component)
             if itemobj and acuobj.state <> 'DELETE':
                 treeid = self.AppendItem(rootnode, itemobj.id)
                 self.SetPyData(treeid, [acuobj.pgef_oid, itemobj.pgef_oid])
@@ -209,7 +208,7 @@
         #print objlist
         returnlist = []
         for entry in objlist:
-            obj = self.dm.getLookupObject(entry[0])
+            obj = self.dm.getLocalObject(entry[0])
             if obj == None:
                 returnlist.append(entry)
                 #print 'no item -  appending <%s>' % entry

Index: PanGalactic/pangalactic/core/workflow/wfactivity_implementation.py
diff -u PanGalactic/pangalactic/core/workflow/wfactivity_implementation.py:1.4 PanGalactic/pangalactic/core/workflow/wfactivity_implementation.py:1.5
--- PanGalactic/pangalactic/core/workflow/wfactivity_implementation.py:1.4	Tue Mar  8 10:18:05 2005
+++ PanGalactic/pangalactic/core/workflow/wfactivity_implementation.py	Tue May  3 03:08:28 2005
@@ -1,10 +1,10 @@
-# $Id: wfactivity_implementation.py,v 1.4 2005/03/08 15:18:05 waterbug Exp $
+# $Id: wfactivity_implementation.py,v 1.5 2005/05/03 07:08:28 waterbug Exp $
 """
 The implementations of each wfactivity object (L{WfActivity <pangalactic.core.workflow.wfactivity>}).
 
-@version: $Revision: 1.4 $
+@version: $Revision: 1.5 $
 """
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 import mx.DateTime
 
@@ -14,7 +14,7 @@
 #    print "wfactivity_impl.startActivity", activity.name
     print "NOTE: wfactivity_impl: extra save, for testing.  Remove RSN"
 
-    wf_obj = dm.localdb.getLookupObject(parent_process_id)
+    wf_obj = dm.cache.getLocalObject(parent_process_id)
 #    print "  notify the ptbs that " + wf_obj.wfdata.id + " is at " + \
 #          activity.name + " state in " + wf_obj.name[0:3]
     

Index: PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py
diff -u PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py:1.5 PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py:1.6
--- PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py:1.5	Sat Apr 30 14:45:24 2005
+++ PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py	Tue May  3 03:08:29 2005
@@ -1,4 +1,4 @@
-# $Id: itemdroptarget.py,v 1.5 2005/04/30 18:45:24 waterbug Exp $
+# $Id: itemdroptarget.py,v 1.6 2005/05/03 07:08:29 waterbug Exp $
 
 import cPickle
 
@@ -10,7 +10,7 @@
 from wxPython.wx import wxPoint, wxTreeItemIcon_Selected
 
 
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 #constants
 
@@ -73,7 +73,7 @@
 
             # If there is no nauoid, set the dropnauoobj to None
             try:
-                dropnauoobj = self.dm.getLookupObject(dropdata[0])
+                dropnauoobj = self.dm.getLocalObject(dropdata[0])
                 #print "have dropnauo", dropnauoobj
             except KeyError:
                 print "keyerror on drop"
@@ -82,7 +82,7 @@
             # get the object for the item being dropped from local storage
             dropitem = None
             try:
-                dropitem = self.dm.getLookupObject(dropdata[1])
+                dropitem = self.dm.getLocalObject(dropdata[1])
                 #print "have dropitem", dropitem.id
             except:
                 return d
@@ -132,22 +132,17 @@
                 # we are dropping a node onto a toplevel node. Are we us?
                 if self.tree.GetPyData(targetnode)[1] == dropitem.pgef_oid:
                     return d
-                targetitem = self.dm.getLookupObject(targetdata[1])
-                targetnauo = self.dm.getAcuByComponent(targetitem)
+                targetitem = self.dm.getLocalObject(targetdata[1])
                 #print 'targetnauo is ', targetnauo
                 if targetnauo == None:
                     targetnauo = "TOPLEVEL"
 
             elif DragFromGrid:
                 #print "drag from grid"
-                targetitem = self.dm.getLookupObject(targetdata[1])
+                targetitem = self.dm.getLocalObject(targetdata[1])
                 #print 'project is: ', state['project']
-                
-                targetnauo = self.dm.getAcuByComponent(targetitem,
-                                                       state['project'])
                 #print '******** targetitem is', targetitem.id
                 #print '******** targetnauo is', targetnauo
-
                 if targetnauo == None:
                     targetnauo = "TOPLEVEL"
 
@@ -155,8 +150,8 @@
                 #print "drop with targetdata[0]"
                 #print "targetdata", targetdata
                 #print 'DragFromGrid is ', DragFromGrid
-                targetitem = self.dm.getLookupObject(targetdata[1])
-                targetnauo = self.dm.getLookupObject(targetdata[0])
+                targetitem = self.dm.getLocalObject(targetdata[1])
+                targetnauo = self.dm.getLocalObject(targetdata[0])
             else:
                 print "wtf"
                 return d

Index: PanGalactic/pangalactic/node/gui/psm/docform.py
diff -u PanGalactic/pangalactic/node/gui/psm/docform.py:1.3 PanGalactic/pangalactic/node/gui/psm/docform.py:1.4
--- PanGalactic/pangalactic/node/gui/psm/docform.py:1.3	Mon Mar 14 14:43:38 2005
+++ PanGalactic/pangalactic/node/gui/psm/docform.py	Tue May  3 03:08:29 2005
@@ -203,7 +203,7 @@
         Doc.base_id = Doc.id
         Doc.name = self.GetTitleWgt().GetValue()
         Doc.doc_type_oid = self.GetTypeWgt().GetValue()
-        Doc._upload_file_name = self.GetFilenameWgt().GetValue()
+        Doc.local_file_path = self.GetFilenameWgt().GetValue()
 
     def ClearForm(self):
         self.GetAuthorWgt().SetValue("")

Index: PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py:1.1 PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py:1.2
--- PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py:1.1	Tue Mar  8 10:35:31 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py	Tue May  3 03:08:30 2005
@@ -1,12 +1,11 @@
-# $Id: pgefgrid.py,v 1.1 2005/03/08 15:35:31 waterbug Exp $
-
+# $Id: pgefgrid.py,v 1.2 2005/05/03 07:08:30 waterbug Exp $
 """
 A grid with settable column labels, import of data in list format, and drag
 and drop.
 
-@version: $Revision: 1.1 $
+@version: $Revision: 1.2 $
 """
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.2 $"[11:-2]
 
 # Python imports
 import cPickle

Index: PanGalactic/pangalactic/node/gui/psm/docdroptarget.py
diff -u PanGalactic/pangalactic/node/gui/psm/docdroptarget.py:1.1 PanGalactic/pangalactic/node/gui/psm/docdroptarget.py:1.2
--- PanGalactic/pangalactic/node/gui/psm/docdroptarget.py:1.1	Wed Oct 20 02:20:37 2004
+++ PanGalactic/pangalactic/node/gui/psm/docdroptarget.py	Tue May  3 03:08:29 2005
@@ -47,7 +47,7 @@
 
             # If there is no nauoid, set the dropnauo to None
             try:
-                droppdr = self.dm.getLookupObject(pdr_doc[0])
+                droppdr = self.dm.getLocalObject(pdr_doc[0])
             except KeyError:
                 print 'droppdr is set to None'
                 droppdr = None

Index: PanGalactic/pangalactic/node/gui/psm/otherdocform.py
diff -u PanGalactic/pangalactic/node/gui/psm/otherdocform.py:1.2 PanGalactic/pangalactic/node/gui/psm/otherdocform.py:1.3
--- PanGalactic/pangalactic/node/gui/psm/otherdocform.py:1.2	Sat Jan 29 16:52:46 2005
+++ PanGalactic/pangalactic/node/gui/psm/otherdocform.py	Tue May  3 03:08:29 2005
@@ -206,7 +206,7 @@
         Doc.id = self.GetIdentifierWgt().GetValue()
         Doc.name = self.GetTitleWgt().GetValue()
         Doc.doc_type_oid = self.GetTypeWgt().GetValue()
-        Doc._upload_file_name = self.GetFilenameWgt().GetValue()
+        Doc.local_file_path = self.GetFilenameWgt().GetValue()
 
     def ClearForm(self):
         self.GetAuthorWgt().SetValue("")

Index: PanGalactic/pangalactic/node/gui/dialogs/searchframe.py
diff -u PanGalactic/pangalactic/node/gui/dialogs/searchframe.py:1.3 PanGalactic/pangalactic/node/gui/dialogs/searchframe.py:1.4
--- PanGalactic/pangalactic/node/gui/dialogs/searchframe.py:1.3	Thu Mar 17 04:01:47 2005
+++ PanGalactic/pangalactic/node/gui/dialogs/searchframe.py	Tue May  3 03:08:29 2005
@@ -183,10 +183,9 @@
         else:
             wx.BeginBusyCursor()
             wx.SafeYield()
-            self.dm.search(searchattrlist)
-            searchresults = self.dm.getSearchResults()
-            if len(searchresults) > 0:
-                self.fillResultGrids(searchresults)
+            results = self.dm.search(searchattrlist)
+            if len(results) > 0:
+                self.fillResultGrids(results)
                 wx.EndBusyCursor()
                 wx.SafeYield()
             else:
@@ -221,10 +220,9 @@
         searchattrdict["Part"] = attrlist
         searchattrdict["Model"] = attrlist
         searchattrdict["Document"] = attrlist
-        self.dm.search(searchattrdict)
-        tempresults = self.dm.getSearchResults()
+        results = self.dm.search(searchattrdict)
 
-        if len(tempresults) == 0:
+        if len(results) == 0:
             wx.EndBusyCursor()
             mdlg.Show(False)
             dlg = wx.MessageDialog(self, "You don't have any Stuff.", "No Stuff",
@@ -233,7 +231,7 @@
             dlg.ShowModal()
             
         else:
-            self.fillResultGrids(tempresults)
+            self.fillResultGrids(results)
             wx.EndBusyCursor()
         mdlg.Destroy()
 

Index: PanGalactic/pangalactic/core/workflow/wfprocessoverview.py
diff -u PanGalactic/pangalactic/core/workflow/wfprocessoverview.py:1.4 PanGalactic/pangalactic/core/workflow/wfprocessoverview.py:1.5
--- PanGalactic/pangalactic/core/workflow/wfprocessoverview.py:1.4	Tue Mar  8 10:18:05 2005
+++ PanGalactic/pangalactic/core/workflow/wfprocessoverview.py	Tue May  3 03:08:28 2005
@@ -1,12 +1,12 @@
-# $Id: wfprocessoverview.py,v 1.4 2005/03/08 15:18:05 waterbug Exp $
+# $Id: wfprocessoverview.py,v 1.5 2005/05/03 07:08:28 waterbug Exp $
 #!/bin/env python
 """
 Here there be classes that produce a tabular display of all locally-stored
 workflows.
 
-@version: $Revision: 1.4 $
+@version: $Revision: 1.5 $
 """
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 # Author:       V. Keech
 # Created:      May 2003
@@ -361,8 +361,8 @@
     def OnView(self, event):
         #print "onview"
         self.getCurrentWorkflow()
-        #print "uploadfilename", self.currentworkflow._upload_file_name
-        if not os.path.exists(self.currentworkflow._upload_file_name + ".pdf"):
+        #print "uploadfilename", self.currentworkflow.local_file_path
+        if not os.path.exists(self.currentworkflow.local_file_path + ".pdf"):
             return 
 
         # readerid is None if we are in MSWindows; we only need to keep

Index: PanGalactic/pangalactic/test/IDTEST
diff -u PanGalactic/pangalactic/test/IDTEST:1.110 PanGalactic/pangalactic/test/IDTEST:1.111
--- PanGalactic/pangalactic/test/IDTEST:1.110	Sat Apr 30 14:45:25 2005
+++ PanGalactic/pangalactic/test/IDTEST	Tue May  3 03:08:31 2005
@@ -1 +1 @@
-1606
\ No newline at end of file
+1614
\ No newline at end of file

Index: PanGalactic/pangalactic/node/tests/runall.py
diff -u PanGalactic/pangalactic/node/tests/runall.py:1.11 PanGalactic/pangalactic/node/tests/runall.py:1.12
--- PanGalactic/pangalactic/node/tests/runall.py:1.11	Tue Mar 23 14:32:20 2004
+++ PanGalactic/pangalactic/node/tests/runall.py	Tue May  3 03:08:30 2005
@@ -2,7 +2,7 @@
 import test_pgefobject
 import test_datamanager
 import test_aboutbox
-import test_loginform
+import test_login
 import test_searchframe
 
 def runTest():
@@ -10,9 +10,8 @@
     all_tests.addTest(test_pgefobject.suite())
     all_tests.addTest(test_datamanager.suite())
     all_tests.addTest(test_aboutbox.suite())
-    all_tests.addTest(test_loginform.suite())
+    all_tests.addTest(test_login.suite())
     all_tests.addTest(test_searchframe.suite())
-    
     return all_tests
 
 def main():

Index: PanGalactic/pangalactic/node/gui/psm/partslistview.py
diff -u PanGalactic/pangalactic/node/gui/psm/partslistview.py:1.5 PanGalactic/pangalactic/node/gui/psm/partslistview.py:1.6
--- PanGalactic/pangalactic/node/gui/psm/partslistview.py:1.5	Thu Mar 10 13:33:18 2005
+++ PanGalactic/pangalactic/node/gui/psm/partslistview.py	Tue May  3 03:08:29 2005
@@ -88,17 +88,17 @@
         self.partslistgrid.DeleteRows(0, self.partslistgrid.GetNumberRows()-1)
         try:
             try:
-                if len(pl._upload_file_name) == 0:
-                    pl._upload_file_name = pl.pgef_oid + ".tsv"
+                if len(pl.local_file_path) == 0:
+                    pl.local_file_path = pl.pgef_oid + ".tsv"
                 tmpdir = os.path.join(workingdir, "tmp")
-                datafilename = os.path.join(tmpdir, pl._upload_file_name)
+                datafilename = os.path.join(tmpdir, pl.local_file_path)
                 if os.path.exists(datafilename):
                     pass
                     #print "download file exists"
                 else:
 #                    print "self.LoggedIn: " + str(self.LoggedIn)
                     if state['loggedin']:
-                        httpGet(tmpdir, pl._upload_file_name,
+                        httpGet(tmpdir, pl.local_file_path,
                                 user, host, port, "parts_list")
                     else:
                         #print "Parts Lists are not available in local mode"

Index: PanGalactic/pangalactic/node/gui/psm/pgefedittree.py
diff -u PanGalactic/pangalactic/node/gui/psm/pgefedittree.py:1.3 PanGalactic/pangalactic/node/gui/psm/pgefedittree.py:1.4
--- PanGalactic/pangalactic/node/gui/psm/pgefedittree.py:1.3	Mon Feb 14 11:47:33 2005
+++ PanGalactic/pangalactic/node/gui/psm/pgefedittree.py	Tue May  3 03:08:29 2005
@@ -9,6 +9,7 @@
         pgeftree.PgefTree.__init__(self, parent, ID, datamanager)
         self.Parent = parent
         self.dropOnNode = False
+        self.dm = datamanager
             
     def StartDragOperation(self):
         # if the following code executes,
@@ -16,7 +17,7 @@
         # being dragged.  quite useful, on occasion
         selectednode = self.GetSelection()
         nodedata = self.GetPyData(selectednode)
-        item = self.dm.getLookupObject(nodedata[1])
+        item = self.dm.getLocalObject(nodedata[1])
         if item:
             print "item: " + item.name
 
@@ -32,7 +33,7 @@
         """Loads the tree from the dicts in the DataManager"""
 
         self.DeleteAllItems()
-        rootitem = datamanager.getLookupObject(rootitemid)
+        rootitem = datamanager.getLocalObject(rootitemid)
         self.nodeStack.append(self.AddRoot(rootitem.id))
         rootnode = self.GetRootItem()
 
@@ -62,8 +63,8 @@
                     PdrNodes.append(pdrid)
 
         for id in PdrNodes:
-            pdrobj = datamanager.getLookupObject(id)
-            plobj = datamanager.getLookupObject(pdrobj.pgef_oid)
+            pdrobj = datamanager.getLocalObject(id)
+            plobj = datamanager.getLocalObject(pdrobj.pgef_oid)
 
             if plobj:
                 treeid = self.AppendItem(rootnode, plobj.id)
@@ -84,46 +85,39 @@
         else:
             self.SelectItem(rootnode)
 
-    def LoadTreefromObjects(self, dm, rootobj, currentdata = None):
+    def LoadTreeFromObject(self, rootobj, currentdata=None):
         """Loads the tree from the data in the local database."""
-        #print "pgefedittree.loadtreefromobjects"
-
+        print "pgefedittree.LoadTreeFromObject"
         if type(rootobj) == str:
-            rootobj = dm.getLookupObject(rootobj)
+            rootobj = self.dm.getLocalObject(rootobj)
         if not rootobj:
             return
-        AcuIds = []
+        acu_oids = []
         highlightednode = None
-
         self.DeleteAllItems()
         self.nodeStack.append(self.AddRoot(rootobj.id))
         rootnode = self.GetRootItem()
-
         self.SetPyData(rootnode, ["ROOT", rootobj.pgef_oid])
         self.SetItemImage(rootnode, self.itemicon)
         self.SetItemImage(rootnode, self.itemicon, wxTreeItemIcon_Selected)
-
         if state['loggedin']:
-            #print "getting more acus"
+            print "checking for more acus"
             if rootobj:
-                dm.getNAUOByAssemblyID([rootobj.pgef_oid])
-                
-        localacus = dm.getLocalAcus(state['project'])
-        for acuid, acuobj in localacus.items():
+                self.dm.getAcusByAssemblyOid(rootobj.pgef_oid)
+        localacus = self.dm.getLocalObjects('Acu')
+        print 'acus found:', localacus
+        for acuobj in localacus:
             if (acuobj.assembly == rootobj.pgef_oid
-                and acuobj.state <> 'DELETE'):
-                AcuIds.append(acuid)
-
-        for acuid in AcuIds:
-            acuobj = dm.getLookupObject(acuid)
-            itemobj = dm.getLookupObject(acuobj.component)
-
-            if itemobj and acuobj.state <> 'DELETE':
+                and acuobj.state != 'DELETE'):
+                acu_oids.append(acuobj.pgef_oid)
+        for acu_oid in acu_oids:
+            acuobj = self.dm.getLocalObject(acu_oid)
+            itemobj = self.dm.getLocalObject(acuobj.component)
+            if itemobj and acuobj.state != 'DELETE':
                 treeid = self.AppendItem(rootnode, itemobj.id)
                 self.SetPyData(treeid, [acuobj.pgef_oid, itemobj.pgef_oid])
                 self.SetItemImage(treeid, self.itemicon)
                 self.SetItemImage(treeid, self.itemicon, wxTreeItemIcon_Selected)
-
         self.SortChildren(rootnode)
         self.Expand(rootnode)
 

Index: PanGalactic/pangalactic/node/gui/psm/psmtool.py
diff -u PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.29 PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.30
--- PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.29	Mon Apr  4 00:13:12 2005
+++ PanGalactic/pangalactic/node/gui/psm/psmtool.py	Tue May  3 03:08:29 2005
@@ -1,10 +1,10 @@
-# $Id: psmtool.py,v 1.29 2005/04/04 04:13:12 waterbug Exp $
+# $Id: psmtool.py,v 1.30 2005/05/03 07:08:29 waterbug Exp $
 # Originally Created 04/05/2001
 """
 PSM Tool is the Product Structure Manager.  It handles visualization,
 navigation, and editing of product structures.
 """
-__version__ = "$Revision: 1.29 $"[11:-2]
+__version__ = "$Revision: 1.30 $"[11:-2]
 
 import os
 import sys
@@ -286,7 +286,7 @@
         bgrid = event.GetEventObject()
         obj = bgrid.getObject(ndx)
         bgrid.SelectRow(ndx)
-        self.version_tree.LoadTreefromObjects(self.dm, obj)
+        self.version_tree.LoadTreeFromObject(obj)
         self.synchGridSelections(obj)
 
     def SelectView(self, event):
@@ -301,7 +301,7 @@
             ndxs = bgrid.GetSelectedRows()
             if len(ndxs) > 0:
                 obj = bgrid.getObject(ndxs[0])
-                self.version_tree.LoadTreefromObjects(self.dm, obj)
+                self.version_tree.LoadTreeFromObject(obj)
 
             # show the treepage that corresponds to the gridpage
             self.tree_notebook.SetSelection(gridpage)
@@ -534,7 +534,7 @@
             self.searchwindow.Show(False)
             self.searchwindow = None
 
-    def commit(self, closing=False, objectlist=None, dont_ask=False):
+    def commit(self, closing=False, objectlist=None, dont_ask=True):
         """
         Save any changes made; retrieve the data from the local storage
         device and send it to the server.
@@ -543,7 +543,7 @@
         print "  -> objectlist: ", objectlist
         retval = []
         if self.dm.uncommittedData():
-            if dont_ask:
+            if not dont_ask:
                 dtext = "Commit ALL uncommitted work?"
                 dlg = pgdialogs.OKCancelDialog(self, -1,
                                                "Commit Data to Server",
@@ -632,24 +632,22 @@
             print "psmtool.PSMTool:  looking for children"
             treetuple = self.tree.GetPyData(node)
             print ' - treetuple:', treetuple
-            obj = self.dm.getLookupObject(treetuple[1])
+            obj = self.dm.getLocalObject(treetuple[1])
             # print ' - obj:', obj
             linkedobjs = []
             if state['loggedin']:
                 print ' - state:  loggedin'
-                linkedobjs = self.dm.getNAUOByAssemblyID([obj.pgef_oid])
+                linkedobjs = self.dm.getAcusByAssemblyOid(obj.pgef_oid)
                 print ' - linkedobjs:', linkedobjs
 
             else:
                 print ' - state:  not loggedin'
-                linkedobjs = self.dm.getLocalAcusByAssemblyID(
-                                                obj.pgef_oid,
-                                                state['project'])
+                linkedobjs = self.dm.getLocalAcusByAssemblyOid(obj.pgef_oid)
                 print ' - linkedobjs:', linkedobjs
             if len(linkedobjs) == 0:
                 self.tree.SetItemHasChildren(node, False)
                 return
-            self.tree.LoadTreefromObjects(self.dm, obj, node)
+            self.tree.LoadTreeFromObject(obj, node)
 
     def GetNickName (self):
         return "PSM"
@@ -746,11 +744,11 @@
         self.version_tree.DeleteAllItems() 
 
         if state['loggedin']:
-            self.dm.getNAUOByAssemblyID([itemid])
+            self.dm.getAcusByAssemblyOid(itemid)
 
-        self.tree.LoadTreefromObjects(self.dm, itemobj)
+        self.tree.LoadTreeFromObject(itemobj)
         self.tree.expandRoot()
-        self.version_tree.LoadTreefromObjects(self.dm, itemobj)
+        self.version_tree.LoadTreeFromObject(itemobj)
 
 
 
@@ -824,7 +822,7 @@
                       wx.ALIGN_CENTRE)
                 dlg.CentreOnParent()
                 dlg.Show(True)
-                self.dm.getItemsByProject([projectid])
+                self.dm.getItemsByProject(projectid)
                 if dlg:
                     dlg.Destroy()
             except:
@@ -871,40 +869,34 @@
                     self.SelectGridRowByItemId(newitem.pgef_oid)
                     wgt.AutoSizeColumns(True)
 
-
     def FillGridFromProject(self, projectid):
         print "PSMTool.FillGridFromProject", projectid
-        localproducts = self.dm.getLocalObjectsOfTypes(["Part", "Model"],
-                                                       projectid)
-        products = localproducts.values()
+        objs = self.dm.getLocalObjects(["Part", "Model"], projectid)
         uncommitted_oids = self.dm.getUncommittedOids()
         plist = []
         mlist = []
-        if len(products) > 0:
-            for item in products:
-                classname = item.__class__.__name__
+        if len(objs) > 0:
+            for obj in objs:
+                classname = obj.__class__.__name__
                 if classname == "Part":
-                    plist.append([item.id, item])
+                    plist.append([obj.id, obj])
                 elif classname == "Model":
-                    mlist.append([item.id, item])
+                    mlist.append([obj.id, obj])
             plist.sort()
             mlist.sort()
         self.FillGridWithParts(self.partgrid, plist, uncommitted_oids)
         self.FillGridWithModels(self.modelgrid, mlist, uncommitted_oids)
-        return len(products)
-
+        return len(objs)
 
     def FillSystemWidgetFromProject(self, projectid):
         print "PSMTool.FillSystemWidgetFromProject"
-        localitems = self.dm.getLocalObjectsOfTypes(["Model"], projectid)
-        localparts = localitems.values()
-        itemlist = []
-        for item in localparts:
-            foo = item.id
-            itemlist.append([foo, item])
-        itemlist.sort()
-        self.topWindow.toppanel.FillSystemWidget(itemlist, "Select a Model")
-
+        objs = self.dm.getLocalObjects(["Model"], projectid)
+        items = []
+        for obj in objs:
+            foo = obj.id
+            items.append([foo, obj])
+        items.sort()
+        self.topWindow.toppanel.FillSystemWidget(items, "Select a Model")
 
     def FillGridWithModels(self, bgrid, productlist, uncommitted_oids=None):
         print "PSMTool.FillGridWithModels"
@@ -996,9 +988,9 @@
         try:
             self.tree.DeleteAllItems() 
             self.dm.clearNauoIDs() 
-            self.dm.getNAUOByAssemblyID([itemid])
-            obj = self.dm.getLookupObject(itemid)
-            self.tree.LoadTreefromObjects(self.dm, obj)
+            self.dm.getAcusByAssemblyOid(itemid)
+            obj = self.dm.getLocalObject(itemid)
+            self.tree.LoadTreeFromObject(obj)
         except:
             print "PSMTool.BuildTree.error"
 
@@ -1017,7 +1009,7 @@
             nodedata = self.tree.GetPyData(node)
             wx.BeginBusyCursor()
             product_id = nodedata[1]
-            temp_obj = self.dm.getLookupObject(product_id)
+            temp_obj = self.dm.getLocalObject(product_id)
             classname = temp_obj.__class__.__name__
             if classname == "Part":
                 pane = 0
@@ -1046,7 +1038,6 @@
             obj = currentgrid.getObject(currentgrid.SelectedRow)
             self.editGridObject(obj)
 
-
     def onGridDClick (self, event):
         print "PSMTool.onGridDClick"
         row = event.GetRow()
@@ -1055,7 +1046,6 @@
         obj = bgrid.getObject(row)
         self.editGridObject(obj)
 
-
     def editGridObject(self, obj):
         print "PSMTool.editGridObject", obj.id, obj.__class__.__name__
         classname = obj.__class__.__name__

Index: PanGalactic/pangalactic/node/gui/psm/pgeftree.py
diff -u PanGalactic/pangalactic/node/gui/psm/pgeftree.py:1.7 PanGalactic/pangalactic/node/gui/psm/pgeftree.py:1.8
--- PanGalactic/pangalactic/node/gui/psm/pgeftree.py:1.7	Mon Feb 14 15:19:19 2005
+++ PanGalactic/pangalactic/node/gui/psm/pgeftree.py	Tue May  3 03:08:29 2005
@@ -1,10 +1,10 @@
-# $Id: pgeftree.py,v 1.7 2005/02/14 20:19:19 waterbug Exp $
+# $Id: pgeftree.py,v 1.8 2005/05/03 07:08:29 waterbug Exp $
 """
 Base class for PanGalaxian's trees
 
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 import wx
 import cPickle, types
@@ -21,7 +21,7 @@
 from pangalactic.node.gui.psm     import itemdroptarget
 from pangalactic.node.io          import treereport
 
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 
 class PgefTree(wx.TreeCtrl):
@@ -109,7 +109,7 @@
         # being dragged.  quite useful, on occasion
         selectednode = self.GetSelection()
         nauo_item = self.GetPyData(selectednode)
-        item = self.dm.getLookupObject(nauo_item[1])
+        item = self.dm.getLocalObject(nauo_item[1])
         if item:
             print "item: " + item.name # + "; parts: " + str(item.has_parts_flag) + \
                   #"; plflag: " + str(item.has_parts_lists_flag) + \
@@ -127,15 +127,13 @@
         #result = dropSource.DoDragDrop(True)    
         dropSource.DoDragDrop(True)    
 
-    
-    def LoadTreefromObjects(self, dm, rootobj, parentnode=None):
+    def LoadTreeFromObject(self, rootobj, parentnode=None):
         """
         Load the tree from the dicts in the DataManager
         """
-        print "PgefTree.LoadTreefromObjects"
+        print "- PgefTree.LoadTreeFromObject"
         print "  - rootobj.pgef_oid =", rootobj.pgef_oid
-        AcuIds = []
-                        
+        acu_oids = []
         if parentnode:
             rootnode = parentnode
             acu_id = self.GetPyData(parentnode)[0]
@@ -143,36 +141,35 @@
             self.nodeStack.append(self.AddRoot(rootobj.id))
             rootnode = self.GetRootItem()
             acu_id = None
-
         self.SetItemImage(rootnode, self.itemicon)
         self.SetItemImage(rootnode, self.itemicon, wx.TreeItemIcon_Selected)
         self.SetPyData(rootnode,[acu_id, rootobj.pgef_oid])
-
         if state['loggedin']:
-            print "  - getting more acus from server ..."
-            dm.getNAUOByAssemblyID([rootobj.pgef_oid])
-                
-        localacus = dm.getLocalAcus(state['project'])
-        for acuid, acuobj in localacus.items():
-            if acuobj.assembly == rootobj.pgef_oid and acuobj.state <> 'DELETE':
-                AcuIds.append(acuid)
-
-        print '  - AcuIds: ', AcuIds
-        for acuid in AcuIds:
-            acuobj = dm.getLookupObject(acuid)
-            itemobj = dm.getLookupObject(acuobj.component)
-
-            if itemobj and acuobj.state <> 'DELETE':
+            print "  - getting acus from server ..."
+            acus = self.dm.getAcusByAssemblyOid(rootobj.pgef_oid)
+            print "    got %s" % str([o.pgef_oid for o in acus])
+        else:
+            print "  - getting acus from cache ..."
+            acus = self.dm.getLocalAcusByAssemblyOid(rootobj.pgef_oid)
+            print "    got %s" % str([o.pgef_oid for o in acus])
+        for acuobj in acus:
+            if (((acuobj.assembly == rootobj.pgef_oid)
+                  or (getattr(acuobj.assembly,
+                              'pgef_oid', '') == rootobj.pgef_oid))
+                and acuobj.state != 'DELETE'):
+                acu_oids.append(acuobj.pgef_oid)
+        print '  - acu_oids: ', acu_oids
+        for oid in acu_oids:
+            acuobj = self.dm.getLocalObject(oid)
+            itemobj = self.dm.getLocalObject(acuobj.component)
+            if itemobj and acuobj.state != 'DELETE':
                 treeid = self.AppendItem(rootnode, itemobj.id)
                 self.SetPyData(treeid, [acuobj.pgef_oid, itemobj.pgef_oid])
                 self.SetItemImage(treeid, self.itemicon)
                 self.SetItemImage(treeid, self.itemicon, wx.TreeItemIcon_Selected)
                 self.SetItemHasChildren(treeid, True)            
-
         self.SortChildren(rootnode)
 
-
-        
     def DumpToPdf(self, event = None):
         dlg = pdfoptions.PDFOptions(self)
         dlg.showall.Show(1)
@@ -233,7 +230,7 @@
         #print objlist
         returnlist = []
         for entry in objlist:
-            obj = self.dm.getLookupObject(entry[0])
+            obj = self.dm.getLocalObject(entry[0])
             if obj == None:
                 returnlist.append(entry)
                 #print 'no item -  appending <%s>' % entry

Index: PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py
diff -u PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.1 PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.2
--- PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.1	Mon Mar 21 17:06:07 2005
+++ PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py	Tue May  3 03:08:30 2005
@@ -1,5 +1,5 @@
 #!/bin/env python
-# $Id: cachebrowser.py,v 1.1 2005/03/21 22:06:07 waterbug Exp $
+# $Id: cachebrowser.py,v 1.2 2005/05/03 07:08:30 waterbug Exp $
 #----------------------------------------------------------------------------
 # Authors:      Ginny, Steve
 #----------------------------------------------------------------------------
@@ -7,9 +7,9 @@
 PanGalaxian cache browser and display customizer
 (Works with PgefObjects in a local ZODB)
 
-@version: $Revision: 1.1 $
+@version: $Revision: 1.2 $
 """
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.2 $"[11:-2]
 
 import wx
 from wx import grid
@@ -51,7 +51,8 @@
         wx.Panel.__init__(self, parent, id, pos, size, style=wx.THICK_FRAME)
         self.Parent = parent
         self.dm = dm
-        self.localdb = dm.localdb
+        self._registry = dm._registry
+        self.cache = dm.cache
         self.dbfile = None
         self.current_config = {}
         # the following section replaces:  ZODBBrowserFunc(self, True)
@@ -129,7 +130,7 @@
         choice.Clear()
         items = []
         if config:
-            for dictname, clearflag, config_access in self.localdb.dictlist:
+            for dictname, clearflag, config_access in self.cache.dictlist:
                 if config_access <= config:
                    items.append(dictname)
         items.sort()
@@ -156,11 +157,11 @@
 
     def GetDisplayConfig(self):
         # print "cachebrowser.getdisplayconfig"
-        self.current_config = self.localdb.getDisplayConfig()
+        self.current_config = self.cache.getDisplayConfig()
         if len(self.current_config) == 0:
-            for dictname, keepflag, access_level in self.localdb.dictlist:
+            for dictname, keepflag, access_level in self.cache.dictlist:
                 self.current_config[dictname] = []
-            self.localdb.setDisplayConfig(self.current_config)
+            self.cache.setDisplayConfig(self.current_config)
         # pprint(self.current_config)
 
     def FileConfig(self, event = None):
@@ -244,7 +245,7 @@
                         dnames = obj.getDisplayOrder()
                         # move any attributes in the class default
                         # to the front/beginning/left/whatever.
-                        # if selection in localdb.NARS_CLASSES:
+                        # if selection in cache.NARS_CLASSES:
                         #     #print "have NARS type"
                         #     pass
                         # else:
@@ -279,7 +280,7 @@
 
     def FillGrid(self, event = None):
         # print "dbbbrowser.fillgrid"
-        if self.localdb:
+        if self.cache:
             self.ClearGrid()
             if self.objectgrid.GetNumberCols() > 0:
                 self.objectgrid.DeleteCols(0, self.objectgrid.GetNumberCols())
@@ -292,15 +293,15 @@
             else:
                 self.customize_button.Enable(True)
             # how many rows should there be?
-            objs = self.localdb.getDict(selection)
+            objs = self.cache.getDict(selection)
             self.objs = []
             numrows = len(objs)
             if numrows > 0:
                 self.objectgrid.AppendRows(numrows)
             # look for a configuration entry, and append the columns
-            self.current_config = self.localdb.getDisplayConfig()
+            self.current_config = self.cache.getDisplayConfig()
             # pprint(self.current_config)
-            if selection == self.localdb.UNCOMMITTEDOBJECTS:
+            if selection == self.cache.uncommittedobjs:
                 # print "have pgefobject mapping"
                 mapping = list(self.current_config["PgefObject"])
                 mapping.append(['pgef_oid', 'OID', 'str'])
@@ -323,7 +324,7 @@
                 if len(mapping) > 0:
                     print "new entry"
                     self.current_config[selection] = mapping
-                    self.localdb.setDisplayConfig(self.current_config)
+                    self.cache.setDisplayConfig(self.current_config)
                     pprint(self.current_config)
             # fill in the grid cells
             curr_row = 0
@@ -338,20 +339,20 @@
                     for col in range(len(mapping)):
                         attr = mapping[col][0]
                         attrvalue = getattr(obj, attr)
-                        # print "attr", attr, attrvalue
-                        if 1: #try:
+                        attr_property = obj._schema.get(attr, None)
+                        if attr_property:
+                            attr_range = attr_property.range
+                            # print "attr", attr, attrvalue
                             val = str(attrvalue)
-                            classname = attrvalue.__class__.__name__
-                            if classname in self.dm._registry.classes:
-                                val = attrvalue.id + " (" + classname + ")"
-                            elif type(attrvalue) in [dict, list]:
-                                if len(attrvalue) > 0:
-                                    if type(attrvalue) is list:
-                                        attrclass = attrvalue[0].__class__.__name__
-                                    else:
-                                        attrclass = attrvalue[attrvalue.keys()[0]].__class__.__name__
-                                    if attrclass in self.dm._registry.classes:
-                                         val = str(len(attrvalue)) + " elements"
+                            if attr_range in self._registry.object_schemas:
+                                if hasattr(attrvalue, 'pgef_oid'):
+                                    val = attr_range + " (oid=" + attrvalue.pgef_oid + ")"
+                                elif type(attrvalue) is str:
+                                    val = attr_range + " (oid=" + attrvalue + ")"
+                                elif type(attrvalue) in [dict, list]:
+                                    if len(attrvalue) > 0:
+                                        val = ' '.join([str(len(attrvalue)),
+                                                        attr_range, "instances"])
                         self.objectgrid.SetCellValue(curr_row, col, val)
                         col += 1
                 else:

Index: PanGalactic/pangalactic/node/gui/psm/partslisttreeframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/partslisttreeframe.py:1.5 PanGalactic/pangalactic/node/gui/psm/partslisttreeframe.py:1.6
--- PanGalactic/pangalactic/node/gui/psm/partslisttreeframe.py:1.5	Wed Mar 23 12:12:32 2005
+++ PanGalactic/pangalactic/node/gui/psm/partslisttreeframe.py	Tue May  3 03:08:29 2005
@@ -1,4 +1,4 @@
-# $Id: partslisttreeframe.py,v 1.5 2005/03/23 17:12:32 waterbug Exp $
+# $Id: partslisttreeframe.py,v 1.6 2005/05/03 07:08:29 waterbug Exp $
 
 import copy
 from wxPython.wx import *
@@ -20,7 +20,7 @@
 except:
     print "partslisttreeframe.plmimport.failed"
 
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 
 class PartsListTreeFrame(doctreeframe.DocTreeFrame):
@@ -54,12 +54,12 @@
     def Setup(self):
         print "partslisttreeframe.setup"
         self.currentdocument = self.dm.newObject("PartsList")
-        self.currentdocument._upload_file_name = ""
+        self.currentdocument.local_file_path = ""
         self.docform.BrowseMode(True)
         
         rootobj = self.tree.GetPyData(self.tree.GetRootItem())
         nodeid = rootobj[1]
-        nodeobj = self.dm.getLookupObject(nodeid)
+        nodeobj = self.dm.getLocalObject(nodeid)
         if nodeobj:
             self.currentdocument(**nodeobj.__dict__)
             self.docform.fillForm(self.currentdocument)
@@ -86,29 +86,29 @@
             partslist = self.dm.newObject("PartsList")
             self.docform.Save(partslist)
             partslist.state = 'ADD'
-            partslist._upload_file_name = partslist.pgef_oid + ".tsv"
+            partslist.local_file_path = partslist.pgef_oid + ".tsv"
 
             if self.PLMtool:
                 partslist._ColumnInfo = self.PLMtool.GetColumnInfo()
                 partslist._ColumnMapping = self.PLMtool.GetColumnMapping()
 
                 partslist._ColumnMappingID = 0 # eventually change to database id
-                partslist._upload_file_name = self.PLMtool.GetPartsListFilename()
+                partslist.local_file_path = self.PLMtool.GetPartsListFilename()
             else:
                 if self.currentdocument:
                     partslist._ColumnInfo = self.currentdocument._ColumnInfo
                     partslist._ColumnMapping = self.currentdocument._ColumnMapping
                     partslist._ColumnMappingID = 0
-                    partslist._upload_file_name = self.currentdocument._upload_file_name
+                    partslist.local_file_path = self.currentdocument.local_file_path
                 else:
-                    partslist._upload_file_name = None
+                    partslist.local_file_path = None
                 
             try:
                 partslist.validate()
                 print "validated partslist"
                 #print partslist
 
-                if not partslist._upload_file_name:
+                if not partslist.local_file_path:
                     if wxPlatform == '__WXMSW__':
                         if not self.PLM_Converted:
                             raise RequiredDataError, "You have not provided a spreadsheet"
@@ -117,16 +117,13 @@
                         self.PLM_Converted = True #vwk for linux testing
 
                 self.dm.add([partslist])
-
-                self.dm.addProjectObjects(state['project'], [partslist])
-
                 if self.EditMode:
                     # print "editpl"
                     self.EditMode = False
                     partslist.updateObject(self.dm.user.id)
                     node = self.tree.GetSelection()
                     data = self.tree.GetPyData(node)
-                    oldpl = self.dm.getLookupObject(data[1])
+                    oldpl = self.dm.getLocalObject(data[1])
                     oldpl.state = 'DELETE' #MODIFY
                     self.dm.add([oldpl])
 
@@ -243,7 +240,7 @@
                 self.currentdocument._ColumnInfo = self.PLMtool.GetColumnInfo()
                 self.currentdocument._ColumnMapping = self.PLMtool.GetColumnMapping()
                 self.currentdocument._ColumnMappingID = 0
-                self.currentdocument._upload_file_name = self.PLMtool.GetPartsListFilename()
+                self.currentdocument.local_file_path = self.PLMtool.GetPartsListFilename()
 
                 self.PLM_Converted = self.PLMtool.Converted
                 self.PLMtool.CloseDown()
@@ -301,7 +298,7 @@
 
         self.tree.LoadPartsLists(self.dm, "Parts Lists")
         treeitemdata = self.tree.GetPyData(self.tree.GetRootItem())
-        self.rootobject = self.dm.getLookupObject(treeitemdata[1])
+        self.rootobject = self.dm.getLocalObject(treeitemdata[1])
         treedlg.Destroy()
 
 
@@ -333,18 +330,18 @@
             partslist = self.dm.newObject("PartsList")
             self.docform.Save(partslist)
             partslist.state = 'ADD'
-            partslist._upload_file_name = partslist.pgef_oid + ".tsv"
+            partslist.local_file_path = partslist.pgef_oid + ".tsv"
 
             if self.PLMtool:
                 partslist._ColumnInfo = self.PLMtool.GetColumnInfo()
                 partslist._ColumnMapping = self.PLMtool.GetColumnMapping()
                 partslist._ColumnMappingID = 0 # eventually change to database id
-                partslist._upload_file_name = self.PLMtool.GetPartsListFilename()
+                partslist.local_file_path = self.PLMtool.GetPartsListFilename()
             else:
                 partslist._ColumnInfo = self.currentdocument._ColumnInfo
                 partslist._ColumnMapping = self.currentdocument._ColumnMapping
                 partslist._ColumnMappingID = 0
-                partslist._upload_file_name = self.currentdocument._upload_file_name
+                partslist.local_file_path = self.currentdocument.local_file_path
 
             try:
                 partslist.validate()

Index: PanGalactic/pangalactic/node/gui/psm/pgefversiontree.py
diff -u PanGalactic/pangalactic/node/gui/psm/pgefversiontree.py:1.4 PanGalactic/pangalactic/node/gui/psm/pgefversiontree.py:1.5
--- PanGalactic/pangalactic/node/gui/psm/pgefversiontree.py:1.4	Mon Apr  4 00:13:12 2005
+++ PanGalactic/pangalactic/node/gui/psm/pgefversiontree.py	Tue May  3 03:08:29 2005
@@ -4,14 +4,12 @@
 
 class PgefVersionTree(pgeftree.PgefTree):
     """Specialized tree for displaying versions hierarchically."""
-    
+
     def __init__(self, parent, ID, datamanager = None):
         pgeftree.PgefTree.__init__(self, parent, ID, datamanager)
-
         self.Parent = parent
         EVT_RIGHT_DOWN(self, self.OnRightDown)
         
-        
     def StartDragOperation(self):
         selectednode = self.GetSelection()
         if selectednode == self.GetRootItem():
@@ -19,76 +17,17 @@
         
         nauo_item = self.GetPyData(selectednode)
 
-        drag_node = self.dm.getLookupObject(nauo_item[1])
+        drag_node = self.dm.getLocalObject(nauo_item[1])
         if drag_node:
             print "node: " + drag_node.name #+
             #"; parts: " + str(debug.has_parts_flag) +
             #"; plflag: " + str(debug.has_parts_lists_flag) +
             #"; state: " + str(debug.state) + " (" + nauo_item[0] + ", " + nauo_item[1] + ")"
-
-##    def LoadTreefromProject(self, datamanager, rootitemid, rootpdrid, currentdata = None):
-##        """Loads the tree from the dicts in the DataManager"""
-##        #print "pgefversiontree.loadtreefromproject"
-##        self.DeleteAllItems()
-##        rootitem = datamanager.getLookupObject(rootitemid)
-###        foo = rootitem.of_pm_id + "." + rootitem.of_pv_id
-##        self.nodeStack.append(self.AddRoot(rootitem.id))
-##        rootnode = self.GetRootItem()
-
-##        if rootitem.has_parts_lists_flag:
-##            self.SetItemHasChildren(rootnode, True)
-            
-##            if state['loggedin']:
-##                if not self.IsExpanded(rootnode): 
-##                    links_objs = datamanager.getPartDocLinksByPartId([rootitemid])
-
-##        self.SetPyData(rootnode, [rootpdrid, rootitemid])
-##        self.SetItemImage(rootnode, self.itemicon)
-##        self.SetItemImage(rootnode, self.itemicon, wxTreeItemIcon_Selected)
-
-##        lookupid = rootitemid
-##        tmppdrid = rootpdrid
-
-##        PdrNodes = []
-##        highlightednode = None
-##        if datamanager.pdrIDs.has_key(lookupid):
-##            #print "found lookupid"
-##            PdrNodes = datamanager.pdrIDs[lookupid]
-
-##        elif not state['loggedin']:
-##            for pdrid, pdrobj in datamanager.getDocPartLinks().items():
-##                if pdrobj.pgef_oid == rootitemid:
-##                    PdrNodes.append(pdrid)
-
-##        for id in PdrNodes:
-##            pdrobj = datamanager.getLookupObject(id)
-##            plobj = datamanager.getPartsList(pdrobj.pgef_oid)
-
-##            if plobj:
-##                treeid = self.AppendItem(rootnode, plobj.id)
-##                self.SetPyData(treeid, [pdrobj.pgef_oid, plobj.pgef_oid])
-##                self.SetItemImage(treeid, self.partslisticon)
-##                self.SetItemImage(treeid, self.partslisticon, wxTreeItemIcon_Selected)
-
-##                if currentdata:
-##                    if plobj.pgef_oid == currentdata[1] and pdrobj.pgef_oid == currentdata[0]:
-##                        #print "found a node to highlight: " + str(plobj.identification)
-##                        highlightednode = treeid
-
-##        self.SortChildren(rootnode)
-##        self.Expand(rootnode)
-
-##        if highlightednode:
-##            self.SelectItem(highlightednode)
-##        else:
-##            self.SelectItem(rootnode)
-
             
     def buildVersionString(self, obj):
         print "pgefversiontree.buildversionstring"
         return obj.id
 
-
     def OnRightDown(self, event):
         print "pgefversiontree.onrightdown"
         targetnode, flags = self.HitTest(wxPoint(event.GetX(), event.GetY()))
@@ -97,32 +36,25 @@
             print event.GetX()
             print event.GetY()
             print "node data:", self.GetPyData(targetnode)
-
         event.Skip()  
 
-
-    def LoadTreefromObjects(self, datamanager, rootproduct):
+    def LoadTreeFromObject(self, rootobj):
         """Loads the tree from the dicts in the DataManager"""
-        print "pgefversiontree: loadtreefromobjects:", rootproduct.id
-        
+        print "pgefversiontree: loadtreefromobjects:", rootobj.id
         self.DeleteAllItems()
 #        self.nodeStack.append(self.AddRoot(state['project']))
-
         tmp_model = None
         tmp_part = None
-
 #        temp_pm = None
 #        temp_pmm = None
 #        temp_pmv = None
 #        temp_pv = None
-
-        classname = rootproduct.__class__.__name__
+        classname = rootobj.__class__.__name__
         print 'classname:', classname
-
         if classname == "Part":
-            tmp_part = rootproduct
+            tmp_part = rootobj
         elif classname == "Model":
-            tmp_model = rootproduct
+            tmp_model = rootobj
             tmp_part = None
         else:
             print "invalid object:", classname
@@ -134,70 +66,6 @@
             self.SetPyData(part_treeid, ['version', tmp_part.pgef_oid])
             self.Expand(part_treeid)
 
-#        elif tmp_model:
-#            self.nodeStack.append(self.AddRoot(tmp_model.id))
-#            model_treeid = self.GetRootItem()
-##            model_treeid = self.AppendItem(rootnode, tmp_model.id)
-#            self.SetPyData(model_treeid, ['version', tmp_model.pgef_oid])
-#            self.Expand(model_treeid)
-
-##        if temp_pm:
-##            foo = temp_pm.id
-##            pm_treeid = self.AppendItem(rootnode, foo)
-##            self.SetPyData(pm_treeid, ['version', temp_pm.pgef_oid])
-##            self.Expand(pm_treeid)
-##            version_obj = temp_pm
-##            version_node = pm_treeid
-
-##        if temp_pv:
-##            foo = temp_pm.id + "." + temp_pv.id
-##            pv_treeid = self.AppendItem(pm_treeid, foo)
-##            self.SetPyData(pv_treeid, ['version', temp_pv.pgef_oid])
-##            self.Expand(pv_treeid)
-##            version_obj = temp_pv
-##            version_node = pv_treeid
-            
-##        if temp_pmm:
-##            foo = temp_pm.id + "." + temp_pv.id + '.' + temp_pmm.id
-##            pmm_treeid = self.AppendItem(pv_treeid, foo)
-##            self.SetPyData(pmm_treeid, ['version', temp_pmm.pgef_oid])
-##            self.Expand(pmm_treeid)
-##            version_obj = temp_pmm
-##            version_node = pmm_treeid
-
-##        if temp_pmv:
-##            foo = temp_pm.id + "." + temp_pv.id + "." + temp_pmm.id + "." + temp_pmv.id
-##            pmv_treeid = self.AppendItem(pmm_treeid, foo)
-##            self.SetPyData(pmv_treeid, ['version', temp_pmv.pgef_oid])
-##            self.Expand(pmv_treeid)
-##            version_obj = temp_pmv
-##            version_node = pmv_treeid
-        
-##        objs = datamanager.getVersionTreeObjects(version_obj)
-##        if objs: 
-##            self.SetItemHasChildren(version_node, True)
-##            for obj in objs:
-##                if obj.state <> 'DELETE':
-##                    treelabel = self.createTreeLabel(obj)
-##                    treeid = self.AppendItem(version_node, treelabel)
-##                    self.SetPyData(treeid, ['version', obj.pgef_oid])
-##                    self.SetItemImage(treeid, self.itemicon)
-##                    self.SetItemImage(treeid, self.itemicon, wxTreeItemIcon_Selected)  
-
-##        self.Expand(rootnode)
-##        if temp_pm:
-##            self.Expand(pm_treeid)
-##        if temp_pv:
-##            self.Expand(pv_treeid)
-##        if temp_pmm:
-##            self.Expand(pmm_treeid)
-##        if temp_pmv:
-##            self.Expand(pmv_treeid)
-
-##        if version_node:
-##            self.SelectItem(version_node)
-
-            
     def createTreeLabel(self, obj):
         print "pgefversiontree.createtreelabel"
         temp = ""

Index: PanGalactic/pangalactic/node/gui/psm/itemeditframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.11 PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.12
--- PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.11	Mon Apr  4 00:13:12 2005
+++ PanGalactic/pangalactic/node/gui/psm/itemeditframe.py	Tue May  3 03:08:29 2005
@@ -1,6 +1,6 @@
-# $Id: itemeditframe.py,v 1.11 2005/04/04 04:13:12 waterbug Exp $
+# $Id: itemeditframe.py,v 1.12 2005/05/03 07:08:29 waterbug Exp $
 
-__version__ = "$Revision: 1.11 $"[11:-2]
+__version__ = "$Revision: 1.12 $"[11:-2]
 
 import wx
 from pangalactic.node.gui.psm import docform
@@ -161,7 +161,6 @@
 
         self.Setup(rootobj, nodedata, displaywgts, mode)
 
-
     def Setup(self, rootobj, nodedata, displaywgts, mode):
         #print "itemeditframe.setup", rootobj.id, rootobj.__class__.__name__
         try:
@@ -188,7 +187,6 @@
         self.setupPane(rootobj, nodedata)
         self.setMode(mode)
 
-
     def setCurrentObject(self, rootobj, nodedata = None):
         #print "itemeditframe.setcurrentobject"
 
@@ -232,14 +230,11 @@
             self.rootobjs[self.DocPage] = rootobj
             self.currentpage = self.DocPage
 
-
     def setupPane(self, rootobj, nodedata=None):
         if not rootobj:
             return
-
         classname = rootobj.__class__.__name__
         currentform = None
-
         if classname == "Part":
             currentform = self.partform
         elif classname == "Model":
@@ -248,16 +243,13 @@
             currentform = self.partslistform
         elif classname == "Document":
             currentform = self.documentform
-
         if currentform:
             currentform.fillForm(rootobj)
-
         self.BuildTree(rootobj, classname)
         root = self.tree.GetRootItem()
         if root:
             self.tree.SelectItem(root)
 
-
     def setMode(self, mode=BROWSE_MODE):
         if mode == NEW_MODE:
             self.CreatingMode(self.currentpage)
@@ -266,7 +258,6 @@
         else:
             self.BrowseMode(True)
 
-
     def Clear(self):
         self.tree.DeleteAllItems()
         self.partform.clearForm()
@@ -276,7 +267,6 @@
         self.propertiesform.propertiesgrid.ClearGrid()
         self.documentform.ClearForm()
 
-
     def SetName(self, name):
         if name == None:
             name = "New"
@@ -285,7 +275,6 @@
     def setDisplayWgt(self, display_wgts):
         self.DisplayWgts = display_wgts
 
-
     def UnsavedDataPageChanging(self, dialog_msg, creating_flag,
                                 currentpage, allow_tabbing = True):
         """
@@ -318,7 +307,6 @@
             dlg.Destroy()
             return True
 
-
     def PageChanging(self, event):
         """
         Handles the checking that needs to be done when we change tabs
@@ -379,7 +367,6 @@
         else:
             self.tree.DeleteAllItems()
 
-
     def BrowseMode(self, gotroot):
         self.partform.BrowseMode(gotroot)
         self.modelform.BrowseMode(gotroot)
@@ -430,7 +417,6 @@
             self.dm.creatingPart = False
             self.dm.creatingModel = False
 
-
     def CreatingMode(self, whichpane):
         """Handles the setting of the correct mode based
            upon which pane of the notebook is being shown.
@@ -492,7 +478,7 @@
                     obj = self.doctree.GetItemText(node)
                     if obj <> "NEW":
                         self.documentform.ResetForm(
-                            self.dm.getLookupObject(obj[1]))
+                            self.dm.getLocalObject(obj[1]))
                     else:
                         self.documentform.ClearForm()
                     self.documentform.BrowseMode(False)
@@ -536,7 +522,6 @@
         else:
             self.documentform.BrowseMode(False)
 
-
     def LinkDocument(self):
         #print "linkdoc"
         link = self.dm.newObject("DocPtRel")
@@ -545,11 +530,8 @@
         link.document = self.currentobj.pgef_oid
         link.state = 'ADD'
         self.dm.add([link])
-
-        self.dm.addProjectObjects(state['project'], [link])
-
         rootdata = self.tree.GetPyData(self.tree.GetRootItem())
-        parent = self.dm.getLookupObject(rootdata[1])
+        parent = self.dm.getLocalObject(rootdata[1])
         if parent:
             if parent.state:
                 if parent.state < 'ADD':
@@ -557,10 +539,8 @@
             else:
                 parent.state = 'MODIFY'
             self.dm.add([parent])
-
         return link
 
-
     def OnUnlinkDocument(self, event):
         # print "unlink doc"
         node = self.doctree.GetSelection()
@@ -575,9 +555,8 @@
                     self.doctree.SetItemHasChildren(parent, False)
                 self.doctree.SelectItem(self.doctree.GetRootItem())
 
-
     def UnlinkDocument(self, pdrid):
-        pdrobj = self.dm.getLookupObject(pdrid)
+        pdrobj = self.dm.getLocalObject(pdrid)
         if pdrobj.state:
             if pdrobj.state < 'DELETE':
                 pdrobj.state = 'DELETE'
@@ -587,7 +566,6 @@
                 pdrobj.state = 'DELETE'
         else:
             pdrobj.state = 'DELETE'
-
         self.dm.RemovePDR(pdrid)
         self.dm.add([pdrobj])
         return True
@@ -610,7 +588,7 @@
                             self.dm.creatingPart = False
                         return
 
-                    temp_obj = self.dm.getLookupObject(obj[1])
+                    temp_obj = self.dm.getLocalObject(obj[1])
                     classname = temp_obj.__class__.__name__
                     if classname == "Part":
                         self.partform.ResetForm(temp_obj)
@@ -623,7 +601,7 @@
                     print msg
                     obj = self.tree.GetItemText(node)
                     if obj <> "NEW":
-                        temp_obj = self.dm.getLookupObject(obj[1])
+                        temp_obj = self.dm.getLocalObject(obj[1])
                         classname = temp_obj.__class__.__name__
                         if classname == "Part":
                             self.partform.ResetForm(temp_obj)
@@ -644,7 +622,6 @@
             self.dm.creatingPart = False
         self.editingtab = None
 
-
     def OnResetModel(self, event):
         #print "itemeditframe.onresetmodel"
         self.EditModel = False
@@ -663,7 +640,7 @@
                             self.dm.creatingModel = False
                         return
 
-                    temp_obj = self.dm.getLookupObject(obj[1])
+                    temp_obj = self.dm.getLocalObject(obj[1])
                     classname = temp_obj.__class__.__name__
                     if classname == "Model":
                         self.modelform.ResetForm(temp_obj)
@@ -676,7 +653,7 @@
                     print msg
                     obj = self.modeltree.GetItemText(node)
                     if obj <> "NEW":
-                        temp_obj = self.dm.getLookupObject(obj[1])
+                        temp_obj = self.dm.getLocalObject(obj[1])
                         classname = temp_obj.__class__.__name__
                         if classname == "Model":
                             self.modelform.ResetForm(temp_obj)
@@ -697,7 +674,6 @@
             self.dm.creatingModel = False
         self.editingtab = None
 
-
     def OnEditPart(self, event):
         #print "itemeditframe.oneditpart", self.currentpage
         self.editingtab = self.currentpage
@@ -707,7 +683,6 @@
             self.partform.HighlightFirstWgt()
             self.partform.EditingMode()            
 
-
     def OnEditModel(self, event):
         #print "itemeditframe.oneditproduct", self.currentpage
         self.editingtab = self.currentpage
@@ -717,22 +692,18 @@
             self.modelform.HighlightFirstWgt()
             self.modelform.EditingMode()            
 
-
-
     def OnNewPartsList(self, event):
         #print "itemedit.onnewpartslist"
         self.dm.creatingPartsList = True
         self.editingtab = self.currentpage
         self.partslistform.CreatingMode()
 
-
     def OnEditPartsList(self, event):
         self.dm.creatingPartsList = True
         self.editingtab = self.currentpage
         self.EditPL = True
         self.partslistform.EditingMode()
 
-
     def OnLinkPartsList(self, event = None):
         # print "onlinkpl"
         link = pdr()
@@ -743,7 +714,6 @@
         link.project = state['project']
         link.owner = link.creator = link.modifier = self.dm.user.id
         self.dm.add([link])
-        self.dm.addProjectObjects(state['project'], [link])
         node = self.partslisttree.GetSelection()
         rootnode = self.partslisttree.GetRootItem()
 
@@ -765,7 +735,7 @@
             self.partslistform.BrowseMode(False)
 
         rootdata = self.tree.GetPyData(self.tree.GetRootItem())
-        parent = self.dm.localdb.getLookupObject(rootdata[1]) #self.rootitemid)
+        parent = self.dm.cache.getLocalObject(rootdata[1]) #self.rootitemid)
         if parent:
             if parent.state:
                 if parent.state < 'ADD':
@@ -774,7 +744,6 @@
                 parent.state = 'MODIFY'
             self.dm.add([parent])
 
-
     def OnPartsListView(self, event):
         #print "itemedit.onpartslistview"
         self.editnb.SetSelection(self.PartDataPage)
@@ -796,7 +765,6 @@
             self.dm.creatingModel = False
             self.partform.CreatingMode()
 
-
     def OnNewModel(self, event):
         """
         Handle the setting of the correct flags and modes for creating a
@@ -818,11 +786,11 @@
         if node.IsOk():
             treetuple = self.tree.GetPyData(node)
             if treetuple[0]:
-                self.dm.removeAcu(treetuple[0], False)
+                self.dm.removeAcu(treetuple[0])
                 parent = self.tree.GetItemParent(node)
                 self.tree.Delete(node)
 
-                nauoobj = self.dm.getLookupObject(treetuple[0])
+                nauoobj = self.dm.getLocalObject(treetuple[0])
                 if nauoobj.state:
                     if nauoobj.state < 'DELETE':
                         nauoobj.state = 'DELETE'
@@ -894,7 +862,7 @@
                 self.currentobj._ColumnInfo = PLM.GetColumnInfo()
                 self.currentobj._ColumnMapping = PLM.GetColumnMapping()
                 self.currentobj._ColumnMappingID = 0
-                self.currentobj._upload_file_name = PLM.GetPartsListFilename()
+                self.currentobj.local_file_path = PLM.GetPartsListFilename()
                 self.PLM_Converted = self.PLMtool.Converted
                 self.PLMtool.CloseDown()
 
@@ -918,7 +886,7 @@
                     obj = self.partslisttree.GetItemText(node)
                     if obj <> "NEW":
                         self.partslistform.ResetForm(
-                            self.dm.getLookupObject(obj[1]))
+                            self.dm.getLocalObject(obj[1]))
                     else:
                         self.partslistform.ClearForm()
                     self.partslistform.BrowseMode(False)
@@ -932,7 +900,6 @@
                                        self.partslistform.NextDocId) - 1)
         #print "end resetpartslist"
 
-
     def OnClose(self, event = None):
         #print "itemeditframe.onclose"
 
@@ -966,24 +933,22 @@
 
         self.Show(False)
 
-
     def BuildTree(self, rootobj, treetype):
         #print "itemeditframe.buildtree"
         textloc = wx.Point(10, 10)
         defsize = wx.Size(400, 75)
-        treedlg = wx.Dialog(self,
-                           -1,
-                           "A Message from PGEF",
-                           wx.DefaultPosition,
-                           defsize,
-                           wx.THICK_FRAME)
+        treedlg = wx.Dialog(self, -1,
+                            "A Message from PGEF",
+                            wx.DefaultPosition,
+                            defsize,
+                            wx.THICK_FRAME)
         msg = wx.StaticText(treedlg, -1,
               "Please wait while PGEF accesses the Item data...",
               textloc, wx.DefaultSize, wx.ALIGN_CENTRE)
         treedlg.CentreOnParent()
         treedlg.Show(True)
 
-        if self.currenttree <> treetype:
+        if self.currenttree != treetype:
             newtree = pgefedittree.PgefEditTree(self.vsplitter, self.tID, self.dm)
             tree_tooltip = ' '.join(
             ["A hierarchical display of the currently selected product.",
@@ -995,10 +960,9 @@
             self.currenttree = treetype
 
         self.tree.DeleteAllItems()
-        self.tree.LoadTreefromObjects(self.dm, rootobj)
+        self.tree.LoadTreeFromObject(rootobj)
         treedlg.Destroy()
 
-
     def OnTreeActivate(self, event):
         # print "treeactivate"
         treeitem = event.GetItem()
@@ -1038,7 +1002,7 @@
                     self.partslistform.BrowseMode(True)
                     self.partslistform.ClearForm()
                 else:
-                    plobj = self.dm.getLookupObject(nodeid)
+                    plobj = self.dm.getLocalObject(nodeid)
                     self.currentobj = self.dm.newObject("PartsList")
                     self.tempobj = self.dm.newObject("PartsList")
                     self.currentobj.__dict__.update(plobj.__dict__)
@@ -1082,7 +1046,7 @@
                 else:
                     self.partform.BrowseMode(False)
 
-                partobj = self.dm.getLookupObject(nodeid)
+                partobj = self.dm.getLocalObject(nodeid)
                 if partobj:
                     self.currentobj = self.dm.newObject("Part")
                     self.tempobj = self.dm.newObject("Part")
@@ -1126,7 +1090,7 @@
                 else:
                     self.modelform.BrowseMode(False)
 
-                modelobj = self.dm.getLookupObject(nodeid)
+                modelobj = self.dm.getLocalObject(nodeid)
                 if modelobj:
                     self.currentobj = self.dm.newObject("Model")
                     self.tempobj = self.dm.newObject("Model")
@@ -1168,7 +1132,7 @@
                     self.documentform.BrowseMode(True)
                     self.documentform.ClearForm()
                 else:
-                    docobj = self.dm.getLookupObject(nodeid)
+                    docobj = self.dm.getLocalObject(nodeid)
                     self.currentobj = self.dm.newObject("Document")
                     self.tempobj = self.dm.newObject("Document")
                     self.currentobj.__dict__.update(docobj.__dict__)
@@ -1176,8 +1140,6 @@
                     self.documentform.fillForm(self.currentobj)
                     self.documentform.BrowseMode(False)
 
-
-
     def ChangesMade(self):
         #print "itemeditframe.changesmade"
         retval = False
@@ -1237,7 +1199,6 @@
                 self.documentform.ClearForm()
         return retval
 
-
     def DiscardChanges(self):
         if self.dm.creatingPartsList:
             plid = prefs.get('nextplid', 1)
@@ -1268,7 +1229,6 @@
         self.dm.creatingPart = False
         self.dm.creatingModel = False
 
-
     def saveObjectChanges(self):
         #print "itemeditframe.saveobjectchanges"
         if self.dm.creatingPart: # or self.dm.creatingModel:
@@ -1285,13 +1245,10 @@
             currentform = self.documentform
         else:
             return False
-
         currentform.Save(save_object)
         save_object.state = 'ADD'
-
         try:
             save_object.validate()
-
         except RequiredDataError, e:
             dlg = wx.MessageDialog(self, e.value, "Required Data Missing.",
                                   wx.OK | wx.ICON_ERROR)
@@ -1299,7 +1256,6 @@
             dlg.Destroy()
             currentform.EditingMode()
             return False
-
         if self.dm.creatingPart:
             self.dm.creatingPart = False
         elif self.dm.creatingModel:
@@ -1311,37 +1267,30 @@
                 save_object._ColumnInfo = PLM.GetColumnInfo()
                 save_object._ColumnMapping = PLM.GetColumnMapping()
                 save_object._ColumnMappingID = 0
-                save_object._upload_file_name = PLM.GetPartsListFilename()
+                save_object.local_file_path = PLM.GetPartsListFilename()
             else:
                 if self.currentobj:
                     o = self.currentobj
                     save_object._ColumnInfo = o._ColumnInfo
                     save_object._ColumnMapping = o._ColumnMapping
                     save_object._ColumnMappingID = 0
-                    save_object._upload_file_name = o._upload_file_name
+                    save_object.local_file_path = o.local_file_path
                 else:
                     return False
-
-            if not save_object._upload_file_name:
+            if not save_object.local_file_path:
                 if wx.Platform == '__WXMSW__':
                     if not self.PLM_Converted:
                         msg = "You have not provided a spreadsheet"
                         raise RequiredDataError, msg
                 else:
                     self.PLM_Converted = True #vwk for linux testing
-
         elif self.dm.creatingDocument:
              self.OnLinkDocument()
              self.dm.creatingDocument = False
-
         self.dm.add([save_object])
-        self.dm.addProjectObjects(state['project'],
-                                  [save_object])
         self.Parent.psmgui.UpdateWgts(save_object)
         return True
 
-
-
     def SetPartsListInfo(self, partslist):
         # print "setpartslistinfo"
         self.PartsListInfo = partslistinfo.PartsListInfo()
@@ -1349,7 +1298,6 @@
         self.PartsListInfo.SetInfo(partslist)
         self.PartsListMap.SetInfo(partslist)
 
-
     def OnSaveObject(self, event = None):
         #print "itemeditframe.onsaveobject"
         node = self.tree.GetSelection()
@@ -1358,7 +1306,6 @@
         else:
             #print "  onsaveobject.badnode"
             data = [None, None]
-
         if self.dm.creatingPart:
             self.currentform = self.partform
         elif self.dm.creatingModel:
@@ -1367,14 +1314,11 @@
             self.currentform = self.partslistform
         elif self.dm.creatingDocument:
             self.currentform = self.documentform
-
         newitem = self.SaveObject(data[1])
         if newitem == None:
             print "  didn't save anything"
             return
-
         self.Parent.psmgui.UpdateWgts(newitem)
-
         if self.dm.creatingPart:
             self.dm.creatingPart = False
         elif self.dm.creatingModel:
@@ -1383,32 +1327,29 @@
             self.dm.creatingPartsList = False
         elif self.dm.creatingDocument:
             self.dm.creatingDocument = False
-
         self.currentform.BrowseMode(True)
         self.currentform.GetNewWgt().SetFocus()
-
         self.dm.refresh = True
         self.editingtab = None
 
-
     def SaveObject(self, itemid):
         """
         Save a new object (or changes to an existing object) into an object
         in the local database.
 
-        @type itemid: string
-        @param itemid: The oid of the object being edited.
-        @return save_object: new/updated object 
+        @param itemid:  The oid of the object being edited.
+        @type  itemid:  C{string}
+
+        @return:  new/updated object 
+        @rtype:   L{pangalactic.core.pgefobject.PgefObject} or subtype
         """
-        #print "itemeditframe.saveobject"
-        #print 'itemid:', itemid
+        # print "itemeditframe.saveobject"
+        # print 'itemid:', itemid
         save_object = None
         newitem = None
-
         if not state['project']:
             print "  Hmmm...  No project.  Not Good.  Aborting."
             return
-
         if self.dm.creatingPart:
             save_object = self.dm.newObject("Part")
         elif self.dm.creatingModel:
@@ -1417,24 +1358,19 @@
             save_object = self.dm.newObject("PartsList")
         elif self.dm.creatingDocument:
             save_object = self.dm.newObject("Document")
-
         self.currentform.Save(save_object)
-
         try:
             #print "validate", save_object.__class__.__name__
             save_object.validate()
-
         except RequiredDataError, e:
             print "e:", e.value
             dlg = wx.MessageDialog(self, e.value, "Required Data Missing.",
                                   wx.OK | wx.ICON_ERROR)
             dlg.ShowModal()
             dlg.Destroy()
-
             self.currentform.EditingMode()
             save_object = None
             return
-
         #self.rootitemid == None and self.rootnauoid == None:
         if self.currentobj.name == "NEW":
             #print "  new item via menu?"
@@ -1452,25 +1388,23 @@
             # we have created a new node while visiting an existing node
             #self.rootitemid = self.currentobj.pgef_oid
             self.BuildTree(save_object, save_object.__class__.__name__)
-
         if self.dm.creatingPartsList:
             if self.PLMtool:
                 PLM = self.PLMtool
                 save_object._ColumnInfo = PLM.GetColumnInfo()
                 save_object._ColumnMapping = PLM.GetColumnMapping()
                 save_object._ColumnMappingID = 0
-                save_object._upload_file_name = PLM.GetPartsListFilename()
+                save_object.local_file_path = PLM.GetPartsListFilename()
             else:
                 if self.currentobj:
                     o = self.currentobj
                     save_object._ColumnInfo = o._ColumnInfo
                     save_object._ColumnMapping = o._ColumnMapping
                     save_object._ColumnMappingID = 0
-                    save_object._upload_file_name = o._upload_file_name
+                    save_object.local_file_path = o.local_file_path
                 else:
                     return False
-
-            if not save_object._upload_file_name:
+            if not save_object.local_file_path:
                 if wx.Platform == '__WXMSW__':
                     if not self.PLM_Converted:
                         msg = "You have not provided a spreadsheet"
@@ -1478,24 +1412,9 @@
                 else:
                     self.PLM_Converted = True #vwk for linux testing
             self.SetPartsListInfo(pl)
-
-        if self.dm.creatingDocument:
-            dfile = self.dm.newFileLink(save_object)
-            dfile.state = 'ADD'
-            self.dm.add([dfile])
-            self.OnLinkDocument()
-
-        if self.dm.creatingModel:
-            dfile = self.dm.newFileLink(save_object)
-            dfile.state = 'ADD'
-            self.dm.add([dfile])
-
         save_object.state = 'ADD'
         self.dm.add([save_object])
         self.currentobj.__dict__.update(save_object.__dict__)
         self.tempobj.__dict__.update(save_object.__dict__)
-
-        self.dm.addProjectObjects(state['project'],
-                                  [save_object])
         return save_object
 

Index: PanGalactic/pangalactic/utils/localdb.py
diff -u PanGalactic/pangalactic/utils/localdb.py:1.128 PanGalactic/pangalactic/utils/localdb.py:1.129
--- PanGalactic/pangalactic/utils/localdb.py:1.128	Sun May  1 02:22:36 2005
+++ PanGalactic/pangalactic/utils/localdb.py	Tue May  3 03:08:31 2005
@@ -1,14 +1,16 @@
 """
 Local object cache manager
 
-@version: $Revision: 1.128 $
+@version: $Revision: 1.129 $
 """
-__version__ = "$Revision: 1.128 $"[11:-2]
+__version__ = "$Revision: 1.129 $"[11:-2]
 
 import os
 import glob
 import mx.DateTime
+from sets import Set
 
+import pangalactic
 from pangalactic.core.workflow.wfprocessinstance import WfProcessInstance
 from pangalactic.core.workflow.wfactivity        import WfActivity
 from pangalactic.core.workflow.wfeventaudit      import WfEventAudit
@@ -17,103 +19,60 @@
 from ZODB.PersistentMapping import PersistentMapping
 import ZODB
 from ZODB import FileStorage, DB
-from ZODB import *
-
+# from ZODB import *
 
 AddNauo = not None
 DeleteNauo = None
 
 # level of access to localdb dicts
-god = 99
-admin = 10
-user = 1
-
-WF_CLASSES = ["WfActivity", "WfProcessInstance", "WfTransition",
-              "WfEventAudit"]
+GOD = 99
+ADMIN = 10
+USER = 1
 
 
 class LocalStorage:
-    OIDLOOKUP = "OidLookup"
-    ORGANIZATION = "Organization"
-    PASSWD = "Passwd"
-    PROJECT = "Project"
-    PROJECTOBJECTS = "ProjectObjects"
-    USER = "User"
-    WFACTIVITY = "WfActivity"
-    WFEVENTAUDIT = "WfEventAudit" 
-    WFPROCESSINSTANCE = "WfProcessInstance"
-    WFTRANSITION = "WfTransition"
-    # tuple fields:
+    # dictlist fields:
     # first field  - the dict name
     # second field - does this dict persist after clearing localdb?
     # third field  - who sees the dict displayed in the dbbrowser?
-    dictlist = [('Acu', 1, user),
-                ('DisplayConfig', 1, admin),
-                ('Dcu', 1, admin),
-                ('Document', 1, user), 
-                ('Model', 1, user), 
-                ('ObjectSchema', 0, user),
-                (OIDLOOKUP, 1, admin),
-                (ORGANIZATION, 0, user),
-                ('Part', 1, user), 
-                ('PartsList', 1, user),
-                (PASSWD, 0, admin),
-                ('FileLink', 1, user),
-                (PROJECT, 0, admin),
-                (PROJECTOBJECTS, 0, user),
-                ("Uncommitted", 1, user), 
-                (USER, 0, admin),
-                (WFACTIVITY, 1, user),
-                (WFEVENTAUDIT, 1, admin),
-                (WFPROCESSINSTANCE, 1, user),
-                (WFTRANSITION, 1, user)]
-
-    DictListNames = [x for x, y, z in dictlist]
-
-    CommittedDicts = ['Acu',
-                      'Dcu',
-                      'Document',
-                      'Model',
-                      'Part',
-                      'PartsList',
-                      'FileLink',
-                      PROJECT,
-                      WFACTIVITY,
-                      WFEVENTAUDIT,
-                      WFPROCESSINSTANCE,
-                      WFTRANSITION]
+    special_names = ['DisplayConfig', 'OidLookup', 'Passwd', 'Uncommitted',
+                     'User']
+    wf_names = ["WfActivity", "WfProcessInstance", "WfTransition",
+                "WfEventAudit"]
 
-    def __init__(self, _registry, clear=False):
+    def __init__(self, _registry):
         """
         Initialize a LocalStorage instance.
 
         @param _registry:  the PanGalacticRegistry instance (singleton)
         @type  _registry:  L{pangalactic.meta.registry.PanGalacticRegistry}
-
-        @param clear:  indicates whether to remove data files
-        @type  clear:  bool
         """
+        # If modifying this stuff, be careful:  order is important
         if not os.path.exists("data"):
             os.makedirs("data")
-        if clear:
-            for file in glob.glob("data/*.fs*"):
-                os.remove(file)
         self._registry = _registry
+        self.core_names = _registry.object_schemas.keys()
+        self.domain_names = Set(self.core_names + self.wf_names)
+        domainlist = [(n, 1, USER) for n in self.domain_names]
+        specials = [(n, 1, ADMIN) for n in self.special_names]
+        # setup() uses dictlist to create and name the cache's dictionaries
+        self.dictlist = specials + domainlist
         self.filename = os.path.join(".", "data", "pgef.fs")
         self.storage = FileStorage.FileStorage(self.filename)
         self.db = DB(self.storage)
         self.dbconnection = self.db.open()
         self.dbroot = self.dbconnection.root()
-        self.Setup()
+        self.setup()
+        self.uncommittedobjs = self.dbroot["Uncommitted"]
 
-    def Pack(self):
+    def pack(self):
         """
         Removes old entries from and cleans a PersistentStorage object
         """
         self.db.pack()
-        self.Commit()
+        self.commit()
 
-    def Clear(self):
+    def clear(self):
         for dict, clear_flag, config in self.dictlist:
             if clear_flag:
                 try:
@@ -123,478 +82,281 @@
                     import shutil
                     shutil.copy("data/pgef.fs","data/pgef.fs.corrupt")
                     del self.dbroot[dict]
-                    self.Setup()
-        self.Commit()
+                    self.setup()
+        self.commit()
 
-    def Commit(self):
+    def commit(self):
         get_transaction().commit()
 
-    def Setup(self):
+    def setup(self):
         for dict, flag, config in self.dictlist:
             if self.dbroot.has_key(dict):
                 pass
             else:
                 self.dbroot[dict] = PersistentMapping()  
-
-    def saveDict(self, dictname, obj):
-        #print "localdb.savedict", dictname, obj.pgef_oid
-        try:
-            for key, value in self.dbroot[dictname].items():
-                del self.dbroot[dictname][key]
-        except:
-            pass
-        self.dbroot[dictname][obj.pgef_oid] = obj
-
-    def SaveUser(self, user=None):
-#        print "localdb.saveuser"
-        if user:
-            self.saveDict(self.USER, user)
+        self.objs = self.dbroot['OidLookup']
 
     def savePasswds(self, login_pwd, new_pwd):
-        pwd_dict = self.dbroot[self.PASSWD]
-        pwd_dict["login"] = login_pwd
-        pwd_dict["current"] = new_pwd
-        self.dbroot[self.PASSWD] = pwd_dict
-        self.Commit()
+        pwd_dict = self.dbroot['Passwd']
+        pwd_dict['login'] = login_pwd
+        pwd_dict['current'] = new_pwd
+        self.dbroot['Passwd'] = pwd_dict
+        self.commit()
 
     def savePasswd(self, pwd_id, passwd_name):
-        pwd_dict = self.dbroot[self.PASSWD]
+        pwd_dict = self.dbroot['Passwd']
         pwd_dict[passwd_id] = passwd_name
 
     def getPasswd(self, passwd_id):
-        pwd_dict = self.dbroot[self.PASSWD]
+        pwd_dict = self.dbroot['Passwd']
         return pwd_dict[passwd_id]
 
-    ######### TODO: define ObjectSchema instances for the Wf classes!!
-
-    def defaultDisplayConfig(self):
-        print "localdb.defaultDisplayConfig"
-        current_config = {}
-        for schemaid in self._registry.object_schemas:
-            print 'configuring display for schema:  %s' % schemaid
-            schema = self._registry.object_schemas[schemaid]
-            current_config[schemaid] = schema._default_display_map
-        self.setDisplayConfig(current_config)
-        print "default config done"
-        return current_config
-
-    def getDisplayConfig(self):
-        print "localdb.getDisplayConfig"
-        foo = self.getDict('DisplayConfig')
-        print "localdb.config.keys", foo.keys()
-        if not foo:
-            foo = self.defaultDisplayConfig()
-        return foo
-
-    def setDisplayConfig(self, config):
-        self.dbroot['DisplayConfig'] = config
-        self.Commit()
-
-    def getLookupObject(self, pgef_oid):
-        dict = self.lookupOid(pgef_oid)
-        return self.getLocalObject(dict, pgef_oid)
-
-    def SavePartsList(self, partslist_list):
-        for obj in partslist_list:
-            self.saveItWithLookup('PartsList', obj, True)
-        self.Commit()
-
-    def GetLocalAcus(self, project=None):
-        #print "getlocalacus", project
-        acu_dict = self.dbroot['Acu']
-        uncommitted_dict = self.dbroot["Uncommitted"]
-
-        objdict = {}
-        for nid, nobj in acu_dict.items():
-            if nobj.state: # != 'DELETE':
-                pass
+    def saveObjects(self, objs, only=None, also=None):
+        """
+        Save some objects in the cache.  Map the object's oid to itself in
+        the dictionary C{self.objs} (which maps to *all* objects in the
+        cache).  By default, also add the object to the dictionary
+        C{self.dbroot[schema]}, where C{schema} is the object's _schema.id.
+        This default can be changed using the (mutually exclusive) C{only}
+        and C{also} parameters (see below).
+
+        @param objs:  objects to be saved
+        @type  objs:  list (usually of instances of
+            L{pangalactic.core.pgefobject.PgefObject}
+
+        @param only:  names of the cache dictionaries to add the object to
+            instead of the dictionary corresponding to the object's
+            _schema.id.
+        @type  only:  C{list} or C{str}
+
+        @param also:  names of the cache dictionaries to add the object to
+            addition to the dictionary corresponding to this object's
+            _schema.id.
+        @type  also:  C{list} or C{str}
+        """
+        # print "localdb.saveObjects"
+        if type(objs) is not list:
+            objs = [objs]
+        if only and also:
+            raise ValueError, '"only" and "also" are mutually exclusive'
+        for obj in objs:
+            self.objs[obj.pgef_oid] = obj
+            if not only:
+                if hasattr(obj, '_schema'):
+                    self.dbroot[obj._schema.id][obj.pgef_oid] = obj
+                    if also:
+                        if type(also) is list:
+                            for name in also:
+                                self.dbroot[name][obj.pgef_oid] = obj
+                        else:
+                            self.dbroot[also][obj.pgef_oid] = obj
             else:
-                childobj = self.getLookupObject(nobj.component)
-                if childobj:
-                    if project and getattr(childobj, 'project', None) == project:
-                        objdict[nid] = nobj
-        for nid, nobj in uncommitted_dict.items():
-            if nobj._schema.id == "Acu":
-                if objdict.has_key(nid):
-                    if nobj.state != 'DELETE':
-                        childobj = self.getLookupObject(nobj.component)
-                        objdict[nid] = nobj
+                if type(only) is list:
+                    for name in only:
+                        self.dbroot[name][obj.pgef_oid] = obj
                     else:
-                        del objdict[nid]
-                else:
-                    if nobj.state != 'DELETE':
-                        childobj = self.getLookupObject(nobj.component)
-                        objdict[nid] = nobj
-                    #else:
-                    #    print "skipping deleted acu", nid
-            #else:
-            #    print "skipping nonacu", nobj.name
-        return objdict
+                        self.dbroot[only][obj.pgef_oid] = obj
+        self.commit()
 
-    def GetAcuByComponent(self, component, project = None):
-        #print "localdb.getacubycomponentid"
-        acudict = self.GetLocalAcus(project)
-        retobj = None
-        for acuid, acuobj in acudict.items():
-            if acuobj.component == component.pgef_oid:
-                retobj = acuobj
-        return retobj
-
-    def GetLocalPartDocLinks(self, project = None):
-        #print "getlocalpartdoclinks"
-        pdr_dict = self.dbroot['Dcu']
-        uncommitted_dict = self.dbroot["Uncommitted"]
+    def saveObject(self, obj, only=None, also=None):
+        """
+        Convenience function for single object.  (See C{saveObjects}, which
+        will also accept a single object to save.)
+        """
+        self.saveObjects(obj, only, also)
 
-        objdict = {}
-        for pdrid, pdrobj in pdr_dict.items():
-            if pdrobj.state: # != 'DELETE':
-                pass
-                #print "skipping deleted pdr", pdrid
-            else:
-                parentobj = self.getLookupObject(pdrobj.product)
-                if project and parentobj.project == project:
-                    objdict[pdrid] = pdrobj
-
-        for pdrid, pdrobj in uncommitted_dict.items():
-            if pdrobj._schema.id == "ProductDocumentRelationship":
-                if objdict.has_key(pdrid):
-                    if pdrobj.state != 'DELETE':
-                        parentobj = self.getLookupObject(pdrobj.product)
-                        if project and parentobj.project == project:
-                            objdict[pdrid] = pdrobj
-#                        else:
-#                            print "skipping pdr", pdrid
-#
-                    else:
-                        #print "removing deleted pdr", pdrid
-                        del objdict[pdrid]
-                else:
-                    if pdrobj.state != 'DELETE':
-                        parentobj = self.getLookupObject(pdrobj.product)
-                        if project and parentobj.project == project:
-                            objdict[pdrid] = pdrobj
-#                    else:
-#                        print "skipping deleted pdr", pdrid
-#            else:
-#                print "skipping nonpdr"
-        return objdict
+    def getLocalObjects(self, object_schema_ids, project=None):
+        """
+        Get all objects with the specified ObjectSchema id from the
+        localdb.  If a project is specified, get only those that have a
+        C{project} attribute with that value.  (Note that that means if a
+        project is specified, only objects with a C{project} attribute will
+        be gotten -- which excludes Acu instances, for example
+
+        @param object_schema_ids:  a list of id's of C{ObjectSchema}
+            instances (a single id is okay, too)
+        @type  object_schema_ids:  C{list} or C{str}
 
-    def getLocalObjectsOfTypes(self, dictnamelist, project):
-        print "localdb.getlocalobjectsoftype"
-        dict_list = []
-        for dictname in dictnamelist:
-            print "dictname", dictname
-            dict_list.append((self.getDict(dictname), dictname))
-        uncommitted_dict = self.dbroot["Uncommitted"]
-        objdict = {}
-        for localdict, objclass in dict_list:
-            if localdict:
-                for nid, nobj in localdict.items():
-                    tmpobj = None
-                    if nobj.state != 'DELETE':
-                        tmpobj = self.getLookupObject(nobj.pgef_oid)
-                    elif tmpobj.state == None:
-                        tmpobj = self.getLookupObject(nobj.pgef_oid)
-                    if tmpobj:
-                        if hasattr(tmpobj, "project"):
-                            if project and tmpobj.project == project:
-    #                            tmpobj.project = tmpobj.project
-                                objdict[nid] = tmpobj
-                        else:
-                            objdict[nid] = tmpobj
-        for nid, nobj in uncommitted_dict.items():
-            classname = nobj._schema.id
-            #print nid, nobj.id, classname
-            for localdict, objclass in dict_list:
-                if classname == objclass:
-                    if objdict.has_key(nid):
-                        #print classname, "exists"
-                        if nobj.state != 'DELETE':
-                            #tmpobj = self.getLookupObject(nobj.pgef_oid)
-                            if hasattr(nobj, "project"):
-                                if project and nobj.project == project:
-#                                    nobj.project = nobj.project
-                                    objdict[nid] = nobj
-                            else:
-                                objdict[nid] = nobj
-                        else:
-                            del objdict[nid]
-                    else:
-                        #print classname, "new", nobj.id
-                        if nobj.state != 'DELETE':
-                            #tmpobj = self.getLookupObject(nobj.pgef_oid)
-                            if hasattr(nobj, "project"):
-                                if project and nobj.project == project:
-#                                    nobj.project = nobj.project
-                                    objdict[nid] = nobj
-                            else:
-                                objdict[nid] = nobj
-
-        #print "objdict", objdict.keys()
-        return objdict    
-
-    def lookupOid(self, oid):
-        """
-        Looks up the oid in the oidLookup dictionary to see in what
-        dictionary a particular object was placed.  This is mainly to help
-        speedup the retrieval of an object from the local cache.
-
-        @type oid: string
-        @param oid: internal id of an object
-        @return dictname:  the name of the internal dictionary where the
-            object is stored.
+        @param project:  a project oid
+        @type  project:  C{str}
         """
-        dictname = None
-        try:
-            dictname = self.dbroot[self.OIDLOOKUP][oid]
-        except KeyError:
-            pass
-        return dictname
-
-    def getDocuments(self):
-        # so far, the only documents with specialized editors are Alerts and Parts Lists.
-        # Thus we only ignore these types.
-        # isinstance is specifically used here for groups of classes
-        # print "localdb.getgeneraldocuments"
-        tmpdict = {}
-        for docoid, doc in self.dbroot['Document'].items():
-            if doc._schema.id == 'Document':
-                if doc.state is not None:
-                    tmpdict[docoid] = doc
-        for docid, doc in self.dbroot["Uncommitted"].items():
-            if isinstance(doc, Document) and not \
-               isinstance(doc, PartsList):
-                if doc.state != 'DELETE':
-                    tmpdict[docid] = doc
-        #print "# documents", len(tmpdict)
-        return tmpdict
-
-    def GetPartsLists(self):
-        tmpdict = {}
-        for docid, doc in self.dbroot['Document'].items():
-            if doc._schema.id == "PartsList":
-                if doc.state is not None:
-                    tmpdict[docid] = doc
-        for docid, doc in self.dbroot["Uncommitted"].items():
-            if doc._schema.id == "PartsList":
-                if doc.state != 'DELETE':
-                    tmpdict[docid] = doc
-        return tmpdict
+        print "localdb.getLocalObjects"
+        objs = []
+        if type(object_schema_ids) is not list:
+            object_schema_ids = [object_schema_ids]
+        for schema_id in object_schema_ids:
+            if self.dbroot.get(schema_id, None):
+                for obj in self.dbroot[schema_id].values():
+                    if (obj.state != 'DELETE'
+                        and (not project or
+                             (hasattr(obj, 'project')
+                              and obj.project == project))):
+                        objs.append(obj)
+            for obj in self.uncommittedobjs.values():
+                if obj._schema.id == schema_id:
+                    if (obj.state != 'DELETE'
+                        and (not project or
+                             (hasattr(obj, 'project')
+                              and obj.project == project))):
+                        objs.append(obj)
+        return objs
 
-    def ClearUncommittedObjects(self, committedobjs):
-        #print "localdb.clearuncommittedobjects", committedobjs
+    def getLocalObject(self, pgef_oid):
+        #print "localdb.getlocalobject", searchdict, pgef_oid
+        return self.objs[pgef_oid]
+
+    def clearUncommittedObjects(self, committedobjs):
+        print " - localdb.clearUncommittedObjects", committedobjs
         try:
             uncommittedobjs = self.dbroot["Uncommitted"]
             for obj in committedobjs:
-                #print "checking", obj.id
+                print "   checking", obj.pgef_oid
                 if uncommittedobjs.has_key(obj.pgef_oid):
                     del uncommittedobjs[obj.pgef_oid]
-                    #print "deleting", obj.id
+                    print "   deleting", obj.id
             self.dbroot["Uncommitted"] = uncommittedobjs
-
         except Exception, e:
-            print "exception: unable to clear uncommitted objects"
-        self.Commit()
-
-    def GetUncommittedDict(self):
-        uncommittedobjs = self.dbroot["Uncommitted"]
-        return uncommittedobjs
+            print "   exception: unable to clear uncommitted objects"
+        self.commit()
 
-    def GetUncommittedObjects(self, projectobjs):
+    def getUncommittedObjects(self):
         #print "localdb.getuncommittedobjects"
         try:
-            uncommittedobjs = self.dbroot["Uncommitted"] 
-            objlist = []
-            objkeys = projectobjs.keys()
-            for objid, obj in uncommittedobjs.items():
-                if objid in objkeys:
-                    objlist.append(obj)
-            return objlist
-
+            return self.dbroot["Uncommitted"].values()
         except:
             print "no uncommitted objects; returning empty list"
             return []
 
-    def getLocalObject(self, searchdict, pgef_oid):
-        #print "localdb.getlocalobject", searchdict, pgef_oid
-        try:
-            retobj = self.dbroot["Uncommitted"][pgef_oid]
-        except:
-            try:
-                retobj = self.dbroot[searchdict][pgef_oid]
-            except:
-                retobj = None
-        return retobj
+    ### TODO:  the Wf classes need ObjectSchemas
 
-    def GetUncommittedPartsListIDs(self):
-        return self.dbroot[self.UNCOMMITTEDPARTSLISTIDS]
+    def defaultDisplayConfig(self):
+        print "localdb.defaultDisplayConfig"
+        current_config = {}
+        for schemaid in self._registry.object_schemas:
+            print 'configuring display for schema:  %s' % schemaid
+            schema = self._registry.object_schemas[schemaid]
+            current_config[schemaid] = schema._default_display_map
+        self.setDisplayConfig(current_config)
+        print "default config done"
+        return current_config
 
-    def addProjectObjects(self, currproject, objlist):
-        # print "localdb.addprojectobjects", currproject, len(objlist)
-        objdict = {}
-        for obj in objlist:
-            objdict[obj.pgef_oid] = obj._schema.id
-        allobjects = self.GetProjectObjects()
-        if allobjects.has_key(currproject):
-            projobjs = allobjects[currproject]
-            objdict.update(projobjs)
-        allobjects[currproject] = objdict
-        self.SetProjectObjects(allobjects)
-        # print "allobjects", allobjects
-
-    def GetProjectObjects(self):
-        #print "localdb.getprojectobjecs"
-        projects = self.dbroot[self.PROJECTOBJECTS]
-        return projects
+    def getDisplayConfig(self):
+        print "localdb.getDisplayConfig"
+        foo = self.getDict('DisplayConfig')
+        # print "localdb.config.keys", foo.keys()
+        if not foo:
+            foo = self.defaultDisplayConfig()
+        return foo
 
-    def SetProjectObjects(self, objects):
-        #print "localdb.setprojectobjects"
-        try:
-            del self.dbroot[self.PROJECTOBJECTS]
-        except:
-            pass
-        self.dbroot[self.PROJECTOBJECTS] = objects
-        self.Commit()
+    def setDisplayConfig(self, config):
+        self.dbroot['DisplayConfig'] = config
+        self.commit()
+
+    def getUncommittedPartsListIDs(self):
+        return self.dbroot[self.UNCOMMITTEDPARTSLISTIDS]
 
     def getCommittedObjects(self):
         #print "localdb.getCommittedObjects"
         objdict = {}
-        for dictname in self.CommittedDicts:
-            objs = self.getDict(dictname)
+        for name in self.domain_names:
+            objs = self.getDict(name)
             # applications may only have some of the dicts that pgef has
             # None is returned if dictname doesn't exist in dbroot
             if objs:  
                 objdict.update(objs)
         return objdict
 
-    def GetObject(self, searchdict, id):
-        try:
-            return self.dbroot[searchdict][id]
-        except:
-            return None
-
-    def saveObjectWithLookup(self, dictname, objlist):
-        #print "localdb.savobjectwithlookup"
-        for obj in objlist:
-            self.dbroot[dictname][obj.pgef_oid] = obj
-            self.dbroot[self.OIDLOOKUP][obj.pgef_oid] = dictname
-
-    def saveObjectNoLookup(self, dictname, objlist):
-        #print "localdb.saveobjectnolookup", dictname, objlist
-        for obj in objlist:
-            self.dbroot[dictname][obj.pgef_oid] = obj
-
-    def saveObject(self, savedict, id, obj):
-        #print "localdb.saveobject", savedict, id
-        try:
-            self.dbroot[savedict][id] = obj
-            self.dbroot[self.OIDLOOKUP][obj.pgef_oid] = savedict
-        except Exception, e:
-            print "Eek.  An EXCEPTION.  localdb.saveObject", e
-            # print e
-            # import traceback
-            # traceback.print_exc()
-
     def AppendUncommittedData(self, uncommitteddict, unsavedlist):
         tmplist = self.dbroot[uncommitteddict]
         tmplist.extend(unsavedlist)
         self.dbroot[uncommitteddict] = tmplist
-        self.Commit()
+        self.commit()
 
     def SaveUncommittedData(self, uncommitteddict, unsavedlist):
         self.dbroot[uncommitteddict] = unsavedlist
-        self.Commit()
-
-    def SetProjects(self, objects):
-        self.dbroot[self.PROJECT] = objects
-        self.Commit()
+        self.commit()
 
-    def getDict(self, dictname):
+    def getDict(self, name):
         # applications may only have some of the dicts that pgef has
-        try:
-            return self.dbroot[dictname]
-        except:
-            return None
+        return self.dbroot.get(name, None)
 
-    def Save(self, unsavedlist, override = False):
-        print "localdb.Save() will be deprecated.  use localdb.save() instead."
-        self.save(unsavedlist, override)
-
-    def save(self, unsavedlist, override=False):
-        #print "localdb.save"
-        retlist = []
-        if unsavedlist:
-            for obj in unsavedlist:
-                classname = obj._schema.id
-                if classname == "WfProcessInstance":
-                    # saving a wfprocess is not typical, hence the specific save method
-                    if self.dbroot[self.WFPROCESSINSTANCE].has_key(obj.pgef_oid):
-                        if self.dbroot[self.WFPROCESSINSTANCE][obj.pgef_oid].state:
-                            if override:
-                                self.SaveWfProcessInstance([obj])
-                        else:
-                            self.SaveWfProcessInstance([obj])
-                    else:
-                        self.SaveWfProcessInstance([obj])
+    def add(self, objs):
+        """
+        Add new locally created objects to the cache.
+        """
+        # print "localdb.add"
+        self.saveObjects(objs, also='Uncommitted')
+        self.commit()
 
-                elif classname == "Acu":
-                    self.saveItWithLookup('Acu', obj, override)
-                    retlist.append(obj)
-
-                elif classname == "Person":
-                    self.saveUser(obj)
-
-                elif classname in self.DictListNames:
-                    #if classname == "WfEventAudit":
-                    #    print "found event"
-                    self.saveItWithLookup(classname, obj, override)
-                    retlist.append(obj)
-                else:
-                    print "NOTE:", classname, "is not in localdb.dictlist"
+    def removeObj(self, obj):
+        """
+        Remove an object from the local cache, either by direct reference
+        or by oid.
+
+        @param obj:  a PgefObject instance or the pgef_oid of an instance
+        @type  obj:  a subtype of C{PgefObject} or a C{str}
+        """
+        if type(obj) is str:
+            if self.objs[obj]:
+                del self.objs[obj]
+        elif obj.pgef_oid in self.objs:
+            del self.objs[obj.pgef_oid]
+        self.commit()
+
+    # FIXME:  Domain-specific stuff (everything from here on) shouldn't be
+    # in localdb
+
+    def SetProjects(self, objects):
+        self.dbroot['Project'] = objects
+        self.commit()
+
+    def getAcusByComponent(self, component):
+        """
+        Get all Acu's that have this C{Model} instance (or oid of a Model
+        instance) as a component (or its oid).
 
-        self.Commit()
-        return retlist
+        @param component:  a component C{Model} or its oid
+        @type  component:  C{Model} or C{str}
 
-    def saveItNoLookup(self, dictname, obj, override):
-        #print "saveitnolookup"
-        if self.dbroot[dictname].has_key(obj.pgef_oid):
-            if self.dbroot[dictname][obj.pgef_oid].state:
-                if override:
-                    self.saveObjectNoLookup(dictname, [obj])
+        @return:  list of Acu instances
+        @rtype:   C{list}
+        """
+        #print "localdb.getAcusByComponent"
+        acus = []
+        for obj in self.dbroot['Acu'].values():
+            if type(component) is str:
+                if (obj.component.pgef_oid == component):
+                    acus.append(obj)
             else:
-                self.saveObjectNoLookup(dictname, [obj])
-        else:
-            self.saveObjectNoLookup(dictname, [obj])
-
-    def saveItWithLookup(self, dictname, obj, override):
-        #print "saveitwithlookup", dictname, obj.id
-        if self.dbroot[dictname].has_key(obj.pgef_oid):
-            if self.dbroot[dictname][obj.pgef_oid].state:
-                if override:
-                    self.saveObjectWithLookup(dictname, [obj])
+                if (obj.component == component.pgef_oid
+                    or obj.component == component):
+                    acus.append(obj)
+        return acus
+
+    def getAcusByAssembly(self, assembly):
+        """
+        Get all Acu's that have this C{Model} instance (or oid of a Model
+        instance) as an assembly (or its oid).
+
+        @param assembly:  an assembly C{Model} or its oid
+        @type  assembly:  C{Model} or C{str}
+
+        @return:  list of Acu instances
+        @rtype:   C{list}
+        """
+        #print "localdb.getAcusByAssembly"
+        acus = []
+        for obj in self.dbroot['Acu'].values():
+            if type(assembly) is str:
+                if (obj.assembly.pgef_oid == assembly):
+                    acus.append(obj)
             else:
-                self.saveObjectWithLookup(dictname, [obj])
-        else:
-            self.saveObjectWithLookup(dictname, [obj])
-
-    def Add(self, unsavedlist):
-        # eventually remove this when all method calls have been changed
-        print "localdb.Add is deprecated.  use localdb.add"
-        self.add(unsavedlist)
-
-    def add(self, unsavedlist):
-        #print "localdb.add"
-        self.saveObjectWithLookup("Uncommitted", unsavedlist)
-        self.Commit()
-
-    def RemoveACU(self, acuobj):
-        if acuobj._schema.id == "Acu":
-            if self.dbroot['Acu'].has_key(acuobj.pgef_oid):
-                del self.dbroot['Acu'][acuobj.pgef_oid]
-        elif type(acuobj) is str:
-            if self.dbroot['Acu'].has_key(acuobj):
-                del self.dbroot['Acu'][acuobj]
-        self.Commit()
+                if (obj.assembly == assembly.pgef_oid
+                    or obj.assembly == assembly):
+                    acus.append(obj)
+        return acus
+
+    # strange special cases for Workflow stuff
 
     def getUncommittedWfObjects(self):
         try:
@@ -629,21 +391,17 @@
         print "localdb.getworkflows"
         wf_dict = self.getDict(self.WFPROCESSINSTANCE)
         uncommitted = self.getUncommittedWorkflows()
-        uncommitted_dict = {}
         for wf in uncommitted:
-            uncommitted_dict[wf.pgef_oid] = wf
-
+            self.uncommittedobjs[wf.pgef_oid] = wf
         objdict = {}
         for wfid, wfobj in wf_dict.items():
             if wfobj.state != 'DELETE':
                 tmpobj = self.getLocalObject(self.WFPROCESSINSTANCE, wfobj.pgef_oid)
             elif tmpobj.state == None:
                 tmpobj = self.getLocalObject(self.WFPROCESSINSTANCE, wfobj.pgef_oid)
-
             if tmpobj:
                 objdict[wfid] = tmpobj
-
-        for wfid, wfobj in uncommitted_dict.items():
+        for wfid, wfobj in self.uncommittedobjs.items():
             if wfobj.__class__.__name__ == "WfProcessInstance":
                 #print "wfobj.name", wfobj.name
                 if objdict.has_key(wfid):
@@ -664,118 +422,27 @@
         #print "objdict", objdict
         return objdict
 
-
-    def SaveWfProcessInstance(self, wflist, recurse = False):
+    def saveWfProcessInstance(self, wflist, recurse=False):
         #print "localdb.SaveWfProcessInstance"
+        self.saveObjects(wflist)
         for wfobj in wflist:
-            self.saveItWithLookup(self.WFPROCESSINSTANCE, wfobj, True)
             for entry in wfobj.history:
-                self.saveItWithLookup(self.WFEVENTAUDIT, entry, True)
-
+                self.saveObject(entry)
             if recurse:
-                for akey, avalue in wfobj.activities.items():
-                    #print "activity", akey, avalue.id, avalue.name, avalue.fields
-                    self.saveItWithLookup(self.WFACTIVITY, avalue, True)
-                for tkey, tvalue in wfobj.transitions_dict.items():
-                    self.saveItWithLookup(self.WFTRANSITION, tvalue, True)
-        self.Commit()
+                self.saveObjects(wfobj.activities.values())
+                self.saveObjects(wfobj.transitions_dict.values())
+        self.commit()
 
-
-    def addWfProcessInstance(self, wflist, recurse = False):
+    def addWfProcessInstance(self, wflist, recurse=False):
         #print "localdb.addWfProcessInstance"
+        self.saveObjects(wflist, only='Uncommitted')
         for wfobj in wflist:
-            self.saveItWithLookup("Uncommitted", wfobj, True)
             for entry in wfobj.history:
-                self.saveItWithLookup("Uncommitted", entry, True)
-
+                self.saveObjects(entry, only='Uncommitted')
             if recurse:
-                for akey, avalue in wfobj.activities.items():
-                    #print "activity", akey, avalue.id, avalue.name, avalue.fields
-                    self.saveItWithLookup("Uncommitted", avalue, True)
-                for tkey, tvalue in wfobj.transitions_dict.items():
-                    self.saveItWithLookup("Uncommitted", tvalue, True)
-        self.Commit()
-
-
-    def getOrganizations(self, context):
-        #print "localdb.getorganizations", context
-        orgs = {}
-        orgdict = self.getDict(self.ORGANIZATION)
-        for okey, org in orgdict.items():
-            if org.id_ns == context:
-                orgs[org.pgef_oid] = org
-        return orgs
-
-
-    def getCategories(self, context):
-        #print "localdb.getcategories", context
-        cats = {}
-        catdict = self.getDict('ObjectSchema')
-        if catdict.has_key(context):
-            cats = catdict[context]
-        return cats
-
-
-    def saveCategories(self, context, values, override = False):
-        #print "localdb.savecategories.values", context
-        if self.dbroot['ObjectSchema'].has_key(context):
-            #print "have dict", context
-            if override:
-                for entry in self.dbroot['ObjectSchema'][context].keys():
-                    del self.dbroot['ObjectSchema'][context][entry]
-                return
-        else:
-            #print "make dict", context
-            self.dbroot['ObjectSchema'][context] = PersistentMapping()  
-        #print "dict", 'ObjectSchema', context, len(values)
-        tmpdict = PersistentMapping()  
-        for obj in values:
-            #print obj.id, obj.name
-            tmpdict[obj.id] = obj
-        self.dbroot['ObjectSchema'][context] = tmpdict
-        self.Commit()
-
-    def getFiles(self, attrlist = None):
-        #print "localdb.getfiles", attrlist
-        if attrlist:
-            tmpdict = {}
-            for docid, doc in self.dbroot['FileLink'].items():
-                #print "checking", doc._schema.id, doc.id
-                retval_list = []
-                for attrname, op, attrvalue in attrlist:
-                    left = getattr(doc, attrname)
-                    #print "  eval", left, op, attrvalue
-                    tmpval = self.evalAttrExp(left, op, attrvalue)
-                    if tmpval:
-                        retval_list.append(tmpval)
-                    #else:
-                    #    print "  missing attribute", attrname
-                tmpdict[docid] = doc
-                for retval in retval_list:
-                    if not retval:
-                        del tmpdict[docid]
-                        break
-            return tmpdict
-        else:
-            return self.dbroot['FileLink']
-
-    def evalAttrExp(self, left, op, right):
-        #print "  eval", left, op, right
-        if left:
-            if hasattr(left, "date"):
-                left = left.date
-
-            qleft = '"' + str(left) + '"'
-            if op != "in":
-                qright = '"' + str(right) + '"'
-            else:
-                qright = str(right)
-            qop = " " + op + " "
-            tmpstr = qleft + qop + qright
-            tmpexp = compile(tmpstr, "", "eval")
-            tmpval = eval(tmpexp)
-            #print "tmpval", tmpval
-            return tmpval
-        return None
-
+                self.saveObjects(wfobj.activities.values(),
+                                 only='Uncommitted')
+                self.saveObjects(wfobj.transitions_dict.values(),
+                                 only='Uncommitted')
+        self.commit()
 

Index: PanGalactic/pangalactic/utils/datamanager.py
diff -u PanGalactic/pangalactic/utils/datamanager.py:1.173 PanGalactic/pangalactic/utils/datamanager.py:1.174
--- PanGalactic/pangalactic/utils/datamanager.py:1.173	Sun May  1 02:22:36 2005
+++ PanGalactic/pangalactic/utils/datamanager.py	Tue May  3 03:08:31 2005
@@ -1,10 +1,10 @@
-# $Id: datamanager.py,v 1.173 2005/05/01 06:22:36 waterbug Exp $
+# $Id: datamanager.py,v 1.174 2005/05/03 07:08:31 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_datamanager -*-
 
 """
 PanGalaxian's local workspace manager.
 
-@version: $Revision: 1.173 $
+@version: $Revision: 1.174 $
 """
 # TODO:  move the transaction/interface stuff, like XmlrpcInterface, into a
 # separate module -- InterfaceManager, which will handle all client
@@ -15,7 +15,7 @@
 # came from (repository, file import, etc.) and what their state is
 # (committed/uncommitted, etc.)
 
-__version__ = "$Revision: 1.173 $"[11:-2]
+__version__ = "$Revision: 1.174 $"[11:-2]
 
 import time
 import mx.DateTime
@@ -25,10 +25,6 @@
 import mimetypes
 from pprint import pprint
 
-import ZODB
-from ZODB import FileStorage
-# from ZODB import *
-
 # PanGalactic imports
 from pangalactic.core.person     import Person
 from pangalactic.core.project    import Project
@@ -38,7 +34,7 @@
 from pangalactic.utils                 import localdb
 from pangalactic.utils.httpupload      import upload
 from pangalactic.utils.pgefexceptions  import LocalStorageError
-from pangalactic.utils.pgefstate       import state
+from pangalactic.utils.pgefstate       import state, readState, writeState
 from pangalactic.utils.preferences     import prefs, readPrefs, writePrefs
 from pangalactic.utils.xmlrpcinterface import XmlrpcInterface
 
@@ -50,28 +46,27 @@
     # TODO:  all fns having to do w/servers,ports,etc will move to
     # InterfaceManager.
 
-    def __init__(self, _registry=None, clearcache=False,
-                 domains='PanGalactic', userid=None):
+    def __init__(self, _registry=None, domains='PanGalactic', userid=None):
         """
         Initialize a DataManager instance.
 
-        @param project:  the name of the current project
-        @type  project:  str
-
-        @param clear:  indicates whether to remove ZODB's files
-        @type  clear:  bool
+        @param _registry:  the PanGalacticRegistry instance (singleton)
+        @type  _registry:  L{pangalactic.meta.registry.PanGalacticRegistry}
 
         @param domains:  specifies which application domains to include
-        @type  domains:  str
+        @type  domains:  C{str}
 
-        @param _registry:  the PanGalacticRegistry instance (singleton)
-        @type  _registry:  L{pangalactic.meta.registry.PanGalacticRegistry}
+        @param userid:  the id of the invoking user (a Person oid)
+        @type  userid:  C{str}
         """
+        readState()
+        readPrefs()
         self._registry = _registry or PanGalacticRegistry()
         try:
-            self.localdb = localdb.LocalStorage(self._registry, clearcache)
-        except ZODB.POSException.StorageSystemError, e:
-            raise LocalStorageError, "Local Database StorageError"
+            self.cache = localdb.LocalStorage(self._registry)
+        except:
+            raise LocalStorageError, "LocalStorageError"
+        self.uncommittedobjs = self.cache.uncommittedobjs
         self.domains = domains
         self.user = Person(id = userid or state['userid'])
         self.server = None
@@ -139,10 +134,10 @@
                                _registry=self._registry)
 
     def getRoot(self):
-        return self.localdb.dbroot
+        return self.cache.dbroot
 
     def getPasswd(self, pwd_id):
-        return self.localdb.getPasswd(pwd_id)
+        return self.cache.getPasswd(pwd_id)
 
     def changePassword(self, login_pwd, new_pwd, userid="", secure=1):
         # print "update local passwds"
@@ -153,13 +148,13 @@
 
     def getConfigAccess(self):
         print "datamanager.getConfigAccess.GOD"
-        return localdb.god
+        return localdb.GOD
         if self.user.god:
-            return localdb.god
+            return localdb.GOD
         elif self.user.id == "admin":
-            return localdb.admin
+            return localdb.ADMIN
         else:
-            return localdb.user
+            return localdb.USER
 
     def getDisplayMap(self, mapname):
         print "DM.getDisplayMap"
@@ -172,32 +167,29 @@
             return {}
 
     def getDisplayConfig(self):
-        return self.localdb.getDisplayConfig()
+        return self.cache.getDisplayConfig()
 
     def setDisplayConfig(self, config):
-        self.localdb.setDisplayConfig(config)
+        self.cache.setDisplayConfig(config)
 
-    def getDict(self, collection):
+    def getDict(self, name):
         """
-        Wrapper for localdb.getDict
+        Get the {oid : obj} dictionary for the named ObjectSchema from the
+        cache (this is a wrapper for cache.getDict).
         """
-        return self.localdb.getDict(collection)
+        return self.cache.getDict(name)
 
     def getUser(self, userid):
-        return self.localdb.getUser(self.localdb.USER, userid)
-
-    def saveUser(self, user):
-        self.localdb.SaveUser(user)
+        return self.cache.getLocalObject(userid)
 
-    def newObject(self, classname):
+    def newObject(self, classname, **kw):
         """
         Create a new object with id "NEW" and with the current project and
         id namespace as its 'project' and 'id_ns' attributes, respectively.
         """
         # print "dm.newobject"
         if classname == "FileLink":
-            e = "FileLink should not be initialized here.  Use newFileLink."
-            raise ValueError, e
+            self.newFileLink(**kw)
         obj = None
         if classname in ["VersionedObject", "Part", "Model", "Document",
                          "PartsList"]:
@@ -205,33 +197,19 @@
             obj = klass(id="NEW",
                         id_ns=state['id_ns'],
                         project=state['project'],
-                        owner=self.user.id)
+                        owner=self.user.id,
+                        **kw)
         return obj
 
-    def newFileLink(self, parentobj, filename=None, drole="", 
-                    dlabel="", mime_type="text/plain", dsequence=-1):
-        classname = parentobj.__class__.__name__
-        if not filename:
-            filename = parentobj._upload_file_name
-        if (classname == "Document"):
-            obj = FileLink(_doc           = parentobj,
-                           name           = dlabel,
-                           parent         = parentobj.pgef_oid,
-                           mime_type      = mime_type,
-                           sequence       = dsequence,
-                           role           = drole,
-                           user_file_name = os.path.basename(filename))
-        elif classname == "Model":
-            obj = FileLink(_model         = parentobj,
-                           name           = dlabel,
-                           parent         = parentobj.pgef_oid,
-                           mime_type      = mime_type,
-                           sequence       = dsequence,
-                           role           = drole,
-                           user_file_name = os.path.basename(filename))
-        else:
-            return None
-        obj.setLocalFilename(filename)
+    def newFileLink(self, file_path='', dlabel='',
+                    mime_type='text/plain', sequence=-1,
+                    **kw):
+        obj = FileLink(name           = dlabel,
+                       mime_type      = mime_type,
+                       sequence       = sequence,
+                       user_file_name = os.path.basename(file_path),
+                       local_path     = os.path.abspath(file_path),
+                       **kw)
         return obj
 
     def login(self, userid, password, secure=1):
@@ -250,15 +228,15 @@
         user2save = copy.deepcopy(self.user)
         user2save._authorization = None
         user2save._password = None
-        self.saveUser(user2save)
-        self.localdb.savePasswds(password, password)
+        self.cache.saveObject(user2save)
+        self.cache.savePasswds(password, password)
         return True
 
-    def getItemsByProject(self, projectlist):
+    def getItemsByProject(self, project):
         """
         Retrieves the items associated with a project
         """
-        print "datamanager.getitemsbyproject"
+        print "dm.getItemsByProject"
         tempobjlist = []
         tempids = {}
         tlids = {}
@@ -270,30 +248,27 @@
             # only need to get the lowest level???  --vwk 8oct2003
             # need to make sure we get all the referenced objects filled
             # in.  pass in objs
-            print "NOTE: user is smallberries for testing"
-            # testing only - remove RSN
-            fieldnames = {"owner" : "smallberries"}
+            fieldnames = {"project" : project}
             docs = self.server.getObjects("Document",
                                           fields=fieldnames,
                                           refs=0,
                                           subtypes=0,
                                           objs=None)
-            # print "docs", docs
+            print "docs", docs
             # do we need to connect docs with parts/models?
-            fieldnames = {"project" : projectlist[0]}
             parts = self.server.getObjects("Part",
                                            fields=fieldnames,
                                            refs=0,
                                            subtypes=0,
                                            objs=None)
-            # print "parts", parts
-            objs = self.server.getObjects("Model",
+            print "parts", parts
+            models = self.server.getObjects("Model",
                                           fields=fieldnames,
                                           refs=0,
                                           subtypes=0,
                                           objs=None)
-            # print "obj", objs
-            # print "\n"
+            print "models", models
+            print "\n"
         except Exception, e:
             print "no items in project"
             import traceback
@@ -301,15 +276,15 @@
             print e
             return
         if docs:
-            # print "len docs", len(docs)
+            print "len docs", len(docs)
             for doc in docs:
                 tempobjlist.append(doc)
                 classname = doc.__class__.__name__
                 tempids[doc.pgef_oid] = classname
                 print "retrieving a", classname, doc.id
-        if objs:
-            # print "len objs", len(objs)
-            for item in objs:
+        if models:
+            print "len models", len(models)
+            for item in models:
                 tempobjlist.append(item)
                 classname = item.__class__.__name__
                 tempids[item.pgef_oid] = classname
@@ -318,51 +293,223 @@
                 elif classname == "Part":
                     print "retrieving a", classname
         if len(tempobjlist) > 0:
-            # print "len downloaded objs", len(tempobjlist)
-            self.localdb.save(tempobjlist)
-            # tbd - need to revisit after the project info is ironed out as
-            # this will not work for more than 1 project in the server
-            # call.
-            currproject = projectlist[0]
-            self.localdb.addProjectObjects(currproject, tempobjlist)
+            print "len downloaded models", len(tempobjlist)
+            self.cache.saveObjects(tempobjlist)
         else:
             print "datamanager.getitemsbyproject: no data found."
         return len(tempobjlist)
 
-    def getOrganizations(self, context = None):
-        # print "getorganizations"
-        objdict = self.localdb.getOrganizations(context)
-        if not objdict:
-            if state['loggedin']:
-                objlist = self.server.getOrganizations(context)
-                self.localdb.save(objlist, override = True)
-            else:
-                objlist = []
-            return objlist
-        return objdict.values()
-
     def add(self, addlist):
-        self.localdb.add(addlist)
+        self.cache.add(addlist)
+
+    def save(self, savelist):
+        self.cache.saveObjects(savelist)
+
+    def clearCache(self):
+        self.cache.clear()
+        self.cache.pack()
+
+    def getLocalObject(self, oid):
+        return self.cache.objs.get(oid, None)
+
+    def getLocalObjects(self, object_schemas, project=None):
+        return self.cache.getLocalObjects(object_schemas, project)
+
+    def approveUser(self, user_info):
+        print "dm.approve", user_info.email
+        self.server.approveUser(user_info)
+
+    def requestUser(self, user_info):
+        print "dm.requestuser"
+        server = self._createServer("anon", "anon")
+        server.requestUser(user_info)
+
+    # FIXME:  the parms arg is weird (see xmlrpcinterface)
+    def search(self, parms):
+        """
+        Search the repository.
+
+        @param parms:  search parameters
+        @type  parms:  dictionary
+        """
+        # print "datamanager.search"
+        try:
+            return self.server.search(parms, self.cache.objs.values())
+        except:
+            print "dm.search.xmlrpc.error"
+            return []
+
+    def uploadFile(self, obj):
+        """
+        Upload the file corresponding to a FileLink object.
+
+        @param obj:  a FileLink object.
+        @type  obj:  L{pangalactic.core.filelink.FileLink}
+        """
+        print " - dm.uploadFile:"
+        print "   - FileLink oid is %s" % obj.pgef_oid
+        print "   - file is %s" % obj.local_path
+        self._uploadFile(obj.pgef_oid, obj.local_path)
+
+    def _uploadFile(self, obj_oid, file_path):
+        """
+        Upload a file using httpupload.upload.
+
+        @param obj_oid:  oid of the FileLink object that corresponds to the
+            file to be uploaded.
+        @type  obj_oid:  C{str}
+
+        @param file_path:  path of the file to be uploaded (can be relative
+            or absolute).
+        @type  file_path:  C{str}
+        """
+        if os.path.exists(file_path):
+            print 'dm._uploadFile'
+            print "  - got file to upload: '%s'" % file_path
+            ctype, encoding = mimetypes.guess_type(file_path)
+            if ctype is None or encoding is not None:
+                # No guess could be made, or the file is encoded
+                # (compressed), so use a generic bag-of-bits type.
+                ctype = 'application/octet-stream'
+            upload(localpath = file_path,
+                   host = self.serverHost,
+                   port = self.serverPort,
+                   srvpath = "/upload",
+                   userid = self.user.id,
+                   passwd = self.user._password,
+                   secure = 1,
+                   useragent = "",
+                   oid = obj_oid,
+                   mimetype = ctype)
+            # print "uploaded"
+        else:
+            print "UploadError:", file_path, "does not exist"
+
+    # FIXME:  files paradigm has changed ...
+    def getFiles(self, obj_list):
+        # print "dm.getfiles", obj_list
+        pgefoids = [a.pgef_oid for a in obj_list]
+        attrlist = [("parent", "in", pgefoids)]
+        parms_dict = {"FileLink" : attrlist}
+        objs_to_link = []
+        objs_to_link.extend(obj_list)
+        local_files = self.cache.getFiles(attrlist)
+        objs_to_link.extend(local_files)
+        # print "parms_dict", parms_dict
+        if state['loggedin']:
+            # print "search server"
+            try:
+                obj_files = self.server.search(parms_dict, objs_to_link)
+                # print "nfiles", len(obj_files)
+            except Exception, e:
+                print "EXCEPTION: dm.getfiles.xmlrpc.error"
+                # import traceback
+                # traceback.print_exc()
+                print e
+                return []
+            self.save(obj_files)
+            return obj_files
+        else:
+            # print "search cache"
+            return local_files
 
-    def save(self, savelist, override = False):
-        self.localdb.save(savelist, override)
+    def uncommittedData(self):
+        """
+        Check for uncommitted work.
+        """
+        print "datamanager.uncommittedData()"
+        if self.getUncommittedObjs():
+            print '  -> yes, uncommitted objects'
+            return True
+        else:
+            print '  -> no uncommitted objects'
+            return False
 
-    def setAction(self, actionflag, searchdict, id):
-        obj = self.localdb.GetObject(searchdict, id)
-        if obj:
-            obj.state = actionflag
+    def commit(self, unsavedobjs):
+        print "datamanager.commit()"
+        if state['loggedin']:
+            # print "  - logged in"
+            if len(unsavedobjs) > 0:
+                # print "  - unsaved", len(unsavedobjs)
+                addlist = []
+                dellist = []
+                for obj in unsavedobjs:
+                    # check for unset attributes and commit-related stuff
+                    # print "  - checking", obj.id, obj.name
+                    obj.creator = self.user.id
+                    if not obj.owner:
+                        obj.owner = obj.creator
+                    if not obj.modifier:
+                        obj.modifier = obj.creator
+                    print "  - setting is_head = True for", obj.__class__.__name__, obj.id
+                    obj.is_head = True
+                    if obj.state == 'DELETE':
+                        obj.mod_datetime = time.strftime("%m/%d/%Y %H:%M:%S")
+                        dellist.append(obj)
+                    elif obj.state == 'MODIFY':
+                        obj.mod_datetime = time.strftime("%m/%d/%Y %H:%M:%S")
+                        addlist.append(obj)
+                    elif obj.state == 'ADD':
+                        addlist.append(obj)
+                actionlist = []
+                # print "  - len addlist", len(addlist)
+                if len(addlist) > 0:
+                    # print "  - call server add"
+                    # we should get back a list of updated objects
+                    # print "  - updated objects are passed back at the end of the list"
+                    objs_to_hookup = self.cache.getCommittedObjects().values()
+                    # print '  - objs_to_hookup (passed to addObjects()):'
+                    # pprint(objs_to_hookup)
+                    # print '  - addlist (objs to add, passed to addObjects()):'
+                    # pprint(addlist)
+                    retval = self.server.addObjects(addlist, objs_to_hookup)
+                    if retval:
+                        for obj in addlist:
+                            obj.state = None
+                            actionlist.append(obj)
+                            if obj.__class__.__name__ == "FileLink":
+                                self.uploadFile(obj)
+                    else:
+                        print "Commit to database failed - addObjects"
+#                if len(dellist) > 0:
+                    # print "datamanager.commit.delete is TBD?"
+                    # retval = self.server.CallServerFunction(dellist, "DelObjects", self.auth)
+                    # if retval:
+                        ## print "del failed"
+                        # for obj in dellist:
+                            # obj.state = None
+                            # obj.record_create_datetime = retval
+                            # obj.record_mod_datetime = retval
+                            # actionlist.append(obj)
+#                    else:
+#                        print "del succeeded"
+                # reset the status flags for the committed objects
+                self.cache.saveObjects(actionlist)
+                self.cache.clearUncommittedObjects(actionlist)
+            else:
+                print "nothing to save"
+        else:
+            print "not logged in; saving objs to cache"
+            self.cache.add(unsavedobjs)
+        self.refresh = False
+        return retval
+
+    def getUncommittedObjs(self):
+        return self.cache.getUncommittedObjects()
 
-    def clearLocalDB(self):
-        self.localdb.Clear()
+    def getUncommittedOids(self):
+        uncommitted_oids = self.cache.uncommittedobjs.keys()
+        # print "uncomm oids", uncommitted_oids
+        return uncommitted_oids
 
-    def packLocalDB(self):
-        self.localdb.Pack()
+    # FIXME:  domain-specific stuff (everything from here on) should not be
+    # in DM -- probably should be in PanGalaxian.
 
     def getProjects(self, context='http://pangalactic.us/test/'):
         """
         Get a list of projects.  If logged in, get them from the
         repository, save them locally, and return them as a list.
-        If local, check whether there are any in localdb; if not, add the
+        If local, check whether there are any in cache; if not, add the
         NoProject project.
         """
         if context == 'test' and prefs.get('context', None):
@@ -389,186 +536,61 @@
                                  id='NoProject',
                                  name='Ni',
                                  description='No project specified')]
-            self.localdb.save(projs)
+            self.save(projs)
         else:
-            print "  in local mode -- checking localdb for projects ..."
-            self.projects = self.localdb.getDict(self.localdb.PROJECT)
+            print "  in local mode -- checking cache for projects ..."
+            self.projects = self.cache.getDict('Project')
             if not self.projects:
                 print '  no local projects ... using NoProject.'
-                self.localdb.save([
+                self.save([
                     Project(pgef_oid='NoProject',
                             id='NoProject',
                             name='Ni',
                             description='No project specified')])
-        self.projects = self.localdb.getDict(self.localdb.PROJECT)
+        self.projects = self.cache.getDict('Project')
         print '  ... returning projects:', self.projects.keys()
         return self.projects
 
-    def getLookupObject(self, pgef_oid):
-        # print "datamanager.getLookupObject", pgef_oid
-        return self.localdb.getLookupObject(pgef_oid)
-
-    def getObject(self, dict, oid):
-        obj = self.localdb.GetLocalObject(dict, oid)
-        return obj
-
-    def getLocalAcus(self, project=None):
-        return self.localdb.GetLocalAcus(project)
-
-    def getAcuByComponent(self, obj, project = None):
-        return self.localdb.GetAcuByComponent(obj, project)
+    def getAcusByAssemblyOid(self, oid):
+        """
+        Retrieves from the server all Acus associated with an assembly oid.
+        """
+        print "- in dm.getAcusByAssemblyOid"
+        print "  - assembly oid:  %s" % oid
+        keydict = {"assembly" : oid}
+        objs = self.server.getLinkedObjs('Acu', keydict,
+                                         self.cache.objs.values())
+        print 'found objs:', objs
+        self.cache.saveObjects(objs)
+        print "  - found acus:  %s" % str([o.pgef_oid for o in objs])
+        print "- end dm.getAcusByAssemblyOid"
+        return objs
+
+    def getLocalAcusByAssemblyOid(self, oid):
+        print " - in dm.getLocalAcusByAssemblyOid"
+        localacus = self.getLocalObjects(['Acu'])
+        print "   local acus:  %s" % str([o.pgef_oid for o in localacus])
+        acus = []
+        for obj in localacus:
+            if obj.assembly == oid:
+                acus.append(obj)
+            elif getattr(obj.assembly, 'pgef_oid', '') == oid:
+                acus.append(obj)
+        print "   local acus with assembly oid == %s:  %s" % (oid,
+                                        str([o.pgef_oid for o in acus]))
+        return acus
+
+    def removeLocalAcu(self, acu):
+        self.cache.removeObj[acu]
 
-    def getLinkedObjsByAcu(self, tmp_obj):
-        # build the list of objects to send back to the server for linkup
-        project_objs = []
-        allprojlist = self.localdb.GetProjectObjects()
-        if allprojlist.has_key(state['project']):
-            projects = allprojlist[state['project']]
-            for poid in projects:
-                obj = self.localdb.getLookupObject(poid)
-                project_objs.append(obj)
-
-        keydict = {"assembly" : tmp_obj.pgef_oid}
-        objlist = self.server.getLinkedObjs("Acu", keydict, project_objs)
-        return objlist
-
-    def getNAUOByAssemblyID(self, assemblyIds):
-        """
-        Retrieves all of the Acus associated with a list of assembly ids.
-        """
-        # print "datamanager.getnauobyassemblyid"
-        retlist = []
-        objlist = []
-        for id in assemblyIds:
-            temp_obj = self.localdb.getLookupObject(id)
-            if not temp_obj:
-                return
-            objlist = self.getLinkedObjsByAcu(temp_obj)
-            if not objlist:
-                return []
-            nauoobjs = []
-            itemobjs = []
-            modelobjs = []
-            for obj in objlist:
-                if obj.isEmpty():
-                    continue
-                classname = obj.__class__.__name__ 
-                if classname == "Acu":
-                    nauoobjs.append(obj)
-                    # print obj.assembly.id, "->", obj.component.id
-                elif classname == "Part":
-                    itemobjs.append(obj)
-                elif classname == "Model":
-                    modelobjs.append(obj)
-            if len(nauoobjs) > 0:
-                updatedacuobjs = []
-                nauoids = []
-                updatedacuobjs = self.localdb.save(nauoobjs)
-#                print "updatedacuobjs", updatedacuobjs
-            # add the nauos to the projectobject dictionary in localdb
-            self.localdb.addProjectObjects(state['project'], nauoobjs)
-            if len(itemobjs) > 0:
-                self.localdb.save(itemobjs)
-            break # only do the first one for now
-        for obj in objlist:
-            classname = obj.__class__.__name__
-            if classname in ["Acu", "Part", "Model"]:
-                item = self.localdb.getLookupObject(obj.pgef_oid)
-                retlist.append(item)
-        # print "end datamanager.getnauobyassemblyid"
-        return retlist
-
-    def getLocalAcusByAssemblyID(self, assemblyId, project):
-        # print "datamanager.getlocalacusbyassemblyid"
-        localacus = self.localdb.GetLocalAcus(project)
-        retlist = []
-        for acu_id, acuobj in localacus.items():
-            if acuobj.assembly == assemblyId:
-                retlist.append(acuobj)
-        return retlist
-
-    def getParts(self):
-        return self.localdb.getDict(self.localdb.PART)
-
-    def getLocalObjectsOfTypes(self, classnamelist, project=None):
-        return self.localdb.getLocalObjectsOfTypes(classnamelist, project)
-
-    def getDocPartLinks(self):
-        return self.localdb.getDict(self.localdb.DOCPTREL)
-
-    def getPartDocLinksByProjectId(self, project_id):
-        return self.localdb.GetLocalPartDocLinks(project_id)
-
-    def getPartDocLinksByPartId(self, idlist):
-        """Retrieves all of the DocPtRels associated with a Part ID"""
-        # print "datamanager.getpartdoclinkbypartid"
-        for objid in ItemIdList:
-            fieldnames = {"document" : objid}
-            objlist = self.server.getObjects("DocPtRel",
-                                             fields = fieldnames,
-                                             refs = 1,
-                                             subtypes = 0,
-                                             objs = None)
-            pdrids = []
-            pdrobjs = []
-            itemobjs = []
-            partslistobjs = []
-            documentobjs = []
-            for obj in objlist:
-                if obj.isEmpty():
-                    continue
-                classname = obj.__class__.__name__
-                if classname == "DocPtRel":
-                    pdrids.append(obj.pgef_oid)
-                    pdrobjs.append(obj)
-                elif classname == "PartsList":
-                    self.partsListIDs[obj.pgef_oid] = obj.id
-                    partslistobjs.append(obj)
-                elif classname == "Document":
-                    self.documentIDs[obj.pgef_oid] = obj.id
-                    documentobjs.append(obj)
-                else:
-                    print "found what?  a", classname
-            if len(partslistobjs) > 0:
-                self.localdb.save(partslistobjs)
-            if len(documentobjs) > 0:
-                self.localdb.save(documentobjs)
-            if len(pdrobjs) > 0:
-                self.localdb.save(pdrobjs)
-            if len(pdrids) > 0:
-                self.pdrIDs[id] = pdrids
-                self.localdb.dbroot['DocPtRelIds'][id] = pdrids
-                newpdrs = []
-                for pdr in pdrobjs:
-                    if pdr.name in ["document", "parts_list"]:
-                        newpdrs.append(pdr)
-                    else:
-                        print "retrieved a pdr that is neither a document nor a parts_list"
-                self.localdb.save(newpdrs)
-            break # only do the first one for now (we only send one at this time)
-        returnlist = []
-        returnlist.extend(pdrobjs)
-        returnlist.extend(partslistobjs)
-        returnlist.extend(documentobjs)
-        return returnlist
-
-    def removeLocalAcu(self, obj):
-        self.localdb.RemoveACU(obj)
-
-    def removeAcu(self, AcuID, prompt = True):
-        """
-        Removes the node from the tree and also from the ACU list.
-        Currently uses the NauoIDs list, and also from
-        local storage via the self.localdb object
+    def removeAcu(self, acu_oid):
+        """
+        Removes the node from the tree and also from the Acu list.
         """
-        ACUobj = self.localdb.getLocalObject(self.localdb.ACUDICT, AcuID)
-        ACUobj.state = 'DELETE'
+        obj = self.getLocalObject(acu_oid)
+        obj.state = 'DELETE'
         # delete the entry for AcuID from the dictionary of its parent
-        try:          
-            if self.nauoIDs.has_key(ACUobj.pgef_oid):
-                del self.nauoIDs[ACUobj.pgef_oid]
-        except:
-            parent_ids = self.nauoIDs['ROOT']
+        self.cache.removeObj[acu_oid]
         for acus in self.nauoIDs.keys():
             temp = self.nauoIDs[acus]
             for key, value in temp.items():
@@ -580,28 +602,6 @@
     def clearNauoIDs(self):
         self.nauoIDs.clear()
 
-    def uncommittedData(self):
-        """
-        Check for uncommitted work.
-        """
-        print "datamanager.uncommittedData()"
-        if not state['project']:
-            return False
-        allprojectobjs = self.localdb.GetProjectObjects()
-        print '  -> allprojectobjs:'
-        pprint(allprojectobjs)
-        if allprojectobjs.has_key(state['project']):
-            projectobjs = allprojectobjs[state['project']]
-            if len(self.localdb.GetUncommittedObjects(projectobjs)) > 0:
-                print '  -> yes, uncommitted objects for', state['project']
-                return True
-            else:
-                print '  -> no uncommitted objects for', state['project']
-                return False
-        else:
-            print 'This is weird -- no projectobj for', state['project']
-            return False
-
     def addAcu(self, acu_to_add, acu_parent):
         # print "datamanager.addacu"
         if acu_parent == 'ROOT':
@@ -651,82 +651,44 @@
             newdict = {}
             newdict[acu_parent.pgef_oid] = newlist
             self.nauoIDs[acu_parent.component] = newdict
-        self.localdb.add([acu_to_add])
-        self.localdb.addProjectObjects(state['project'], [acu_to_add])
-
-    def addProjectObjects(self, projname, objlist):
-        self.localdb.addProjectObjects(projname, objlist)
-
-    def approveUser(self, user_info):
-        print "dm.approve", user_info.email
-        self.server.approveUser(user_info)
-
-    def requestUser(self, user_info):
-        print "dm.requestuser"
-        server = self._createServer("anon", "anon")
-        server.requestUser(user_info)
-
-    def search(self, classattrdict):
-        # print "datamanager.search", classattrdict
-        objs_to_hookup = self.localdb.getCommittedObjects()
-        try:
-            self.searchresults = self.server.search(classattrdict, objs_to_hookup)
-            # print "# results", len(self.searchresults)
-        except:
-            print "dm.search.xmlrpc.error"
-            return []
-
-    def searchOrgs(self, attrlist):
-        print "dm.searchorgs; more TBD RSN", attrlist
-        print "NOTE: search returns fake results for now"
-        if state['loggedin']:
-            objlist = self.server.getOrganizations("test") #"CAGE") # CAGE will work RSN?
-            self.localdb.save(objlist, override = True)
-            self.searchresults = objlist
-        else:
-            objdict = self.localdb.getOrganizations("test")
-            self.searchresults = objdict.values()
-
-    def getSearchResults(self):
-        # print "datamanager.getsearchresults"
-        return getattr(self, 'searchresults', [])
+        self.cache.add([acu_to_add])
 
     def getUncommittedWorkflows(self):
-        return self.localdb.getUncommittedWorkflows()
+        return self.cache.getUncommittedWorkflows()
 
     def getUncommittedWfObjects(self):
-        return self.localdb.getUncommittedWfObjects()
+        return self.cache.getUncommittedWfObjects()
 
     def getWorkflows(self, attrlist = None):
         # print "datamanager.getworkflows"
         if state['loggedin']:
             print "NOTE: dm.getworkflows.need to get workflows from server tbd"
-            return self.localdb.GetWorkflows(attrlist)
+            return self.cache.GetWorkflows(attrlist)
         else:
-            return self.localdb.GetWorkflows(attrlist)
+            return self.cache.GetWorkflows(attrlist)
 
     def saveWfProcessInstance(self, wf_obj, wfdata, recurse = True):
         # print "dm.savewfprocessinstance"
         wf_obj.wfdata = wfdata
         wf_obj.wfdata_name = wf_obj.wfdata.getName()
         # print "wf_obj", wf_obj
-        self.localdb.SaveWfProcessInstance([wf_obj], recurse)
+        self.cache.SaveWfProcessInstance([wf_obj], recurse)
 
     def addWfProcessInstance(self, wf_obj, wfdata, recurse = True):
         print "dm.addwfprocessinstance"
         wf_obj.wfdata = wfdata
         wf_obj.wfdata_name = wf_obj.wfdata.getName()
         # print "wf_obj", wf_obj
-        self.localdb.addWfProcessInstance([wf_obj], recurse)
+        self.cache.addWfProcessInstance([wf_obj], recurse)
 
     def saveWfProcessTemplate(self, wf_obj):
-        self.localdb.SaveWfProcessTemplate([wf_obj], recurse = True)
+        self.cache.SaveWfProcessTemplate([wf_obj], recurse = True)
 
     def addWfProcessTemplate(self, wf_obj):
-        self.localdb.addWfProcessTemplate([wf_obj], recurse = True)
+        self.cache.addWfProcessTemplate([wf_obj], recurse = True)
 
     def addWorkflow(self, wf_obj):
-        self.localdb.add([wf_obj])
+        self.cache.add([wf_obj])
 
     def getWfProcessTemplate(self, template_oid):
         templatedict = self.getWfProcessTemplates()
@@ -734,178 +696,14 @@
 
     def getWfProcessTemplates(self):
         # print "datamanager.getWfProcessTemplates"
-        templatedict = self.localdb.GetLocalWorkflowTemplates()
-        if len(templatedict) > 0:
-            return templatedict
-        else:
-            wfobjlist = wffactory.getDefaultWorkflows()
-            wfobjdict = {}
-            for wfobj in wfobjlist:
-                self.localdb.SaveWfProcessTemplate([wfobj], recurse = True)
-                wfobjdict[wfobj.pgef_oid] = wfobj
-            return wfobjdict
-
-    def _uploadFile(self, obj_oid, file_name):
-        if os.path.exists(file_name):
-            print 'dm._uploadFile'
-            print "  - got file to upload: '%s'" % file_name
-            ctype, encoding = mimetypes.guess_type(file_name)
-            if ctype is None or encoding is not None:
-                # No guess could be made, or the file is encoded (compressed), so
-                # use a generic bag-of-bits type.
-                ctype = 'application/octet-stream'
-            upload(localpath = file_name,
-                   host = self.serverHost,
-                   port = self.serverPort,
-                   srvpath = "/upload",
-                   userid = self.user.id,
-                   passwd = self.user._password,
-                   secure = 1,
-                   useragent = "",
-                   oid = obj_oid,
-                   mimetype = ctype)
-            # print "uploaded"
-        else:
-            print "UploadError:", file_name, "does not exist"
-
-    def uploadFile(self, obj):
-        print "datamanager.uploadfile", obj.id, obj._local_file_name
-        self._uploadFile(obj.pgef_oid, obj._local_file_name)
-
-    def commit(self, unsavedobjs):
-        print "datamanager.commit()"
-        if state['loggedin']:
-            # print "  - logged in"
-            if len(unsavedobjs) > 0:
-                # print "  - unsaved", len(unsavedobjs)
-                addlist = []
-                dellist = []
-                for obj in unsavedobjs:
-                    # check for unset attributes and commit-related stuff
-                    # print "  - checking", obj.id, obj.name
-                    obj.creator = self.user.id
-                    if not obj.owner:
-                        obj.owner = obj.creator
-                    if not obj.modifier:
-                        obj.modifier = obj.creator
-                    print "  - setting is_head = True for", obj.__class__.__name__, obj.id
-                    obj.is_head = True
-                    if obj.state == 'DELETE':
-                        obj.mod_datetime = time.strftime("%m/%d/%Y %H:%M:%S")
-                        dellist.append(obj)
-                    elif obj.state == 'MODIFY':
-                        obj.mod_datetime = time.strftime("%m/%d/%Y %H:%M:%S")
-                        addlist.append(obj)
-                    elif obj.state == 'ADD':
-                        addlist.append(obj)
-                actionlist = []
-                # print "  - len addlist", len(addlist)
-                if len(addlist) > 0:
-                    # print "  - call server add"
-                    # we should get back a list of updated objects
-                    # print "  - updated objects are passed back at the end of the list"
-                    objs_to_hookup = self.localdb.getCommittedObjects().values()
-                    # print '  - objs_to_hookup (passed to addObjects()):'
-                    # pprint(objs_to_hookup)
-                    # print '  - addlist (objs to add, passed to addObjects()):'
-                    # pprint(addlist)
-                    retval = self.server.addObjects(addlist, objs_to_hookup)
-                    if retval:
-                        for obj in addlist:
-                            obj.state = None
-                            actionlist.append(obj)
-                            if obj.__class__.__name__ == "FileLink":
-                                self.uploadFile(obj)
-                    else:
-                        print "Commit to database failed - AddObjects"
-#                if len(dellist) > 0:
-                    # print "datamanager.commit.delete is TBD?"
-                    # retval = self.server.CallServerFunction(dellist, "DelObjects", self.auth)
-                    # if retval:
-                        ## print "del failed"
-                        # for obj in dellist:
-                            # obj.state = None
-                            # obj.record_create_datetime = retval
-                            # obj.record_mod_datetime = retval
-                            # actionlist.append(obj)
-#                    else:
-#                        print "del succeeded"
-                # reset the status flags for the committed objects
-                self.localdb.save(actionlist, override = True)
-                self.localdb.ClearUncommittedObjects(actionlist)
-            else:
-                print "nothing to save"
-        else:
-            print "not logged in"
-            self.localdb.add(unsavedobjs)
-        self.refresh = False
-        return retval
-
-    def getUncommittedOids(self):
-        uncommitted_oids = self.localdb.GetUncommittedDict().keys()
-        # print "uncomm oids", uncommitted_oids
-        return uncommitted_oids
-
-    def getUncommittedObjs(self):
-        uncommitted_objs = self.localdb.GetUncommittedDict()
-        return uncommitted_objs
-
-    def getCategories(self, context):
-        # print "datamanager.getcategories"
-        objdict = self.localdb.getCategories(context)
-        if not objdict:
-            if state['loggedin']:
-                objlist = self.server.getCategories(context)
-                self.localdb.saveCategories(context, objlist)
-            else:
-                objlist = []
-            return objlist
-        return objdict.values()
-
-    def translateAttrinfo(self, attrinfo):
-        # print "dm.translateattrinfo", attrinfo
-        if attrinfo[1] == "IS NOT":
-#            print "NOTE: <IS NOT> is not yet implemented?"
-            server_info = (attrinfo[0], attrinfo[1], "NULL")
-            local_info = (attrinfo[0], "<>", None)
-        elif attrinfo[1] == "IS":
-#            print "NOTE: <IS> is not yet implemented?"
-            server_info = (attrinfo[0], attrinfo[1], "NULL")
-            local_info = (attrinfo[0], "==", None)
-        elif attrinfo[1] == "==":
-            server_info = (attrinfo[0], "=", attrinfo[2])
-            local_info = attrinfo
-        else:
-            server_info = attrinfo
-            local_info = attrinfo
-        return (server_info, local_info)
-
-    def getFiles(self, obj_list):
-        # print "dm.getfiles", obj_list
-        pgefoids = [a.pgef_oid for a in obj_list]
-        attrlist = [("parent", "in", pgefoids)]
-        classattrdict = {"FileLink" : attrlist}
-        objs_to_link = []
-        objs_to_link.extend(obj_list)
-        local_files = self.localdb.getFiles(attrlist)
-        objs_to_link.extend(local_files)
-        # print "classattrdict", classattrdict
-        if state['loggedin']:
-            # print "search server"
-            try:
-                obj_files = self.server.search(classattrdict, objs_to_link)
-                # print "nfiles", len(obj_files)
-            except Exception, e:
-                print "EXCEPTION: dm.getfiles.xmlrpc.error"
-                # import traceback
-                # traceback.print_exc()
-                print e
-                return []
-            self.save(obj_files)
-            return obj_files
-        else:
-            # print "search localdb"
-            return local_files
+        templates = self.cache.getLocalObjects(['WorkflowTemplate'])
+        if len(templates) > 0:
+            return templates
+        else:
+            wfobjs = wffactory.getDefaultWorkflows()
+            for wfobj in wfobjs:
+                self.cache.SaveWfProcessTemplate([wfobj], recurse = True)
+            return wfobjs
 
     def commitWfObjs(self, unsavedobjs = None):
         print "datamanager.commitwfs"
@@ -914,7 +712,7 @@
         fileaddlist = []
         genfilelist = []
         if not unsavedobjs:
-            unsavedobjs = self.localdb.getUncommittedWfObjects()
+            unsavedobjs = self.cache.getUncommittedWfObjects()
         timetuple = mx.DateTime.now()
         newtime = timetuple.strftime("%m/%d/%Y %H:%M:%S")
         retval = None
@@ -960,10 +758,10 @@
                     # do we ever delete?
                     pass
                 # reset the status flags for the committed objects
-                self.localdb.save(actionlist, override = True)
-                self.localdb.ClearUncommittedObjects(actionlist)
+                self.cache.saveObjects(actionlist)
+                self.cache.clearUncommittedObjects(actionlist)
         else:
-            self.localdb.add(unsavedobjs)
+            self.cache.add(unsavedobjs)
         self.Refresh = False
         if retval:
             return retval

Index: PanGalactic/pangalactic/utils/xmlrpcinterface.py
diff -u PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.78 PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.79
--- PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.78	Sun Apr 10 23:31:28 2005
+++ PanGalactic/pangalactic/utils/xmlrpcinterface.py	Tue May  3 03:08:31 2005
@@ -3,10 +3,10 @@
 """
 PanGalactic Client XML-RPC Interfaces
 
-@version: $Revision: 1.78 $
+@version: $Revision: 1.79 $
 """
 
-__version__ = "$Revision: 1.78 $"[11:-2]
+__version__ = "$Revision: 1.79 $"[11:-2]
 
 import base64
 import xmlrpclib
@@ -142,16 +142,10 @@
                                  password))
         else:
             self._RPC =  xmlrpclib.ServerProxy(conns)
-
         self.not_yet_list = ["PartsList",
                              "GidepAgencyActionNotice",
                              "GidepProductChangeNotice",
                              "GidepDmsmsNotice"]
-#                             "GidepAlert",
-#                             "GidepProblemAdvisory",
-#                             "NasaAdvisory",
-#                             "ProblemImpactStatement"]
-    
 
     def yo(self):
         return self._RPC.yo()
@@ -242,7 +236,6 @@
         #else:
         #    print "no data"
 
-
     def getCategories(self, context):
         """
         Get all Category objects for the given context.
@@ -253,7 +246,6 @@
             newobjs, objs = self._factory.rememberAll(data, [])
             return newobjs
 
-
     def getOrganizations(self, context):
 #        print "xmlrpc.getorganizations", context
         crit = {"id_ns" : context}
@@ -262,16 +254,13 @@
             newobjs, objs = self._factory.rememberAll(data, [])
             return newobjs
 
-
-    def getLinkedObjs(self, classname, criteria, objs = None):
+    def getLinkedObjs(self, schema_id, criteria, objs=None):
         #print "xmlrpcinterface.getlinkedobjs"
-        if objs == None:
-            objs = []
-        data = self._RPC.getObjects(classname, 1, 0, criteria)
+        newobjs = []
+        data = self._RPC.getObjects(schema_id, 1, 0, criteria)
         if data:
             newobjs, objs = self._factory.rememberAll(data, objs)
-            return newobjs
-
+        return newobjs
 
     def approveUser(self, user_info):
         print "xmlrpc.approveuser"
@@ -279,7 +268,6 @@
     def requestUser(self, user_info):
         print "xmlrpc.requestuser"
 
-        
     def search(self, class_attr_dict, localobjs = None):
         """
         Return a list of objects in any of the classes in class_attr_dict
@@ -318,9 +306,7 @@
             else:
                 print "no data found for", classname
         return retlist        
-    
-        
-        
+
     def searchAlerts(self, class_attr_dict, localobjs = None):
         """
         Return a list of objects in any of the classes in class_attr_dict
@@ -356,7 +342,6 @@
             else:
                 print "no data found", classname
         return retlist        
-    
  
     def startWfActivity(self, wf_activity, wf_obj):
         print "xmlrpc.startActivity", wf_activity.name, wf_obj.name

Index: PanGalactic/pangalactic/core/workflow/workflow_wizard.py
diff -u PanGalactic/pangalactic/core/workflow/workflow_wizard.py:1.4 PanGalactic/pangalactic/core/workflow/workflow_wizard.py:1.5
--- PanGalactic/pangalactic/core/workflow/workflow_wizard.py:1.4	Tue Mar  8 10:18:05 2005
+++ PanGalactic/pangalactic/core/workflow/workflow_wizard.py	Tue May  3 03:08:28 2005
@@ -1,11 +1,11 @@
-# $Id: workflow_wizard.py,v 1.4 2005/03/08 15:18:05 waterbug Exp $
+# $Id: workflow_wizard.py,v 1.5 2005/05/03 07:08:28 waterbug Exp $
 """
 The GUI that is used to create or edit a workflow template (L{WfProcess
 <pangalactic.core.workflow.wfprocess>}).
 
-@version: $Revision: 1.4 $
+@version: $Revision: 1.5 $
 """
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 from wxPython.wx import *
 from wxPython.grid import *
@@ -393,8 +393,8 @@
         activities = []
         for tkey, tvalue in wfobj.transitions_dict.items():
             #print "transition", tkey, tvalue.oid, tvalue.from_activity, tvalue.to_activity
-            from_activity = self.dm.getLookupObject(tvalue.from_activity)
-            to_activity = self.dm.getLookupObject(tvalue.to_activity)
+            from_activity = self.dm.getLocalObject(tvalue.from_activity)
+            to_activity = self.dm.getLocalObject(tvalue.to_activity)
             self.transitiongrid.SetCellValue(row, from_col, from_activity.name)
             self.transitiongrid.SetCellValue(row, to_col, to_activity.name)
         

From waterbug at step.nasa.gov  Tue May  3 16:34:51 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May  3 16:34:53 2005
Subject: [pangalactic-commits] TODO and itemeditframe preliminary tweaks.
Message-ID: <200505032034.j43KYp6r011060@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/TODO 1.21 1.22
PanGalactic/pangalactic/node/gui/psm/itemeditframe.py 1.12 1.13
PanGalactic/pangalactic/utils/toolframe.py 1.14 1.15

Log message:
TODO and itemeditframe preliminary tweaks.

Index: PanGalactic/TODO
diff -u PanGalactic/TODO:1.21 PanGalactic/TODO:1.22
--- PanGalactic/TODO:1.21	Sat Apr 30 14:45:22 2005
+++ PanGalactic/TODO	Tue May  3 16:34:49 2005
@@ -9,15 +9,18 @@
 To Do Before Release (in rough order of precedence)
 ---------------------------------------------------
 [-] fix ItemEditFrame
-    - right now, drop/drag assembly does not activate 'Save' button, does
-      not show up in main assembly tree, and does not show up next time
-      ItemEditFrame comes up
     - show 'iteration' (not editable) and 'version' (editable)
+      - increment iteration when 'new' or 'edit' is invoked, but allow
+        version to be set by user (or kept the same)
+    - use objectviewer to browse and edit additional attributes
     - new/edit should put new object in grid immediately (doesn't now) and
       once the new/edited object has been changed, the 'Close' button
       should be activated so the user can close the window (don't really
       need 'Save' button -- that should be implicit, as in Mozilla bookmark
       editor)
+    - right now, drop/drag assembly does not activate 'Save' button, does
+      not show up in main assembly tree, and does not show up next time
+      ItemEditFrame comes up
 [-] new editor concept for all objs:
     - use object viewer as the editor
     - assembly tree w/drag/drop (as it is now)
@@ -103,5 +106,5 @@
     - one-many (aggregate attrs)
 
 --------------------------------------------------------------------------
-# $Id: TODO,v 1.21 2005/04/30 18:45:22 waterbug Exp $
+# $Id: TODO,v 1.22 2005/05/03 20:34:49 waterbug Exp $
 

Index: PanGalactic/pangalactic/node/gui/psm/itemeditframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.12 PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.13
--- PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.12	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/itemeditframe.py	Tue May  3 16:34:49 2005
@@ -1,6 +1,10 @@
-# $Id: itemeditframe.py,v 1.12 2005/05/03 07:08:29 waterbug Exp $
+# $Id: itemeditframe.py,v 1.13 2005/05/03 20:34:49 waterbug Exp $
+"""
+GUI providing browsing/editing capabilities for Part, Model, Document, and
+PartsList objects.
+"""
 
-__version__ = "$Revision: 1.12 $"[11:-2]
+__version__ = "$Revision: 1.13 $"[11:-2]
 
 import wx
 from pangalactic.node.gui.psm import docform
@@ -14,10 +18,9 @@
 from pangalactic.node.gui.psm import modelform
 from pangalactic.node.gui.psm import propertiesform 
 from pangalactic.node.gui.psm import pgefversiontree
-
 from pangalactic.utils.preferences import prefs, writePrefs
 from pangalactic.utils.pgefstate import state
-from pangalactic.utils import toolframe
+from pangalactic.utils.toolframe import ToolFrame
 from pangalactic.utils.pgefexceptions import RequiredDataError
 
 try:
@@ -29,13 +32,38 @@
 EDIT_MODE = 2
 BROWSE_MODE = 3
 
-class ItemEditFrame(toolframe.ToolFrame):
+class ItemEditFrame(ToolFrame):
     """
-    Encapsulates the logic for graphically editing a product
+    GUI providing browsing/editing capabilities for Part, Model, Document,
+    and PartsList objects.
     """
 
-    def __init__(self, parent, datamanager, rootobj, nodedata,
+    def __init__(self, parent, dm, rootobj, nodedata,
                  displaywgts, mode):
+        """
+        Initialize an ItemEditFrame instance.
+
+        @param parent:  the parent widget
+        @type  parent:  a wx object
+
+        @param dm:  the (app singleton) DataManager instance
+        @type  dm:  L{pangalactic.utils.datamanager.DataManager}
+
+        @param rootobj:  the object being browsed and/or edited
+        @type  rootobj:  L{pangalactic.core.pgefobject.PgefObject}
+
+        @param nodedata:  data from a tree (?) -- not used for anything
+            that I can see
+        @type  nodedata:  
+
+        @param displaywgts:  widgets of the frame (not used for anything --
+            might be unnecessary here)
+        @type  displaywgts:  [wxPython widgets]
+
+        @param mode:  an integer code that sets the mode to create, edit,
+            or browse
+        @type  mode:  C{int}
+        """
         toolframe.ToolFrame.__init__(self,
                                      parent,
                                      -1,
@@ -47,21 +75,16 @@
         self.menuBar.SetHelpString(toolframe.ID_FILE_EXIT,
                                    "Close this window")
         self.CentreOnParent()
-
         self.Parent = parent
-        if datamanager:
-            self.SetDataManager(datamanager)
+        if dm:
+            self.dm = dm
         else:
             raise RequiredDataError, "A datamanager instance is required"
-
         self.editingtab = None
-
         self.vsplitter = wx.SplitterWindow(self, -1)
-
         #create the notebook
         self.nbid = wx.NewId()
         self.editnb = wx.Notebook(self.vsplitter, self.nbid)
-
         #create the tree
         self.tID = wx.NewId()
         self.treeMap = {}
@@ -75,7 +98,6 @@
         self.modeltree = None
         self.partslisttree = None
         self.doctree = None
-
         self.partform = partform.PartForm(self.editnb, -1)
         self.editnb.AddPage(self.partform,
                             "Part")
@@ -101,29 +123,24 @@
         self.PartsListPage = 3
         self.PartDataPage = 4
         self.DocPage = 5
-
         self.tabnames = {self.PartPage:       'Part',
                          self.ModelPage:      'Model',
                          self.PropertiesPage: 'Part Properties',
                          self.PartsListPage:  'Parts Lists',
                          self.PartDataPage:   'Parts List Data',
                          self.DocPage:        'Documents'}
-
         self.rootobjs = {self.PartPage:       None,
                          self.ModelPage:      None,
                          self.PropertiesPage: None,
                          self.PartsListPage:  None,
                          self.PartDataPage:   None,
                          self.DocPage:        None}
-
         self.dm.creatingPart = False
         self.dm.creatingModel = False
         self.dm.creatingDocument = False
         self.dm.creatingPartsList = False
-
         self.vsplitter.SetMinimumPaneSize(20)
         self.vsplitter.SplitVertically(self.tree, self.editnb, 220)
-
         wx.EVT_BUTTON(self, modelform.MODEL_BROWSE_BUTTON, self.modelform.browse)
         wx.EVT_BUTTON(self, modelform.ID_NEW_MODEL, self.OnNewModel)
         wx.EVT_BUTTON(self, modelform.ID_SAVE_MODEL, self.OnSaveObject)
@@ -131,14 +148,12 @@
         wx.EVT_BUTTON(self, modelform.ID_RESET_MODEL_FORM, self.OnResetModel)
         wx.EVT_BUTTON(self, modelform.DELETE_MODEL, self.OnDeleteNauo)
         wx.EVT_BUTTON(self, modelform.ID_MODEL_CLOSE, self.OnClose)
-
         wx.EVT_BUTTON(self, partform.ID_NEW_PART, self.OnNewPart)
         wx.EVT_BUTTON(self, partform.ID_EDIT_PART, self.OnEditPart)
         wx.EVT_BUTTON(self, partform.ID_SAVE_PART, self.OnSaveObject)
         wx.EVT_BUTTON(self, partform.ID_RESET_PART_FORM, self.OnResetPart)
         wx.EVT_BUTTON(self, partform.DELETE_PART, self.OnDeleteNauo)
         wx.EVT_BUTTON(self, partform.ID_PART_CLOSE, self.OnClose)
-
         wx.EVT_BUTTON(self, docform.DOC_BROWSE_BUTTON, self.documentform.Browse)
         wx.EVT_BUTTON(self, docform.DOC_NEW_BUTTON, self.OnNewDoc) 
         wx.EVT_BUTTON(self, docform.DOC_EDIT_BUTTON, self.OnEditDoc)
@@ -146,19 +161,16 @@
         wx.EVT_BUTTON(self, docform.DOC_CANCEL_BUTTON, self.OnResetDoc)
         wx.EVT_BUTTON(self, docform.DOC_CLOSE_BUTTON, self.OnClose)
         wx.EVT_BUTTON(self, docform.DOC_DELLINK_BUTTON, self.OnUnlinkDocument)
-
         wx.EVT_BUTTON(self, partslistform.ID_BUTTON_PARTS_CLOSE, self.OnClose)
         wx.EVT_BUTTON(self, partslistform.ID_BUTTON_NEW_PARTSLIST, self.OnNewPartsList)
         wx.EVT_BUTTON(self, partslistform.ID_BUTTON_SAVE_PARTSLIST, self.OnSaveObject)
         wx.EVT_BUTTON(self, partslistform.ID_BUTTON_RESET_PARTSLIST, self.OnResetPartsList)
         wx.EVT_BUTTON(self, partslistform.ID_BUTTON_EDIT_PARTSLIST, self.OnEditPartsList)
         wx.EVT_BUTTON(self, partslistform.IMPORTPARTSLIST_BUTTON, self.OnImportPartsList)
-
         wx.EVT_CLOSE(self, self.OnClose)
         wx.EVT_TREE_SEL_CHANGED(self, self.tID, self.OnTreeActivate)
         wx.EVT_NOTEBOOK_PAGE_CHANGING(self, self.nbid, self.PageChanging)
         wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.nbid, self.PageChanged)
-
         self.Setup(rootobj, nodedata, displaywgts, mode)
 
     def Setup(self, rootobj, nodedata, displaywgts, mode):
@@ -187,30 +199,28 @@
         self.setupPane(rootobj, nodedata)
         self.setMode(mode)
 
-    def setCurrentObject(self, rootobj, nodedata = None):
+    def setCurrentObject(self, rootobj, nodedata=None):
         #print "itemeditframe.setcurrentobject"
-
         if not rootobj:
             #print "  whoopsie"
             return
-
-        classname = rootobj.__class__.__name__
-        if not classname in ["Part", "Model", "Document", "PartsList"]:
+        schema_id = rootobj._schema.id
+        if not schema_id in ["Part", "Model", "Document", "PartsList"]:
+            # TODO:  allow subtypes of these, using the object "viewer" to
+            # enable browsing and editing additional attributes to the ones
+            # on the main notebook pages.
             return
-
-        self.currentobj = self.dm.newObject(classname)
-        self.tempobj = self.dm.newObject(classname)
+        self.currentobj = self.dm.newObject(schema_id)
+        self.tempobj = self.dm.newObject(schema_id)
         self.currentobj.__dict__.update(rootobj.__dict__)
         self.tempobj.__dict__.update(self.currentobj.__dict__)
-
-        if classname == "Part":
+        if schema_id == "Part":
             self.rootobjs[self.PartPage] = rootobj
             self.rootobjs[self.PropertiesPage] = rootobj
             self.rootobjs[self.PartsListPage] = rootobj
             self.rootobjs[self.PartDataPage] = rootobj
             self.currentpage = self.PartPage
-
-        elif classname == "Model":
+        elif schema_id == "Model":
             self.rootobjs[self.ModelPage] = rootobj
             # TODO:  this needs to be completely redone using 'PartModel'
             # TODO:  and publish/subscribe events for the other pages
@@ -221,12 +231,10 @@
             #     self.rootobjs[self.PartsListPage] = rootobj.of_part
             #     self.rootobjs[self.PartDataPage] = rootobj.of_part
             self.currentpage = self.ModelPage
-
-        elif classname == "PartsList":
+        elif schema_id == "PartsList":
             self.rootobjs[self.PartsListPage] = rootobj
             self.currentpage = self.PartsListPage
-
-        elif classname == "Document":
+        elif schema_id == "Document":
             self.rootobjs[self.DocPage] = rootobj
             self.currentpage = self.DocPage
 
@@ -252,11 +260,11 @@
 
     def setMode(self, mode=BROWSE_MODE):
         if mode == NEW_MODE:
-            self.CreatingMode(self.currentpage)
+            self.setCreatingMode(self.currentpage)
         elif mode == EDIT_MODE:
-            self.EditingMode(self.currentpage)
+            self.setEditingMode(self.currentpage)
         else:
-            self.BrowseMode(True)
+            self.setBrowseMode(True)
 
     def Clear(self):
         self.tree.DeleteAllItems()
@@ -299,7 +307,7 @@
                                   wx.OK | wx.CANCEL | wx.ICON_EXCLAMATION)
             retval = dlg.ShowModal()
             if retval == wx.ID_OK:
-                self.BrowseMode(True)
+                self.setBrowseMode(True)
                 return False
             elif retval == wx.ID_CANCEL:
                 self.editnb.SetSelection(self.currentpage)
@@ -314,25 +322,21 @@
         @param event: Standard wx.Python Event Object
         """
         #print 'currentpage in pagechanging is: ' , self.currentpage
-
         if self.currentpage == self.PartPage:
             self.dm.creatingPart = self.UnsavedDataPageChanging(
                                         "Discard unsaved Part changes?",
                                         self.dm.creatingPart,
                                         self.currentpage)
-
         elif self.currentpage == self.ModelPage:
             self.dm.creatingModel = self.UnsavedDataPageChanging(
                                         "Discard unsaved Model changes?",
                                         self.dm.creatingModel,
                                         self.currentpage)
-
         elif self.currentpage == self.PartsListPage:
             self.dm.creatingPartsList = self.UnsavedDataPageChanging(
                                         "Discard unsaved Parts List changes?",
                                         self.dm.creatingPartsList,
                                         self.currentpage)
-
         elif self.currentpage == self.DocPage:
             self.dm.creatingDocument = self.UnsavedDataPageChanging(
                                         "Discard unsaved Document changes?",
@@ -342,16 +346,13 @@
     def PageChanged(self, event=None):
         #print "itemeditframe.pagechanged"
         self.currentpage = self.editnb.GetSelection()
-
-        if self.dm.creatingPart or \
-           self.dm.creatingModel or \
-           self.dm.creatingPartsList or \
-           self.dm.creatingDocument:
-
+        if (self.dm.creatingPart
+            or self.dm.creatingModel
+            or self.dm.creatingPartsList
+            or self.dm.creatingDocument):
             if self.editingtab == self.currentpage:
-                self.EditingMode(self.currentpage)
+                self.setEditingMode(self.currentpage)
                 self.sb.ClearMsg()
-
             else:
                 self.sb.SetMsg(
                     'Currently editing on %s tab' % self.tabnames[
@@ -360,23 +361,21 @@
         else:
             # added to set modes for non-editing notebook tabs. vwk.
             self.setMode()
-
         if self.rootobjs[self.currentpage]:
             self.setCurrentObject(self.rootobjs[self.currentpage])
             self.setupPane(self.rootobjs[self.currentpage])
         else:
             self.tree.DeleteAllItems()
 
-    def BrowseMode(self, gotroot):
+    def setBrowseMode(self, gotroot):
         self.partform.BrowseMode(gotroot)
         self.modelform.BrowseMode(gotroot)
         self.partslistform.BrowseMode(gotroot)
         self.documentform.BrowseMode(gotroot)
 
-    def EditingMode(self, whichpane):
+    def setEditingMode(self, whichpane):
         #print 'itemeditframe.editmode', whichpane
         self.editingtab = self.currentpage
-
         if whichpane == self.PartPage: 
             self.partform.EditingMode()
             self.modelform.BrowseMode()
@@ -386,7 +385,6 @@
             self.dm.creatingPartsList = False
             self.dm.creatingModel = False
             self.dm.creatingPart = True
-
         elif whichpane == self.ModelPage:
             self.modelform.EditingMode()
             self.partform.BrowseMode(True)
@@ -396,7 +394,6 @@
             self.dm.creatingPartsList = False
             self.dm.creatingModel = True
             self.dm.creatingPart = False
-
         if whichpane == self.PartsListPage:
             self.partform.BrowseMode(True)
             self.modelform.BrowseMode(True)
@@ -406,7 +403,6 @@
             self.dm.creatingPartsList = True
             self.dm.creatingPart = False
             self.dm.creatingModel = False
-
         elif whichpane == self.DocPage:
             self.partform.BrowseMode(True)
             self.modelform.BrowseMode(True)
@@ -417,7 +413,7 @@
             self.dm.creatingPart = False
             self.dm.creatingModel = False
 
-    def CreatingMode(self, whichpane):
+    def setCreatingMode(self, whichpane):
         """Handles the setting of the correct mode based
            upon which pane of the notebook is being shown.
 
@@ -577,7 +573,7 @@
             node = self.tree.GetSelection()
             if node.IsOk():
                 if node == self.tree.GetRootItem():
-                    self.BrowseMode(True)
+                    self.setBrowseMode(True)
 
                     obj = self.tree.GetPyData(node)
                     if obj[0] == 'New':
@@ -612,11 +608,11 @@
             else:
                 if self.currentpage == self.PartPage:
                     self.partform.clearForm()
-                self.BrowseMode(True)
+                self.setBrowseMode(True)
         else:
             if self.currentpage == self.PartPage:
                 self.partform.clearForm()
-            self.BrowseMode(True)
+            self.setBrowseMode(True)
 
         if self.dm.creatingPart:
             self.dm.creatingPart = False
@@ -629,7 +625,7 @@
             node = self.modeltree.GetSelection()
             if node.IsOk():
                 if node == self.modeltree.GetRootItem():
-                    self.BrowseMode(True)
+                    self.setBrowseMode(True)
 
                     obj = self.modeltree.GetPyData(node)
                     if obj[0] == 'New':
@@ -664,11 +660,11 @@
             else:
                 if self.currentpage == self.ModelPage:
                     self.modelform.clearForm()
-                self.BrowseMode(True)
+                self.setBrowseMode(True)
         else:
             if self.currentpage == self.ModelPage:
                 self.modelform.clearForm()
-            self.BrowseMode(True)
+            self.setBrowseMode(True)
 
         if self.dm.creatingModel:
             self.dm.creatingModel = False

Index: PanGalactic/pangalactic/utils/toolframe.py
diff -u PanGalactic/pangalactic/utils/toolframe.py:1.14 PanGalactic/pangalactic/utils/toolframe.py:1.15
--- PanGalactic/pangalactic/utils/toolframe.py:1.14	Thu Mar 17 04:01:48 2005
+++ PanGalactic/pangalactic/utils/toolframe.py	Tue May  3 16:34:50 2005
@@ -1,11 +1,12 @@
+# $Id: toolframe.py,v 1.15 2005/05/03 20:34:50 waterbug Exp $
 """
 Generic wx.Frame subclass for tool windows
+
+@version: $Revision: 1.15 $
 """
+__version__ = "$Revision: 1.15 $"[11:-2]
 
 import wx
-# from wxPython.wx import wxStatusBar, wxFrame, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, EVT_MENU
-# from wxPython.wx import wxMenu,wxMessageDialog,wxALIGN_CENTRE, wxNewId
-# from wxPython.wx import wxOK, wxCENTRE, wxICON_EXCLAMATION, wxApp, wxSize, wxMenuBar
 
 from pangalactic.utils.aboutbox import AboutBox
 from pangalactic.utils.datamanager import DataManager
@@ -15,19 +16,22 @@
 ID_HELP_CONTENTS = wx.NewId()
 ID_HELP_TESTING = wx.NewId()
 
-HELPTEXT = "This is a test HelpWindow.\nIt is only a test HelpWindow.\n\n" + \
-           "Had this been a real HelpWindow, this window would\n" + \
-           "have been filled with meaningful drivel."
+HELPTEXT = """
+This is a test HelpWindow.
+It is only a test HelpWindow.
+Had this been a real HelpWindow, it would
+have been filled with meaningful information
+instead of this useless drivel."""
+
 HELPTITLE = "General"
 
 # WDR: classes
 class ToolFrameStatusBar(wx.StatusBar):
-    """This method created the statusbar that is used on the main form """
+    """This method creates the statusbar that is used on the main form """
     def __init__(self, parent):
         wx.StatusBar.__init__(self, parent, -1)
         self.SetFieldsCount(3)
         
-        
     def SetMsg(self, msgtext):
         self.SetStatusText(" " + msgtext, 1)
 
@@ -77,12 +81,7 @@
         wx.EVT_MENU(self, ID_FILE_EXIT, self.OnExit)
         wx.EVT_MENU(self, ID_HELP_ABOUT, self.OnAbout)
         wx.EVT_MENU(self, ID_HELP_CONTENTS, self.onContents)
-        
 
-    def SetDataManager(self, datamanager):
-        if datamanager:
-            self.dm = datamanager
-        
     def ConfigureStatusBar(self, width):
         flyover_len = int(width * 0.35)
         msg_len = int(width * 0.4)
@@ -118,7 +117,6 @@
         self.HelpText = help_text
         self.HelpTitle = "About " + self.AppTitle
 
-
     def OnAbout(self, event):
         # this can be overridden by the child for more in-depth help
         dlg = AboutBox(self, -1, "About " + self.AppTitle, wx.DefaultPosition, wx.Size(300, 200))
@@ -127,7 +125,6 @@
         dlg.CentreOnParent()
         dlg.Show(True)
 
-
     def onContents(self, event):
         # this can be overridden by the child for more in-depth help
         dlg = wx.MessageDialog(self, self.HelpText,

From waterbug at step.nasa.gov  Wed May  4 06:24:14 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May  4 06:24:18 2005
Subject: [pangalactic-commits] Revised TODO and mo' meta.
Message-ID: <200505041024.j44AOET4015483@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/TODO 1.22 1.23
PanGalactic/pangalactic/core/filelink.py 1.5 1.6
PanGalactic/pangalactic/meta/objectschema.py 1.1 1.2
PanGalactic/pangalactic/meta/ontology.py 1.6 1.7
PanGalactic/pangalactic/meta/pgefproperty.py 1.15 1.16
PanGalactic/pangalactic/node/gui/psm/itemeditframe.py 1.13 1.14
PanGalactic/pangalactic/test/IDTEST 1.111 1.112

Log message:
Revised TODO and mo' meta.

Index: PanGalactic/pangalactic/core/filelink.py
diff -u PanGalactic/pangalactic/core/filelink.py:1.5 PanGalactic/pangalactic/core/filelink.py:1.6
--- PanGalactic/pangalactic/core/filelink.py:1.5	Tue Apr 12 23:59:28 2005
+++ PanGalactic/pangalactic/core/filelink.py	Wed May  4 06:24:11 2005
@@ -1,4 +1,4 @@
-# $Id: filelink.py,v 1.5 2005/04/13 03:59:28 waterbug Exp $
+# $Id: filelink.py,v 1.6 2005/05/04 10:24:11 waterbug Exp $
 """
 A FileLink object is a semantic link to a system file.  Note that a file
 may have more than one FileLink associated with it (in somewhat the same
@@ -10,9 +10,9 @@
 A FileLink could possibly be used as a semantic link to any file-like
 object, but the implications of this have not yet been explored.
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 from pangalactic import PGEF_URI
 from pangalactic.core.pgefobject import PgefObject
@@ -49,8 +49,9 @@
         Property(
             id='role',
             id_ns=PGEF_URI,
-            name='File Role',
+            name='Role',
             range='str',
+            default_display='True',
             description="""
             The purpose or meaning of this particular file relative to a
             Representation to which it is related -- e.g.  "attachment",
@@ -61,6 +62,7 @@
             id_ns=PGEF_URI,
             name='Sequence',
             range='int',
+            default_display='True',
             description="""
             An integer that can be used to specify the ordering of this
             file within an ordered set of files -- attachments, for
@@ -73,6 +75,7 @@
             name='Sequence Context',
             range='str',
             default='role',
+            default_display='True',
             description="""
             The name of the attribute within the context of which the
             'sequence' attribute is meaningful.  IOW, if the
@@ -100,6 +103,7 @@
             id_ns=PGEF_URI,
             name='User File Name',
             range='str',
+            default_display='True',
             description="""
             The user or owner's local name for the system file.
             """),
@@ -119,6 +123,7 @@
             id_ns=PGEF_URI,
             name='Bytes',
             range='int',
+            default_display='True',
             description="""
             The size of the file in bytes.
             """),
@@ -128,6 +133,7 @@
             name='MIME Type',
             range='Mime',
             property_type='object',
+            default_display='True',
             description="""
             The MIME type of the file's content.
             """)

Index: PanGalactic/TODO
diff -u PanGalactic/TODO:1.22 PanGalactic/TODO:1.23
--- PanGalactic/TODO:1.22	Tue May  3 16:34:49 2005
+++ PanGalactic/TODO	Wed May  4 06:24:11 2005
@@ -8,27 +8,26 @@
 ---------------------------------------------------
 To Do Before Release (in rough order of precedence)
 ---------------------------------------------------
-[-] fix ItemEditFrame
-    - show 'iteration' (not editable) and 'version' (editable)
-      - increment iteration when 'new' or 'edit' is invoked, but allow
-        version to be set by user (or kept the same)
-    - use objectviewer to browse and edit additional attributes
-    - new/edit should put new object in grid immediately (doesn't now) and
-      once the new/edited object has been changed, the 'Close' button
-      should be activated so the user can close the window (don't really
-      need 'Save' button -- that should be implicit, as in Mozilla bookmark
-      editor)
-    - right now, drop/drag assembly does not activate 'Save' button, does
-      not show up in main assembly tree, and does not show up next time
-      ItemEditFrame comes up
-[-] new editor concept for all objs:
-    - use object viewer as the editor
-    - assembly tree w/drag/drop (as it is now)
+[-] NEW!  *REPLACE* ItemEditFrame with late-bound object viewer/editors
+    - new editor concept for all objs:  use object viewer as the editor
     - 'links' to objects from object Properties (related objs may or may
       not be editable by any particular user)
     - 'nekkid object': small window (as in wx demo) with icon to show what
       the object is and some state indication (altered locally, editable,
       etc. ... configurable appearance)
+    - assembly tree w/drag/drop (as it is now) for any objects that can be
+      assemblies
+    - 'iteration' should *not* be editable; 'version' should be editable
+      - increment iteration when 'new' or 'edit' is invoked, but allow
+        version to be set by user (or kept the same)
+    - new/edit should put new object in the appropriate grid immediately
+      (doesn't now) and once the new/edited object has been changed, the
+      'Close' button should be activated so the user can close the window
+      (don't really need 'Save' button -- that should be implicit, as in
+      Mozilla bookmark editor)
+[-] right now, drop/drag assembly does not activate 'Save' button, does
+    not show up in main assembly tree, and does not show up next time
+    ItemEditFrame comes up
 [*] debug commit function for objs with files
 [*] oseb import
     - use oseb.py deserialize the result of an ExpressEngine mapping into
@@ -106,5 +105,5 @@
     - one-many (aggregate attrs)
 
 --------------------------------------------------------------------------
-# $Id: TODO,v 1.22 2005/05/03 20:34:49 waterbug Exp $
+# $Id: TODO,v 1.23 2005/05/04 10:24:11 waterbug Exp $
 

Index: PanGalactic/pangalactic/meta/ontology.py
diff -u PanGalactic/pangalactic/meta/ontology.py:1.6 PanGalactic/pangalactic/meta/ontology.py:1.7
--- PanGalactic/pangalactic/meta/ontology.py:1.6	Tue Apr 26 00:53:50 2005
+++ PanGalactic/pangalactic/meta/ontology.py	Wed May  4 06:24:11 2005
@@ -1,12 +1,12 @@
-# $Id: ontology.py,v 1.6 2005/04/26 04:53:50 waterbug Exp $
+# $Id: ontology.py,v 1.7 2005/05/04 10:24:11 waterbug Exp $
 
 """
 A set of named elements, which can include datatypes, classes, and
 properties.
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 from sets import Set
 from pangalactic.meta.utils import getDefault
@@ -21,63 +21,104 @@
     # it being a subclass of Namespace).
     _schema = {
 
-        'id'          : {'range'        :'str',
-                         'description'  :"""
+        'id'             : {
+                            'id'             :'id',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'ID',
+                            'range'          :'str',
+                            'default_display':'True',
+                            'description'    :"""
         [rdf:ID] Identifier of the C{Ontology} within some context or
         namespace.  This also serves as the "prefix" for names (of classes
         and properties) defined within the C{Ontology} (which is a
         namespace).
         """},
 
-        'id_ns'       : {'range'        :'str',
-                         'description'  :"""
+        'id_ns'          : {
+                            'id'             :'id_ns',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Namespace',
+                            'range'          :'str',
+                            'default_display':'True',
+                            'description'    :"""
         [xml:base] The context, base URL, or namespace within which the
         C{Ontology}'s 'id' is unique.
         """},
 
-        'uri'         : {'range'        :'str',
-                         'description'  :"""
+        'uri'            : {
+                            'id'             :'uri',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'URI',
+                            'range'          :'str',
+                            'default_display':'True',
+                            'description'    :"""
         [pgef:uri]  The Universal Resource Identifier (URI) assigned to
         this schema.
         """},
 
-        'name'        : {'range'        :'str',
-                         'description'  :"""
+        'name'           : {
+                            'id'             :'name',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Name',
+                            'range'          :'str',
+                            'default_display':'True',
+                            'description'    :"""
         [rdfs:label] Human-readable identifier of the C{Ontology}.
         """},
 
-        'version'     : {'range'        :'str',
-                         'default'      :'baseline',
-                         'description'  :"""
+        'version'        : {
+                            'id'             :'version',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Version',
+                            'range'          :'str',
+                            'default'        :'baseline',
+                            'default_display':'True',
+                            'description'    :"""
         [owl:versionInfo] A user-modifiable string used to identify a
         baseline, release, or version.
         """},
 
-        'iteration'   : {'range'        :'int',
-                         'default'      :'0',
-                         'description'  :"""
+        'iteration'      : {
+                            'id'             :'iteration',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Iteration',
+                            'range'          :'int',
+                            'default'        :'0',
+                            'description'    :"""
         [pgef:iteration] An application-assigned sequential integer
         identifying the precedence order of revisions of the object.
         """},
 
-        'description' : {'range'        :'str',
-                         'description'  :"""
+        'description'    : {
+                            'id'             :'description',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Description',
+                            'range'          :'str',
+                            'description'    :"""
         [rdf:Description]  A narrative about the characteristics and
         identifying features of the C{Ontology}.
         """},
 
-        'objectschemas' : {'range'           :'ObjectSchema',
-                           'property_type'   :'object',
-                           'max_cardinality' :0,
-                           'description'     :"""
+        'objectschemas'  : {
+                            'id'             :'object_schemas',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'ObjectSchemas',
+                            'range'          :'ObjectSchema',
+                            'property_type'  :'object',
+                            'max_cardinality':0,
+                            'description'    :"""
         [owl:Class] [uml:Type]  A list of the C{ObjectSchema} instances
         contained in this C{Ontology}.
         """},
 
-        'includes'    : {'range'           :'Ontology',
-                         'property_type'   :'object',
-                         'max_cardinality' :0,
-                         'description'     :"""
+        'includes'       : {
+                            'id'             :'includes',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Includes',
+                            'range'          :'Ontology',
+                            'property_type'  :'object',
+                            'max_cardinality':0,
+                            'description'    :"""
         [pgef:includes]  A list of the other C{Ontology}s included in this
         C{Ontology}.
         """}

Index: PanGalactic/pangalactic/meta/objectschema.py
diff -u PanGalactic/pangalactic/meta/objectschema.py:1.1 PanGalactic/pangalactic/meta/objectschema.py:1.2
--- PanGalactic/pangalactic/meta/objectschema.py:1.1	Sun Apr 10 23:31:25 2005
+++ PanGalactic/pangalactic/meta/objectschema.py	Wed May  4 06:24:11 2005
@@ -1,4 +1,4 @@
-# $Id: objectschema.py,v 1.1 2005/04/11 03:31:25 waterbug Exp $
+# $Id: objectschema.py,v 1.2 2005/05/04 10:24:11 waterbug Exp $
 
 """
 This module defines the C{ObjectSchema} class, which specifies the
@@ -13,28 +13,9 @@
 assigned at initialization time to instances of a class that has an
 instance of C{ObjectSchema} as its C{_schema}.
 
-In RDF and OWL (an RDF-based ontology representation vocabulary), a
-Property is a binary relationship.  RDF treats all Properties alike, but
-OWL separates them into two types:  "Datatype Properties" and "Object
-Properties".
-
-  * An rdf:Property is a relationship between two resources, which can be
-    anything, and which are called the domain (rdfs:domain) and range
-    (rdfs:range) of the rdf:Property.
-
-  * An owl:DatatypeProperty has an rdfs:domain that is an owl:Class and an
-    rdfs:range that is either an RDF literal or an XML Schema datatype.
-
-  * An owl:ObjectProperty has an rdfs:domain and an rdfs:range that are
-    both members of owl:Class.
-
-All three are represented in PGEF as instances of Property in a
-C{ObjectSchema}, in which the C{ObjectSchema} corresponds to the class that
-is the domain of the binary relationship.
-
-@version: $Revision: 1.1 $
+@version: $Revision: 1.2 $
 """
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.2 $"[11:-2]
 
 from sets import Set
 from pangalactic.meta.utils import getDefault
@@ -89,8 +70,13 @@
     # TODO:  generate ivar documentation for __doc__ from _schema.
     _schema = {
 
-        'id'          : {'range'        :'str',
-                         'description'  :"""
+        'id'             : {
+                            'id'             :'id',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'ID',
+                            'range'          :'str',
+                            'default_display':'True',
+                            'description'    :"""
         [xmlns:LocalPart] [rdf:ID]  Identifier of the C{ObjectSchema}
         within some context or namespace.  For PgefObject and its
         subclasses, the context of their C{ObjectSchema} (_schema) id is
@@ -100,35 +86,57 @@
         (http://www.w3.org/TR/REC-xml-names/#dt-qname).
         """},
 
-        'id_ns'       : {'range'        :'str',
-                         'description'  :"""
+        'id_ns'          : {
+                            'id'             :'id_ns',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Namespace',
+                            'range'          :'str',
+                            'default_display':'True',
+                            'description'    :"""
         [xml:base]  The context, base URI, or namespace within which the
-        'id' is unique.  This should be the URI for the PgefSchema
-        to which this C{ObjectSchema} belongs.
+        'id' is unique.  This should be the URI for the C{Ontology}
+        to which the C{ObjectSchema} belongs.
         """},
 
-        'name'        : {'range'        :'str',
-                         'description'  :"""
+        'name'           : {
+                            'id'             :'name',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Name',
+                            'range'          :'str',
+                            'description'    :"""
         [rdfs:label]  A human-readable identifier of the C{ObjectSchema}.
         """},
 
-        'abbrev'      : {'range'        :'str',
-                         'description'  :"""
-        [pgef:abbrev]  The standard PGEF abbreviation for this
-        C{ObjectSchema} (used in forming the names of relationship tables
-        and foreign key constraint names).
+        'abbrev'         : {
+                            'id'             :'abbrev',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Abbreviation',
+                            'range'          :'str',
+                            'description'    :"""
+        [pgef:abbrev]  The standard PGEF abbreviation for the
+        C{ObjectSchema}.
         """},
 
-        'base'        : {'range'        :'ObjectSchema',
-                         'property_type':'object',
-                         'description'  :"""
-        [rdfs:subClassOf]  The immediate parent of this C{ObjectSchema}
+        'base'           : {
+                            'id'             :'base',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Base Schema',
+                            'range'          :'ObjectSchema',
+                            'property_type'  :'object',
+                            'default_display':'True',
+                            'description'    :"""
+        [rdfs:subClassOf]  The immediate parent of the C{ObjectSchema}
         (if any).
         """},
 
-        'version'     : {'range'        :'str',
-                         'default'      :'baseline',
-                         'description'  :"""
+        'version'        : {
+                            'id'             :'version',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Version',
+                            'range'          :'str',
+                            'default'        :'baseline',
+                            'default_display':'True',
+                            'description'    :"""
         [owl:versionInfo]  A user-modifiable string used to identify a
         baseline, release, or version.  From the "OWL Web Ontology Language
         Guide":  "... owl:versionInfo provides a hook suitable for use by
@@ -137,24 +145,50 @@
         addition to ontologies."
         """},
 
-        'iteration'   : {'range'        :'int',
-                         'default'      :'0',
-                         'description'  :"""
+        'iteration'      : {
+                            'id'             :'iteration',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Iteration',
+                            'range'          :'int',
+                            'default'        :'0',
+                            'description'    :"""
         [pgef:iteration]  An application-assigned sequential integer
-        identifying the precedence order of revisions of the object.
+        identifying the precedence order of revisions of the
+        C{ObjectSchema}.
+        """},
+
+        'description'    : {
+                            'id'             :'description',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Description',
+                            'range'          :'str',
+                            'description'    :"""
+        [rdf:Description][rdfs:comment]  A plain text narrative on the
+        salient features of the C{ObjectSchema}.
         """},
 
-        'description' : {'range'        :'str',
-                         'description'  :"""
-        [rdf:Description][rdfs:comment]  A narrative about the
-        characteristics and identifying features of the object.
+        'definition'     : {
+                            'id'             :'definition',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Definition',
+                            'range'          :'Document',
+                            'property_type'  :'object',
+                            'description'    :"""
+        [pgef:definition]  A Document that defines the C{ObjectSchema}.
+        This is meant to support references to standardized domain object
+        definitions, e.g. such as might be found in an IEC 61360
+        dictionary.
         """},
 
-        'properties'  : {'range'          :'Property',
-                         'property_type'  :'object',
-                         'max_cardinality':0,
-                         'description'    :"""
-        [rdf:Property]  A set of PgefProperties for which this
+        'properties'     : {'range'          :'Property',
+                            'id'             :'id',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'ID',
+                            'range'          :'str',
+                            'property_type'  :'object',
+                            'max_cardinality':0,
+                            'description'    :"""
+        [rdf:Property]  A set of PgefProperties for which the
         C{ObjectSchema} is the domain.
         """}
         }

Index: PanGalactic/pangalactic/meta/pgefproperty.py
diff -u PanGalactic/pangalactic/meta/pgefproperty.py:1.15 PanGalactic/pangalactic/meta/pgefproperty.py:1.16
--- PanGalactic/pangalactic/meta/pgefproperty.py:1.15	Tue Apr 12 23:33:45 2005
+++ PanGalactic/pangalactic/meta/pgefproperty.py	Wed May  4 06:24:11 2005
@@ -1,4 +1,4 @@
-# $Id: pgefproperty.py,v 1.15 2005/04/13 03:33:45 waterbug Exp $
+# $Id: pgefproperty.py,v 1.16 2005/05/04 10:24:11 waterbug Exp $
 
 """
 The PanGalactic Property class (not to be confused with the Python built-in
@@ -23,9 +23,28 @@
 instances (TODO: p.m.View), and maps between schema instances (TODO:
 p.m.Map).
 
-@version: $Revision: 1.15 $
+In RDF and OWL (an RDF-based ontology representation vocabulary), a
+Property is a binary relationship.  RDF treats all Properties alike, but
+OWL separates them into two types:  "Datatype Properties" and "Object
+Properties".
+
+  * An rdf:Property is a relationship between two resources, which can be
+    anything, and which are called the domain (rdfs:domain) and range
+    (rdfs:range) of the rdf:Property.
+
+  * An owl:DatatypeProperty has an rdfs:domain that is an owl:Class and an
+    rdfs:range that is either an RDF literal or an XML Schema datatype.
+
+  * An owl:ObjectProperty has an rdfs:domain and an rdfs:range that are
+    both members of owl:Class.
+
+All three are represented in PGEF as instances of Property in a
+C{ObjectSchema}, in which the C{ObjectSchema} corresponds to the class that
+is the domain of the binary relationship.
+
+@version: $Revision: 1.16 $
 """
-__version__ = "$Revision: 1.15 $"[11:-2]
+__version__ = "$Revision: 1.16 $"[11:-2]
 
 
 from pangalactic.meta.utils import getDefault
@@ -47,136 +66,224 @@
     PGEF using C{ObjectSchema} and L{pangalactic.meta.ontology.Ontology}),
     and in the future, views of schema instances (TODO: PgefView), and maps
     between schema instances (TODO: PgefMap).
+
+    In RDF and OWL (an RDF-based ontology representation vocabulary), a
+    Property is a binary relationship.  RDF treats all Properties alike,
+    but OWL separates them into two types:  "Datatype Properties" and
+    "Object Properties".
+
+      * An rdf:Property is a relationship between two resources, which can
+        be anything, and which are called the domain (rdfs:domain) and
+        range (rdfs:range) of the rdf:Property.
+
+      * An owl:DatatypeProperty has an rdfs:domain that is an owl:Class and
+        an rdfs:range that is either an RDF literal or an XML Schema
+        datatype.
+
+      * An owl:ObjectProperty has an rdfs:domain and an rdfs:range that are
+        both members of owl:Class.
+
+    All three are represented in PGEF as instances of Property in a
+    C{ObjectSchema}, in which the C{ObjectSchema} corresponds to the class
+    that is the domain of the binary relationship.
     """
     # TODO: figure out how to generate the @ivar's and other docstring
     # elements from the _schema.
     # TODO: add attributes used in IEC 61360 and EOTD dictionaries
 
     _schema = {
-        'id'             : {'range'        :'str',
-                            'description'  :"""
+        'id'             : {
+                            'id'             :'id',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'ID',
+                            'range'          :'str',
+                            'default_display':'True',
+                            'description'    :"""
         [rdf:ID] Identifier of the Property within some context or
         namespace (for PgefObject and its subclasses, the context of their
         Property id's is the PanGalactic ontology's namespace).  (In
         RDF parlance, this is a "fragment identifier".)
         """},
 
-        'id_ns'          : {'range'        :'str',
-                            'description'  :"""
+        'id_ns'          : {
+                            'id'             :'id_ns',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Namespace',
+                            'range'          :'str',
+                            'default_display':'True',
+                            'description'    :"""
         [xml:base] The context, base URL, or namespace within which the
         'id' is unique.
         """},
 
-        'name'           : {'range'        :'str',
-                            'description'  :"""
+        'name'           : {
+                            'id'             :'name',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Name',
+                            'range'          :'str',
+                            'description'    :"""
         [rdfs:label] Human-readable identifier of the Property.
         """},
 
-        'abbrev'         : {'range'        :'str',
-                            'description'  :"""
-        [pgef:abbrev] The standard abbreviation for this classname (used in
-        forming the names of relationship tables and foreign key constraint
-        names).
+        'abbrev'         : {
+                            'id'             :'abbrev',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Abbreviation',
+                            'range'          :'str',
+                            'description'    :"""
+        [pgef:abbrev] The standard abbreviation for the Property.
         """},
 
-        'domain'         : {'range'        :'str',
-                            'description'  :"""
-        [rdfs:domain]  The id of the 'relating' C{ObjectSchema} of this
+        'domain'         : {
+                            'id'             :'domain',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Domain',
+                            'range'          :'str',
+                            'default_display':'True',
+                            'description'    :"""
+        [rdfs:domain]  The id of the 'relating' C{ObjectSchema} of the
         Property.
         """},
 
-        'range'          : {'range'        :'str',
-                            'default'      :'str',
-                            'description'  :"""
-        [rdfs:range] The name of the PGEF type used to represent
-        range values of this Property.  The interpretation of
-        'range' depends on the value of 'property_type':  if
-        property_type is 'datatype', range will be a Python
-        built-in type or a defined pgef_type; if 'property_type' is
-        'object', range will be the id of a C{ObjectSchema}.
-        This is the same concept as RDF Schema 'range' except that the
-        primitive types are Python built-in types, whereas in RDF Schema
-        they are XML Schema Datatypes (xsd).
-        """},
-
-        'property_type'  : {'range'        :'str',
-                            'default'      :'datatype',
-                            'description'  :"""
+        'range'          : {
+                            'id'             :'range',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Range',
+                            'range'          :'str',
+                            'default'        :'str',
+                            'default_display':'True',
+                            'description'    :"""
+        [rdfs:range] The name of the PGEF type used to represent range
+        values of the Property.  The interpretation of 'range' depends on
+        the value of 'property_type':  if property_type is 'datatype',
+        range will be a Python built-in type or a defined pgef_type; if
+        'property_type' is 'object', range will be the id of a
+        C{ObjectSchema}.  This is the same concept as RDF Schema 'range'
+        except that the primitive types are Python built-in types, whereas
+        in RDF Schema they are XML Schema Datatypes (xsd).
+        """},
+
+        'property_type'  : {
+                            'id'             :'property_type',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Property Type',
+                            'range'          :'str',
+                            'default'        :'datatype',
+                            'description'    :"""
         Discriminator attribute between [owl:DatatypeProperty] and
         [owl:ObjectProperty]  Values:  'datatype' or 'object'.  Specifies
-        whether the Property is an 'Object Property' (in which case its
-        range is a C{ObjectSchema}) or a 'Datatype Property' (in which
-        case its range is a datatype).
+        whether the Property is an Object Property (in which case its
+        range is a C{ObjectSchema}) or a Datatype Property (in which case
+        its range is a datatype).
         """},
 
-        'base'           : {'range'        :'Property',
-                            'property_type':'object',
-                            'description'  :"""
-        [rdfs:subClassOf] The immediate parent of this Property (if
-        any).
+        'base'           : {
+                            'id'             :'base',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Base Property',
+                            'range'          :'Property',
+                            'property_type'  :'object',
+                            'description'    :"""
+        [rdfs:subClassOf] The immediate parent of the Property (if any).
         """},
 
-        'min_cardinality': {'range'        :'int',
-                            'default'      :'0',
-                            'description'  :"""
+        'min_cardinality': {
+                            'id'             :'min_cardinality',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Minimum Cardinality',
+                            'range'          :'int',
+                            'default'        :'0',
+                            'description'    :"""
         [owl:minCardinality] The minimum number of instances of the range
-        datatype for an instance of this Property.
+        datatype for an instance of the Property.
         """},
 
-        'max_cardinality': {'range'        :'int',
-                            'default'      :'1',
-                            'description'  :"""
+        'max_cardinality': {
+                            'id'             :'max_cardinality',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Maximum Cardinality',
+                            'range'          :'int',
+                            'default'        :'1',
+                            'description'    :"""
         [owl:maxCardinality] The maximum number of instances of the range
-        datatype for an instance of this Property.
+        datatype for an instance of the Property.
         """},
 
-        'default'        : {'range'        :'str',
-                            'description'  :"""
-        [pgef:default] The default value for this Property.
+        'default'        : {
+                            'id'             :'default',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Default Value',
+                            'range'          :'str',
+                            'description'    :"""
+        [pgef:default] The default value for the Property.
         """},
 
-        'version'        : {'range'        :'str',
-                            'default'      :'baseline',
-                            'description'  :"""
+        'version'        : {
+                            'id'             :'version',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Version',
+                            'range'          :'str',
+                            'default'        :'baseline',
+                            'description'    :"""
         [owl:versionInfo] A user-modifiable string used to identify a
-        baseline, release, or version.
+        baseline, release, or version of the Property.
         """},
 
-        'iteration'      : {'range'        :'int',
+        'iteration'      : {
+                            'id'             :'iteration',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Iteration',
+                            'range'          :'int',
                             'description'  :"""
         [pgef:iteration] An application-assigned sequential integer
         identifying the precedence order of revisions of the Property.
         """},
 
-        'ontology'       : {'range'        :'Ontology',
-                            'property_type':'object',
-                            'description'  :"""
+        'ontology'       : {
+                            'id'             :'iteration',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Iteration',
+                            'range'          :'Ontology',
+                            'property_type'  :'object',
+                            'description'    :"""
         [rdfs:isDefinedBy]  The L{pangalactic.meta.ontology.Ontology} that
         owns this Property.  Note that in RDFS, isDefinedBy is a
-        relationship between a Property and a Resource that contains its
+        relationship between the Property and a Resource that contains its
         definition.
         """},
 
         # TODO:  this is a multi-valued datatype property, so will be
         # mapped in Chronosynclastic to an ARRAY of strings, when that is
         # implemented.
-        'known_aliases'  : {'range'          :'str',
+        'known_aliases'  : {
+                            'id'             :'known_aliases',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Known Aliases',
+                            'range'          :'str',
                             'max_cardinality':'0',
                             'description'    :"""
         [owl:equivalentProperty]  Synonymous OntoProperties.  This is
         represented as list containing 2-tuples C{(Property.id,
         Ontology.id)}, in which C{Ontology.id} should be unique within the
         application context so that an OWL C{equivalentProperty}
-        relationship between this Property and its aliases can be verified.
+        relationship between the Property and its aliases can be verified.
         """},
 
-        'description'    : {'range'        :'str',
+        'description'    : {
+                            'id'             :'description',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Description',
+                            'range'          :'str',
                             'description'  :"""
-        [rdf:comment]  A textual narrative on the characteristics and
-        identifying features of the object.
+        [rdf:comment]  A plain text narrative on the characteristics and
+        identifying features of the Property.
         """},
 
-        'comment'        : {'range'        :'str',
+        'comment'        : {
+                            'id'             :'comment',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Comment',
+                            'range'          :'str',
                             'description'  :"""
         [rdfs:comment]  Provides information about the Property that
         may be incidental, temporal, or contextual, and is usually in
@@ -184,29 +291,41 @@
         'comment' is determined by the application context.
         """},
 
-        'definition'     : {'range'        :'Document',
-                            'property_type':'object',
-                            'description'  :"""
-        [pgef:definition]  A Document that defines this Property (i.e.,
-        the necessary and sufficient conditions to for something to be an
+        'definition'     : {
+                            'id'             :'definition',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Definition',
+                            'range'          :'Document',
+                            'property_type'  :'object',
+                            'description'    :"""
+        [pgef:definition]  A Document that defines the Property (i.e.,
+        the necessary and sufficient conditions for something to be an
         instance of this Property).  This is meant to support
         references to standardized data definitions, e.g. such as might be
         found in an IEC 61360 dictionary.
         """},
 
-        'default_display': {'range'        :'bool',
-                            'default'      :'',
-                            'description'  :"""
-        [pgef:default_display] indicates whether this Property is included
+        'default_display': {
+                            'id'             :'default_display',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Default Display',
+                            'range'          :'bool',
+                            'default'        :'',
+                            'description'    :"""
+        [pgef:default_display] indicates whether the Property is included
         in the default set of properties shown when an object from the
         'rdfs:domain' (or simply the parent application object) is
         displayed in a grid.
         """},
 
-        'display_name'   : {'range'        :'bool',
-                            'description'  :"""
+        'display_name'   : {
+                            'id'             :'display_name',
+                            'id_ns'          :'http://pangalactic.us/pgef/',
+                            'name'           :'Display Name',
+                            'range'          :'str',
+                            'description'    :"""
         [pgef:display_name] the default name (which may be distinct from
-        this Property's 'name' attribute) to use as the heading for this
+        the Property's 'name' attribute) to use as the heading for the
         Property when it is displayed in a grid.
         """}
         }

Index: PanGalactic/pangalactic/node/gui/psm/itemeditframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.13 PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.14
--- PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.13	Tue May  3 16:34:49 2005
+++ PanGalactic/pangalactic/node/gui/psm/itemeditframe.py	Wed May  4 06:24:12 2005
@@ -1,10 +1,10 @@
-# $Id: itemeditframe.py,v 1.13 2005/05/03 20:34:49 waterbug Exp $
+# $Id: itemeditframe.py,v 1.14 2005/05/04 10:24:12 waterbug Exp $
 """
 GUI providing browsing/editing capabilities for Part, Model, Document, and
 PartsList objects.
 """
 
-__version__ = "$Revision: 1.13 $"[11:-2]
+__version__ = "$Revision: 1.14 $"[11:-2]
 
 import wx
 from pangalactic.node.gui.psm import docform
@@ -16,7 +16,6 @@
 from pangalactic.node.gui.psm import pgefedittree
 from pangalactic.node.gui.psm import partform
 from pangalactic.node.gui.psm import modelform
-from pangalactic.node.gui.psm import propertiesform 
 from pangalactic.node.gui.psm import pgefversiontree
 from pangalactic.utils.preferences import prefs, writePrefs
 from pangalactic.utils.pgefstate import state
@@ -89,10 +88,7 @@
         self.tID = wx.NewId()
         self.treeMap = {}
         self.tree = pgefedittree.PgefEditTree(self.vsplitter, self.tID, self.dm)
-        tree_tooltip = ' '.join([
-        "A hierarchical display of the currently selected product.",
-        "Click on a product to display its data on the Data tab on",
-        "the Attributes tab."])
+        tree_tooltip = "The assembly structure of the currently selected item."
         self.tree.SetToolTip(wx.ToolTip(tree_tooltip))
         self.currenttree = None
         self.modeltree = None
@@ -104,9 +100,6 @@
         self.modelform = modelform.ModelForm(self.editnb, -1)
         self.editnb.AddPage(self.modelform,
                             "Model")
-        self.propertiesform = propertiesform.PropertiesForm(self.editnb, -1)
-        self.editnb.AddPage(self.propertiesform,
-                            "Product Properties")
         self.partslistform = partslistform.PartsListForm(self.editnb, -1)
         self.editnb.AddPage(self.partslistform,
                             "Parts Lists")
@@ -119,19 +112,16 @@
         #notebook page indices
         self.PartPage = 0
         self.ModelPage = 1
-        self.PropertiesPage = 2
-        self.PartsListPage = 3
-        self.PartDataPage = 4
-        self.DocPage = 5
+        self.PartsListPage = 2
+        self.PartDataPage = 3
+        self.DocPage = 4
         self.tabnames = {self.PartPage:       'Part',
                          self.ModelPage:      'Model',
-                         self.PropertiesPage: 'Part Properties',
                          self.PartsListPage:  'Parts Lists',
                          self.PartDataPage:   'Parts List Data',
                          self.DocPage:        'Documents'}
         self.rootobjs = {self.PartPage:       None,
                          self.ModelPage:      None,
-                         self.PropertiesPage: None,
                          self.PartsListPage:  None,
                          self.PartDataPage:   None,
                          self.DocPage:        None}
@@ -216,7 +206,6 @@
         self.tempobj.__dict__.update(self.currentobj.__dict__)
         if schema_id == "Part":
             self.rootobjs[self.PartPage] = rootobj
-            self.rootobjs[self.PropertiesPage] = rootobj
             self.rootobjs[self.PartsListPage] = rootobj
             self.rootobjs[self.PartDataPage] = rootobj
             self.currentpage = self.PartPage
@@ -227,7 +216,6 @@
             # TODO:  (which should be plug-ins) -- e.g., PyDispatcher
             # if rootobj.of_part:
             #     self.rootobjs[self.PartPage] = rootobj.of_part
-            #     self.rootobjs[self.PropertiesPage] = rootobj.of_part
             #     self.rootobjs[self.PartsListPage] = rootobj.of_part
             #     self.rootobjs[self.PartDataPage] = rootobj.of_part
             self.currentpage = self.ModelPage
@@ -272,7 +260,6 @@
         self.modelform.clearForm()
         self.partslistform.ClearForm()
         self.partslistview.partslistgrid.ClearGrid()
-        self.propertiesform.propertiesgrid.ClearGrid()
         self.documentform.ClearForm()
 
     def SetName(self, name):

Index: PanGalactic/pangalactic/test/IDTEST
diff -u PanGalactic/pangalactic/test/IDTEST:1.111 PanGalactic/pangalactic/test/IDTEST:1.112
--- PanGalactic/pangalactic/test/IDTEST:1.111	Tue May  3 03:08:31 2005
+++ PanGalactic/pangalactic/test/IDTEST	Wed May  4 06:24:12 2005
@@ -1 +1 @@
-1614
\ No newline at end of file
+1622
\ No newline at end of file

From waterbug at step.nasa.gov  Wed May  4 10:58:06 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May  4 10:58:08 2005
Subject: [pangalactic-commits] import of localdb not needed.
Message-ID: <200505041458.j44Ew6BD019362@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py 1.2 1.3

Log message:
import of localdb not needed.

Index: PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py
diff -u PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.2 PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.3
--- PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.2	Tue May  3 03:08:30 2005
+++ PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py	Wed May  4 10:58:05 2005
@@ -1,5 +1,5 @@
 #!/bin/env python
-# $Id: cachebrowser.py,v 1.2 2005/05/03 07:08:30 waterbug Exp $
+# $Id: cachebrowser.py,v 1.3 2005/05/04 14:58:05 waterbug Exp $
 #----------------------------------------------------------------------------
 # Authors:      Ginny, Steve
 #----------------------------------------------------------------------------
@@ -7,9 +7,9 @@
 PanGalaxian cache browser and display customizer
 (Works with PgefObjects in a local ZODB)
 
-@version: $Revision: 1.2 $
+@version: $Revision: 1.3 $
 """
-__version__ = "$Revision: 1.2 $"[11:-2]
+__version__ = "$Revision: 1.3 $"[11:-2]
 
 import wx
 from wx import grid
@@ -23,7 +23,6 @@
 from pangalactic.utils import toolframe
 from pangalactic.utils import objectviewer
 from pangalactic.utils import configuregrid
-from pangalactic.utils import localdb
 from pangalactic.utils.pgefstate import state
 
 from pprint import pprint

From waterbug at step.nasa.gov  Thu May  5 09:25:17 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May  5 09:25:19 2005
Subject: [pangalactic-commits] Turn editing back on.
Message-ID: <200505051325.j45DPHv8032208@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/utils/objectviewer.py 1.8 1.9

Log message:
Turn editing back on.

Index: PanGalactic/pangalactic/utils/objectviewer.py
diff -u PanGalactic/pangalactic/utils/objectviewer.py:1.8 PanGalactic/pangalactic/utils/objectviewer.py:1.9
--- PanGalactic/pangalactic/utils/objectviewer.py:1.8	Sat Apr 30 14:45:25 2005
+++ PanGalactic/pangalactic/utils/objectviewer.py	Thu May  5 09:25:16 2005
@@ -1,8 +1,14 @@
-import os.path
+# $Id: objectviewer.py,v 1.9 2005/05/05 13:25:16 waterbug Exp $
+"""
+Late-bound viewer for PgefObjects
+
+@version: $Revision: 1.9 $
+"""
+__version__ = "$Revision: 1.9 $"[11:-2]
 
+import os.path
 import wx
 from wx import grid
-
 from pangalactic.core.pgefobject import PgefObject
 import pangalactic.utils.toolframe as toolframe
 
@@ -41,13 +47,12 @@
         self.ObjGrid.SetColAttr(self.RightCol, rattr)
         self.NextRow = 0
         self.SelectedRow = None
-#        grid.EVT_GRID_CELL_LEFT_DCLICK(self.ObjGrid, self.OnEdit)
+        grid.EVT_GRID_CELL_LEFT_DCLICK(self.ObjGrid, self.OnEdit)
         grid.EVT_GRID_CELL_CHANGE(self.ObjGrid, self.OnCellChange)
         grid.EVT_GRID_SELECT_CELL(self, self.OnSelectCell)
         grid.EVT_GRID_EDITOR_SHOWN(self, self.OnEditorShown)
         grid.EVT_GRID_EDITOR_HIDDEN(self, self.OnEditorHidden)
         self.Bind(wx.EVT_BUTTON, self.onClose, self.close_button)
-
         self.SetToolTips()
         self.SetData(obj)
         self.CentreOnParent()
@@ -119,13 +124,13 @@
         self.SelectedRow = event.GetRow()
         event.Skip()
 
-#    def OnEdit(self, event):
-#        # print "onedit"
-#        self.SelectedRow = event.GetRow()
-#        if self.ObjGrid.CanEnableCellControl():
-#            self.ObjGrid.EnableCellEditControl()
-#            self.ObjGrid.ShowCellEditControl()
-#        event.Skip()
+    def OnEdit(self, event):
+        # print "onedit"
+        self.SelectedRow = event.GetRow()
+        if self.ObjGrid.CanEnableCellControl():
+            self.ObjGrid.EnableCellEditControl()
+            self.ObjGrid.ShowCellEditControl()
+        event.Skip()
 
     def FindRow(self, rightval):
         for ndx in range(self.NextRow):

From waterbug at step.nasa.gov  Thu May  5 23:06:15 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May  5 23:06:17 2005
Subject: [pangalactic-commits] Exploit new wx menu-creation syntax.
Message-ID: <200505060306.j4636F56012110@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.4 1.5

Log message:
Exploit new wx menu-creation syntax.

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.4 PanGalactic/pangalactic/node/pangalaxian_new.py:1.5
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.4	Sat Apr 30 14:45:24 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Thu May  5 23:06:13 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.4 2005/04/30 18:45:24 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.5 2005/05/06 03:06:13 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.4 $
+@version: $Revision: 1.5 $
 """
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 # Python core modules
 import sys
@@ -74,101 +74,65 @@
         # Menu Bar
         self.pgxn_menubar = wx.MenuBar()
         self.SetMenuBar(self.pgxn_menubar)
-        self.m_file_menu = wx.Menu()
-        m_file_new_menu = wx.Menu()
-        self.m_file_new_part = wx.MenuItem(m_file_new_menu, wx.NewId(), "&Part...", "Create a Part ...", wx.ITEM_NORMAL)
-        m_file_new_menu.AppendItem(self.m_file_new_part)
-        self.m_file_new_model = wx.MenuItem(m_file_new_menu, wx.NewId(), "&Model...", "Create a Model ...", wx.ITEM_NORMAL)
-        m_file_new_menu.AppendItem(self.m_file_new_model)
-        self.m_file_new_partslist = wx.MenuItem(m_file_new_menu, wx.NewId(), "Parts &List...", "Create a new Parts List ...", wx.ITEM_NORMAL)
-        m_file_new_menu.AppendItem(self.m_file_new_partslist)
-        self.m_file_new_doc = wx.MenuItem(m_file_new_menu, wx.NewId(), "&Document...", "Create a new Document ...", wx.ITEM_NORMAL)
-        m_file_new_menu.AppendItem(self.m_file_new_doc)
-        self.m_file_menu.AppendMenu(wx.NewId(), "&New", m_file_new_menu, "")
-        self.m_file_login = wx.MenuItem(self.m_file_menu, wx.NewId(), "Log&in", "Login to hub ...", wx.ITEM_NORMAL)
-        self.m_file_menu.AppendItem(self.m_file_login)
-        self.m_file_logout = wx.MenuItem(self.m_file_menu, wx.NewId(), "Log&out", "Logout from hub ...", wx.ITEM_NORMAL)
-        self.m_file_menu.AppendItem(self.m_file_logout)
-        self.m_file_export = wx.MenuItem(self.m_file_menu, wx.NewId(), "&Export", "Export file as ...", wx.ITEM_NORMAL)
-        self.m_file_menu.AppendItem(self.m_file_export)
-        self.m_file_exit = wx.MenuItem(self.m_file_menu, wx.NewId(), "E&xit", "Exit PanGalaxian ...", wx.ITEM_NORMAL)
-        self.m_file_menu.AppendItem(self.m_file_exit)
-        self.pgxn_menubar.Append(self.m_file_menu, "&File")
-        self.m_tools_menu = wx.Menu()
-        m_tools_part_menu = wx.Menu()
-        self.m_tools_new_part = wx.MenuItem(m_tools_part_menu, wx.NewId(), "&New...", "Create a Part ...", wx.ITEM_NORMAL)
-        m_tools_part_menu.AppendItem(self.m_tools_new_part)
-        self.m_tools_edit_part = wx.MenuItem(m_tools_part_menu, wx.NewId(), "&Edit...", "Edit a Part ...", wx.ITEM_NORMAL)
-        m_tools_part_menu.AppendItem(self.m_tools_edit_part)
-        self.m_tools_view_part = wx.MenuItem(m_tools_part_menu, wx.NewId(), "&View...", "View a Part ...", wx.ITEM_NORMAL)
-        m_tools_part_menu.AppendItem(self.m_tools_view_part)
-        self.m_tools_menu.AppendMenu(wx.NewId(), "&Parts", m_tools_part_menu, "")
-        m_tools_model_menu = wx.Menu()
-        self.m_tools_new_model = wx.MenuItem(m_tools_model_menu, wx.NewId(), "&New...", "Create a new Model ...", wx.ITEM_NORMAL)
-        m_tools_model_menu.AppendItem(self.m_tools_new_model)
-        self.m_tools_edit_model = wx.MenuItem(m_tools_model_menu, wx.NewId(), "&Edit...", "Edit a Model ...", wx.ITEM_NORMAL)
-        m_tools_model_menu.AppendItem(self.m_tools_edit_model)
-        self.m_tools_view_model = wx.MenuItem(m_tools_model_menu, wx.NewId(), "&View...", "View a Model ...", wx.ITEM_NORMAL)
-        m_tools_model_menu.AppendItem(self.m_tools_view_model)
-        self.m_tools_menu.AppendMenu(wx.NewId(), "&Models", m_tools_model_menu, "")
-        m_tools_partslist_menu = wx.Menu()
-        self.m_tools_new_partslist = wx.MenuItem(m_tools_partslist_menu, wx.NewId(), "&New...", "Create a Parts List ...", wx.ITEM_NORMAL)
-        m_tools_partslist_menu.AppendItem(self.m_tools_new_partslist)
-        self.m_tools_edit_partslist = wx.MenuItem(m_tools_partslist_menu, wx.NewId(), "&Edit...", "Edit a Parts List ...", wx.ITEM_NORMAL)
-        m_tools_partslist_menu.AppendItem(self.m_tools_edit_partslist)
-        self.m_tools_view_partslist = wx.MenuItem(m_tools_partslist_menu, wx.NewId(), "&View...", "View a Parts List ...", wx.ITEM_NORMAL)
-        m_tools_partslist_menu.AppendItem(self.m_tools_view_partslist)
-        self.m_tools_menu.AppendMenu(wx.NewId(), "Parts &Lists", m_tools_partslist_menu, "")
-        m_tools_doc_menu = wx.Menu()
-        self.m_tools_new_doc = wx.MenuItem(m_tools_doc_menu, wx.NewId(), "&New...", "Create a Document ...", wx.ITEM_NORMAL)
-        m_tools_doc_menu.AppendItem(self.m_tools_new_doc)
-        self.m_tools_edit_doc = wx.MenuItem(m_tools_doc_menu, wx.NewId(), "&Edit...", "Edit a Document ...", wx.ITEM_NORMAL)
-        m_tools_doc_menu.AppendItem(self.m_tools_edit_doc)
-        self.m_tools_view_doc = wx.MenuItem(m_tools_doc_menu, wx.NewId(), "&View...", "View a Document ...", wx.ITEM_NORMAL)
-        m_tools_doc_menu.AppendItem(self.m_tools_view_doc)
-        self.m_tools_menu.AppendMenu(wx.NewId(), "&Documents", m_tools_doc_menu, "")
-        self.m_tools_menu.AppendSeparator()
-        self.m_tools_search = wx.MenuItem(self.m_tools_menu, wx.NewId(), "&Search...", "Search repository ...", wx.ITEM_NORMAL)
-        self.m_tools_menu.AppendItem(self.m_tools_search)
-        self.m_tools_report = wx.MenuItem(self.m_tools_menu, wx.NewId(), "&Report...", "Generate a PDF report from the grid contents ...", wx.ITEM_NORMAL)
-        self.m_tools_menu.AppendItem(self.m_tools_report)
-        self.pgxn_menubar.Append(self.m_tools_menu, "&Tools")
-        self.m_repository_menu = wx.Menu()
-        self.m_repo_commit = wx.MenuItem(self.m_repository_menu, wx.NewId(), "&Commit ...", "Commit local changes to repository ...", wx.ITEM_NORMAL)
-        self.m_repository_menu.AppendItem(self.m_repo_commit)
-        self.m_repo_getmystuff = wx.MenuItem(self.m_repository_menu, wx.NewId(), "&Get My Stuff...", "Get objects owned by me ...", wx.ITEM_NORMAL)
-        self.m_repository_menu.AppendItem(self.m_repo_getmystuff)
-        self.m_repo_selectrepo = wx.MenuItem(self.m_repository_menu, wx.NewId(), "Select &Repository...", "Select a Repository ...", wx.ITEM_NORMAL)
-        self.m_repository_menu.AppendItem(self.m_repo_selectrepo)
-        self.pgxn_menubar.Append(self.m_repository_menu, "&Repository")
-        self.m_cache_menu = wx.Menu()
-        self.m_cache_browse = wx.MenuItem(self.m_cache_menu, wx.NewId(), "&Browse Local Objects...", "Browse locally cached objects ...", wx.ITEM_NORMAL)
-        self.m_cache_menu.AppendItem(self.m_cache_browse)
-        self.m_cache_clear = wx.MenuItem(self.m_cache_menu, wx.NewId(), "&Clear Local Objects...", "Remove objects from local cache", wx.ITEM_NORMAL)
-        self.m_cache_menu.AppendItem(self.m_cache_clear)
-        self.pgxn_menubar.Append(self.m_cache_menu, "&Cache")
-        self.m_options_menu = wx.Menu()
-        self.m_options_userid = wx.MenuItem(self.m_options_menu, wx.NewId(), "&Userid...", "Set userid ...", wx.ITEM_NORMAL)
-        self.m_options_menu.AppendItem(self.m_options_userid)
-        self.m_options_passwd = wx.MenuItem(self.m_options_menu, wx.NewId(), "Change &Password...", "Change your password ...", wx.ITEM_NORMAL)
-        self.m_options_menu.AppendItem(self.m_options_passwd)
-        self.m_options_outputdir = wx.MenuItem(self.m_options_menu, wx.NewId(), "Set Output &Directory...", "Select a directory to write files to ...", wx.ITEM_NORMAL)
-        self.m_options_menu.AppendItem(self.m_options_outputdir)
-        self.m_options_repo = wx.MenuItem(self.m_options_menu, wx.NewId(), "&Repository...", "Select a Repository ...", wx.ITEM_NORMAL)
-        self.m_options_menu.AppendItem(self.m_options_repo)
-        self.m_options_proxy = wx.MenuItem(self.m_options_menu, wx.NewId(), "Pro&xy...", "Use a proxy web server", wx.ITEM_NORMAL)
-        self.m_options_menu.AppendItem(self.m_options_proxy)
-        self.m_options_loginconfirm = wx.MenuItem(self.m_options_menu, wx.NewId(), "Show Login &Confirmation", "Confirm when login succeeds ...", wx.ITEM_NORMAL)
-        self.m_options_menu.AppendItem(self.m_options_loginconfirm)
-        self.m_options_tooltips = wx.MenuItem(self.m_options_menu, wx.NewId(), "Show &Tooltips", "Allow tooltip pop-up messages", wx.ITEM_CHECK)
-        self.m_options_menu.AppendItem(self.m_options_tooltips)
-        self.pgxn_menubar.Append(self.m_options_menu, "&Options")
-        self.m_help_menu = wx.Menu()
-        self.m_help_about = wx.MenuItem(self.m_help_menu, wx.NewId(), "&About", "Info about PanGalaxian ...", wx.ITEM_NORMAL)
-        self.m_help_menu.AppendItem(self.m_help_about)
-        self.m_help_contents = wx.MenuItem(self.m_help_menu, wx.NewId(), "&Contents", "Contents of help docs ...", wx.ITEM_NORMAL)
-        self.m_help_menu.AppendItem(self.m_help_contents)
-        self.pgxn_menubar.Append(self.m_help_menu, "&Help")
+        self.file_menu = wx.Menu()
+        self.pgxn_menubar.Append(self.file_menu, "&File")
+        self.file_new_menu = wx.Menu()
+        self.file_menu.AppendMenu(-1, "&New", self.file_new_menu, "")
+        self.file_new_part_menu      = self.file_new_menu.Append(-1, "&Part...", "Create a Part ...", wx.ITEM_NORMAL)
+        self.file_new_model_menu     = self.file_new_menu.Append(-1, "&Model...", "Create a Model ...", wx.ITEM_NORMAL)
+        self.file_new_partslist_menu = self.file_new_menu.Append(-1, "Parts &List...", "Create a new Parts List ...", wx.ITEM_NORMAL)
+        self.file_new_doc_menu       = self.file_new_menu.Append(-1, "&Document...", "Create a new Document ...", wx.ITEM_NORMAL)
+        self.file_login_menu         = self.file_menu.Append(-1, "Log&in", "Login to hub ...", wx.ITEM_NORMAL)
+        self.file_logout_menu        = self.file_menu.Append(-1, "Log&out", "Logout from hub ...", wx.ITEM_NORMAL)
+        self.file_export_menu        = self.file_menu.Append(-1, "&Export", "Export file as ...", wx.ITEM_NORMAL)
+        self.file_exit_menu          = self.file_menu.Append(-1, "E&xit", "Exit PanGalaxian ...", wx.ITEM_NORMAL)
+        self.tools_menu = wx.Menu()
+        self.tools_part_menu = wx.Menu()
+        self.tools_menu.AppendMenu(-1, "&Parts", self.tools_part_menu, "")
+        self.tools_new_part_menu  = self.tools_part_menu.Append(-1, "&New...", "Create a Part ...", wx.ITEM_NORMAL)
+        self.tools_edit_part_menu = self.tools_part_menu.Append(-1, "&Edit...", "Edit a Part ...", wx.ITEM_NORMAL)
+        self.tools_view_part_menu = self.tools_part_menu.Append(-1, "&View...", "View a Part ...", wx.ITEM_NORMAL)
+        self.tools_model_menu = wx.Menu()
+        self.tools_new_model_menu  = self.tools_model_menu.Append(-1, "&New...", "Create a new Model ...", wx.ITEM_NORMAL)
+        self.tools_edit_model_menu = self.tools_model_menu.Append(-1, "&Edit...", "Edit a Model ...", wx.ITEM_NORMAL)
+        self.tools_view_model_menu = self.tools_model_menu.Append(-1, "&View...", "View a Model ...", wx.ITEM_NORMAL)
+        self.tools_menu.AppendMenu(-1, "&Models", self.tools_model_menu, "")
+        self.tools_partslist_menu = wx.Menu()
+        self.tools_new_partslist_menu  = self.tools_partslist_menu.Append(-1, "&New...", "Create a Parts List ...", wx.ITEM_NORMAL)
+        self.tools_edit_partslist_menu = self.tools_partslist_menu.Append(-1, "&Edit...", "Edit a Parts List ...", wx.ITEM_NORMAL)
+        self.tools_view_partslist_menu = self.tools_partslist_menu.Append(-1, "&View...", "View a Parts List ...", wx.ITEM_NORMAL)
+        self.tools_menu.AppendMenu(-1, "Parts &Lists", self.tools_partslist_menu, "")
+        self.tools_doc_menu = wx.Menu()
+        self.tools_new_doc_menu  = self.tools_doc_menu.Append(-1, "&New...", "Create a Document ...", wx.ITEM_NORMAL)
+        self.tools_edit_doc_menu = self.tools_doc_menu.Append(-1, "&Edit...", "Edit a Document ...", wx.ITEM_NORMAL)
+        self.tools_view_doc_menu = self.tools_doc_menu.Append(-1, "&View...", "View a Document ...", wx.ITEM_NORMAL)
+        self.tools_menu.AppendMenu(-1, "&Documents", self.tools_doc_menu, "")
+        self.tools_menu.AppendSeparator()
+        self.tools_search_menu = self.tools_menu.Append(-1, "&Search...", "Search repository ...", wx.ITEM_NORMAL)
+        self.tools_report_menu = self.tools_menu.Append(-1, "&Report...", "Generate a PDF report from the grid contents ...", wx.ITEM_NORMAL)
+        self.pgxn_menubar.Append(self.tools_menu, "&Tools")
+        self.repository_menu = wx.Menu()
+        self.repo_commit_menu     = self.repository_menu.Append(-1, "&Commit ...", "Commit local changes to repository ...", wx.ITEM_NORMAL)
+        self.repo_getmystuff_menu = self.repository_menu.Append(-1, "&Get My Stuff...", "Get objects owned by me ...", wx.ITEM_NORMAL)
+        self.repo_selectrepo_menu = self.repository_menu.Append(-1, "Select &Repository...", "Select a Repository ...", wx.ITEM_NORMAL)
+        self.pgxn_menubar.Append(self.repository_menu, "&Repository")
+        self.cache_menu = wx.Menu()
+        self.cache_browse_menu = self.cache_menu.Append(-1, "&Browse Local Objects...", "Browse locally cached objects ...", wx.ITEM_NORMAL)
+        self.cache_clear_menu = self.cache_menu.Append(-1, "&Clear Local Objects...", "Remove objects from local cache", wx.ITEM_NORMAL)
+        self.pgxn_menubar.Append(self.cache_menu, "&Cache")
+        self.options_menu = wx.Menu()
+        self.options_userid_menu       = self.options_menu.Append(-1, "&Userid...", "Set userid ...", wx.ITEM_NORMAL)
+        self.options_passwd_menu       = self.options_menu.Append(-1, "Change &Password...", "Change your password ...", wx.ITEM_NORMAL)
+        self.options_outputdir_menu    = self.options_menu.Append(-1, "Set Output &Directory...", "Select a directory to write files to ...", wx.ITEM_NORMAL)
+        self.options_repo_menu         = self.options_menu.Append(-1, "&Repository...", "Select a Repository ...", wx.ITEM_NORMAL)
+        self.options_proxy_menu        = self.options_menu.Append(-1, "Pro&xy...", "Use a proxy web server", wx.ITEM_NORMAL)
+        self.options_loginconfirm_menu = self.options_menu.Append(-1, "Show Login &Confirmation", "Confirm when login succeeds ...", wx.ITEM_NORMAL)
+        self.options_tooltips_menu     = self.options_menu.Append(-1, "Show &Tooltips", "Allow tooltip pop-up messages", wx.ITEM_CHECK)
+        self.pgxn_menubar.Append(self.options_menu, "&Options")
+        self.help_menu = wx.Menu()
+        self.help_about_menu    = self.help_menu.Append(-1, "&About", "Info about PanGalaxian ...", wx.ITEM_NORMAL)
+        self.help_contents_menu = self.help_menu.Append(-1, "&Contents", "Contents of help docs ...", wx.ITEM_NORMAL)
+        self.pgxn_menubar.Append(self.help_menu, "&Help")
         # Menu Bar end
 
         self.__set_properties()
@@ -268,20 +232,19 @@
         self.searchwindow = None
         self.psmplugin = None
         self.closing = False
-        self.adminmenu = None
         #########
         ### GodMenu is disabled until further notice ...
         # self.GodMenu = None
         # self.GodMode = None
         showloginconfirm = prefs.get('ShowLoginConfirmed', True)
-        self.m_options_loginconfirm.Check(bool(int(showloginconfirm)))
+        self.options_loginconfirm_menu.Check(bool(int(showloginconfirm)))
         show_tooltips = prefs.get("ShowToolTips", True)
         if show_tooltips:
             wx.ToolTip_Enable(True)
-            self.m_options_tooltips.Check(True)
+            self.options_tooltips_menu.Check(True)
         else:
             wx.ToolTip_Enable(False)
-            self.m_options_tooltips.Check(False)
+            self.options_tooltips_menu.Check(False)
         self.contexts = state.get('contexts', None) or ['[no context]']
         self.bindEvents()
         # self.onModeChange()
@@ -319,59 +282,59 @@
         self.Bind(wx.EVT_SIZE, self.onSize)
         ###################################################
         # bind menu events
-        # (note:  all PanGalaxian menu event names begin with 'm_')
+        # (note:  all PanGalaxian menu event names begin with 'menu_')
         #
         # File menu
-        self.Bind(wx.EVT_MENU, self.onNewPart, self.m_file_new_part)
-        # self.Bind(wx.EVT_MENU, self.onNewModel, self.m_file_new_model)
-        # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.m_file_new_partslist)
-        # self.Bind(wx.EVT_MENU, self.onNewDocument, self.m_file_new_document)
-        # self.Bind(wx.EVT_MENU, self.onLogin, self.m_file_login)
-        # self.Bind(wx.EVT_MENU, self.onLogout, self.m_file_logout)
-        # self.Bind(wx.EVT_MENU, self.onExport, self.m_file_export)
-        self.Bind(wx.EVT_MENU, self.onExit, self.m_file_exit)
+        self.Bind(wx.EVT_MENU, self.onNewPart, self.file_new_part_menu)
+        # self.Bind(wx.EVT_MENU, self.onNewModel, self.file_new_model_menu)
+        # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.file_new_partslist_menu)
+        # self.Bind(wx.EVT_MENU, self.onNewDocument, self.file_new_document_menu)
+        # self.Bind(wx.EVT_MENU, self.onLogin, self.file_login_menu)
+        # self.Bind(wx.EVT_MENU, self.onLogout, self.file_logout_menu)
+        # self.Bind(wx.EVT_MENU, self.onExport, self.file_export_menu)
+        self.Bind(wx.EVT_MENU, self.onExit, self.file_exit_menu)
         #
         # Tools menu
-        # self.Bind(wx.EVT_MENU, self.onNewPart, self.m_tools_new_part)
-        # self.Bind(wx.EVT_MENU, self.onEditPart, self.m_tools_edit_part)
-        # self.Bind(wx.EVT_MENU, self.onViewPart, self.m_tools_view_part)
-        # self.Bind(wx.EVT_MENU, self.onNewModel, self.m_tools_new_model)
-        # self.Bind(wx.EVT_MENU, self.onEditModel, self.m_tools_edit_model)
-        # self.Bind(wx.EVT_MENU, self.onViewModel, self.m_tools_view_model)
-        # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.m_tools_new_partslist)
-        # self.Bind(wx.EVT_MENU, self.onEditPartsList, self.m_tools_edit_partslist)
-        # self.Bind(wx.EVT_MENU, self.onViewPartsList, self.m_tools_view_partslist)
-        # self.Bind(wx.EVT_MENU, self.onNewDocument, self.m_tools_new_document)
-        # self.Bind(wx.EVT_MENU, self.onEditDocument, self.m_tools_edit_document)
-        # self.Bind(wx.EVT_MENU, self.onViewDocument, self.m_tools_view_document)
-        # self.Bind(wx.EVT_MENU, self.onReport, self.m_tools_report)
+        # self.Bind(wx.EVT_MENU, self.onNewPart, self.tools_new_part_menu)
+        # self.Bind(wx.EVT_MENU, self.onEditPart, self.tools_edit_part_menu)
+        # self.Bind(wx.EVT_MENU, self.onViewPart, self.tools_view_part_menu)
+        # self.Bind(wx.EVT_MENU, self.onNewModel, self.tools_new_model_menu)
+        # self.Bind(wx.EVT_MENU, self.onEditModel, self.tools_edit_model_menu)
+        # self.Bind(wx.EVT_MENU, self.onViewModel, self.tools_view_model_menu)
+        # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.tools_new_partslist_menu)
+        # self.Bind(wx.EVT_MENU, self.onEditPartsList, self.tools_edit_partslist_menu)
+        # self.Bind(wx.EVT_MENU, self.onViewPartsList, self.tools_view_partslist_menu)
+        # self.Bind(wx.EVT_MENU, self.onNewDocument, self.tools_new_document_menu)
+        # self.Bind(wx.EVT_MENU, self.onEditDocument, self.tools_edit_document_menu)
+        # self.Bind(wx.EVT_MENU, self.onViewDocument, self.tools_view_document_menu)
+        # self.Bind(wx.EVT_MENU, self.onReport, self.tools_report_menu)
         #                      was: onGridToPdf
-        # self.Bind(wx.EVT_MENU, self.onSearch, self.m_tools_search)
+        # self.Bind(wx.EVT_MENU, self.onSearch, self.tools_search_menu)
         #
         # Repository menu
-        # self.Bind(wx.EVT_MENU, self.onCommit, self.m_repo_commit)
-        # self.Bind(wx.EVT_MENU, self.onGetMyStuff, self.m_repo_getmystuff)
-        # self.Bind(wx.EVT_MENU, self.onSelectRepo, self.m_repo_selectrepo)
+        # self.Bind(wx.EVT_MENU, self.onCommit, self.repo_commit_menu)
+        # self.Bind(wx.EVT_MENU, self.onGetMyStuff, self.repo_getmystuff_menu)
+        # self.Bind(wx.EVT_MENU, self.onSelectRepo, self.repo_selectrepo_menu)
         #                      was: onServerSettings
         #
         # Cache menu
-        # self.Bind(wx.EVT_MENU, self.onCacheBrowse, self.m_cache_browse)
+        # self.Bind(wx.EVT_MENU, self.onCacheBrowse, self.cache_browse_menu)
         #                      was: onDBBrowser
-        # self.Bind(wx.EVT_MENU, self.onCacheClear, self.m_cache_clear)
+        # self.Bind(wx.EVT_MENU, self.onCacheClear, self.cache_clear_menu)
         #                      was: onClearLocalDB
         #
         # Options menu
-        # self.Bind(wx.EVT_MENU, self.onSetUserId, self.m_options_userid)
-        # self.Bind(wx.EVT_MENU, self.onSetPasswd, self.m_options_passwd)
+        # self.Bind(wx.EVT_MENU, self.onSetUserId, self.options_userid_menu)
+        # self.Bind(wx.EVT_MENU, self.onSetPasswd, self.options_passwd_menu)
         #                      was: onPasswd
-        # self.Bind(wx.EVT_MENU, self.onSetOutputDir, self.m_options_outputdir)
-        # self.Bind(wx.EVT_MENU, self.onProxySettings, self.m_options_proxy)
-        self.Bind(wx.EVT_MENU, self.onEnableTooltips, self.m_options_tooltips)
-        # self.Bind(wx.EVT_MENU, self.onShowLoginConfirmed, self.m_options_loginconfirm)
+        # self.Bind(wx.EVT_MENU, self.onSetOutputDir, self.options_outputdir_menu)
+        # self.Bind(wx.EVT_MENU, self.onProxySettings, self.options_proxy_menu)
+        self.Bind(wx.EVT_MENU, self.onEnableTooltips, self.options_tooltips_menu)
+        # self.Bind(wx.EVT_MENU, self.onShowLoginConfirmed, self.options_loginconfirm_menu)
         #
         # Help menu
-        self.Bind(wx.EVT_MENU, self.onHelpAbout, self.m_help_about)
-        self.Bind(wx.EVT_MENU, self.onHelpContents, self.m_help_contents)
+        self.Bind(wx.EVT_MENU, self.onHelpAbout, self.help_about_menu)
+        self.Bind(wx.EVT_MENU, self.onHelpContents, self.help_contents_menu)
         #
         # Admin menu (do later ...)
         # self.Bind(wx.EVT_MENU, self.onAdminPasswd)
@@ -400,7 +363,7 @@
 
     def onEnableTooltips(self, event):
         print "PanGalaxian.OnEnableTooltips"
-        if self.m_options_tooltips.IsChecked():
+        if self.options_tooltips_menu.IsChecked():
             wx.ToolTip_Enable(True)
             prefs["ShowToolTips"] = True
         else:

From waterbug at step.nasa.gov  Mon May  9 00:01:52 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May  9 00:01:54 2005
Subject: [pangalactic-commits] Express schema "pger" should be "pgef".
Message-ID: <200505090401.j4941qQA028149@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/sandbox/demo/demo1/ap203-to-pgef.exx None 1.1
PanGalactic/sandbox/demo/demo1/map_203data_to_pgef None 1.1
PanGalactic/sandbox/demo/demo1/pgef.exp None 1.1
PanGalactic/sandbox/demo/demo1/ap203-to-pger.exx 1.1 None
PanGalactic/sandbox/demo/demo1/map_203data_to_pger 1.1 None
PanGalactic/sandbox/demo/demo1/pger.exp 1.1 None

Log message:
Express schema "pger" should be "pgef".

From waterbug at step.nasa.gov  Mon May  9 09:19:52 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May  9 09:19:54 2005
Subject: [pangalactic-commits] New PgefObject-aware grid.
Message-ID: <200505091319.j49DJqN2001727@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py None 1.1
PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py 1.3 1.4
PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py 1.2 1.3

Log message:
New PgefObject-aware grid.

Index: PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py
diff -u PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.3 PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.4
--- PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.3	Wed May  4 10:58:05 2005
+++ PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py	Mon May  9 09:19:49 2005
@@ -1,5 +1,5 @@
 #!/bin/env python
-# $Id: cachebrowser.py,v 1.3 2005/05/04 14:58:05 waterbug Exp $
+# $Id: cachebrowser.py,v 1.4 2005/05/09 13:19:49 waterbug Exp $
 #----------------------------------------------------------------------------
 # Authors:      Ginny, Steve
 #----------------------------------------------------------------------------
@@ -7,9 +7,9 @@
 PanGalaxian cache browser and display customizer
 (Works with PgefObjects in a local ZODB)
 
-@version: $Revision: 1.3 $
+@version: $Revision: 1.4 $
 """
-__version__ = "$Revision: 1.3 $"[11:-2]
+__version__ = "$Revision: 1.4 $"[11:-2]
 
 import wx
 from wx import grid
@@ -146,11 +146,11 @@
             self.Parent.Parent.psmgui.onStateChange()
         self.Parent.Close()
 
-    def OnRefresh(self, event = None):
+    def OnRefresh(self, event=None):
         self.ClearGrid()        
         self.FillGrid()
 
-    def SetDBFile(self, file = None):
+    def SetDBFile(self, file=None):
         if file:
             self.dbfile = file
 
@@ -163,7 +163,7 @@
             self.cache.setDisplayConfig(self.current_config)
         # pprint(self.current_config)
 
-    def FileConfig(self, event = None):
+    def FileConfig(self, event=None):
         collection_name = self.rootitems.GetStringSelection()
         if collection_name:
             tmpsize = wx.Size(750, 500)
@@ -277,7 +277,7 @@
                 return []
         return mapping
 
-    def FillGrid(self, event = None):
+    def FillGrid(self, event=None):
         # print "dbbbrowser.fillgrid"
         if self.cache:
             self.ClearGrid()

Index: PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py:1.2 PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py:1.3
--- PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py:1.2	Tue May  3 03:08:30 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py	Mon May  9 09:19:49 2005
@@ -1,556 +1,198 @@
-# $Id: pgefgrid.py,v 1.2 2005/05/03 07:08:30 waterbug Exp $
+# $Id: pgefgrid.py,v 1.3 2005/05/09 13:19:49 waterbug Exp $
 """
-A grid with settable column labels, import of data in list format, and drag
-and drop.
+PGEF table-based, configurable data grid.  (This isn't being used for
+anything yet, but is designed for handling random tabular data.  The grid
+to use for objects is PgefObjectGrid.)
 
-@version: $Revision: 1.2 $
+@version: $Revision: 1.3 $
 """
-__version__ = "$Revision: 1.2 $"[11:-2]
+__version__ = "$Revision: 1.3 $"[11:-2]
 
-# Python imports
-import cPickle
-import os
-import ConfigParser
-from pprint import pprint
 
-# wxPython imports
 import wx
-from wx import grid
-from wx.lib.gridmovers import GridColMover, EVT_GRID_COL_MOVE
+import wx.grid           as gridlib
+import wx.lib.gridmovers as gridmovers
 
-# PanGalactic imports
-from pangalactic.utils import pdfoptions        
-from pangalactic.utils import objectreport      
-from pangalactic.utils import pgefevents        
-from pangalactic.utils import pgefexceptions    
-from pangalactic.utils import pgefdatatable     
-from pangalactic.utils import toolframe
-from pangalactic.utils import objectviewer
-from pangalactic.utils.configuregrid import ConfigureGrid
-from pangalactic.core.pgefobject import PgefObject
-
-ID_POPUP_CONFIG_GRID = wx.NewId()
-ID_POPUP_CLEAR_SELECTION = wx.NewId()
-ID_POPUP_EDIT = wx.NewId()
-OBJECT_VIEWER = wx.NewId()
-
-
-class MyCustomRenderer(grid.GridCellRenderer):
-    def __init__(self,bmp):
-        grid.GridCellRenderer.__init__(self)
-        self.bmp = bmp     
-
-    def Draw(self, grid, attr, dc, rect, row, col, isSelected):
-        dc.FloodFill(rect.x, rect.y, wx.WHITE)
-        dc.SetBackgroundMode(wx.SOLID)
-        dc.DrawBitmap(self.bmp, rect.x, rect.y)     
-
-    def GetBestSize(self, grid, attr, dc, row, col):
-        return wx.Size(self.bmp.GetWidth(), self.bmp.GetHeight())     
-
-    def Clone(self):
-        return MyCustomRenderer
-
-
-class BaseGrid(grid.Grid):
-    """
-    Wrapper for the grid that adds the drag and drop functionality to
-    the base grid class.  Also adds the ability to set the labels for the
-    grid columns and to fill a row of data given the data in a list format
-
-    BaseRightClickMenuOptions: These are the default menu options that
-                               are in the popup menu that appears on
-                               a right mouse click.
-    
-    RightClickMenuOptions: These menu options are appended to the end of
-                           the popup menu above.  They will vary depending
-                           on the type of grid.
-    """
-
-    BaseRightClickMenuOptions = [(OBJECT_VIEWER,
-                                  "Object Viewer..."),
-                                 (ID_POPUP_CLEAR_SELECTION,
-                                  "Clear Selection"),
-                                 (pdfoptions.ID_CREATEPDF_POPUP,
-                                  "Generate PDF for this table...")]
-    RightClickMenuOptions = []
-
-    def __init__(self, parent, id, classname=None, dm=None, intable=None):
-        print 'in BaseGrid.__init__ ...'
-        grid.Grid.__init__(self, parent, id)
-        # single row column labels + extra for larger font
-        self.SetColLabelSize(30)
-        self.AutoSizeColumns(True)
-        # get rid of the annoying outline of the selected cell
-        self.SetCellHighlightPenWidth(0)
-        self.vertical_offset = 0
-
-        self.dm = dm
-        if intable:
-            self.table = intable
-        else:
-            self.table = pgefdatatable.PgefDataTable()
-
-        self.classname = classname
-        self.current_config = self.dm.getDisplayConfig()
-        # print '  - current_config ='
-        # pprint(self.current_config)
-        # print '\n  - self.classname is:', self.classname
-        # print '\n  - setting display map to:'
-        # pprint(self.current_config[classname])
-        self.table.setDisplayMap(self.current_config[classname])
-        self.SetTable(self.table, True)
-
-        self.moveTo = None
-        self.DropVariable = None
-        self.allow_config_flag = 1
-        self.sort_column = None
-        self.SelectedRow = -1
-        self.SelObjectOid = None
-        
-        evthandler = pgefevents.PgefDragDropHandler(self)            
-
-        wx.EVT_MOTION(self.GetGridWindow(), self.OnMove)
-        wx.EVT_MOTION(self.GetGridRowLabelWindow(), self.OnMove)
-        grid.EVT_GRID_COL_SIZE(self, self.OnColResize)
-        grid.EVT_GRID_CELL_LEFT_CLICK(self, self.OnLeftClick)
-        grid.EVT_GRID_LABEL_LEFT_CLICK(self, self.OnLeftClick)
-        grid.EVT_GRID_CELL_RIGHT_CLICK(self, self.OnRightDown)
-        wx.EVT_MENU(self, pdfoptions.ID_CREATEPDF_POPUP, self.DumpToPdf)
-        wx.EVT_MENU(self, ID_POPUP_CONFIG_GRID, self.ConfigGrid)
-        wx.EVT_MENU(self, ID_POPUP_CLEAR_SELECTION, self.OnClearSelection)
-        wx.EVT_MENU(self, OBJECT_VIEWER, self.OnViewObj)
-
-        grid.EVT_GRID_LABEL_RIGHT_CLICK(self, self.OnLabelRightClicked)
-
-        self.PushEventHandler(evthandler)
-        GridColMover(self)
-        self.SetDefaultCellOverflow(False)
-        self.FitInside()
-        EVT_GRID_COL_MOVE(self,self.GetId(),self.OnColMove)
-
-
-    # Event method called when a column move needs to take place
-    def OnColMove(self, evt):
-        frm = evt.GetMoveColumn()       # Column being moved
-        to = evt.GetBeforeColumn()      # Column before which to insert
-        self.GetTable().MoveColumn(frm, to)
-        self.AutoSizeColumns()
-
-
-    def SetColumnAttr(self, typelist = None):
-        if typelist == None:
-            raise pgefexceptions.RequiredDataError, "A column type list must be provided"
-        column = 0
-        
-        for columntype in typelist:
-            attr = grid.GridCellAttr()
-            if columntype == "bool":
-                print "have bool"
-                attr.SetEditor(grid.GridCellBoolEditor())
-                attr.SetReadOnly(False)
-
-            elif columntype == "image":
-                print "have image"
-                attr.SetBackgroundColour(wx.GREEN)
-#                attr.SetRenderer(MyCustomRenderer(self.gridimage))
-                attr.SetReadOnly(True)
-                
-            else:
-                attr.SetEditor(grid.GridCellTextEditor())             
-                attr.SetReadOnly(True)
-
-            self.SetColAttr(column, attr)
-            
-            if columntype == "bool":
-                self.SetColFormatBool(column) 
-                
-            column += 1
+from pangalactic.utils.pgefstate import state, readState, writeState
 
-            
-    def OnLeftClick(self, event):
-        #print "basegrid.leftclick"
-        if event.GetId() == self.GetId():
-            temprow = event.GetRow()
-            if temprow == wx.NOT_FOUND:
-                self.DropVariable = None
-                self.SelectedRow = -1
-            else:
-                self.DropVariable = temprow
-                self.SelectedRow = temprow
-                self.SelectRow(temprow)
-        else:
-            event.Skip()
+class PgefDataTable(gridlib.PyGridTableBase):
+    def __init__(self, displaymap=None):
+        """
+        Initialize a PgefDataTable.
 
+        @param displaymap:  a list of tuples of the form
 
-    def OnColResize(self, event):
-        if event.GetId() == self.GetId():
-            try:
-                self.ForceRefresh()
-            except:
-                self.Refresh(True)
+            C{[(identifier, label, type), ... ]}
 
-            
-    def OnMove(self, event):
-        """
-        Initiates the drag and drop operation if the control key is pressed
+        @type  displaymap:  C{list}
         """
-        if event.LeftIsDown() and self.DropVariable != None:
-            self.StartDragOperation(self.DropVariable)
+        gridlib.PyGridTableBase.__init__(self)
+        if displaymap:
+            self.displaymap = displaymap
         else:
-            event.Skip()
-
-            
-    def OnClearSelection(self, event):
-        self.ClearSelection()
-
-            
-## snitched from griddraganddrop.py in the demo to use in the method below
-##                
-##        # the x,y coordinates here are Unscrolled coordinates.  They must be changed
-##        # to scrolled coordinates.
-##        x, y = self.grid.CalcUnscrolledPosition(x, y)
-
-##        # now we need to get the row and column from the grid
-##        # but we need to first remove the RowLabel and ColumnLabel
-##        # bounding boxes
-##        # Why this isn't done for us, I'll never know...
-##        x = x - self.grid.GetGridRowLabelWindow().GetRect().width
-##        y = y - self.grid.GetGridColLabelWindow().GetRect().height
-##        col = self.grid.XToCol(x)
-##        row = self.grid.YToRow(y)
-
-##        if row > -1 and col > -1:
-##            self.grid.SetCellValue(row, col, filenames[0])
-##            self.grid.AutoSizeColumn(col)
-##            self.grid.Refresh()
-                
-
-    def setVerticalOffset(self, offset):
-        self.vertical_offset = offset
+            displaymap = [('a', 'A', 'str'),
+                          ('b', 'B', 'str'),
+                          ('c', 'C', 'str')]
+        self.identifiers = [x[0] for x in displaymap]
+        self.rowLabels = ['1']
+        self.colLabels = dict([(x[0], x[1]) for x in displaymap])
+        self.data = [{'a':'',
+                      'b':'',
+                      'c':''
+                      }
+                     ]
+
+    #--------------------------------------------------
+    # required methods for the wxPyGridTableBase interface
+
+    def GetNumberRows(self):
+        return len(self.data)
+
+    def GetNumberCols(self):
+        return len(self.identifiers)
+
+    def IsEmptyCell(self, row, col):
+        id = self.identifiers[col]
+        return not self.data[row][id]
+
+    def GetValue(self, row, col):
+        id = self.identifiers[col]
+        return self.data[row][id]
+
+    def SetValue(self, row, col, value):
+        id = self.identifiers[col]
+        self.data[row][id] = value
+
+    #--------------------------------------------------
+    # Some optional methods
+
+    # Called when the grid needs to display column labels
+    def GetColLabelValue(self, col):
+        id = self.identifiers[col]
+        return self.colLabels[id]
+
+    # Called when the grid needs to display row labels
+    def GetRowLabelValue(self,row):
+        return self.rowLabels[row]
+
+    #--------------------------------------------------
+    # Methods added for demo purposes.
+
+    # The physical moving of the cols/rows is left to the implementer.
+    # Because of the dynamic nature of a wxGrid the physical moving of
+    # columns differs from implementation to implementation
+
+    # Move the column
+    def MoveColumn(self,frm,to):
+        grid = self.GetView()
+
+        if grid:
+            # Move the identifiers
+            old = self.identifiers[frm]
+            del self.identifiers[frm]
 
+            if to > frm:
+                self.identifiers.insert(to-1,old)
+            else:
+                self.identifiers.insert(to,old)
 
-    def OnRightDown(self, event):
-        """
-        Generate and show the menu for a mouse right-click
-        """
-        if event.GetId() == self.GetId():
-            menu = wx.Menu()
-            x,y = event.GetPosition()
-            sx, sy = self.CalcUnscrolledPosition(x, y)
-            curr_row = self.YToRow(sy - self.GetGridColLabelWindow().GetRect().height)
-            if curr_row >= 0:
-                self.SelectRow(curr_row)
-                self.SelectedRow = curr_row
-
-            for menuid, menulabel in self.BaseRightClickMenuOptions:
-                if menuid == OBJECT_VIEWER:
-                    if isinstance(self.getObject(curr_row), PgefObject):
-                        menu.Append(menuid, menulabel)
-                else:
-                    menu.Append(menuid, menulabel)
+            # Notify the grid
+            grid.BeginBatch()
+            msg = gridlib.GridTableMessage(
+                    self, gridlib.GRIDTABLE_NOTIFY_COLS_DELETED, frm, 1
+                    )
                     
-            for menuid, menulabel in self.RightClickMenuOptions:
-                if menuid == OBJECT_VIEWER:
-                    if isinstance(self.getObject(curr_row), PgefObject):
-                        menu.Append(menuid, menulabel)
-                else:
-                    menu.Append(menuid, menulabel)
-
-            gridx, gridy = self.GetPositionTuple()
-            self.PopupMenuXY(menu, x+gridx, y+gridy-self.vertical_offset)
-
+            grid.ProcessTableMessage(msg)
             
-    def StartDragOperation(self, selectedrow):
-        """
-        Handles the data encapsulation and packaging for the drag and drop
-        """
+            msg = gridlib.GridTableMessage(
+                    self, gridlib.GRIDTABLE_NOTIFY_COLS_INSERTED, to, 1
+                    )
+
+            grid.ProcessTableMessage(msg)
+            grid.EndBatch()
+
+    # Move the row
+    def MoveRow(self,frm,to):
+        grid = self.GetView()
+
+        if grid:
+            # Move the rowLabels and data rows
+            oldLabel = self.rowLabels[frm]
+            oldData = self.data[frm]
+            del self.rowLabels[frm]
+            del self.data[frm]
+
+            if to > frm:
+                self.rowLabels.insert(to-1,oldLabel)
+                self.data.insert(to-1,oldData)
+            else:
+                self.rowLabels.insert(to,oldLabel)
+                self.data.insert(to,oldData)
 
-        if selectedrow < 0:
-            return False
+            # Notify the grid
+            grid.BeginBatch()
 
-        itemid = self.GetObjectOid(selectedrow) 
-        if itemid == "":
-            return False
-        
-        data = [None, itemid, "GRID", self.GetId()]
-        datapickle = cPickle.dumps(data, 1)
-        dragitem = wx.CustomDataObject(wx.CustomDataFormat("PGEF_Item"))
-        dragitem.SetData(datapickle)
-        dropSource = wx.DropSource(self)
-        dropSource.SetData(dragitem)
-        dropSource.DoDragDrop(True)
-
-        
-    def CanConfigDisplay(self):
-        if self.table._data:
-            return 1
-        else:
-            return None
+            msg = gridlib.GridTableMessage(
+                    self, gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED, frm, 1
+                    )
 
+            grid.ProcessTableMessage(msg)
 
-    def ClearGrid(self):
-        self.table.ClearTableBase()
+            msg = gridlib.GridTableMessage(
+                    self, gridlib.GRIDTABLE_NOTIFY_ROWS_INSERTED, to, 1
+                    )
 
-        
-    def RefreshFromObjects(self):
-        self.table.RefreshGrid()
-        self.FitInside()
-
-
-    def AddData(self, obj, colour = None):
-        #print "base.adddata", colour
-        self.BeginBatch()
-        nrows = self.GetNumberRows()
-        # try:
-        #     for obj in data:
-        #         self.table.AddData(obj)
-        # except TypeError:
-        self.table.AddData(obj)
-
-        # set the background colour of the row(s), if any is specified
-        if colour:
-            #print "have colour", colour
-            new_nrows = self.GetNumberRows()
-            rowlist = [rownum + nrows for rownum in range(new_nrows - nrows)]
-            self.SetRowBackgroundColour(rowlist, colour)
-            
-        self.AutoSizeColumns(True)
-        self.FitInside()
-        self.EndBatch()
-
-
-    def SetColBackgroundColour(self, col, colour):
-        #print "base.setcolbackgroundcolour"
-        numrows = self.GetNumberRows()
-        for row in range(numrows):
-            self.SetCellBackgroundColour(row, col, colour)
-
-        
-    def SetRowBackgroundColour(self, rowlist, colour):
-        #print "base.setrowbackgroundcolour", rowlist, colour
-        numcols = self.GetNumberCols()
-        self.BeginBatch()
-        for row in rowlist:
-            for col in range(numcols):
-                #print "    set colour for row, col", row, col
-                self.SetCellBackgroundColour(row, col, colour)
-        self.EndBatch()           
-
-        
-    def ResetBackgroundColour(self, value):
-        nrows = self.GetNumberRows()
-        numcols = self.GetNumberCols()
-        self.BeginBatch()
-        colour = self.GetDefaultCellBackgroundColour()
-        for row in range(nrows):
-            if self.GetObjectOid(row) == value:
-                for col in range(numcols):
-                    self.SetCellBackgroundColour(row, col, colour)
-        self.EndBatch()           
-                
-        
-    def DumpToPdf(self, event=None):
-        gridrows = self.GetNumberRows()
-        if gridrows <= 0:
-            return
-
-        dlg = pdfoptions.PDFOptions(self)
-        dlg.Layout()
-        result = dlg.ShowModal()
-
-        if result == wx.ID_OK:
-            filename = dlg.filename.GetValue()
-            if not filename.endswith(".pdf"):
-                filename += ".pdf"
-            
-            if dlg.portrait.GetValue():
-                page_orientation = "portrait"
-            else:
-                page_orientation = "landscape"
-                
-            hide_gridlines = dlg.hide_gridlines.GetValue()
-            
-            if dlg.table_or_list.GetValue():
-                tabular = 0
-            else:
-                tabular = 1
-                
-            title = dlg.pdftitle.GetValue()
-            footer = dlg.footertext.GetValue()
-            
-            temp = objectreport.ObjectReport(filename, 
-                                             self.table._data,
-                                             title,
-                                             footer,
-                                             orientation=page_orientation,
-                                             tabular=tabular,
-                                             hidegridlines=hide_gridlines)
-
-            temp.current_config = self.current_config[self.classname]
-            fn = temp.generate()
-
-            dtext = fn + "\n\nhas been generated."
-            dlg = wx.MessageDialog(self, dtext, "All Done",
-                                  wx.OK | wx.ICON_EXCLAMATION)
-            dlg.CentreOnParent()
-            dlg.ShowModal() 
-            dlg.Destroy()
+            grid.ProcessTableMessage(msg)
+            grid.EndBatch()
 
-            
-    def WriteDisplay(self, display_list):
-        #print "save display config"
-        if self.classname:
-            config = ConfigParser.ConfigParser()
-            tmppath = os.path.join("data", "grid.ini")
-            if os.path.exists(tmppath):
-                config.read(tmppath)
-                if config.has_section(self.classname):
-                    config.remove_section(self.classname)
-
-            outfile = open(tmppath, "w+")
-            config.add_section(self.classname)
-            config.set(self.classname, "display", display_list)
-            config.write(outfile)
-            outfile.close()
+#---------------------------------------------------------------------------
 
-            
-    def ConfigGrid(self, event=None):
-        print "in Basegrid.ConfigGrid ..."
-        tmpsize = wx.Size(750, 500)
-        gridframe = wx.Dialog(self, -1,
-                             "Customize Grid Layout",
-                             wx.DefaultPosition, tmpsize,
-                             style=wx.CAPTION|wx.SYSTEM_MENU|wx.THICK_FRAME )
-
-        if not len(self.table._data) > 0:
-            gridframe = None
-            print "  ... sorry, nothing to configure"
-            return 
-
-        gridframe.mainpanel = ConfigureGrid(gridframe, -1,
-                                            dm=self.dm,
-                                            collection_name=self.classname,
-                                            current_config=self.current_config)
-        gridframe.CentreOnParent()
-        result = gridframe.Show(True)
-        if result == wx.ID_OK:
-            displaymap = gridframe.mainpanel.GetDisplayList()
-            self.RefreshDisplay(displaymap)
-            self.WriteDisplay(displaymap)
-            self.current_config[self.classname] = displaymap
-            self.dm.setDisplayConfig(self.current_config)
 
+class PgefGrid(gridlib.Grid):
+    def __init__(self, parent, displaymap=None):
+        gridlib.Grid.__init__(self, parent, -1)
 
-    def RefreshDisplay(self, displaymap):
-        #print "basegrid.refreshdisplay"
-        if displaymap:
-            self.table.setDisplayMap(self.current_config[classname])
-            self.table.RefreshGrid()
-            self.AutoSizeColumns()
-
-        
-    def GetObjectOid(self, row):
-        return self.table.GetObjectOid(row)
+        table = PgefDataTable(displaymap)
 
+        # The second parameter means that the grid is to take ownership of the
+        # table and will destroy it when done.  Otherwise you would need to keep
+        # a reference to it and call it's Destroy method later.
+        self.SetTable(table, True)
 
-    def getSelectedObject(self):
-        #print "basegrid.getselectedobject"
-        if self.SelectedRow:
-            #print "have selectedrow"
-            return self.getObject(self.SelectedRow)
-        else:
-            rows = self.GetSelectedRows()
-            if len(rows) > 0:
-                self.SelectedRow = rows[0]
-                return self.getObject(self.SelectedRow)
-            else:
-                #print "oops"
-                return None
-            
-        
-    def getObject(self, row=None):
-        return self.table.getObject(row)
-                
-
-    def getObjectByOid(self, oid):
-        return self.table.getObjectByOid(oid)
-
-
-    def OnLabelRightClicked(self, evt):
-#        print "grid.rclick"
-        row, col = evt.GetRow(), evt.GetCol()
-        if col < 0:
-            return 
-        self.sort_column = col
-        self.colPopup(col, evt)
+        # Enable Column moving
+        gridmovers.GridColMover(self)
+        self.Bind(gridmovers.EVT_GRID_COL_MOVE, self.OnColMove, self)
 
-        
-    def colPopup(self, col, evt):
-        """
-        (col, evt) -> display a popup menu when a column label is
-        right clicked
-        """
-
-        # check for a selected row; if there is one,
-        # remember what it is and reselect it after
-        # the sort.
-        self.SelObjectOid = None
-        rows = self.GetSelectedRows()
-        if len(rows) > 0:
-            # an object was already selected.
-            # save the pgef_oid.
-            self.SelObjectOid = self.table.GetObjectOid(rows[0])
-
-        obj_colours = {}
-        for ndx in range(self.GetNumberRows()):
-            tmp_colour = self.GetCellBackgroundColour(ndx, 0)
-            obj_oid = self.table.GetObjectOid(ndx)
-            obj_colours[obj_oid] = tmp_colour
-
-        x = self.GetColSize(col)/2
-        menu = wx.Menu()
-        sortID = wx.NewId()
-        self.sort_column = col
-        xo, yo = evt.GetPosition()
-        self.Refresh()
-        menu.Append(sortID, "Sort Column")
-
-        def sort(event, self=self, col=self.sort_column):
-            self.table.sortColumn(col)
-
-            # reselect the previously selected object, if any
-            if self.SelObjectOid:
-                row, obj = self.table.getObjectByOid(self.SelObjectOid)
-                #print "re-selecting", row, obj.id
-                self.SelectRow(row)
-
-            # re-colour the rows
-            for oid, colour in obj_colours.items():
-                row, obj = self.table.getObjectByOid(oid)
-                self.SetRowBackgroundColour([row], colour)
-                
-            self.Reset()
-
-        wx.EVT_MENU(self, sortID, sort)
-        self.PopupMenu(menu, wx.Point(xo, 0))
-        menu.Destroy()
-
-
-    def Reset(self):
-        """reset the view based on the data in the table.  Call
-        this when rows are added or destroyed"""
-        self.table.ResetView(self)
-
-        
-    def OnViewObj(self, event):
-        #print "basegrid.onviewobj"
-        if self.SelectedRow < 0:
-            return
-        
-        obj = self.getObject(self.SelectedRow)
-        tmpsize = wx.Size(800, 500)
-        foo = objectviewer.ObjectViewer(self, -1, obj, tmpsize)
+        # Enable Row moving
+        gridmovers.GridRowMover(self)
+        self.Bind(gridmovers.EVT_GRID_ROW_MOVE, self.OnRowMove, self)
 
+    # Event method called when a column move needs to take place
+    def OnColMove(self,evt):
+        frm = evt.GetMoveColumn()       # Column being moved
+        to = evt.GetBeforeColumn()      # Before which column to insert
+        self.GetTable().MoveColumn(frm,to)
 
+    # Event method called when a row move needs to take place
+    def OnRowMove(self,evt):
+        frm = evt.GetMoveRow()          # Row being moved
+        to = evt.GetBeforeRow()         # Before which row to insert
+        self.GetTable().MoveRow(frm,to)
+
+#---------------------------------------------------------------------------
+
+class TestFrame(wx.Frame):
+    def __init__(self, parent):
+        wx.Frame.__init__(self, parent, -1,
+                          "PgefGrid", size=(640,480))
+        grid = PgefGrid(self)
+
+#---------------------------------------------------------------------------
+
+if __name__ == '__main__':
+    import sys
+    app = wx.PySimpleApp()
+    frame = TestFrame(None)
+    frame.Show(True)
+    app.MainLoop()
 

From waterbug at step.nasa.gov  Mon May  9 09:29:30 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May  9 09:29:31 2005
Subject: [pangalactic-commits] 'pger' -> 'pgef'.
Message-ID: <200505091329.j49DTUnP002238@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/src/express/exx/ap203-to-pgef.exx None 1.1
PanGalactic/src/express/exx/ap210-to-pgef.exx None 1.1
PanGalactic/src/express/exx/ap214-to-pgef.exx None 1.1
PanGalactic/src/express/exx/pdms-to-pgef.exx None 1.1
PanGalactic/src/express/exx/pgef-to-ap203.exx None 1.1
PanGalactic/src/express/exx/pgef-to-ap210.exx None 1.1
PanGalactic/src/express/exx/pgef-to-pdms.exx None 1.1
PanGalactic/src/express/exx/ap203-to-pger.exx 1.4 None
PanGalactic/src/express/exx/ap210-to-pger.exx 1.3 None
PanGalactic/src/express/exx/ap214-to-pger.exx 1.1 None
PanGalactic/src/express/exx/pdms-to-pger.exx 1.1 None
PanGalactic/src/express/exx/pger-to-ap203.exx 1.1 None
PanGalactic/src/express/exx/pger-to-ap210.exx 1.1 None
PanGalactic/src/express/exx/pger-to-pdms.exx 1.1 None

Log message:
'pger' -> 'pgef'.

From waterbug at step.nasa.gov  Mon May  9 18:10:50 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May  9 18:10:53 2005
Subject: [pangalactic-commits] Can now read and write simplified OSEB. :)
Message-ID: <200505092210.j49MAomd010171@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/io/oseb.py 1.4 1.5

Log message:
Can now read and write simplified OSEB. :)

Index: PanGalactic/pangalactic/node/io/oseb.py
diff -u PanGalactic/pangalactic/node/io/oseb.py:1.4 PanGalactic/pangalactic/node/io/oseb.py:1.5
--- PanGalactic/pangalactic/node/io/oseb.py:1.4	Fri Mar 11 17:16:37 2005
+++ PanGalactic/pangalactic/node/io/oseb.py	Mon May  9 18:10:48 2005
@@ -1,4 +1,4 @@
-# $Id: oseb.py,v 1.4 2005/03/11 22:16:37 waterbug Exp $
+# $Id: oseb.py,v 1.5 2005/05/09 22:10:48 waterbug Exp $
 """
 A generic (no dependencies on the rest of PanGalactic) reader/writer for
 Simplified OSEB (OSEB = Object Serialization Early Binding, a serialization
@@ -20,12 +20,14 @@
 Note that S-OSEB keeps to the OSEB and STEP Part 21 convention of using '$'
 to signify null values.
 
-@version: $Revision: 1.4 $
+@version: $Revision: 1.5 $
 """
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 import sys
-import cElementTree as ElementTree
+import cElementTree as ET
+from cElementTree import Element, SubElement, ElementTree
+from elementtree.ElementTree import tostring
 from pprint import pprint
 
 
@@ -41,11 +43,23 @@
         be included in the instance dictionaries unless a value is supplied
         for null, in which case they will be included with that value
     @type  null:  C{str}
+
+    @return:  a dictionary of instance dictionaries, mapped by their
+        C{x-id} attributes.
+
+             {x-id-1 : {attr:value, ...},
+              x-id-2 : {attr:value, ...},
+              ...}
+
+        ... where each C{x-id-n} attribute is of the form '#'+str(int) and
+        must be unique within the dataset.
+
+    @rtype:   C{dict}
     """
     osebdataset = {}
-    root = ElementTree.parse(f)
+    root = ET.parse(f)
     osebdataset['header'] = root.find('header').attrib
-    data = root.find('pdm_data')
+    data = root.find('data')
     osebdataset['data'] = {}
     for elem in data.getiterator():
         if elem.attrib.get('x-id', None):
@@ -57,6 +71,53 @@
             osebdataset['data'][xid] = inst
     return osebdataset
 
+def write(osebdataset, schema='pgef', fname='data.oseb', description='',
+          null='$'):
+    """
+    Write an OSEB dataset out to an S-OSEB file/stream.
+
+    @param osebdataset:  a dictionary of dictionaries of the form:
+
+             {x-id-1 : {attr:value, ...},
+              x-id-2 : {attr:value, ...},
+              ...}
+
+        ... where each C{x-id-n} attribute is of the form '#'+str(int) and
+        must be unique within the dataset.
+
+    @type  osebdataset:  C{dict}
+
+    @param schema:  name of the schema governing the data
+    @type  schema:  C{str}
+
+    @param fname:  the name of the file to write to
+    @type  fname:  C{str}
+
+    @param description:  some text describing the data
+    @type  description:  C{str}
+
+    @param null:  a value to use for nulls in the data, which are
+        represented by '$' in S-OSEB.  Attributes with null values will not
+        be included in the instance dictionaries unless a value is supplied
+        for null, in which case they will be included with that value
+    @type  null:  C{str}
+    """
+    root = Element('oseb_data_set')
+    header = SubElement(root, 'header')
+    header.set('schema', schema)
+    header.set('filename', fname)
+    header.set('description', description)
+    data = SubElement(root, 'data')
+    for xid, attrs in osebdataset.items():
+        tag = attrs.pop('instance_type')
+        attrs['x-id'] = xid
+        e = SubElement(data, tag, **attrs)
+    f = file(fname, 'w')
+    f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
+    f.write(tostring(root))
+    f.close()
+
+
 if __name__ == '__main__':
     res = read(sys.argv[1])
     pprint(res)

From waterbug at step.nasa.gov  Tue May 10 02:04:09 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May 10 02:04:11 2005
Subject: [pangalactic-commits] Found this checksum script.
Message-ID: <200505100604.j4A649ts011834@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/utils/checksum.py None 1.1

Log message:
Found this checksum script.

From waterbug at step.nasa.gov  Tue May 10 18:19:43 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May 10 18:19:46 2005
Subject: [pangalactic-commits] Tiny whitespace tweak.
Message-ID: <200505102219.j4AMJhch025336@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.5 1.6

Log message:
Tiny whitespace tweak.

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.5 PanGalactic/pangalactic/node/pangalaxian_new.py:1.6
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.5	Thu May  5 23:06:13 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Tue May 10 18:19:42 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.5 2005/05/06 03:06:13 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.6 2005/05/10 22:19:42 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 # Python core modules
 import sys
@@ -118,7 +118,7 @@
         self.pgxn_menubar.Append(self.repository_menu, "&Repository")
         self.cache_menu = wx.Menu()
         self.cache_browse_menu = self.cache_menu.Append(-1, "&Browse Local Objects...", "Browse locally cached objects ...", wx.ITEM_NORMAL)
-        self.cache_clear_menu = self.cache_menu.Append(-1, "&Clear Local Objects...", "Remove objects from local cache", wx.ITEM_NORMAL)
+        self.cache_clear_menu  = self.cache_menu.Append(-1, "&Clear Local Objects...", "Remove objects from local cache", wx.ITEM_NORMAL)
         self.pgxn_menubar.Append(self.cache_menu, "&Cache")
         self.options_menu = wx.Menu()
         self.options_userid_menu       = self.options_menu.Append(-1, "&Userid...", "Set userid ...", wx.ITEM_NORMAL)

From waterbug at step.nasa.gov  Tue May 10 18:22:38 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May 10 18:22:39 2005
Subject: [pangalactic-commits] Sync with src/express/exx version.
Message-ID: <200505102222.j4AMMcw9025395@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/sandbox/demo/demo1/ap203-to-pgef.exx 1.1 1.2

Log message:
Sync with src/express/exx version.

From waterbug at step.nasa.gov  Tue May 10 20:49:33 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May 10 20:49:35 2005
Subject: [pangalactic-commits] pger.exp -> pgef.exp
Message-ID: <200505110049.j4B0nXA0026822@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/src/express/exp/pgef.exp None 1.1
PanGalactic/src/express/exp/pger.exp 1.5 None

Log message:
pger.exp -> pgef.exp

From waterbug at step.nasa.gov  Wed May 11 03:07:55 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May 11 03:07:58 2005
Subject: [pangalactic-commits] Revamp of 'state' (now p.n.g.state) ...
Message-ID: <200505110707.j4B77tm5029282@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/core/workflow/wfprocessoverview.py 1.5 1.6
PanGalactic/pangalactic/node/pangalaxian.py 1.54 1.55
PanGalactic/pangalactic/node/pangalaxian_new.py 1.6 1.7
PanGalactic/pangalactic/node/pangalaxian_old.py 1.4 1.5
PanGalactic/pangalactic/node/gui/state.py None 1.1
PanGalactic/pangalactic/node/gui/dialogs/searchform.py 1.5 1.6
PanGalactic/pangalactic/node/gui/plm/epimsmapping.py 1.2 1.3
PanGalactic/pangalactic/node/gui/plm/plmtool.py 1.2 1.3
PanGalactic/pangalactic/node/gui/psm/docform.py 1.4 1.5
PanGalactic/pangalactic/node/gui/psm/doctreeframe.py 1.9 1.10
PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py 1.8 1.9
PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py 1.6 1.7
PanGalactic/pangalactic/node/gui/psm/itemeditframe.py 1.14 1.15
PanGalactic/pangalactic/node/gui/psm/modelform.py 1.3 1.4
PanGalactic/pangalactic/node/gui/psm/otherdocform.py 1.3 1.4
PanGalactic/pangalactic/node/gui/psm/partform.py 1.3 1.4
PanGalactic/pangalactic/node/gui/psm/partslistform.py 1.2 1.3
PanGalactic/pangalactic/node/gui/psm/partslisttreeframe.py 1.6 1.7
PanGalactic/pangalactic/node/gui/psm/partslistview.py 1.6 1.7
PanGalactic/pangalactic/node/gui/psm/pgefdoctree.py 1.4 1.5
PanGalactic/pangalactic/node/gui/psm/pgefedittree.py 1.4 1.5
PanGalactic/pangalactic/node/gui/psm/pgeftree.py 1.8 1.9
PanGalactic/pangalactic/node/gui/psm/pgefversiontree.py 1.5 1.6
PanGalactic/pangalactic/node/gui/psm/projectframe.py 1.2 1.3
PanGalactic/pangalactic/node/gui/psm/propertiesform.py 1.4 1.5
PanGalactic/pangalactic/node/gui/psm/psmtool.py 1.30 1.31
PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py 1.4 1.5
PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py 1.3 1.4
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.1 1.2
PanGalactic/pangalactic/node/gui/widgets/pgeftree.py 1.5 1.6
PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py 1.2 1.3
PanGalactic/pangalactic/repo/pgersecurity.py 1.2 1.3
PanGalactic/pangalactic/utils/basegrid.py 1.44 1.45
PanGalactic/pangalactic/utils/cagesearchframe.py 1.8 1.9
PanGalactic/pangalactic/utils/configuregrid.py 1.12 1.13
PanGalactic/pangalactic/utils/datamanager.py 1.174 1.175
PanGalactic/pangalactic/utils/localdb.py 1.129 1.130
PanGalactic/pangalactic/utils/usersearchframe.py 1.12 1.13
PanGalactic/pangalactic/utils/pgefstate.py 1.7 None
PanGalactic/pangalactic/utils/preferences.py 1.8 None

Log message:
Revamp of 'state' (now p.n.g.state) ...
it now includes prefs and displaymaps.

Index: PanGalactic/pangalactic/node/gui/psm/modelform.py
diff -u PanGalactic/pangalactic/node/gui/psm/modelform.py:1.3 PanGalactic/pangalactic/node/gui/psm/modelform.py:1.4
--- PanGalactic/pangalactic/node/gui/psm/modelform.py:1.3	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/modelform.py	Wed May 11 03:07:48 2005
@@ -1,9 +1,7 @@
 import os
 from wxPython.wx import *
 
-from pangalactic.utils.preferences import prefs, writePrefs
-from pangalactic.utils.pgefstate import state
-
+from pangalactic.node.gui.state import state, prefs, displaymaps
 from pangalactic.node.gui.psm.modelform_wdr import *
 
 
@@ -207,7 +205,6 @@
         if nextid:
             nextid = int(nextid) - 1
         prefs["nextid"] = nextid
-        writePrefs()
         #print "nextid", nextid
         self.NextId = None
 

Index: PanGalactic/pangalactic/utils/cagesearchframe.py
diff -u PanGalactic/pangalactic/utils/cagesearchframe.py:1.8 PanGalactic/pangalactic/utils/cagesearchframe.py:1.9
--- PanGalactic/pangalactic/utils/cagesearchframe.py:1.8	Tue May  3 03:08:31 2005
+++ PanGalactic/pangalactic/utils/cagesearchframe.py	Wed May 11 03:07:50 2005
@@ -1,5 +1,6 @@
 from wxPython.wx import *
 
+from pangalactic.node.gui.state import displaymaps
 from pangalactic.utils import cagesearchgui
 from pangalactic.utils import orggrid
 from pangalactic.utils import toolframe
@@ -131,8 +132,7 @@
             searchresults = self.dm.getSearchResults()
 
             if len(searchresults) > 0:
-                current_config = self.dm.getDisplayConfig()
-                config = current_config["Organization"]
+                config = displaymaps["Organization"]
 
                 ndx = 0
                 self.resultsgrid.BeginBatch()

Index: PanGalactic/pangalactic/node/gui/psm/pgefversiontree.py
diff -u PanGalactic/pangalactic/node/gui/psm/pgefversiontree.py:1.5 PanGalactic/pangalactic/node/gui/psm/pgefversiontree.py:1.6
--- PanGalactic/pangalactic/node/gui/psm/pgefversiontree.py:1.5	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/pgefversiontree.py	Wed May 11 03:07:48 2005
@@ -1,6 +1,6 @@
 from wxPython.wx import wxTreeCtrl, wxTreeItemIcon_Selected, EVT_RIGHT_DOWN, wxPoint
 import pgeftree
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state
 
 class PgefVersionTree(pgeftree.PgefTree):
     """Specialized tree for displaying versions hierarchically."""

Index: PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py
diff -u PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py:1.6 PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py:1.7
--- PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py:1.6	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py	Wed May 11 03:07:48 2005
@@ -1,16 +1,16 @@
-# $Id: itemdroptarget.py,v 1.6 2005/05/03 07:08:29 waterbug Exp $
+# $Id: itemdroptarget.py,v 1.7 2005/05/11 07:07:48 waterbug Exp $
 
 import cPickle
 
 from pangalactic.core.model import Model
 from pangalactic.core.acu import Acu
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state
 from pangalactic.utils import pgefevents
 from wxPython.wx import wxCustomDataObject, wxCustomDataFormat, wxPyDropTarget
 from wxPython.wx import wxPoint, wxTreeItemIcon_Selected
 
 
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 #constants
 

Index: PanGalactic/pangalactic/node/gui/psm/partslistform.py
diff -u PanGalactic/pangalactic/node/gui/psm/partslistform.py:1.2 PanGalactic/pangalactic/node/gui/psm/partslistform.py:1.3
--- PanGalactic/pangalactic/node/gui/psm/partslistform.py:1.2	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/partslistform.py	Wed May 11 03:07:48 2005
@@ -1,12 +1,11 @@
-# $Id: partslistform.py,v 1.2 2005/05/03 07:08:29 waterbug Exp $
+# $Id: partslistform.py,v 1.3 2005/05/11 07:07:48 waterbug Exp $
 
-__version__ = "$Revision: 1.2 $"[11:-2]
+__version__ = "$Revision: 1.3 $"[11:-2]
 
 from wxPython.wx import wxPanel, wxTAB_TRAVERSAL, wxPyTypeCast, wxPyDefaultPosition, wxPyDefaultSize
 from wxPython.wx import wxFileDialog
 from partslistform_wdr import *
-from pangalactic.utils.pgefstate import state
-from pangalactic.utils.preferences import prefs, writePrefs
+from pangalactic.node.gui.state import state, prefs, displaymaps
 
 
 class PartsListForm(wxPanel):
@@ -161,7 +160,6 @@
             wgt.SetValue(state['project'] + "-PL-" + self.NextDocId)
         wgt.SetFocus()
         prefs['nextplid'] = self.NextDocId
-        writePrefs()
         self.current_pl = None
 
         button = self.GetImportPartsListButton()

Index: PanGalactic/pangalactic/node/gui/plm/plmtool.py
diff -u PanGalactic/pangalactic/node/gui/plm/plmtool.py:1.2 PanGalactic/pangalactic/node/gui/plm/plmtool.py:1.3
--- PanGalactic/pangalactic/node/gui/plm/plmtool.py:1.2	Wed Oct 20 02:25:24 2004
+++ PanGalactic/pangalactic/node/gui/plm/plmtool.py	Wed May 11 03:07:47 2005
@@ -13,23 +13,20 @@
 from wxPython.wx import wxPyTypeCast, wxNewId, wxBeginBusyCursor, wxEndBusyCursor, wxSafeYield
 from wxPython.wx import wxDefaultSize, wxDefaultPosition, wxVERTICAL, wxYES_NO
 from wxPython.wx import EVT_BUTTON, EVT_COMBOBOX, EVT_LISTBOX, EVT_SPINCTRL, EVT_CHECKBOX, EVT_MENU
-from pangalactic.utils.pgefstate import state
 
-try:
-    from ms2file import *
-    from pythonwin_excelwrapper import *
-except:
-    print "NOTE: Conversion for import of MS Excel Parts Lists is not available."
-    
 from pangalactic.utils import toolframe
-from pangalactic.utils.preferences import prefs
-from pangalactic.utils.pgefstate import state
-
+from pangalactic.node.gui.state import state, prefs, displaymaps
 from pangalactic.node.gui.plm.ms2file_new_wdr import *
 from pangalactic.node.gui.plm.epimsgrid import *
 from pangalactic.node.gui.plm.epimsevent import *
 import pangalactic.node.gui.plm.epimsmapping
 
+try:
+    from ms2file import *
+    from pythonwin_excelwrapper import *
+except:
+    print "NOTE: Conversion for import of MS Excel Parts Lists is not available."
+    
 
 HELP_TEXT = "This tool supports the conversion of an MS Excel spreadsheet into a tab-delimited file that can be uploaded into EPIMS.\n\nThe tool reads in a copy of the data from Excel's ACTIVE worksheet.  It removes any <RETURN>s and <TAB>s inside cells, and removes any blank rows and blank columns.  It then outputs its version of the data to a <TAB>-delimited text file that by default has the same base name as the input file, with an additional specification for the selected worksheet, and with a <.tsv> extension.\n\nDuring the session, the tool maintains a log file in the same directory as the input file.  The log file has the same base name as the input file, with an extension of <.log>.\n\nNOTES:\n\nThe data must include a row of column headings.\n\nWhen the tool encounters 5 (or more) blank rows/columns in succession, it assumes that these are the outer boundaries of the data in the spreadsheet.\n\nUnprintable characters are translated into tilde's.  (This means any characters above ASCII 127.)\n\n\nNEW in this release:\n\n1. You can specify a specific worksheet to process.\n\n2. You can specify the minimum number of data-filled cells per row.\n\n3. You can preview the first 10 rows of the selected worksheet.\n\n4.  You can specify the row containing column headings by clicking on the row in the sample grid (ditto for the initial row of data).\n\n5. Column headings can span more than one row.\n\n"
 

Index: PanGalactic/pangalactic/node/gui/psm/pgefdoctree.py
diff -u PanGalactic/pangalactic/node/gui/psm/pgefdoctree.py:1.4 PanGalactic/pangalactic/node/gui/psm/pgefdoctree.py:1.5
--- PanGalactic/pangalactic/node/gui/psm/pgefdoctree.py:1.4	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/pgefdoctree.py	Wed May 11 03:07:48 2005
@@ -1,5 +1,5 @@
 from wxPython.wx import wxTreeCtrl, wxTreeItemIcon_Selected
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state
 import pgefedittree
 
 

Index: PanGalactic/pangalactic/node/gui/psm/itemeditframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.14 PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.15
--- PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.14	Wed May  4 06:24:12 2005
+++ PanGalactic/pangalactic/node/gui/psm/itemeditframe.py	Wed May 11 03:07:48 2005
@@ -1,10 +1,10 @@
-# $Id: itemeditframe.py,v 1.14 2005/05/04 10:24:12 waterbug Exp $
+# $Id: itemeditframe.py,v 1.15 2005/05/11 07:07:48 waterbug Exp $
 """
 GUI providing browsing/editing capabilities for Part, Model, Document, and
 PartsList objects.
 """
 
-__version__ = "$Revision: 1.14 $"[11:-2]
+__version__ = "$Revision: 1.15 $"[11:-2]
 
 import wx
 from pangalactic.node.gui.psm import docform
@@ -17,8 +17,7 @@
 from pangalactic.node.gui.psm import partform
 from pangalactic.node.gui.psm import modelform
 from pangalactic.node.gui.psm import pgefversiontree
-from pangalactic.utils.preferences import prefs, writePrefs
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state, prefs, displaymaps
 from pangalactic.utils.toolframe import ToolFrame
 from pangalactic.utils.pgefexceptions import RequiredDataError
 

Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.54 PanGalactic/pangalactic/node/pangalaxian.py:1.55
--- PanGalactic/pangalactic/node/pangalaxian.py:1.54	Tue May  3 03:08:28 2005
+++ PanGalactic/pangalactic/node/pangalaxian.py	Wed May 11 03:07:45 2005
@@ -1,17 +1,18 @@
 #!/usr/bin/env python 
 
-# $Id: pangalaxian.py,v 1.54 2005/05/03 07:08:28 waterbug Exp $
+# $Id: pangalaxian.py,v 1.55 2005/05/11 07:07:45 waterbug Exp $
 
 """
 Main application module for the PGEF desktop client.
 
-@version: $Revision: 1.54 $
+@version: $Revision: 1.55 $
 """
-__version__ = "$Revision: 1.54 $"[11:-2]
+__version__ = "$Revision: 1.55 $"[11:-2]
 
 import sys
 import os
 import time
+from pprint import pprint
 
 import wxversion
 wxversion.select("2.5")
@@ -19,17 +20,16 @@
 
 from pangalactic.node.gui.dialogs.login import LoginDialog
 from pangalactic.node.gui.psm import psmtool
+from pangalactic.node.gui.state import state, writeState
+from pangalactic.node.gui.state import prefs, displaymaps
 from pangalactic.node.gui.widgets.cachebrowser import CacheBrowser
 from pangalactic.core.person import Person
 from pangalactic.node.images import toolkitimages
 from pangalactic.utils import oid
-from pangalactic.utils import toolstate
 from pangalactic.utils import toolframe
 from pangalactic.utils import userinfo
 from pangalactic.utils.aboutbox        import AboutBox
 from pangalactic.utils.changepasswd    import ChangePasswd
-from pangalactic.utils.pgefstate       import state, readState, writeState
-from pangalactic.utils.preferences     import prefs, readPrefs, writePrefs
 from pangalactic.utils.proxyclass      import ProxyDialog
 from pangalactic.utils.serverclass     import ServerDialog
 from pangalactic.utils.usersearchframe import UserSearchFrame
@@ -183,10 +183,6 @@
     def __init__(self, parent, ID, title, pos, size):
         wx.Frame.__init__(self, parent, ID, title,pos, size)
         wx.InitAllImageHandlers()
-        # First populate the state and prefs dictionaries with whatever may
-        # have been saved from a previous session ...
-        readState()
-        readPrefs()
         # Next try to start up the local cache (ZODB), since if we
         # don't have that, we can't really do anything.  To do that, we
         # need a userid ...
@@ -216,7 +212,6 @@
             if dlg.ShowModal() == wx.ID_OK:
                 prefs['userid'] = username.GetValue()
                 prefs['email'] = email.GetValue()
-                writePrefs()
             dlg.Destroy()
         useroid = prefs.get('email',
                             None) or prefs.get('userid',
@@ -479,13 +474,12 @@
         # blab about my state
         print "PanGalaxian.onStateChange"
         print "  - prefs:"
-        for p in prefs:
-            print "    * %s = %s" % (p, prefs[p])
+        pprint(prefs)
         print "  - state:"
         for s in state:
-            print "    * %s = %s" % (s, state[s])
-        writeState()
-        writePrefs()
+            if s != 'displaymaps':
+                print "    * %s" % s
+                pprint(state[s])
         # actually do stuff ...
         self.dm.onStateChange()
         self.psmgui.onStateChange()
@@ -963,7 +957,6 @@
         # I don't understand why this is necessary, since os was imported
         # up above, but this scope doesn't seem to see it!  8^/
         import os
-        writePrefs()
         writeState()
         if self.closing:
             event.Skip()

Index: PanGalactic/pangalactic/node/gui/psm/otherdocform.py
diff -u PanGalactic/pangalactic/node/gui/psm/otherdocform.py:1.3 PanGalactic/pangalactic/node/gui/psm/otherdocform.py:1.4
--- PanGalactic/pangalactic/node/gui/psm/otherdocform.py:1.3	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/otherdocform.py	Wed May 11 03:07:48 2005
@@ -2,8 +2,7 @@
 from wxPython.wx  import *
 from otherdoc_wdr import *
 
-from pangalactic.utils.preferences import prefs, writePrefs
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state, prefs, displaymaps
 #import pangalactic.core.document as document
 
 class OtherDocForm(wxPanel):
@@ -182,7 +181,6 @@
                                   "-DOC-",
                                   self.NextDocId]))
         prefs["nextdocid"] = self.NextDocId
-        writePrefs()
 
         self.EditingMode()
 

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.2 PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.3
--- PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.2	Fri Feb 18 02:14:42 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py	Wed May 11 03:07:49 2005
@@ -1,11 +1,11 @@
-# $Id: pgxnstatusbar.py,v 1.2 2005/02/18 07:14:42 waterbug Exp $
+# $Id: pgxnstatusbar.py,v 1.3 2005/05/11 07:07:49 waterbug Exp $
 
 """
 Custom status bar for PanGalaxian (the PGEF desktop client).
 
-@version: $Revision: 1.2 $
+@version: $Revision: 1.3 $
 """
-__version__ = "$Revision: 1.2 $"[11:-2]
+__version__ = "$Revision: 1.3 $"[11:-2]
 
 # Python core modules
 from pprint import pprint
@@ -17,9 +17,8 @@
 
 # PanGalactic modules
 from pangalactic.node.gui.dialogs.login import LoginDialog
+from pangalactic.node.gui.state import state, prefs, displaymaps
 from pangalactic.node.images import toolkitimages
-from pangalactic.utils.pgefstate       import state, readState, writeState
-from pangalactic.utils.preferences     import prefs, readPrefs, writePrefs
 
 
 class PgxnStatusBar(wx.StatusBar):

Index: PanGalactic/pangalactic/node/gui/dialogs/searchform.py
diff -u PanGalactic/pangalactic/node/gui/dialogs/searchform.py:1.5 PanGalactic/pangalactic/node/gui/dialogs/searchform.py:1.6
--- PanGalactic/pangalactic/node/gui/dialogs/searchform.py:1.5	Mon Mar 21 11:16:45 2005
+++ PanGalactic/pangalactic/node/gui/dialogs/searchform.py	Wed May 11 03:07:47 2005
@@ -1,13 +1,13 @@
 """
 General PanGalaxian search form
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 
 import wx
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state
 
 
 class SearchForm(wx.Panel):

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.6 PanGalactic/pangalactic/node/pangalaxian_new.py:1.7
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.6	Tue May 10 18:19:42 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Wed May 11 03:07:45 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.6 2005/05/10 22:19:42 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.7 2005/05/11 07:07:45 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 # Python core modules
 import sys
@@ -28,21 +28,20 @@
 import dispatch
 
 # PanGalactic modules
-from pangalactic.core.person                    import Person
-from pangalactic.node.gui.dialogs.login         import LoginDialog
+from pangalactic.core.person import Person
+from pangalactic.node.gui.dialogs.login import LoginDialog
+from pangalactic.node.gui.state import state, writeState
+from pangalactic.node.gui.state import prefs, displaymaps
 from pangalactic.node.gui.widgets.cachebrowser  import CacheBrowser
 from pangalactic.node.gui.widgets.pgxnpanes     import PgxnPanes
 from pangalactic.node.gui.widgets.pgxnstatusbar import PgxnStatusBar
 from pangalactic.node.gui.widgets.pgxntoolbar   import PgxnToolBar
-from pangalactic.node.images                    import toolkitimages
+from pangalactic.node.images import toolkitimages
 from pangalactic.utils import oid
-from pangalactic.utils import toolstate
 from pangalactic.utils import toolframe
 from pangalactic.utils import userinfo
 from pangalactic.utils.aboutbox        import AboutBox
 from pangalactic.utils.changepasswd    import ChangePasswd
-from pangalactic.utils.pgefstate       import state, readState, writeState
-from pangalactic.utils.preferences     import prefs, readPrefs, writePrefs
 from pangalactic.utils.proxyclass      import ProxyDialog
 from pangalactic.utils.serverclass     import ServerDialog
 from pangalactic.utils.usersearchframe import UserSearchFrame
@@ -145,8 +144,6 @@
         if not os.path.exists('tmp'):
             os.makedirs('tmp')
         # Look for a userid ... if none, run first-time dialog/wizard
-        readState()
-        readPrefs()
         if not prefs.get('userid', None):
             # TODO:  make first-time dialog a conf wizard for prefs, etc.
             # TODO:  make conf wiz usable any time (alt.: dlg for expt. users)
@@ -175,7 +172,6 @@
             if dlg.ShowModal() == wx.ID_OK:
                 prefs['userid'] = username.GetValue()
                 prefs['email'] = email.GetValue()
-                writePrefs()
             dlg.Destroy()
         useroid = prefs.get('email',
                             None) or prefs.get('userid',
@@ -359,6 +355,7 @@
         """
         PanGalaxian exit process.
         """
+        writeState()
         self.Close()
 
     def onEnableTooltips(self, event):

Index: PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py:1.8 PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py:1.9
--- PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py:1.8	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py	Wed May 11 03:07:48 2005
@@ -4,12 +4,11 @@
 from pangalactic.node.gui.psm import docform
 from pangalactic.node.gui.psm import pgefdoctree
 from pangalactic.node.gui.psm import doctreeframe
+from pangalactic.node.gui.state import state, prefs, displaymaps
 from pangalactic.core.document import Document
 from pangalactic.utils.pgefexceptions import RequiredDataError
-from pangalactic.utils.pgefstate import state
-from pangalactic.utils.preferences import prefs, writePrefs
 
-__version__ = "$Revision: 1.8 $"[11:-2]
+__version__ = "$Revision: 1.9 $"[11:-2]
 
 
 class DocumentTreeFrame(doctreeframe.DocTreeFrame):
@@ -204,7 +203,6 @@
             docid = prefs.get('nextdocid', 0)
             docid = int(docid) - 1
             prefs['nextdocid'] = docid
-            writePrefs()
             self.docform.NextDocId = str(int(self.docform.NextDocId) - 1)
         self.creatingDocument = False
 

Index: PanGalactic/pangalactic/node/gui/psm/propertiesform.py
diff -u PanGalactic/pangalactic/node/gui/psm/propertiesform.py:1.4 PanGalactic/pangalactic/node/gui/psm/propertiesform.py:1.5
--- PanGalactic/pangalactic/node/gui/psm/propertiesform.py:1.4	Sun Mar  6 19:02:53 2005
+++ PanGalactic/pangalactic/node/gui/psm/propertiesform.py	Wed May 11 03:07:48 2005
@@ -6,7 +6,7 @@
 
 from pangalactic.node.gui.psm.propertiesform_wdr import *
 from pangalactic.utils.httpdownload import httpGet
-from pangalactic.utils.pgefstate    import state
+from pangalactic.node.gui.state    import state
 
 
 class PropertiesForm(wxPanel):

Index: PanGalactic/pangalactic/core/workflow/wfprocessoverview.py
diff -u PanGalactic/pangalactic/core/workflow/wfprocessoverview.py:1.5 PanGalactic/pangalactic/core/workflow/wfprocessoverview.py:1.6
--- PanGalactic/pangalactic/core/workflow/wfprocessoverview.py:1.5	Tue May  3 03:08:28 2005
+++ PanGalactic/pangalactic/core/workflow/wfprocessoverview.py	Wed May 11 03:07:45 2005
@@ -1,12 +1,12 @@
-# $Id: wfprocessoverview.py,v 1.5 2005/05/03 07:08:28 waterbug Exp $
+# $Id: wfprocessoverview.py,v 1.6 2005/05/11 07:07:45 waterbug Exp $
 #!/bin/env python
 """
 Here there be classes that produce a tabular display of all locally-stored
 workflows.
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 # Author:       V. Keech
 # Created:      May 2003
@@ -25,7 +25,7 @@
 from pangalactic.utils import toolstate
 from pangalactic.utils import pgdialogs
 from pangalactic.utils import toolframe
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state
 
 WF_WIZARD = wxNewId()
 WF_SAVE = wxNewId()

Index: PanGalactic/pangalactic/node/pangalaxian_old.py
diff -u PanGalactic/pangalactic/node/pangalaxian_old.py:1.4 PanGalactic/pangalactic/node/pangalaxian_old.py:1.5
--- PanGalactic/pangalactic/node/pangalaxian_old.py:1.4	Mon Mar 14 14:55:58 2005
+++ PanGalactic/pangalactic/node/pangalaxian_old.py	Wed May 11 03:07:45 2005
@@ -1,13 +1,13 @@
 #!/usr/bin/env python 
 
-# $Id: pangalaxian_old.py,v 1.4 2005/03/14 19:55:58 waterbug Exp $
+# $Id: pangalaxian_old.py,v 1.5 2005/05/11 07:07:45 waterbug Exp $
 
 """
 Main application module for the PGEF desktop client.
 
-@version: $Revision: 1.4 $
+@version: $Revision: 1.5 $
 """
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 import sys
 import os
@@ -20,6 +20,8 @@
 from pangalactic.node.gui.dialogs.login import LoginDialog
 from pangalactic.node.gui.dialogs import searchframe
 from pangalactic.node.gui.psm import psmtool
+from pangalactic.node.gui.state import state, writeState
+from pangalactic.node.gui.state import prefs, displaymaps
 from pangalactic.core.person import Person
 from pangalactic.node.images import toolkitimages
 from pangalactic.utils import oid
@@ -29,8 +31,6 @@
 from pangalactic.utils import userinfo
 from pangalactic.utils.aboutbox        import AboutBox
 from pangalactic.utils.changepasswd    import ChangePasswd
-from pangalactic.utils.pgefstate       import state, readState, writeState
-from pangalactic.utils.preferences     import prefs, readPrefs, writePrefs
 from pangalactic.utils.proxyclass      import ProxyDialog
 from pangalactic.utils.serverclass     import ServerDialog
 from pangalactic.utils.usersearchframe import UserSearchFrame
@@ -183,11 +183,7 @@
     def __init__(self, parent, ID, title, pos, size):
         wx.Frame.__init__(self, parent, ID, title,pos, size)
         wx.InitAllImageHandlers()
-        # First populate the state and prefs dictionaries with whatever may
-        # have been saved from a previous session ...
-        readState()
-        readPrefs()
-        # Next try to start up the local cache (ZODB), since if we
+        # First try to start up the local cache (ZODB), since if we
         # don't have that, we can't really do anything.  To do that, we
         # need a userid ...
         if not prefs.get('userid', None):
@@ -216,7 +212,6 @@
             if dlg.ShowModal() == wx.ID_OK:
                 prefs['userid'] = username.GetValue()
                 prefs['email'] = email.GetValue()
-                writePrefs()
             dlg.Destroy()
         useroid = prefs.get('email',
                             None) or prefs.get('userid',
@@ -480,8 +475,6 @@
         print "  - state:"
         for s in state:
             print "    * %s = %s" % (s, state[s])
-        writeState()
-        writePrefs()
         # actually do stuff ...
         self.dm.onStateChange()
         self.psmgui.onStateChange()
@@ -977,7 +970,6 @@
         # I don't understand why this is necessary, since os was imported
         # up above, but this scope doesn't seem to see it!  8^/
         import os
-        writePrefs()
         writeState()
         if self.closing:
             event.Skip()

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.1 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.2
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.1	Mon May  9 09:19:50 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Wed May 11 03:07:49 2005
@@ -1,17 +1,17 @@
-# $Id: pgefobjectgrid.py,v 1.1 2005/05/09 13:19:50 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.2 2005/05/11 07:07:49 waterbug Exp $
 """
 PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.1 $
+@version: $Revision: 1.2 $
 """
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.2 $"[11:-2]
 
 
 import wx
 import wx.grid           as gridlib
 import wx.lib.gridmovers as gridmovers
 
-from pangalactic.utils.pgefstate import state, readState, writeState
+from pangalactic.node.gui.state import state, prefs, displaymaps
 
 class PgefObjectTable(gridlib.PyGridTableBase):
     def __init__(self, objs=None):

Index: PanGalactic/pangalactic/node/gui/psm/pgefedittree.py
diff -u PanGalactic/pangalactic/node/gui/psm/pgefedittree.py:1.4 PanGalactic/pangalactic/node/gui/psm/pgefedittree.py:1.5
--- PanGalactic/pangalactic/node/gui/psm/pgefedittree.py:1.4	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/pgefedittree.py	Wed May 11 03:07:48 2005
@@ -1,6 +1,6 @@
 from wxPython.wx import wxTreeCtrl, wxTreeItemIcon_Selected
 from pangalactic.node.gui.psm import pgeftree
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state
 
 class PgefEditTree(pgeftree.PgefTree):
     """Specialized tree for modifying single level of parent-children."""

Index: PanGalactic/pangalactic/node/gui/psm/docform.py
diff -u PanGalactic/pangalactic/node/gui/psm/docform.py:1.4 PanGalactic/pangalactic/node/gui/psm/docform.py:1.5
--- PanGalactic/pangalactic/node/gui/psm/docform.py:1.4	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/docform.py	Wed May 11 03:07:48 2005
@@ -3,8 +3,7 @@
 from wxPython.wx import *
 
 from pangalactic.node.gui.psm.docform_wdr import *
-from pangalactic.utils.preferences import prefs, writePrefs
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state, prefs, displaymaps
 
 
 class DocForm(wxPanel):
@@ -180,7 +179,6 @@
                                   "-DOC-",
                                   self.NextDocId]))
         prefs["nextdocid"] = self.NextDocId
-        writePrefs()
         self.EditingMode()
         wgt = self.GetBrowseWgt()
         wgt.SetFocus()

Index: PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py:1.3 PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py:1.4
--- PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py:1.3	Mon May  9 09:19:49 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefgrid.py	Wed May 11 03:07:49 2005
@@ -1,19 +1,19 @@
-# $Id: pgefgrid.py,v 1.3 2005/05/09 13:19:49 waterbug Exp $
+# $Id: pgefgrid.py,v 1.4 2005/05/11 07:07:49 waterbug Exp $
 """
 PGEF table-based, configurable data grid.  (This isn't being used for
 anything yet, but is designed for handling random tabular data.  The grid
 to use for objects is PgefObjectGrid.)
 
-@version: $Revision: 1.3 $
+@version: $Revision: 1.4 $
 """
-__version__ = "$Revision: 1.3 $"[11:-2]
+__version__ = "$Revision: 1.4 $"[11:-2]
 
 
 import wx
 import wx.grid           as gridlib
 import wx.lib.gridmovers as gridmovers
 
-from pangalactic.utils.pgefstate import state, readState, writeState
+from pangalactic.node.gui.state import state, prefs, displaymaps
 
 class PgefDataTable(gridlib.PyGridTableBase):
     def __init__(self, displaymap=None):

Index: PanGalactic/pangalactic/node/gui/psm/doctreeframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/doctreeframe.py:1.9 PanGalactic/pangalactic/node/gui/psm/doctreeframe.py:1.10
--- PanGalactic/pangalactic/node/gui/psm/doctreeframe.py:1.9	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/doctreeframe.py	Wed May 11 03:07:48 2005
@@ -1,4 +1,4 @@
-# $Id: doctreeframe.py,v 1.9 2005/05/03 07:08:29 waterbug Exp $
+# $Id: doctreeframe.py,v 1.10 2005/05/11 07:07:48 waterbug Exp $
 
 import wx
 from wx import grid
@@ -7,10 +7,10 @@
 from pangalactic.node.gui.psm import treeframe
 from pangalactic.node.images import toolkitimages
 from pangalactic.utils.pgefexceptions import RequiredDataError
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state
 from pangalactic.utils import basegrid
 
-__version__ = "$Revision: 1.9 $"[11:-2]
+__version__ = "$Revision: 1.10 $"[11:-2]
 
 
 NEW_MODE = 1

Index: PanGalactic/pangalactic/node/gui/plm/epimsmapping.py
diff -u PanGalactic/pangalactic/node/gui/plm/epimsmapping.py:1.2 PanGalactic/pangalactic/node/gui/plm/epimsmapping.py:1.3
--- PanGalactic/pangalactic/node/gui/plm/epimsmapping.py:1.2	Tue Feb  8 15:45:25 2005
+++ PanGalactic/pangalactic/node/gui/plm/epimsmapping.py	Wed May 11 03:07:47 2005
@@ -4,7 +4,7 @@
 from epimsgrid import *
 
 from pangalactic.utils import toolframe
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state
 
 MAPGRID_FOREIGN = wxNewId()
 DELETEMAPROW = wxNewId()

Index: PanGalactic/pangalactic/utils/basegrid.py
diff -u PanGalactic/pangalactic/utils/basegrid.py:1.44 PanGalactic/pangalactic/utils/basegrid.py:1.45
--- PanGalactic/pangalactic/utils/basegrid.py:1.44	Tue May  3 03:08:31 2005
+++ PanGalactic/pangalactic/utils/basegrid.py	Wed May 11 03:07:50 2005
@@ -1,13 +1,13 @@
-# $Id: basegrid.py,v 1.44 2005/05/03 07:08:31 waterbug Exp $
+# $Id: basegrid.py,v 1.45 2005/05/11 07:07:50 waterbug Exp $
 
 """
 Wrapper for the grid that adds the drag and drop functionality to the base
 grid class.  Also adds the ability to set the labels for the grid columns
 and to fill a row of data given the data in a list format
 
-@version: $Revision: 1.44 $
+@version: $Revision: 1.45 $
 """
-__version__ = "$Revision: 1.44 $"[11:-2]
+__version__ = "$Revision: 1.45 $"[11:-2]
 
 import cPickle
 import os
@@ -18,6 +18,7 @@
 from wx import grid
 from wx.lib.gridmovers import GridColMover, EVT_GRID_COL_MOVE
 
+from pangalactic.node.gui.state import displaymaps
 from pangalactic.utils import pdfoptions        
 from pangalactic.utils import objectreport      
 from pangalactic.utils import pgefevents        
@@ -80,13 +81,12 @@
         else:
             self.table = pgefdatatable.PgefDataTable()
         self.classname = classname
-        self.current_config = self.dm.getDisplayConfig()
-        # print '  - current_config ='
-        # pprint(self.current_config)
+        # print '  - displaymaps ='
+        # pprint(displaymaps)
         # print '\n  - self.classname is:', self.classname
         # print '\n  - setting display map to:'
-        # pprint(self.current_config[classname])
-        self.table.setDisplayMap(self.current_config[classname])
+        # pprint(displaymaps[classname])
+        self.table.setDisplayMap(displaymaps[classname])
         self.SetTable(self.table, True)
         self.moveTo = None
         self.DropVariable = None
@@ -289,7 +289,7 @@
                                              tabular=tabular,
                                              hidegridlines=hide_gridlines)
 
-            temp.current_config = self.current_config[self.classname]
+            temp.current_config = displaymaps[self.classname]
             fn = temp.generate()
 
             dtext = fn + "\n\nhas been generated."
@@ -331,20 +331,20 @@
         gridframe.mainpanel = ConfigureGrid(gridframe, -1,
                                             dm=self.dm,
                                             collection_name=self.classname,
-                                            current_config=self.current_config)
+                                            current_config=displaymaps)
         gridframe.CentreOnParent()
         result = gridframe.Show(True)
         if result == wx.ID_OK:
             displaymap = gridframe.mainpanel.GetDisplayList()
             self.RefreshDisplay(displaymap)
             self.WriteDisplay(displaymap)
-            self.current_config[self.classname] = displaymap
-            self.dm.setDisplayConfig(self.current_config)
+            displaymaps[self.classname] = displaymap
+            self.dm.setDisplayConfig(displaymaps)
 
     def RefreshDisplay(self, displaymap):
         #print "basegrid.refreshdisplay"
         if displaymap:
-            self.table.setDisplayMap(self.current_config[classname])
+            self.table.setDisplayMap(displaymaps[classname])
             self.table.RefreshGrid()
             self.AutoSizeColumns()
 

Index: PanGalactic/pangalactic/node/gui/psm/partslistview.py
diff -u PanGalactic/pangalactic/node/gui/psm/partslistview.py:1.6 PanGalactic/pangalactic/node/gui/psm/partslistview.py:1.7
--- PanGalactic/pangalactic/node/gui/psm/partslistview.py:1.6	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/partslistview.py	Wed May 11 03:07:48 2005
@@ -6,7 +6,7 @@
 
 from pangalactic.node.gui.psm.partslistview_wdr import *
 from pangalactic.utils.httpdownload import httpGet
-from pangalactic.utils.pgefstate    import state
+from pangalactic.node.gui.state    import state
 
 try:
     import pangalactic.node.gui.plm.ms2file as ms2file

Index: PanGalactic/pangalactic/node/gui/psm/pgeftree.py
diff -u PanGalactic/pangalactic/node/gui/psm/pgeftree.py:1.8 PanGalactic/pangalactic/node/gui/psm/pgeftree.py:1.9
--- PanGalactic/pangalactic/node/gui/psm/pgeftree.py:1.8	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/pgeftree.py	Wed May 11 03:07:48 2005
@@ -1,10 +1,10 @@
-# $Id: pgeftree.py,v 1.8 2005/05/03 07:08:29 waterbug Exp $
+# $Id: pgeftree.py,v 1.9 2005/05/11 07:07:48 waterbug Exp $
 """
 Base class for PanGalaxian's trees
 
-@version: $Revision: 1.8 $
+@version: $Revision: 1.9 $
 """
-__version__ = "$Revision: 1.8 $"[11:-2]
+__version__ = "$Revision: 1.9 $"[11:-2]
 
 import wx
 import cPickle, types
@@ -17,11 +17,11 @@
 from pangalactic.node.images      import toolkitimages
 from pangalactic.utils            import pdfoptions
 from pangalactic.utils            import pgefevents
-from pangalactic.utils.pgefstate  import state
+from pangalactic.node.gui.state  import state
 from pangalactic.node.gui.psm     import itemdroptarget
 from pangalactic.node.io          import treereport
 
-__version__ = "$Revision: 1.8 $"[11:-2]
+__version__ = "$Revision: 1.9 $"[11:-2]
 
 
 class PgefTree(wx.TreeCtrl):

Index: PanGalactic/pangalactic/repo/pgersecurity.py
diff -u PanGalactic/pangalactic/repo/pgersecurity.py:1.2 PanGalactic/pangalactic/repo/pgersecurity.py:1.3
--- PanGalactic/pangalactic/repo/pgersecurity.py:1.2	Mon Feb 14 11:47:34 2005
+++ PanGalactic/pangalactic/repo/pgersecurity.py	Wed May 11 03:07:49 2005
@@ -1,14 +1,14 @@
-# $Id: pgersecurity.py,v 1.2 2005/02/14 16:47:34 waterbug Exp $
+# $Id: pgersecurity.py,v 1.3 2005/05/11 07:07:49 waterbug Exp $
 
 """
 Manager of security permissions for PGER.
 
-@version: $Revision: 1.2 $
+@version: $Revision: 1.3 $
 """
-__version__ = "$Revision: 1.2 $"[11:-2]
+__version__ = "$Revision: 1.3 $"[11:-2]
 
 from pangalactic.core.person import Person
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state
 
 class Roles:
     def __init__(self):

Index: PanGalactic/pangalactic/node/gui/widgets/pgeftree.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgeftree.py:1.5 PanGalactic/pangalactic/node/gui/widgets/pgeftree.py:1.6
--- PanGalactic/pangalactic/node/gui/widgets/pgeftree.py:1.5	Tue May  3 03:08:30 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgeftree.py	Wed May 11 03:07:49 2005
@@ -1,10 +1,10 @@
-# $Id: pgeftree.py,v 1.5 2005/05/03 07:08:30 waterbug Exp $
+# $Id: pgeftree.py,v 1.6 2005/05/11 07:07:49 waterbug Exp $
 """
 Base class for PanGalaxian's trees
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 import wx
 import cPickle, types
@@ -12,11 +12,11 @@
 from pangalactic.node.images      import toolkitimages
 from pangalactic.utils            import pdfoptions
 from pangalactic.utils            import pgefevents
-from pangalactic.utils.pgefstate  import state
+from pangalactic.node.gui.state  import state
 from pangalactic.node.gui.psm     import itemdroptarget
 from pangalactic.node.io          import treereport
 
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 
 class PgefTree(wx.TreeCtrl):

Index: PanGalactic/pangalactic/node/gui/psm/psmtool.py
diff -u PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.30 PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.31
--- PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.30	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/psmtool.py	Wed May 11 03:07:48 2005
@@ -1,10 +1,10 @@
-# $Id: psmtool.py,v 1.30 2005/05/03 07:08:29 waterbug Exp $
+# $Id: psmtool.py,v 1.31 2005/05/11 07:07:48 waterbug Exp $
 # Originally Created 04/05/2001
 """
 PSM Tool is the Product Structure Manager.  It handles visualization,
 navigation, and editing of product structures.
 """
-__version__ = "$Revision: 1.30 $"[11:-2]
+__version__ = "$Revision: 1.31 $"[11:-2]
 
 import os
 import sys
@@ -19,9 +19,7 @@
 from pangalactic.node.images import toolkitimages
 from pangalactic.utils import basegrid
 from pangalactic.utils import httpdownload
-from pangalactic.utils.preferences import prefs
-from pangalactic.utils.pgefstate import state
-
+from pangalactic.node.gui.state import state, prefs, displaymaps
 from pangalactic.node.gui.psm import toolbarpanel
 from pangalactic.node.gui.psm import pgeftree
 from pangalactic.node.gui.psm import pgefversiontree

Index: PanGalactic/pangalactic/node/gui/psm/projectframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/projectframe.py:1.2 PanGalactic/pangalactic/node/gui/psm/projectframe.py:1.3
--- PanGalactic/pangalactic/node/gui/psm/projectframe.py:1.2	Tue Feb  8 15:45:25 2005
+++ PanGalactic/pangalactic/node/gui/psm/projectframe.py	Wed May 11 03:07:48 2005
@@ -1,17 +1,17 @@
-# $Id: projectframe.py,v 1.2 2005/02/08 20:45:25 waterbug Exp $
+# $Id: projectframe.py,v 1.3 2005/05/11 07:07:48 waterbug Exp $
 
 """
 Window for editing data about a Project.
 
-@version: $Revision: 1.2 $
+@version: $Revision: 1.3 $
 """
-__version__ = "$Revision: 1.2 $"[11:-2]
+__version__ = "$Revision: 1.3 $"[11:-2]
 
 from wxPython.wx import EVT_CLOSE, wxDefaultSize, wxDefaultPosition
 
 from projectinfo_wdr import *
 import pangalactic.utils.toolframe as toolframe
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state
 
 class ProjectFrame(toolframe.ToolFrame):
     """

Index: PanGalactic/pangalactic/node/gui/psm/partslisttreeframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/partslisttreeframe.py:1.6 PanGalactic/pangalactic/node/gui/psm/partslisttreeframe.py:1.7
--- PanGalactic/pangalactic/node/gui/psm/partslisttreeframe.py:1.6	Tue May  3 03:08:29 2005
+++ PanGalactic/pangalactic/node/gui/psm/partslisttreeframe.py	Wed May 11 03:07:48 2005
@@ -1,12 +1,11 @@
-# $Id: partslisttreeframe.py,v 1.6 2005/05/03 07:08:29 waterbug Exp $
+# $Id: partslisttreeframe.py,v 1.7 2005/05/11 07:07:48 waterbug Exp $
 
 import copy
 from wxPython.wx import *
 
 from pangalactic.utils                 import toolframe
 from pangalactic.utils.pgefexceptions  import RequiredDataError
-from pangalactic.utils.pgefstate       import state
-from pangalactic.utils.preferences     import prefs, writePrefs
+from pangalactic.node.gui.state        import state, prefs, displaymaps
 from pangalactic.node.gui.psm          import doctreeframe
 from pangalactic.node.gui.psm          import pgefdoctree
 from pangalactic.node.gui.psm          import partslistform
@@ -20,7 +19,7 @@
 except:
     print "partslisttreeframe.plmimport.failed"
 
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 
 class PartsListTreeFrame(doctreeframe.DocTreeFrame):
@@ -320,7 +319,6 @@
             docid = prefs.get('nextplid', '1')
             docid = int(docid) - 1
             prefs['nextplid'] = docid
-            writePrefs()
             self.docform.NextDocId = str(int(self.docform.NextDocId) - 1)
 
         self.creatingDocument = False

Index: PanGalactic/pangalactic/node/gui/psm/partform.py
diff -u PanGalactic/pangalactic/node/gui/psm/partform.py:1.3 PanGalactic/pangalactic/node/gui/psm/partform.py:1.4
--- PanGalactic/pangalactic/node/gui/psm/partform.py:1.3	Sat Jan 29 16:52:46 2005
+++ PanGalactic/pangalactic/node/gui/psm/partform.py	Wed May 11 03:07:48 2005
@@ -2,9 +2,7 @@
 
 #import pangalactic.core.part as part
 
-from pangalactic.utils.preferences import prefs, writePrefs
-from pangalactic.utils.pgefstate import state
-
+from pangalactic.node.gui.state import state, prefs, displaymaps
 from pangalactic.node.gui.psm.partform_wdr import *
 
 
@@ -185,7 +183,6 @@
         nextid = prefs.get('nextid', '1')
         nextid = int(nextid) - 1
         prefs['nextid'] = nextid
-        writePrefs()
         self.NextId = None
         #print "nextid", nextid
 

Index: PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py
diff -u PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.4 PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.5
--- PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.4	Mon May  9 09:19:49 2005
+++ PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py	Wed May 11 03:07:49 2005
@@ -1,5 +1,5 @@
 #!/bin/env python
-# $Id: cachebrowser.py,v 1.4 2005/05/09 13:19:49 waterbug Exp $
+# $Id: cachebrowser.py,v 1.5 2005/05/11 07:07:49 waterbug Exp $
 #----------------------------------------------------------------------------
 # Authors:      Ginny, Steve
 #----------------------------------------------------------------------------
@@ -7,9 +7,9 @@
 PanGalaxian cache browser and display customizer
 (Works with PgefObjects in a local ZODB)
 
-@version: $Revision: 1.4 $
+@version: $Revision: 1.5 $
 """
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 import wx
 from wx import grid
@@ -23,7 +23,7 @@
 from pangalactic.utils import toolframe
 from pangalactic.utils import objectviewer
 from pangalactic.utils import configuregrid
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state, prefs, displaymaps
 
 from pprint import pprint
 
@@ -53,7 +53,6 @@
         self._registry = dm._registry
         self.cache = dm.cache
         self.dbfile = None
-        self.current_config = {}
         # the following section replaces:  ZODBBrowserFunc(self, True)
         vboxsizer0 = wx.BoxSizer(wx.VERTICAL)
         hboxsizer0 = wx.BoxSizer(wx.HORIZONTAL)
@@ -102,7 +101,6 @@
         self.Bind(wx.EVT_BUTTON, self.FileConfig, self.customize_button)
         self.Bind(wx.EVT_BUTTON, self.OnClose, self.close_button)
         self.Bind(wx.EVT_CLOSE, self.OnClose)
-        self.GetDisplayConfig()
         self.objectgrid.SetColLabelSize(30)
         self.objectgrid.SetCellHighlightPenWidth(0)
         self.objectgrid.EnableEditing(False)
@@ -154,15 +152,6 @@
         if file:
             self.dbfile = file
 
-    def GetDisplayConfig(self):
-        # print "cachebrowser.getdisplayconfig"
-        self.current_config = self.cache.getDisplayConfig()
-        if len(self.current_config) == 0:
-            for dictname, keepflag, access_level in self.cache.dictlist:
-                self.current_config[dictname] = []
-            self.cache.setDisplayConfig(self.current_config)
-        # pprint(self.current_config)
-
     def FileConfig(self, event=None):
         collection_name = self.rootitems.GetStringSelection()
         if collection_name:
@@ -176,7 +165,7 @@
                                         cfg_frame, -1,
                                         dm=self.dm,
                                         collection_name=collection_name,
-                                        current_config=self.current_config)
+                                        current_config=displaymaps)
             cfg_frame.CentreOnParent()
             cfg_frame.Show(True)
             htext = "The upper section shows lists of what is not (left)\n" + \
@@ -298,20 +287,19 @@
             if numrows > 0:
                 self.objectgrid.AppendRows(numrows)
             # look for a configuration entry, and append the columns
-            self.current_config = self.cache.getDisplayConfig()
-            # pprint(self.current_config)
+            # pprint(displaymaps)
             if selection == self.cache.uncommittedobjs:
                 # print "have pgefobject mapping"
-                mapping = list(self.current_config["PgefObject"])
+                mapping = list(displaymaps["PgefObject"])
                 mapping.append(['pgef_oid', 'OID', 'str'])
                 mapping.insert(0, ['schema_id', 'Schema', 'str'])
                 self.objectgrid.AppendCols(len(mapping))
                 for col in range(len(mapping)):
                     self.objectgrid.SetColLabelValue(col, mapping[col][1])
                 # print "mapping", mapping
-            elif self.current_config.has_key(selection) and (len(self.current_config[selection]) > 0):
+            elif displaymaps.has_key(selection) and (len(displaymaps[selection]) > 0):
                 # there is an entry in the configuration dictionary
-                mapping = self.current_config[selection]
+                mapping = displaymaps[selection]
                 self.objectgrid.AppendCols(len(mapping))
                 for col in range(len(mapping)):
                     self.objectgrid.SetColLabelValue(col, mapping[col][1])
@@ -322,9 +310,9 @@
                 mapping = self.newConfigEntry(selection, objs)
                 if len(mapping) > 0:
                     print "new entry"
-                    self.current_config[selection] = mapping
-                    self.cache.setDisplayConfig(self.current_config)
-                    pprint(self.current_config)
+                    displaymaps[selection] = mapping
+                    self.cache.setDisplayConfig(displaymaps)
+                    pprint(displaymaps)
             # fill in the grid cells
             curr_row = 0
             col = 0

Index: PanGalactic/pangalactic/utils/usersearchframe.py
diff -u PanGalactic/pangalactic/utils/usersearchframe.py:1.12 PanGalactic/pangalactic/utils/usersearchframe.py:1.13
--- PanGalactic/pangalactic/utils/usersearchframe.py:1.12	Tue May  3 03:08:31 2005
+++ PanGalactic/pangalactic/utils/usersearchframe.py	Wed May 11 03:07:50 2005
@@ -1,18 +1,19 @@
-# $Id: usersearchframe.py,v 1.12 2005/05/03 07:08:31 waterbug Exp $
+# $Id: usersearchframe.py,v 1.13 2005/05/11 07:07:50 waterbug Exp $
 """
 wx frame for doing searches for users.
 
-@version: $Revision: 1.12 $
+@version: $Revision: 1.13 $
 """
-__version__ = "$Revision: 1.12 $"[11:-2]
+__version__ = "$Revision: 1.13 $"[11:-2]
 
 from wxPython.wx import *
 
+from pangalactic.node.gui.state import displaymaps
 from pangalactic.utils import toolframe
 from pangalactic.utils import usergrid
 from pangalactic.utils import userinfo
 from pangalactic.utils import usersearchgui
-from pangalactic.utils.pgefstate import state
+from pangalactic.node.gui.state import state
 
 class UserSearchFrame(toolframe.ToolFrame):
     USER_SEARCH_GRID = wxNewId()
@@ -154,8 +155,7 @@
             searchresults = self.dm.getSearchResults()
 
             if len(searchresults) > 0:
-                current_config = self.dm.getDisplayConfig()
-                config = current_config["Person"]
+                config = displaymaps["Person"]
 
                 ndx = 0
                 self.resultsgrid.BeginBatch()

Index: PanGalactic/pangalactic/utils/datamanager.py
diff -u PanGalactic/pangalactic/utils/datamanager.py:1.174 PanGalactic/pangalactic/utils/datamanager.py:1.175
--- PanGalactic/pangalactic/utils/datamanager.py:1.174	Tue May  3 03:08:31 2005
+++ PanGalactic/pangalactic/utils/datamanager.py	Wed May 11 03:07:50 2005
@@ -1,10 +1,10 @@
-# $Id: datamanager.py,v 1.174 2005/05/03 07:08:31 waterbug Exp $
+# $Id: datamanager.py,v 1.175 2005/05/11 07:07:50 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_datamanager -*-
 
 """
 PanGalaxian's local workspace manager.
 
-@version: $Revision: 1.174 $
+@version: $Revision: 1.175 $
 """
 # TODO:  move the transaction/interface stuff, like XmlrpcInterface, into a
 # separate module -- InterfaceManager, which will handle all client
@@ -15,7 +15,7 @@
 # came from (repository, file import, etc.) and what their state is
 # (committed/uncommitted, etc.)
 
-__version__ = "$Revision: 1.174 $"[11:-2]
+__version__ = "$Revision: 1.175 $"[11:-2]
 
 import time
 import mx.DateTime
@@ -30,12 +30,12 @@
 from pangalactic.core.project    import Project
 from pangalactic.core.filelink   import FileLink
 from pangalactic.core.workflow   import wffactory
-from pangalactic.meta.registry         import PanGalacticRegistry
+from pangalactic.meta.registry   import PanGalacticRegistry
+from pangalactic.node.gui.state  import state, prefs, displaymaps
+from pangalactic.node.gui.state  import prefs, displaymaps
 from pangalactic.utils                 import localdb
 from pangalactic.utils.httpupload      import upload
 from pangalactic.utils.pgefexceptions  import LocalStorageError
-from pangalactic.utils.pgefstate       import state, readState, writeState
-from pangalactic.utils.preferences     import prefs, readPrefs, writePrefs
 from pangalactic.utils.xmlrpcinterface import XmlrpcInterface
 
 
@@ -59,8 +59,6 @@
         @param userid:  the id of the invoking user (a Person oid)
         @type  userid:  C{str}
         """
-        readState()
-        readPrefs()
         self._registry = _registry or PanGalacticRegistry()
         try:
             self.cache = localdb.LocalStorage(self._registry)
@@ -81,6 +79,10 @@
         self.creatingPartsList = False
         self.creatingDocument = False
         self.creatingWorkflow = False
+        if not displaymaps:
+            # initialize default display maps
+            for schema_id, schema in self._registry.object_schemas.items():
+                displaymaps[schema_id] = schema._default_display_map
 
     def getServerHost(self):
         return state['server'].split(':')[0]
@@ -156,22 +158,6 @@
         else:
             return localdb.USER
 
-    def getDisplayMap(self, mapname):
-        print "DM.getDisplayMap"
-        foo = self.getDisplayConfig()
-        if foo.has_key(mapname):
-            print mapname, "map", foo[mapname]
-            return foo[mapname]
-        else:
-            print "dm.getdisplaymap: no entry for:", mapname, "wha' happened?"
-            return {}
-
-    def getDisplayConfig(self):
-        return self.cache.getDisplayConfig()
-
-    def setDisplayConfig(self, config):
-        self.cache.setDisplayConfig(config)
-
     def getDict(self, name):
         """
         Get the {oid : obj} dictionary for the named ObjectSchema from the

Index: PanGalactic/pangalactic/utils/configuregrid.py
diff -u PanGalactic/pangalactic/utils/configuregrid.py:1.12 PanGalactic/pangalactic/utils/configuregrid.py:1.13
--- PanGalactic/pangalactic/utils/configuregrid.py:1.12	Sat Jan 15 01:10:54 2005
+++ PanGalactic/pangalactic/utils/configuregrid.py	Wed May 11 03:07:50 2005
@@ -1,9 +1,10 @@
-# $Id: configuregrid.py,v 1.12 2005/01/15 06:10:54 waterbug Exp $
+# $Id: configuregrid.py,v 1.13 2005/05/11 07:07:50 waterbug Exp $
 
-__version__ = "$Revision: 1.12 $"[11:-2]
+__version__ = "$Revision: 1.13 $"[11:-2]
 
 import wx
 from wx.lib.mixins.listctrl import ColumnSorterMixin
+from pangalactic.node.gui.state import displaymaps
 from pangalactic.utils.configuredisplay import ConfigureDisplay
 
 # import pprint
@@ -25,7 +26,7 @@
         if current_config:
             self.current_config = current_config
         else:
-            self.current_config = self.dm.getDisplayConfig()
+            self.current_config = displaymaps
 
         # pprint.pprint(self.current_config)
         self.Setup()

Index: PanGalactic/pangalactic/utils/localdb.py
diff -u PanGalactic/pangalactic/utils/localdb.py:1.129 PanGalactic/pangalactic/utils/localdb.py:1.130
--- PanGalactic/pangalactic/utils/localdb.py:1.129	Tue May  3 03:08:31 2005
+++ PanGalactic/pangalactic/utils/localdb.py	Wed May 11 03:07:50 2005
@@ -1,9 +1,9 @@
 """
 Local object cache manager
 
-@version: $Revision: 1.129 $
+@version: $Revision: 1.130 $
 """
-__version__ = "$Revision: 1.129 $"[11:-2]
+__version__ = "$Revision: 1.130 $"[11:-2]
 
 import os
 import glob
@@ -229,29 +229,6 @@
 
     ### TODO:  the Wf classes need ObjectSchemas
 
-    def defaultDisplayConfig(self):
-        print "localdb.defaultDisplayConfig"
-        current_config = {}
-        for schemaid in self._registry.object_schemas:
-            print 'configuring display for schema:  %s' % schemaid
-            schema = self._registry.object_schemas[schemaid]
-            current_config[schemaid] = schema._default_display_map
-        self.setDisplayConfig(current_config)
-        print "default config done"
-        return current_config
-
-    def getDisplayConfig(self):
-        print "localdb.getDisplayConfig"
-        foo = self.getDict('DisplayConfig')
-        # print "localdb.config.keys", foo.keys()
-        if not foo:
-            foo = self.defaultDisplayConfig()
-        return foo
-
-    def setDisplayConfig(self, config):
-        self.dbroot['DisplayConfig'] = config
-        self.commit()
-
     def getUncommittedPartsListIDs(self):
         return self.dbroot[self.UNCOMMITTEDPARTSLISTIDS]
 

From waterbug at step.nasa.gov  Thu May 12 02:49:08 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May 12 02:49:10 2005
Subject: [pangalactic-commits] All God's chillun got a display_name.
Message-ID: <200505120649.j4C6n8HT015761@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/meta/pgefproperty.py 1.16 1.17

Log message:
All God's chillun got a display_name.

Index: PanGalactic/pangalactic/meta/pgefproperty.py
diff -u PanGalactic/pangalactic/meta/pgefproperty.py:1.16 PanGalactic/pangalactic/meta/pgefproperty.py:1.17
--- PanGalactic/pangalactic/meta/pgefproperty.py:1.16	Wed May  4 06:24:11 2005
+++ PanGalactic/pangalactic/meta/pgefproperty.py	Thu May 12 02:49:07 2005
@@ -1,4 +1,4 @@
-# $Id: pgefproperty.py,v 1.16 2005/05/04 10:24:11 waterbug Exp $
+# $Id: pgefproperty.py,v 1.17 2005/05/12 06:49:07 waterbug Exp $
 
 """
 The PanGalactic Property class (not to be confused with the Python built-in
@@ -42,9 +42,9 @@
 C{ObjectSchema}, in which the C{ObjectSchema} corresponds to the class that
 is the domain of the binary relationship.
 
-@version: $Revision: 1.16 $
+@version: $Revision: 1.17 $
 """
-__version__ = "$Revision: 1.16 $"[11:-2]
+__version__ = "$Revision: 1.17 $"[11:-2]
 
 
 from pangalactic.meta.utils import getDefault
@@ -337,6 +337,10 @@
         """
         for a in self._schema:
             setattr(self, a, kw.get(a, getDefault(self._schema[a])))
+        if not getattr(self, 'name', None):
+            self.name = self.id.capitalize()
+        if not getattr(self, 'display_name', None):
+            self.display_name = self.name
 
 
     ######################################################################

From waterbug at step.nasa.gov  Thu May 12 20:29:53 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May 12 20:29:55 2005
Subject: [pangalactic-commits] Intermediate check-in;
	ObjectGrid not working yet.
Message-ID: <200505130029.j4D0TrwH031258@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.7 1.8
PanGalactic/pangalactic/node/gui/state.py 1.1 1.2
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.2 1.3
PanGalactic/pangalactic/test/IDTEST 1.112 1.113
PanGalactic/pangalactic/utils/datamanager.py 1.175 1.176

Log message:
Intermediate check-in; ObjectGrid not working yet.

Index: PanGalactic/pangalactic/node/gui/state.py
diff -u PanGalactic/pangalactic/node/gui/state.py:1.1 PanGalactic/pangalactic/node/gui/state.py:1.2
--- PanGalactic/pangalactic/node/gui/state.py:1.1	Wed May 11 03:07:46 2005
+++ PanGalactic/pangalactic/node/gui/state.py	Thu May 12 20:29:50 2005
@@ -1,31 +1,28 @@
-# $Id: state.py,v 1.1 2005/05/11 07:07:46 waterbug Exp $
+# $Id: state.py,v 1.2 2005/05/13 00:29:50 waterbug Exp $
 
 """
 Global state for a PGEF application, which is written to a file for
 persistence between sessions, in 'JavaScript Object Notation' (JSON) --
 see: <http://www.crockford.com/JSON/index.html>.
 
-@version: $Revision: 1.1 $
+@version: $Revision: 1.2 $
 """
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.2 $"[11:-2]
 
 from pprint import pprint
 
 # overall state of PanGalaxian
 state = {}
-read = 0
 
-if not read:
-    try:
-        # TODO:  add checksum check for security
-        f = file('state.json')
-        state = eval(f.read())
-        f.close()
-    except:
-        print 'could not open state.json'
-        f = file('state.json','w')
-        f.close()
-    read = 1
+try:
+    # TODO:  add checksum check for security
+    f = file('state.json')
+    state = eval(f.read())
+    f.close()
+except:
+    print 'could not open state.json'
+    f = file('state.json','w')
+    f.close()
 
 # PanGalaxian user preferences
 if not state.get('prefs', None):

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.7 PanGalactic/pangalactic/node/pangalaxian_new.py:1.8
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.7	Wed May 11 03:07:45 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Thu May 12 20:29:50 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.7 2005/05/11 07:07:45 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.8 2005/05/13 00:29:50 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 # Python core modules
 import sys
@@ -77,61 +77,61 @@
         self.pgxn_menubar.Append(self.file_menu, "&File")
         self.file_new_menu = wx.Menu()
         self.file_menu.AppendMenu(-1, "&New", self.file_new_menu, "")
-        self.file_new_part_menu      = self.file_new_menu.Append(-1, "&Part...", "Create a Part ...", wx.ITEM_NORMAL)
-        self.file_new_model_menu     = self.file_new_menu.Append(-1, "&Model...", "Create a Model ...", wx.ITEM_NORMAL)
-        self.file_new_partslist_menu = self.file_new_menu.Append(-1, "Parts &List...", "Create a new Parts List ...", wx.ITEM_NORMAL)
-        self.file_new_doc_menu       = self.file_new_menu.Append(-1, "&Document...", "Create a new Document ...", wx.ITEM_NORMAL)
-        self.file_login_menu         = self.file_menu.Append(-1, "Log&in", "Login to hub ...", wx.ITEM_NORMAL)
-        self.file_logout_menu        = self.file_menu.Append(-1, "Log&out", "Logout from hub ...", wx.ITEM_NORMAL)
-        self.file_export_menu        = self.file_menu.Append(-1, "&Export", "Export file as ...", wx.ITEM_NORMAL)
-        self.file_exit_menu          = self.file_menu.Append(-1, "E&xit", "Exit PanGalaxian ...", wx.ITEM_NORMAL)
+        self.file_new_part      = self.file_new_menu.Append(-1, "&Part...", "Create a Part ...", wx.ITEM_NORMAL)
+        self.file_new_model     = self.file_new_menu.Append(-1, "&Model...", "Create a Model ...", wx.ITEM_NORMAL)
+        self.file_new_partslist = self.file_new_menu.Append(-1, "Parts &List...", "Create a new Parts List ...", wx.ITEM_NORMAL)
+        self.file_new_doc       = self.file_new_menu.Append(-1, "&Document...", "Create a new Document ...", wx.ITEM_NORMAL)
+        self.file_login         = self.file_menu.Append(-1, "Log&in", "Login to hub ...", wx.ITEM_NORMAL)
+        self.file_logout        = self.file_menu.Append(-1, "Log&out", "Logout from hub ...", wx.ITEM_NORMAL)
+        self.file_export        = self.file_menu.Append(-1, "&Export", "Export file as ...", wx.ITEM_NORMAL)
+        self.file_exit          = self.file_menu.Append(-1, "E&xit", "Exit PanGalaxian ...", wx.ITEM_NORMAL)
         self.tools_menu = wx.Menu()
         self.tools_part_menu = wx.Menu()
         self.tools_menu.AppendMenu(-1, "&Parts", self.tools_part_menu, "")
-        self.tools_new_part_menu  = self.tools_part_menu.Append(-1, "&New...", "Create a Part ...", wx.ITEM_NORMAL)
-        self.tools_edit_part_menu = self.tools_part_menu.Append(-1, "&Edit...", "Edit a Part ...", wx.ITEM_NORMAL)
-        self.tools_view_part_menu = self.tools_part_menu.Append(-1, "&View...", "View a Part ...", wx.ITEM_NORMAL)
+        self.tools_new_part  = self.tools_part_menu.Append(-1, "&New...", "Create a Part ...", wx.ITEM_NORMAL)
+        self.tools_edit_part = self.tools_part_menu.Append(-1, "&Edit...", "Edit a Part ...", wx.ITEM_NORMAL)
+        self.tools_view_part = self.tools_part_menu.Append(-1, "&View...", "View a Part ...", wx.ITEM_NORMAL)
         self.tools_model_menu = wx.Menu()
-        self.tools_new_model_menu  = self.tools_model_menu.Append(-1, "&New...", "Create a new Model ...", wx.ITEM_NORMAL)
-        self.tools_edit_model_menu = self.tools_model_menu.Append(-1, "&Edit...", "Edit a Model ...", wx.ITEM_NORMAL)
-        self.tools_view_model_menu = self.tools_model_menu.Append(-1, "&View...", "View a Model ...", wx.ITEM_NORMAL)
         self.tools_menu.AppendMenu(-1, "&Models", self.tools_model_menu, "")
+        self.tools_new_model  = self.tools_model_menu.Append(-1, "&New...", "Create a new Model ...", wx.ITEM_NORMAL)
+        self.tools_edit_model = self.tools_model_menu.Append(-1, "&Edit...", "Edit a Model ...", wx.ITEM_NORMAL)
+        self.tools_view_model = self.tools_model_menu.Append(-1, "&View...", "View a Model ...", wx.ITEM_NORMAL)
         self.tools_partslist_menu = wx.Menu()
-        self.tools_new_partslist_menu  = self.tools_partslist_menu.Append(-1, "&New...", "Create a Parts List ...", wx.ITEM_NORMAL)
-        self.tools_edit_partslist_menu = self.tools_partslist_menu.Append(-1, "&Edit...", "Edit a Parts List ...", wx.ITEM_NORMAL)
-        self.tools_view_partslist_menu = self.tools_partslist_menu.Append(-1, "&View...", "View a Parts List ...", wx.ITEM_NORMAL)
         self.tools_menu.AppendMenu(-1, "Parts &Lists", self.tools_partslist_menu, "")
+        self.tools_new_partslist  = self.tools_partslist_menu.Append(-1, "&New...", "Create a Parts List ...", wx.ITEM_NORMAL)
+        self.tools_edit_partslist = self.tools_partslist_menu.Append(-1, "&Edit...", "Edit a Parts List ...", wx.ITEM_NORMAL)
+        self.tools_view_partslist = self.tools_partslist_menu.Append(-1, "&View...", "View a Parts List ...", wx.ITEM_NORMAL)
         self.tools_doc_menu = wx.Menu()
-        self.tools_new_doc_menu  = self.tools_doc_menu.Append(-1, "&New...", "Create a Document ...", wx.ITEM_NORMAL)
-        self.tools_edit_doc_menu = self.tools_doc_menu.Append(-1, "&Edit...", "Edit a Document ...", wx.ITEM_NORMAL)
-        self.tools_view_doc_menu = self.tools_doc_menu.Append(-1, "&View...", "View a Document ...", wx.ITEM_NORMAL)
         self.tools_menu.AppendMenu(-1, "&Documents", self.tools_doc_menu, "")
+        self.tools_new_doc  = self.tools_doc_menu.Append(-1, "&New...", "Create a Document ...", wx.ITEM_NORMAL)
+        self.tools_edit_doc = self.tools_doc_menu.Append(-1, "&Edit...", "Edit a Document ...", wx.ITEM_NORMAL)
+        self.tools_view_doc = self.tools_doc_menu.Append(-1, "&View...", "View a Document ...", wx.ITEM_NORMAL)
         self.tools_menu.AppendSeparator()
-        self.tools_search_menu = self.tools_menu.Append(-1, "&Search...", "Search repository ...", wx.ITEM_NORMAL)
-        self.tools_report_menu = self.tools_menu.Append(-1, "&Report...", "Generate a PDF report from the grid contents ...", wx.ITEM_NORMAL)
+        self.tools_search = self.tools_menu.Append(-1, "&Search...", "Search repository ...", wx.ITEM_NORMAL)
+        self.tools_report = self.tools_menu.Append(-1, "&Report...", "Generate a PDF report from the grid contents ...", wx.ITEM_NORMAL)
         self.pgxn_menubar.Append(self.tools_menu, "&Tools")
         self.repository_menu = wx.Menu()
-        self.repo_commit_menu     = self.repository_menu.Append(-1, "&Commit ...", "Commit local changes to repository ...", wx.ITEM_NORMAL)
-        self.repo_getmystuff_menu = self.repository_menu.Append(-1, "&Get My Stuff...", "Get objects owned by me ...", wx.ITEM_NORMAL)
-        self.repo_selectrepo_menu = self.repository_menu.Append(-1, "Select &Repository...", "Select a Repository ...", wx.ITEM_NORMAL)
         self.pgxn_menubar.Append(self.repository_menu, "&Repository")
+        self.repo_commit     = self.repository_menu.Append(-1, "&Commit ...", "Commit local changes to repository ...", wx.ITEM_NORMAL)
+        self.repo_getmystuff = self.repository_menu.Append(-1, "&Get My Stuff...", "Get objects owned by me ...", wx.ITEM_NORMAL)
+        self.repo_selectrepo = self.repository_menu.Append(-1, "Select &Repository...", "Select a Repository ...", wx.ITEM_NORMAL)
         self.cache_menu = wx.Menu()
-        self.cache_browse_menu = self.cache_menu.Append(-1, "&Browse Local Objects...", "Browse locally cached objects ...", wx.ITEM_NORMAL)
-        self.cache_clear_menu  = self.cache_menu.Append(-1, "&Clear Local Objects...", "Remove objects from local cache", wx.ITEM_NORMAL)
         self.pgxn_menubar.Append(self.cache_menu, "&Cache")
+        self.cache_browse = self.cache_menu.Append(-1, "&Browse Local Objects...", "Browse locally cached objects ...", wx.ITEM_NORMAL)
+        self.cache_clear  = self.cache_menu.Append(-1, "&Clear Local Objects...", "Remove objects from local cache", wx.ITEM_NORMAL)
         self.options_menu = wx.Menu()
-        self.options_userid_menu       = self.options_menu.Append(-1, "&Userid...", "Set userid ...", wx.ITEM_NORMAL)
-        self.options_passwd_menu       = self.options_menu.Append(-1, "Change &Password...", "Change your password ...", wx.ITEM_NORMAL)
-        self.options_outputdir_menu    = self.options_menu.Append(-1, "Set Output &Directory...", "Select a directory to write files to ...", wx.ITEM_NORMAL)
-        self.options_repo_menu         = self.options_menu.Append(-1, "&Repository...", "Select a Repository ...", wx.ITEM_NORMAL)
-        self.options_proxy_menu        = self.options_menu.Append(-1, "Pro&xy...", "Use a proxy web server", wx.ITEM_NORMAL)
-        self.options_loginconfirm_menu = self.options_menu.Append(-1, "Show Login &Confirmation", "Confirm when login succeeds ...", wx.ITEM_NORMAL)
-        self.options_tooltips_menu     = self.options_menu.Append(-1, "Show &Tooltips", "Allow tooltip pop-up messages", wx.ITEM_CHECK)
         self.pgxn_menubar.Append(self.options_menu, "&Options")
+        self.options_userid       = self.options_menu.Append(-1, "&Userid...", "Set userid ...", wx.ITEM_NORMAL)
+        self.options_passwd       = self.options_menu.Append(-1, "Change &Password...", "Change your password ...", wx.ITEM_NORMAL)
+        self.options_outputdir    = self.options_menu.Append(-1, "Set Output &Directory...", "Select a directory to write files to ...", wx.ITEM_NORMAL)
+        self.options_repo         = self.options_menu.Append(-1, "&Repository...", "Select a Repository ...", wx.ITEM_NORMAL)
+        self.options_proxy        = self.options_menu.Append(-1, "Pro&xy...", "Use a proxy web server", wx.ITEM_NORMAL)
+        self.options_loginconfirm = self.options_menu.Append(-1, "Show Login &Confirmation", "Confirm when login succeeds ...", wx.ITEM_NORMAL)
+        self.options_tooltips     = self.options_menu.Append(-1, "Show &Tooltips", "Allow tooltip pop-up messages", wx.ITEM_CHECK)
         self.help_menu = wx.Menu()
-        self.help_about_menu    = self.help_menu.Append(-1, "&About", "Info about PanGalaxian ...", wx.ITEM_NORMAL)
-        self.help_contents_menu = self.help_menu.Append(-1, "&Contents", "Contents of help docs ...", wx.ITEM_NORMAL)
         self.pgxn_menubar.Append(self.help_menu, "&Help")
+        self.help_about    = self.help_menu.Append(-1, "&About", "Info about PanGalaxian ...", wx.ITEM_NORMAL)
+        self.help_contents = self.help_menu.Append(-1, "&Contents", "Contents of help docs ...", wx.ITEM_NORMAL)
         # Menu Bar end
 
         self.__set_properties()
@@ -233,14 +233,14 @@
         # self.GodMenu = None
         # self.GodMode = None
         showloginconfirm = prefs.get('ShowLoginConfirmed', True)
-        self.options_loginconfirm_menu.Check(bool(int(showloginconfirm)))
+        self.options_loginconfirm.Check(bool(int(showloginconfirm)))
         show_tooltips = prefs.get("ShowToolTips", True)
         if show_tooltips:
             wx.ToolTip_Enable(True)
-            self.options_tooltips_menu.Check(True)
+            self.options_tooltips.Check(True)
         else:
             wx.ToolTip_Enable(False)
-            self.options_tooltips_menu.Check(False)
+            self.options_tooltips.Check(False)
         self.contexts = state.get('contexts', None) or ['[no context]']
         self.bindEvents()
         # self.onModeChange()
@@ -281,56 +281,56 @@
         # (note:  all PanGalaxian menu event names begin with 'menu_')
         #
         # File menu
-        self.Bind(wx.EVT_MENU, self.onNewPart, self.file_new_part_menu)
-        # self.Bind(wx.EVT_MENU, self.onNewModel, self.file_new_model_menu)
-        # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.file_new_partslist_menu)
-        # self.Bind(wx.EVT_MENU, self.onNewDocument, self.file_new_document_menu)
-        # self.Bind(wx.EVT_MENU, self.onLogin, self.file_login_menu)
-        # self.Bind(wx.EVT_MENU, self.onLogout, self.file_logout_menu)
-        # self.Bind(wx.EVT_MENU, self.onExport, self.file_export_menu)
-        self.Bind(wx.EVT_MENU, self.onExit, self.file_exit_menu)
+        self.Bind(wx.EVT_MENU, self.onNewPart, self.file_new_part)
+        # self.Bind(wx.EVT_MENU, self.onNewModel, self.file_new_model)
+        # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.file_new_partslist)
+        # self.Bind(wx.EVT_MENU, self.onNewDocument, self.file_new_document)
+        # self.Bind(wx.EVT_MENU, self.onLogin, self.file_login)
+        # self.Bind(wx.EVT_MENU, self.onLogout, self.file_logout)
+        # self.Bind(wx.EVT_MENU, self.onExport, self.file_export)
+        self.Bind(wx.EVT_MENU, self.onExit, self.file_exit)
         #
         # Tools menu
-        # self.Bind(wx.EVT_MENU, self.onNewPart, self.tools_new_part_menu)
-        # self.Bind(wx.EVT_MENU, self.onEditPart, self.tools_edit_part_menu)
-        # self.Bind(wx.EVT_MENU, self.onViewPart, self.tools_view_part_menu)
-        # self.Bind(wx.EVT_MENU, self.onNewModel, self.tools_new_model_menu)
-        # self.Bind(wx.EVT_MENU, self.onEditModel, self.tools_edit_model_menu)
-        # self.Bind(wx.EVT_MENU, self.onViewModel, self.tools_view_model_menu)
-        # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.tools_new_partslist_menu)
-        # self.Bind(wx.EVT_MENU, self.onEditPartsList, self.tools_edit_partslist_menu)
-        # self.Bind(wx.EVT_MENU, self.onViewPartsList, self.tools_view_partslist_menu)
-        # self.Bind(wx.EVT_MENU, self.onNewDocument, self.tools_new_document_menu)
-        # self.Bind(wx.EVT_MENU, self.onEditDocument, self.tools_edit_document_menu)
-        # self.Bind(wx.EVT_MENU, self.onViewDocument, self.tools_view_document_menu)
-        # self.Bind(wx.EVT_MENU, self.onReport, self.tools_report_menu)
+        # self.Bind(wx.EVT_MENU, self.onNewPart, self.tools_new_part)
+        # self.Bind(wx.EVT_MENU, self.onEditPart, self.tools_edit_part)
+        # self.Bind(wx.EVT_MENU, self.onViewPart, self.tools_view_part)
+        # self.Bind(wx.EVT_MENU, self.onNewModel, self.tools_new_model)
+        # self.Bind(wx.EVT_MENU, self.onEditModel, self.tools_edit_model)
+        # self.Bind(wx.EVT_MENU, self.onViewModel, self.tools_view_model)
+        # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.tools_new_partslist)
+        # self.Bind(wx.EVT_MENU, self.onEditPartsList, self.tools_edit_partslist)
+        # self.Bind(wx.EVT_MENU, self.onViewPartsList, self.tools_view_partslist)
+        # self.Bind(wx.EVT_MENU, self.onNewDocument, self.tools_new_document)
+        # self.Bind(wx.EVT_MENU, self.onEditDocument, self.tools_edit_document)
+        # self.Bind(wx.EVT_MENU, self.onViewDocument, self.tools_view_document)
+        # self.Bind(wx.EVT_MENU, self.onReport, self.tools_report)
         #                      was: onGridToPdf
-        # self.Bind(wx.EVT_MENU, self.onSearch, self.tools_search_menu)
+        # self.Bind(wx.EVT_MENU, self.onSearch, self.tools_search)
         #
         # Repository menu
-        # self.Bind(wx.EVT_MENU, self.onCommit, self.repo_commit_menu)
-        # self.Bind(wx.EVT_MENU, self.onGetMyStuff, self.repo_getmystuff_menu)
-        # self.Bind(wx.EVT_MENU, self.onSelectRepo, self.repo_selectrepo_menu)
+        # self.Bind(wx.EVT_MENU, self.onCommit, self.repo_commit)
+        # self.Bind(wx.EVT_MENU, self.onGetMyStuff, self.repo_getmystuff)
+        # self.Bind(wx.EVT_MENU, self.onSelectRepo, self.repo_selectrepo)
         #                      was: onServerSettings
         #
         # Cache menu
-        # self.Bind(wx.EVT_MENU, self.onCacheBrowse, self.cache_browse_menu)
+        # self.Bind(wx.EVT_MENU, self.onCacheBrowse, self.cache_browse)
         #                      was: onDBBrowser
-        # self.Bind(wx.EVT_MENU, self.onCacheClear, self.cache_clear_menu)
+        # self.Bind(wx.EVT_MENU, self.onCacheClear, self.cache_clear)
         #                      was: onClearLocalDB
         #
         # Options menu
-        # self.Bind(wx.EVT_MENU, self.onSetUserId, self.options_userid_menu)
-        # self.Bind(wx.EVT_MENU, self.onSetPasswd, self.options_passwd_menu)
+        # self.Bind(wx.EVT_MENU, self.onSetUserId, self.options_userid)
+        # self.Bind(wx.EVT_MENU, self.onSetPasswd, self.options_passwd)
         #                      was: onPasswd
-        # self.Bind(wx.EVT_MENU, self.onSetOutputDir, self.options_outputdir_menu)
-        # self.Bind(wx.EVT_MENU, self.onProxySettings, self.options_proxy_menu)
-        self.Bind(wx.EVT_MENU, self.onEnableTooltips, self.options_tooltips_menu)
-        # self.Bind(wx.EVT_MENU, self.onShowLoginConfirmed, self.options_loginconfirm_menu)
+        # self.Bind(wx.EVT_MENU, self.onSetOutputDir, self.options_outputdir)
+        # self.Bind(wx.EVT_MENU, self.onProxySettings, self.options_proxy)
+        self.Bind(wx.EVT_MENU, self.onEnableTooltips, self.options_tooltips)
+        # self.Bind(wx.EVT_MENU, self.onShowLoginConfirmed, self.options_loginconfirm)
         #
         # Help menu
-        self.Bind(wx.EVT_MENU, self.onHelpAbout, self.help_about_menu)
-        self.Bind(wx.EVT_MENU, self.onHelpContents, self.help_contents_menu)
+        self.Bind(wx.EVT_MENU, self.onHelpAbout, self.help_about)
+        self.Bind(wx.EVT_MENU, self.onHelpContents, self.help_contents)
         #
         # Admin menu (do later ...)
         # self.Bind(wx.EVT_MENU, self.onAdminPasswd)
@@ -360,7 +360,7 @@
 
     def onEnableTooltips(self, event):
         print "PanGalaxian.OnEnableTooltips"
-        if self.options_tooltips_menu.IsChecked():
+        if self.options_tooltips.IsChecked():
             wx.ToolTip_Enable(True)
             prefs["ShowToolTips"] = True
         else:

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.2 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.3
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.2	Wed May 11 03:07:49 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Thu May 12 20:29:50 2005
@@ -1,11 +1,12 @@
-# $Id: pgefobjectgrid.py,v 1.2 2005/05/11 07:07:49 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.3 2005/05/13 00:29:50 waterbug Exp $
 """
 PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.2 $
+@version: $Revision: 1.3 $
 """
-__version__ = "$Revision: 1.2 $"[11:-2]
+__version__ = "$Revision: 1.3 $"[11:-2]
 
+from pprint import pprint
 
 import wx
 import wx.grid           as gridlib
@@ -28,20 +29,52 @@
         # able to pick whether to display them in one table (LCD display
         # mapping) or in multiple tables (possibly a notebook of tables).
         gridlib.PyGridTableBase.__init__(self)
+        self.setup(objs)
+
+    def setup(self, objs=None):
+        """
+        Generate column labels and data based on a provided set of objects.
+
+        @param objs:  a collection (set or list) of instances of
+            L{pangalactic.core.pgefobject.PgefObject}
+        @type  objs:  C{list or Set}
+        """
         if objs:
+            self.rowLabels = [str(i) for i in range(1, len(objs)+1)]
             self.objs = objs
             # assumption that all objs have the same schema (see TODO)
             self.schema = objs[0]._schema
-            self.identifiers = self.schema.keys()
-        self.rowLabels = ['1']
-        self.colLabels = dict([(x[0], x[1]) for x in displaymap])
-        self.data = [{'a':'',
-                      'b':'',
-                      'c':''
-                      }
-                     ]
+            # if the current displaymap-state is not the default, use it
+            if displaymaps[self.schema.id] != self.schema._default_display_map:
+                self.displaymap = displaymaps[self.schema.id]
+            # otherwise, if there is a preferred displaymap, use it
+            elif prefs.get('displaymaps', None):
+                if prefs['displaymaps'][self.schema.id]:
+                    self.displaymap = prefs['displaymaps'][self.schema.id]
+            # or if neither of these, use the default
+            else:
+                self.displaymap = self.schema._default_display_map
+            print 'self.displaymap:'
+            pprint(self.displaymap)
+            self.identifiers = [x[0] for x in self.displaymap]
+            self.colLabels = dict([(x[0], x[1]) for x in self.displaymap])
+            self.data = [dict([(i, getattr(o, i)) for i in self.identifiers])
+                         for o in self.objs]
+            print 'self.data:'
+            pprint(self.data)
+            print 'self.objs:'
+            print self.objs
+        else:
+            self.colLabels = []
+            self.rowLabels = []
+            self.objs = []
+            self.data = []
+            self.schema = None
+            # if no objects, use default displaymap for PgefObject
+            self.displaymap = displaymaps['PgefObject']
+            self.identifiers = [x[0] for x in self.displaymap]
+            self.colLabels = dict([(x[0], x[1]) for x in self.displaymap])
 
-    #--------------------------------------------------
     # required methods for the wxPyGridTableBase interface
 
     def GetNumberRows(self):
@@ -113,80 +146,165 @@
     # Move the row
     def MoveRow(self,frm,to):
         grid = self.GetView()
-
         if grid:
             # Move the rowLabels and data rows
             oldLabel = self.rowLabels[frm]
             oldData = self.data[frm]
             del self.rowLabels[frm]
             del self.data[frm]
-
             if to > frm:
                 self.rowLabels.insert(to-1,oldLabel)
                 self.data.insert(to-1,oldData)
             else:
                 self.rowLabels.insert(to,oldLabel)
                 self.data.insert(to,oldData)
-
             # Notify the grid
             grid.BeginBatch()
-
             msg = gridlib.GridTableMessage(
                     self, gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED, frm, 1
                     )
-
             grid.ProcessTableMessage(msg)
-
             msg = gridlib.GridTableMessage(
                     self, gridlib.GRIDTABLE_NOTIFY_ROWS_INSERTED, to, 1
                     )
-
             grid.ProcessTableMessage(msg)
             grid.EndBatch()
 
-#---------------------------------------------------------------------------
 
-
-class PgefGrid(gridlib.Grid):
-    def __init__(self, parent, displaymap=None):
+class PgefObjectGrid(gridlib.Grid):
+    def __init__(self, parent, objs=None):
         gridlib.Grid.__init__(self, parent, -1)
-
-        table = PgefDataTable(displaymap)
-
+        wx.ToolTip_Enable(True)
+        table = PgefObjectTable(objs)
         # The second parameter means that the grid is to take ownership of the
         # table and will destroy it when done.  Otherwise you would need to keep
         # a reference to it and call it's Destroy method later.
         self.SetTable(table, True)
+        self.bindEvents()
 
-        # Enable Column moving
-        gridmovers.GridColMover(self)
-        self.Bind(gridmovers.EVT_GRID_COL_MOVE, self.OnColMove, self)
+    # Some useful properties
 
-        # Enable Row moving
-        gridmovers.GridRowMover(self)
-        self.Bind(gridmovers.EVT_GRID_ROW_MOVE, self.OnRowMove, self)
+    def get_objs(self):
+        return self.GetTable().objs
+
+    def set_objs(self, value):
+        self.GetTable().setup(objs)
+
+    def delete_objs(self):
+        raise TypeError, 'objs attribute cannot be deleted.'
 
-    # Event method called when a column move needs to take place
-    def OnColMove(self,evt):
+    objs = property(get_objs, set_objs, delete_objs, 'objs')
+
+    def get_schema(self):
+        return self.GetTable().schema
+
+    def set_schema(self, value):
+        raise TypeError, 'schema attribute cannot be set.'
+
+    def delete_schema(self):
+        raise TypeError, 'schema attribute cannot be deleted.'
+
+    schema = property(get_schema, set_schema, delete_schema, 'schema')
+
+    def get_ids(self):
+        return self.GetTable().identifiers
+
+    def set_ids(self, value):
+        raise TypeError, 'identifiers attribute cannot be set.'
+
+    def delete_ids(self):
+        raise TypeError, 'identifiers attribute cannot be deleted.'
+
+    identifiers = property(get_ids, set_ids, delete_ids, 'identifiers')
+
+    def onColMove(self,evt):
+        """
+        Move a column when the relevant event is received.
+        """
         frm = evt.GetMoveColumn()       # Column being moved
         to = evt.GetBeforeColumn()      # Before which column to insert
         self.GetTable().MoveColumn(frm,to)
 
-    # Event method called when a row move needs to take place
-    def OnRowMove(self,evt):
+    def onRowMove(self,evt):
+        """
+        Move a row when the relevant event is received.
+        """
         frm = evt.GetMoveRow()          # Row being moved
         to = evt.GetBeforeRow()         # Before which row to insert
         self.GetTable().MoveRow(frm,to)
 
-#---------------------------------------------------------------------------
+    def onLabelRightClick(self, evt):
+        """
+        Show grid menu when upper left label area is right-clicked.
+        """
+        if (evt.GetRow(), evt.GetCol()) == (-1,-1) and self.objs:
+            self.grid_menu = wx.Menu()
+            self.visible_cols_menu = wx.Menu()
+            self.grid_menu.AppendMenu(-1, 'Visible Columns',
+                                      self.visible_cols_menu,
+                                      'Select columns to be visible in grid')
+            self.visible_cols = {}
+            labels = [self.schema[i].display_name for i in self.schema]
+            labels.sort()
+            label_id = dict([(self.schema[i].display_name, i) for i in self.schema])
+            for label in labels:
+                self.visible_cols[label] = self.visible_cols_menu.Append(
+                                                           -1, label,
+                                                           label_id[label],
+                                                            wx.ITEM_CHECK)
+                if label_id[label] in self.identifiers:
+                    self.visible_cols[label].Check(True)
+            self.set_pref = self.grid_menu.Append(-1, 'Set As Preference',
+                         'Set as your preferred columns to display for %s' % (
+                                                              self.schema.id),
+                         wx.ITEM_NORMAL)
+            all_labels = [self.schema[i].display_name
+                          for i in self.schema]
+            for label in all_labels:
+                self.Bind(wx.EVT_MENU, self.onSetVisibleCols,
+                          self.visible_cols[label])
+            self.PopupMenu(self.grid_menu, evt.GetPosition())
+            self.grid_menu.Destroy()
+        else:
+            print "No objects -- can't configure columns without objects."
+
+    def bindEvents(self):
+        """
+        Bind all events to handlers.
+        """
+        # Enable Column moving
+        gridmovers.GridColMover(self)
+        self.Bind(gridmovers.EVT_GRID_COL_MOVE, self.onColMove, self)
+        # Enable Row moving
+        gridmovers.GridRowMover(self)
+        self.Bind(gridmovers.EVT_GRID_ROW_MOVE, self.onRowMove, self)
+        self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_CLICK, self.onLabelRightClick)
+
+    def onSetVisibleCols(self, evt):
+        '- onSetVisibleCols'
+        displaymaps[self.schema.id] = []
+        properties = dict([(self.schema[a].display_name, self.schema[a])
+                            for a in self.schema])
+        for dn in properties:
+            if self.visible_cols[dn].IsChecked():
+                displaymaps[self.schema.id].append(
+                    [properties[dn].id,
+                     properties[dn].display_name,
+                     properties[dn].range])
+        self.GetTable().setup(self.objs)
+
 
 class TestFrame(wx.Frame):
     def __init__(self, parent):
         wx.Frame.__init__(self, parent, -1,
                           "PgefGrid", size=(640,480))
-        grid = PgefGrid(self)
+        # make up an object for testing ...
+        from pangalactic.core.pgefobject import PgefObject as PO
+        from pangalactic.test.utils4test import popTestData
+        po = PO()
+        popTestData(po)
+        grid = PgefObjectGrid(self, [po])
 
-#---------------------------------------------------------------------------
 
 if __name__ == '__main__':
     import sys

Index: PanGalactic/pangalactic/test/IDTEST
diff -u PanGalactic/pangalactic/test/IDTEST:1.112 PanGalactic/pangalactic/test/IDTEST:1.113
--- PanGalactic/pangalactic/test/IDTEST:1.112	Wed May  4 06:24:12 2005
+++ PanGalactic/pangalactic/test/IDTEST	Thu May 12 20:29:51 2005
@@ -1 +1 @@
-1622
\ No newline at end of file
+1630
\ No newline at end of file

Index: PanGalactic/pangalactic/utils/datamanager.py
diff -u PanGalactic/pangalactic/utils/datamanager.py:1.175 PanGalactic/pangalactic/utils/datamanager.py:1.176
--- PanGalactic/pangalactic/utils/datamanager.py:1.175	Wed May 11 03:07:50 2005
+++ PanGalactic/pangalactic/utils/datamanager.py	Thu May 12 20:29:51 2005
@@ -1,10 +1,10 @@
-# $Id: datamanager.py,v 1.175 2005/05/11 07:07:50 waterbug Exp $
+# $Id: datamanager.py,v 1.176 2005/05/13 00:29:51 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_datamanager -*-
 
 """
 PanGalaxian's local workspace manager.
 
-@version: $Revision: 1.175 $
+@version: $Revision: 1.176 $
 """
 # TODO:  move the transaction/interface stuff, like XmlrpcInterface, into a
 # separate module -- InterfaceManager, which will handle all client
@@ -15,7 +15,7 @@
 # came from (repository, file import, etc.) and what their state is
 # (committed/uncommitted, etc.)
 
-__version__ = "$Revision: 1.175 $"[11:-2]
+__version__ = "$Revision: 1.176 $"[11:-2]
 
 import time
 import mx.DateTime
@@ -32,7 +32,6 @@
 from pangalactic.core.workflow   import wffactory
 from pangalactic.meta.registry   import PanGalacticRegistry
 from pangalactic.node.gui.state  import state, prefs, displaymaps
-from pangalactic.node.gui.state  import prefs, displaymaps
 from pangalactic.utils                 import localdb
 from pangalactic.utils.httpupload      import upload
 from pangalactic.utils.pgefexceptions  import LocalStorageError

From waterbug at step.nasa.gov  Fri May 13 05:06:35 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 13 05:06:37 2005
Subject: [pangalactic-commits] "Smart" pgefobjectgrid works (sort of)! :)
Message-ID: <200505130906.j4D96ZkZ002554@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/state.py 1.2 1.3
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.3 1.4

Log message:
"Smart" pgefobjectgrid works (sort of)! :)

Index: PanGalactic/pangalactic/node/gui/state.py
diff -u PanGalactic/pangalactic/node/gui/state.py:1.2 PanGalactic/pangalactic/node/gui/state.py:1.3
--- PanGalactic/pangalactic/node/gui/state.py:1.2	Thu May 12 20:29:50 2005
+++ PanGalactic/pangalactic/node/gui/state.py	Fri May 13 05:06:32 2005
@@ -1,13 +1,13 @@
-# $Id: state.py,v 1.2 2005/05/13 00:29:50 waterbug Exp $
+# $Id: state.py,v 1.3 2005/05/13 09:06:32 waterbug Exp $
 
 """
 Global state for a PGEF application, which is written to a file for
 persistence between sessions, in 'JavaScript Object Notation' (JSON) --
 see: <http://www.crockford.com/JSON/index.html>.
 
-@version: $Revision: 1.2 $
+@version: $Revision: 1.3 $
 """
-__version__ = "$Revision: 1.2 $"[11:-2]
+__version__ = "$Revision: 1.3 $"[11:-2]
 
 from pprint import pprint
 
@@ -24,12 +24,15 @@
     f = file('state.json','w')
     f.close()
 
-# PanGalaxian user preferences
+# user preferences
 if not state.get('prefs', None):
     state['prefs'] = {}
 prefs = state['prefs']
+# user's preferred display maps for objects
+if not prefs.get('displaymaps', None):
+    prefs['displaymaps'] = {}
 
-# PanGalaxian user config for displaying objects
+# current state of display maps for objects
 if not state.get('displaymaps', None):
     state['displaymaps'] = {}
 displaymaps = state['displaymaps']

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.3 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.4
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.3	Thu May 12 20:29:50 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Fri May 13 05:06:33 2005
@@ -1,10 +1,10 @@
-# $Id: pgefobjectgrid.py,v 1.3 2005/05/13 00:29:50 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.4 2005/05/13 09:06:33 waterbug Exp $
 """
 PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.3 $
+@version: $Revision: 1.4 $
 """
-__version__ = "$Revision: 1.3 $"[11:-2]
+__version__ = "$Revision: 1.4 $"[11:-2]
 
 from pprint import pprint
 
@@ -29,21 +29,19 @@
         # able to pick whether to display them in one table (LCD display
         # mapping) or in multiple tables (possibly a notebook of tables).
         gridlib.PyGridTableBase.__init__(self)
-        self.setup(objs)
+        self.objs = objs or []
+        self.setup()
+        self._rows = self.GetNumberRows()
+        self._cols = self.GetNumberCols()
 
-    def setup(self, objs=None):
+    def setup(self):
         """
-        Generate column labels and data based on a provided set of objects.
-
-        @param objs:  a collection (set or list) of instances of
-            L{pangalactic.core.pgefobject.PgefObject}
-        @type  objs:  C{list or Set}
+        Generate column labels and data based on the current set of objects.
         """
-        if objs:
-            self.rowLabels = [str(i) for i in range(1, len(objs)+1)]
-            self.objs = objs
+        if self.objs:
+            self.row_labels = [str(i) for i in range(1, len(self.objs)+1)]
             # assumption that all objs have the same schema (see TODO)
-            self.schema = objs[0]._schema
+            self.schema = self.objs[0]._schema
             # if the current displaymap-state is not the default, use it
             if displaymaps[self.schema.id] != self.schema._default_display_map:
                 self.displaymap = displaymaps[self.schema.id]
@@ -57,7 +55,8 @@
             print 'self.displaymap:'
             pprint(self.displaymap)
             self.identifiers = [x[0] for x in self.displaymap]
-            self.colLabels = dict([(x[0], x[1]) for x in self.displaymap])
+            self.col_labels = dict([(x[0], x[1]) for x in self.displaymap])
+            # TODO:  use types to determine 'data' to display
             self.data = [dict([(i, getattr(o, i)) for i in self.identifiers])
                          for o in self.objs]
             print 'self.data:'
@@ -65,15 +64,13 @@
             print 'self.objs:'
             print self.objs
         else:
-            self.colLabels = []
-            self.rowLabels = []
-            self.objs = []
             self.data = []
             self.schema = None
+            self.row_labels = []
             # if no objects, use default displaymap for PgefObject
             self.displaymap = displaymaps['PgefObject']
             self.identifiers = [x[0] for x in self.displaymap]
-            self.colLabels = dict([(x[0], x[1]) for x in self.displaymap])
+            self.col_labels = dict([(x[0], x[1]) for x in self.displaymap])
 
     # required methods for the wxPyGridTableBase interface
 
@@ -95,127 +92,128 @@
         id = self.identifiers[col]
         self.data[row][id] = value
 
-    #--------------------------------------------------
-    # Some optional methods
-
-    # Called when the grid needs to display column labels
     def GetColLabelValue(self, col):
-        id = self.identifiers[col]
-        return self.colLabels[id]
-
-    # Called when the grid needs to display row labels
-    def GetRowLabelValue(self,row):
-        return self.rowLabels[row]
-
-    #--------------------------------------------------
-    # Methods added for demo purposes.
+        """
+        Get row labels to display.
+        """
+        return self.col_labels[self.identifiers[col]]
 
-    # The physical moving of the cols/rows is left to the implementer.
-    # Because of the dynamic nature of a wxGrid the physical moving of
-    # columns differs from implementation to implementation
+    def GetRowLabelValue(self, row):
+        """
+        Get row labels to display.
+        """
+        return self.row_labels[row]
 
-    # Move the column
-    def MoveColumn(self,frm,to):
+    def MoveColumn(self, frm, to):
+        """
+        Move the column
+        """
         grid = self.GetView()
-
         if grid:
-            # Move the identifiers
+            # move the identifiers
             old = self.identifiers[frm]
             del self.identifiers[frm]
-
             if to > frm:
-                self.identifiers.insert(to-1,old)
+                self.identifiers.insert(to-1, old)
             else:
-                self.identifiers.insert(to,old)
-
-            # Notify the grid
+                self.identifiers.insert(to, old)
+            # notify the grid
             grid.BeginBatch()
             msg = gridlib.GridTableMessage(
-                    self, gridlib.GRIDTABLE_NOTIFY_COLS_DELETED, frm, 1
-                    )
-                    
+                    self, gridlib.GRIDTABLE_NOTIFY_COLS_DELETED, frm, 1)
             grid.ProcessTableMessage(msg)
-            
             msg = gridlib.GridTableMessage(
-                    self, gridlib.GRIDTABLE_NOTIFY_COLS_INSERTED, to, 1
-                    )
-
+                    self, gridlib.GRIDTABLE_NOTIFY_COLS_INSERTED, to, 1)
             grid.ProcessTableMessage(msg)
             grid.EndBatch()
-
-    # Move the row
-    def MoveRow(self,frm,to):
-        grid = self.GetView()
-        if grid:
-            # Move the rowLabels and data rows
-            oldLabel = self.rowLabels[frm]
-            oldData = self.data[frm]
-            del self.rowLabels[frm]
-            del self.data[frm]
+            # adjust the displaymap
+            oldmap = self.displaymap[frm]
             if to > frm:
-                self.rowLabels.insert(to-1,oldLabel)
-                self.data.insert(to-1,oldData)
+                self.displaymap.insert(to-1, oldmap)
             else:
-                self.rowLabels.insert(to,oldLabel)
-                self.data.insert(to,oldData)
-            # Notify the grid
-            grid.BeginBatch()
-            msg = gridlib.GridTableMessage(
-                    self, gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED, frm, 1
-                    )
-            grid.ProcessTableMessage(msg)
-            msg = gridlib.GridTableMessage(
-                    self, gridlib.GRIDTABLE_NOTIFY_ROWS_INSERTED, to, 1
-                    )
-            grid.ProcessTableMessage(msg)
-            grid.EndBatch()
+                self.displaymap.insert(to, oldmap)
+
+    def ResetView(self, grid):
+        """
+        (Grid) -> Reset the grid view.   Called to update the grid if
+        rows and/or columns have been added or deleted
+        """
+        grid.BeginBatch()
+        for current, new, delmsg, addmsg in [
+            (self._rows, self.GetNumberRows(), gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED, gridlib.GRIDTABLE_NOTIFY_ROWS_APPENDED),
+            (self._cols, self.GetNumberCols(), gridlib.GRIDTABLE_NOTIFY_COLS_DELETED, gridlib.GRIDTABLE_NOTIFY_COLS_APPENDED),
+        ]:
+            if new < current:
+                msg = gridlib.GridTableMessage(self,delmsg,new,current-new)
+                grid.ProcessTableMessage(msg)
+            elif new > current:
+                msg = gridlib.GridTableMessage(self,addmsg,new-current)
+                grid.ProcessTableMessage(msg)
+                self.UpdateValues(grid)
+        grid.EndBatch()
+        self._rows = self.GetNumberRows()
+        self._cols = self.GetNumberCols()
+        # update the scrollbars and the displayed part of the grid
+        grid.AdjustScrollbars()
+        grid.ForceRefresh()
+
+    def UpdateValues(self, grid):
+        """
+        Update all displayed values.
+        """
+        # This sends an event to the grid table to update all of the values
+        msg = gridlib.GridTableMessage(self, gridlib.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
+        grid.ProcessTableMessage(msg)
+
+    def SortColumn(self, col):
+        """
+        col -> sort the data based on the column indexed by col
+        """
+        id = self.identifiers[col]
+        _data = []
+        _objs = []
+        index = 0
+        for row in self.data:
+            _data.append((row.get(id, None), index, row))
+            index += 1
+        _data.sort()
+        self.data = []
+        for sortvalue, i, row in _data:
+            self.data.append(row)
+            _objs.append(self.objs[i])
+        self.objs = _objs
 
 
 class PgefObjectGrid(gridlib.Grid):
     def __init__(self, parent, objs=None):
         gridlib.Grid.__init__(self, parent, -1)
         wx.ToolTip_Enable(True)
-        table = PgefObjectTable(objs)
+        self._table = PgefObjectTable(objs)
         # The second parameter means that the grid is to take ownership of the
         # table and will destroy it when done.  Otherwise you would need to keep
         # a reference to it and call it's Destroy method later.
-        self.SetTable(table, True)
+        self.SetTable(self._table)
+        self.objs = self._table.objs
+        self.schema = self._table.schema
+        self.identifiers = self._table.identifiers
         self.bindEvents()
 
-    # Some useful properties
-
-    def get_objs(self):
-        return self.GetTable().objs
-
-    def set_objs(self, value):
-        self.GetTable().setup(objs)
-
-    def delete_objs(self):
-        raise TypeError, 'objs attribute cannot be deleted.'
-
-    objs = property(get_objs, set_objs, delete_objs, 'objs')
-
-    def get_schema(self):
-        return self.GetTable().schema
-
-    def set_schema(self, value):
-        raise TypeError, 'schema attribute cannot be set.'
-
-    def delete_schema(self):
-        raise TypeError, 'schema attribute cannot be deleted.'
-
-    schema = property(get_schema, set_schema, delete_schema, 'schema')
-
-    def get_ids(self):
-        return self.GetTable().identifiers
-
-    def set_ids(self, value):
-        raise TypeError, 'identifiers attribute cannot be set.'
-
-    def delete_ids(self):
-        raise TypeError, 'identifiers attribute cannot be deleted.'
+    def reset(self):
+        """
+        Reset the view -- called when the current set of objects and/or the
+        displaymap may have changed.
+        """
+        self._table.setup()
+        self._table.ResetView(self)
 
-    identifiers = property(get_ids, set_ids, delete_ids, 'identifiers')
+    def onLabelRightClick(self, evt):
+        # Did we click on a row, a column, or the upper left corner?
+        if not self.objs:
+            print "No objects -- can't operate on empty grid."
+            return
+        row, col = evt.GetRow(), evt.GetCol()
+        if (row, col) == (-1,-1): self.gridPopup(evt)
+        elif row == -1: self.colPopup(col, evt)
 
     def onColMove(self,evt):
         """
@@ -223,50 +221,65 @@
         """
         frm = evt.GetMoveColumn()       # Column being moved
         to = evt.GetBeforeColumn()      # Before which column to insert
-        self.GetTable().MoveColumn(frm,to)
-
-    def onRowMove(self,evt):
-        """
-        Move a row when the relevant event is received.
-        """
-        frm = evt.GetMoveRow()          # Row being moved
-        to = evt.GetBeforeRow()         # Before which row to insert
-        self.GetTable().MoveRow(frm,to)
+        self._table.MoveColumn(frm,to)
 
-    def onLabelRightClick(self, evt):
+    def gridPopup(self, evt):
         """
         Show grid menu when upper left label area is right-clicked.
         """
-        if (evt.GetRow(), evt.GetCol()) == (-1,-1) and self.objs:
-            self.grid_menu = wx.Menu()
-            self.visible_cols_menu = wx.Menu()
-            self.grid_menu.AppendMenu(-1, 'Visible Columns',
-                                      self.visible_cols_menu,
-                                      'Select columns to be visible in grid')
-            self.visible_cols = {}
-            labels = [self.schema[i].display_name for i in self.schema]
-            labels.sort()
-            label_id = dict([(self.schema[i].display_name, i) for i in self.schema])
-            for label in labels:
-                self.visible_cols[label] = self.visible_cols_menu.Append(
-                                                           -1, label,
-                                                           label_id[label],
-                                                            wx.ITEM_CHECK)
-                if label_id[label] in self.identifiers:
-                    self.visible_cols[label].Check(True)
-            self.set_pref = self.grid_menu.Append(-1, 'Set As Preference',
-                         'Set as your preferred columns to display for %s' % (
-                                                              self.schema.id),
-                         wx.ITEM_NORMAL)
-            all_labels = [self.schema[i].display_name
-                          for i in self.schema]
-            for label in all_labels:
-                self.Bind(wx.EVT_MENU, self.onSetVisibleCols,
-                          self.visible_cols[label])
-            self.PopupMenu(self.grid_menu, evt.GetPosition())
-            self.grid_menu.Destroy()
-        else:
-            print "No objects -- can't configure columns without objects."
+        self.grid_menu = wx.Menu()
+        self.visible_cols_menu = wx.Menu()
+        self.grid_menu.AppendMenu(-1, 'Visible Columns',
+                                  self.visible_cols_menu,
+                                  'Select columns to be visible in grid')
+        self.visible_cols = {}
+        labels = [self.schema[i].display_name for i in self.schema]
+        labels.sort()
+        label_id = dict([(self.schema[i].display_name, i) for i in self.schema])
+        for label in labels:
+            self.visible_cols[label] = self.visible_cols_menu.Append(
+                                                       -1, label,
+                                                       label_id[label],
+                                                        wx.ITEM_CHECK)
+            if label_id[label] in self.identifiers:
+                self.visible_cols[label].Check(True)
+        self.set_pref = self.grid_menu.Append(-1, 'Set As Preference',
+                     'Set as your preferred columns to display for %s' % (
+                                                          self.schema.id),
+                     wx.ITEM_NORMAL)
+        all_labels = [self.schema[i].display_name
+                      for i in self.schema]
+        for label in all_labels:
+            self.Bind(wx.EVT_MENU, self.onSetVisibleCols,
+                      self.visible_cols[label])
+        self.Bind(wx.EVT_MENU, self.onSetPrefDisplaymap,
+                      self.set_pref)
+        self.PopupMenu(self.grid_menu, evt.GetPosition())
+        self.grid_menu.Destroy()
+        self.reset()
+
+    def colPopup(self, col, evt):
+        """
+        (col, evt) -> display a popup menu when a column label is right
+        clicked.
+        """
+        x = self.GetColSize(col)/2
+        menu = wx.Menu()
+        id1 = wx.NewId()
+        sortID = wx.NewId()
+        xo, yo = evt.GetPosition()
+        self.SelectCol(col)
+        cols = self.GetSelectedCols()
+        self.Refresh()
+        menu.Append(sortID, "Sort Column")
+        def sort(event, self=self, col=col):
+            self._table.SortColumn(col)
+            self.reset()
+        if len(cols) == 1:
+            self.Bind(wx.EVT_MENU, sort, id=sortID)
+        self.PopupMenu(menu, (xo, 0))
+        menu.Destroy()
+        return
 
     def bindEvents(self):
         """
@@ -275,13 +288,13 @@
         # Enable Column moving
         gridmovers.GridColMover(self)
         self.Bind(gridmovers.EVT_GRID_COL_MOVE, self.onColMove, self)
-        # Enable Row moving
-        gridmovers.GridRowMover(self)
-        self.Bind(gridmovers.EVT_GRID_ROW_MOVE, self.onRowMove, self)
         self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_CLICK, self.onLabelRightClick)
 
     def onSetVisibleCols(self, evt):
-        '- onSetVisibleCols'
+        """
+        Reset the choice of columns to be displayed in the grid.
+        """
+        print ' - onSetVisibleCols'
         displaymaps[self.schema.id] = []
         properties = dict([(self.schema[a].display_name, self.schema[a])
                             for a in self.schema])
@@ -291,7 +304,14 @@
                     [properties[dn].id,
                      properties[dn].display_name,
                      properties[dn].range])
-        self.GetTable().setup(self.objs)
+
+    def onSetPrefDisplaymap(self, evt):
+        """
+        Set the current displaymap as the user's preferred displaymap for
+        the current object schema.
+        """
+        print ' - onSetPrefDisplaymap'
+        prefs['displaymaps'][self.schema.id] = self.displaymap
 
 
 class TestFrame(wx.Frame):
@@ -301,9 +321,9 @@
         # make up an object for testing ...
         from pangalactic.core.pgefobject import PgefObject as PO
         from pangalactic.test.utils4test import popTestData
-        po = PO()
-        popTestData(po)
-        grid = PgefObjectGrid(self, [po])
+        objs = [PO(id='foo'), PO(id='bar'), PO(id='baz')]
+        for po in objs:  popTestData(po)
+        grid = PgefObjectGrid(self, objs)
 
 
 if __name__ == '__main__':

From waterbug at step.nasa.gov  Sat May 14 01:49:12 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sat May 14 01:49:15 2005
Subject: [pangalactic-commits] Mainly:  factory now *is* a registry,
	instead of just *having* one ...
Message-ID: <200505140549.j4E5nCDC018077@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/TODO 1.23 1.24
PanGalactic/pangalactic/meta/factory.py 1.17 1.18
PanGalactic/pangalactic/meta/names.py 1.15 1.16
PanGalactic/pangalactic/meta/objectschema.py 1.2 1.3
PanGalactic/pangalactic/meta/ontology.py 1.7 1.8
PanGalactic/pangalactic/meta/registry.py 1.29 1.30
PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py 1.5 1.6
PanGalactic/pangalactic/repo/chronosynclastic.py 1.40 1.41
PanGalactic/pangalactic/repo/pger.py 1.98 1.99
PanGalactic/pangalactic/repo/pgerxmlrpc.py 1.19 1.20
PanGalactic/pangalactic/test/IDTEST 1.113 1.114
PanGalactic/pangalactic/test/test_chronosynclastic_.py 1.10 1.11
PanGalactic/pangalactic/test/test_chronosynclastic_getRefdRowKeys.py 1.5 1.6
PanGalactic/pangalactic/test/test_chronosynclastic_transactionalInsert.py 1.9 1.10
PanGalactic/pangalactic/test/test_chronosynclastic_updateObjects.py 1.4 1.5
PanGalactic/pangalactic/test/test_pger_getObjectsE.py 1.5 1.6
PanGalactic/pangalactic/test/test_pger_getObjectsO.py 1.5 1.6
PanGalactic/pangalactic/test/test_xmlrpc_getObjects.py 1.7 1.8
PanGalactic/pangalactic/test/test_xmlrpc_search.py 1.8 1.9
PanGalactic/pangalactic/test/utils4test.py 1.3 1.4
PanGalactic/pangalactic/utils/datamanager.py 1.176 1.177
PanGalactic/pangalactic/utils/localdb.py 1.130 1.131
PanGalactic/pangalactic/utils/xmlrpcinterface.py 1.79 1.80
PanGalactic/src/sql/createPgerDbTables.py 1.4 1.5

Log message:
Mainly:  factory now *is* a registry, instead of just *having* one ...
(I like that much better ... more elegant! :)
plus many little tweaks, docstring fiddlings, etc.

Index: PanGalactic/pangalactic/test/test_xmlrpc_getObjects.py
diff -u PanGalactic/pangalactic/test/test_xmlrpc_getObjects.py:1.7 PanGalactic/pangalactic/test/test_xmlrpc_getObjects.py:1.8
--- PanGalactic/pangalactic/test/test_xmlrpc_getObjects.py:1.7	Sun Apr 24 17:05:21 2005
+++ PanGalactic/pangalactic/test/test_xmlrpc_getObjects.py	Sat May 14 01:49:06 2005
@@ -1,4 +1,4 @@
-# $Id: test_xmlrpc_getObjects.py,v 1.7 2005/04/24 21:05:21 waterbug Exp $
+# $Id: test_xmlrpc_getObjects.py,v 1.8 2005/05/14 05:49:06 waterbug Exp $
 
 """
 Functional test for PgerXmlrpcService.xmlrpc_getObjects
@@ -15,7 +15,7 @@
 from pangalactic.repo.pger import Pger
 from pangalactic.repo.pgerxmlrpc import PgerXmlrpcService
 
-schemaid = 'PgefObject'
+schema_id = 'PgefObject'
 
 pgr = Pger()
 xmlsrv = PgerXmlrpcService(engine=pgr, userid='Fester.Bestertester@earth.milkyway.univ')
@@ -24,7 +24,7 @@
 
 def success(extracts):
     print "\n***  XMLRPC Command:"
-    print """     Server.getObjects('%s', 0, 1, %s)\n""" % (schemaid,
+    print """     Server.getObjects('%s', 0, 1, %s)\n""" % (schema_id,
                                                             repr(parms))
     print "***  Extract list obtained as result:"
     print "===================================="
@@ -41,7 +41,6 @@
         print "\n***  Remembered objects:"
         print ""
         pprint(remembered)
-    print "%s objects in objs list" % len(objs)
     print "%s objects remembered." % len(remembered)
     reactor.stop()
 
@@ -49,7 +48,7 @@
     print error
     reactor.stop()
 
-res = xmlsrv.xmlrpc_getObjects(schemaid, 0, 1, parms)
+res = xmlsrv.xmlrpc_getObjects(schema_id, 0, 1, parms)
 res.addCallbacks(success, failure)
 
 reactor.run()

Index: PanGalactic/pangalactic/test/test_chronosynclastic_.py
diff -u PanGalactic/pangalactic/test/test_chronosynclastic_.py:1.10 PanGalactic/pangalactic/test/test_chronosynclastic_.py:1.11
--- PanGalactic/pangalactic/test/test_chronosynclastic_.py:1.10	Tue Apr 26 00:53:51 2005
+++ PanGalactic/pangalactic/test/test_chronosynclastic_.py	Sat May 14 01:49:06 2005
@@ -1,4 +1,4 @@
-# $Id: test_chronosynclastic_.py,v 1.10 2005/04/26 04:53:51 waterbug Exp $
+# $Id: test_chronosynclastic_.py,v 1.11 2005/05/14 05:49:06 waterbug Exp $
 
 """
 Test for Chronosynclastic Infundibulum
@@ -131,7 +131,7 @@
 # 
 # reactor.run()
 # 
-# # $Id: test_chronosynclastic_.py,v 1.10 2005/04/26 04:53:51 waterbug Exp $
+# # $Id: test_chronosynclastic_.py,v 1.11 2005/05/14 05:49:06 waterbug Exp $
 # 
 # """
 # Test for inserting a row using pangalactic.repo.pgerdb module
@@ -147,11 +147,11 @@
 # from pangalactic.core.model import Model
 # from pangalactic.core.project import Project
 # from pangalactic.repo.pgerdb import PgerDb
-# from pangalactic.repo.pgerregistry import PgerObjectRegistry as POR
-# from pangalactic.repo.pgerfactory import PgerObjectFactory as POF
+# from pangalactic.repo.registry import PanGalacticRegistry as PGR
+# from pangalactic.repo.factory import PgerObjectFactory as PGF
 # 
-# reg = POR()
-# fac = POF(reg)
+# reg = PGR()
+# fac = PGF(reg)
 # pgerdb = PgerDb()
 # 
 # f = open('IDTEST')
@@ -216,7 +216,7 @@
 # 
 # reactor.run()
 # 
-# # $Id: test_chronosynclastic_.py,v 1.10 2005/04/26 04:53:51 waterbug Exp $
+# # $Id: test_chronosynclastic_.py,v 1.11 2005/05/14 05:49:06 waterbug Exp $
 # 
 # """
 # Test for inserting a row using pangalactic.repo.pgerdb module
@@ -259,7 +259,7 @@
 # reactor.run()
 # 
 # 
-# # $Id: test_chronosynclastic_.py,v 1.10 2005/04/26 04:53:51 waterbug Exp $
+# # $Id: test_chronosynclastic_.py,v 1.11 2005/05/14 05:49:06 waterbug Exp $
 # 
 # """
 # Tests for pgerdb
@@ -461,7 +461,7 @@
 #         PsycopgTestCase.skip = "Connection to PostgreSQL using psycopg failed: " + str(e)
 # 
 # 
-# # $Id: test_chronosynclastic_.py,v 1.10 2005/04/26 04:53:51 waterbug Exp $
+# # $Id: test_chronosynclastic_.py,v 1.11 2005/05/14 05:49:06 waterbug Exp $
 # 
 # """
 # Functional test for pangalactic.repo.pgerdb module
@@ -495,7 +495,7 @@
 # 
 # reactor.run() # start the main loop
 # 
-# # $Id: test_chronosynclastic_.py,v 1.10 2005/04/26 04:53:51 waterbug Exp $
+# # $Id: test_chronosynclastic_.py,v 1.11 2005/05/14 05:49:06 waterbug Exp $
 # 
 # """
 # Functional test for PgerDb running a query on a sequence value
@@ -532,7 +532,7 @@
 # 
 # reactor.run() # start the main loop
 # 
-# # $Id: test_chronosynclastic_.py,v 1.10 2005/04/26 04:53:51 waterbug Exp $
+# # $Id: test_chronosynclastic_.py,v 1.11 2005/05/14 05:49:06 waterbug Exp $
 # 
 # """
 # Test for updating a row using pangalactic.repo.pgerdb module
@@ -578,7 +578,7 @@
 # # 
 # # reactor.run()
 # # 
-# # $Id: test_chronosynclastic_.py,v 1.10 2005/04/26 04:53:51 waterbug Exp $
+# # $Id: test_chronosynclastic_.py,v 1.11 2005/05/14 05:49:06 waterbug Exp $
 # 
 # """
 # Test for updating a row using pangalactic.repo.pgerdb module

Index: PanGalactic/pangalactic/test/test_pger_getObjectsE.py
diff -u PanGalactic/pangalactic/test/test_pger_getObjectsE.py:1.5 PanGalactic/pangalactic/test/test_pger_getObjectsE.py:1.6
--- PanGalactic/pangalactic/test/test_pger_getObjectsE.py:1.5	Wed Apr 27 01:54:48 2005
+++ PanGalactic/pangalactic/test/test_pger_getObjectsE.py	Sat May 14 01:49:06 2005
@@ -1,4 +1,4 @@
-# $Id: test_pger_getObjectsE.py,v 1.5 2005/04/27 05:54:48 waterbug Exp $
+# $Id: test_pger_getObjectsE.py,v 1.6 2005/05/14 05:49:06 waterbug Exp $
 
 """
 Functional test for pangalactic.repo.pger module
@@ -23,7 +23,7 @@
 pgr = Pger()
 
 res = pgr.getObjects(requestor='test',
-                     schemaid='Representation',
+                     schema_id='Representation',
                      id_ns='http://pangalactic.us/test/')
 res.addCallbacks(success, failure)
 

Index: PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py
diff -u PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.5 PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.6
--- PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.5	Wed May 11 03:07:49 2005
+++ PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py	Sat May 14 01:49:04 2005
@@ -1,5 +1,5 @@
 #!/bin/env python
-# $Id: cachebrowser.py,v 1.5 2005/05/11 07:07:49 waterbug Exp $
+# $Id: cachebrowser.py,v 1.6 2005/05/14 05:49:04 waterbug Exp $
 #----------------------------------------------------------------------------
 # Authors:      Ginny, Steve
 #----------------------------------------------------------------------------
@@ -7,9 +7,9 @@
 PanGalaxian cache browser and display customizer
 (Works with PgefObjects in a local ZODB)
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 import wx
 from wx import grid
@@ -50,7 +50,7 @@
         wx.Panel.__init__(self, parent, id, pos, size, style=wx.THICK_FRAME)
         self.Parent = parent
         self.dm = dm
-        self._registry = dm._registry
+        self.factory = dm.factory
         self.cache = dm.cache
         self.dbfile = None
         # the following section replaces:  ZODBBrowserFunc(self, True)
@@ -331,7 +331,7 @@
                             attr_range = attr_property.range
                             # print "attr", attr, attrvalue
                             val = str(attrvalue)
-                            if attr_range in self._registry.object_schemas:
+                            if attr_range in self.factory.object_schemas:
                                 if hasattr(attrvalue, 'pgef_oid'):
                                     val = attr_range + " (oid=" + attrvalue.pgef_oid + ")"
                                 elif type(attrvalue) is str:

Index: PanGalactic/pangalactic/meta/ontology.py
diff -u PanGalactic/pangalactic/meta/ontology.py:1.7 PanGalactic/pangalactic/meta/ontology.py:1.8
--- PanGalactic/pangalactic/meta/ontology.py:1.7	Wed May  4 06:24:11 2005
+++ PanGalactic/pangalactic/meta/ontology.py	Sat May 14 01:49:02 2005
@@ -1,16 +1,15 @@
-# $Id: ontology.py,v 1.7 2005/05/04 10:24:11 waterbug Exp $
+# $Id: ontology.py,v 1.8 2005/05/14 05:49:02 waterbug Exp $
 
 """
 A set of named elements, which can include datatypes, classes, and
 properties.
 
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 from sets import Set
 from pangalactic.meta.utils import getDefault
-from pangalactic.meta.names import Namespace
 
 class Ontology:
     """

Index: PanGalactic/pangalactic/test/test_chronosynclastic_getRefdRowKeys.py
diff -u PanGalactic/pangalactic/test/test_chronosynclastic_getRefdRowKeys.py:1.5 PanGalactic/pangalactic/test/test_chronosynclastic_getRefdRowKeys.py:1.6
--- PanGalactic/pangalactic/test/test_chronosynclastic_getRefdRowKeys.py:1.5	Mon Apr 25 01:53:52 2005
+++ PanGalactic/pangalactic/test/test_chronosynclastic_getRefdRowKeys.py	Sat May 14 01:49:06 2005
@@ -1,4 +1,4 @@
-# $Id: test_chronosynclastic_getRefdRowKeys.py,v 1.5 2005/04/25 05:53:52 waterbug Exp $
+# $Id: test_chronosynclastic_getRefdRowKeys.py,v 1.6 2005/05/14 05:49:06 waterbug Exp $
 
 """
 Functional test for pangalactic.repo.chronosynclastic module
@@ -11,7 +11,7 @@
 from twisted.internet import reactor
 from pangalactic.repo.chronosynclastic import Infundibulum as I
 
-schemaid = "Representation"
+schema_id = "Representation"
 
 def success(resultsets):
     if resultsets:
@@ -35,7 +35,7 @@
 
 inf = I()
 
-out = inf._selectByObjectSchema(schemaid, 0, ('id_ns', 'like', 'test'))
+out = inf._selectByObjectSchema(schema_id, 0, ('id_ns', 'like', 'test'))
 
 out.addCallbacks(success, failure)
 

Index: PanGalactic/pangalactic/test/test_xmlrpc_search.py
diff -u PanGalactic/pangalactic/test/test_xmlrpc_search.py:1.8 PanGalactic/pangalactic/test/test_xmlrpc_search.py:1.9
--- PanGalactic/pangalactic/test/test_xmlrpc_search.py:1.8	Tue Oct 12 04:04:26 2004
+++ PanGalactic/pangalactic/test/test_xmlrpc_search.py	Sat May 14 01:49:06 2005
@@ -1,4 +1,4 @@
-# $Id: test_xmlrpc_search.py,v 1.8 2004/10/12 08:04:26 waterbug Exp $
+# $Id: test_xmlrpc_search.py,v 1.9 2005/05/14 05:49:06 waterbug Exp $
 
 """
 Functional test for PgerXmlrpcService.search()
@@ -9,12 +9,12 @@
 from pangalactic.repo.pger import Pger
 from pangalactic.repo.pgerxmlrpc import PgerXmlrpcService
 
-schemaid = 'Part'
+schema_id = 'Part'
 
 def success(resultsets):
     pprint(resultsets)
     print
-    print '[ %s %s instances. ]' % (len(resultsets), schemaid)
+    print '[ %s %s instances. ]' % (len(resultsets), schema_id)
     print
     reactor.stop()
 
@@ -25,7 +25,7 @@
 pgr = Pger()
 xmlsrv = PgerXmlrpcService(pgr)
 
-res = xmlsrv.xmlrpc_search(schemaid, 0, 0,
+res = xmlsrv.xmlrpc_search(schema_id, 0, 0,
                            [('owner', 'like', 'bigboote')]
                            )
 res.addCallbacks(success, failure)

Index: PanGalactic/pangalactic/test/test_chronosynclastic_updateObjects.py
diff -u PanGalactic/pangalactic/test/test_chronosynclastic_updateObjects.py:1.4 PanGalactic/pangalactic/test/test_chronosynclastic_updateObjects.py:1.5
--- PanGalactic/pangalactic/test/test_chronosynclastic_updateObjects.py:1.4	Sat Jan 29 16:52:48 2005
+++ PanGalactic/pangalactic/test/test_chronosynclastic_updateObjects.py	Sat May 14 01:49:06 2005
@@ -1,4 +1,4 @@
-# $Id: test_chronosynclastic_updateObjects.py,v 1.4 2005/01/29 21:52:48 waterbug Exp $
+# $Id: test_chronosynclastic_updateObjects.py,v 1.5 2005/05/14 05:49:06 waterbug Exp $
 
 """
 Test for inserting a row using pangalactic.repo.pgerdb module
@@ -42,7 +42,7 @@
 testnameupd = 'Test Org 1 [updateObjects test %s]' % tmpid
 
 out = inf.updateObjects(requestor='test',
-                        schemaid='Organization',
+                        schema_id='Organization',
                         oids=['TO1'], # Test Organization 1
                         updates={'name':testnameupd})
 out.addCallbacks(success, failure)

Index: PanGalactic/pangalactic/test/IDTEST
diff -u PanGalactic/pangalactic/test/IDTEST:1.113 PanGalactic/pangalactic/test/IDTEST:1.114
--- PanGalactic/pangalactic/test/IDTEST:1.113	Thu May 12 20:29:51 2005
+++ PanGalactic/pangalactic/test/IDTEST	Sat May 14 01:49:06 2005
@@ -1 +1 @@
-1630
\ No newline at end of file
+1650
\ No newline at end of file

Index: PanGalactic/pangalactic/test/test_pger_getObjectsO.py
diff -u PanGalactic/pangalactic/test/test_pger_getObjectsO.py:1.5 PanGalactic/pangalactic/test/test_pger_getObjectsO.py:1.6
--- PanGalactic/pangalactic/test/test_pger_getObjectsO.py:1.5	Wed Apr 27 01:54:48 2005
+++ PanGalactic/pangalactic/test/test_pger_getObjectsO.py	Sat May 14 01:49:06 2005
@@ -1,4 +1,4 @@
-# $Id: test_pger_getObjectsO.py,v 1.5 2005/04/27 05:54:48 waterbug Exp $
+# $Id: test_pger_getObjectsO.py,v 1.6 2005/05/14 05:49:06 waterbug Exp $
 
 """
 Functional test for pangalactic.repo.pger module
@@ -29,7 +29,7 @@
 pgr = Pger()
 
 out = pgr.getObjects(requestor='test',
-                     schemaid='Representation',
+                     schema_id='Representation',
                      ret='objects',
                      id_ns='http://pangalactic.us/test/')
 out.addCallbacks(success, failure)

Index: PanGalactic/pangalactic/test/utils4test.py
diff -u PanGalactic/pangalactic/test/utils4test.py:1.3 PanGalactic/pangalactic/test/utils4test.py:1.4
--- PanGalactic/pangalactic/test/utils4test.py:1.3	Wed Apr 27 15:06:31 2005
+++ PanGalactic/pangalactic/test/utils4test.py	Sat May 14 01:49:06 2005
@@ -1,4 +1,4 @@
-# $Id: utils4test.py,v 1.3 2005/04/27 19:06:31 waterbug Exp $
+# $Id: utils4test.py,v 1.4 2005/05/14 05:49:06 waterbug Exp $
 
 """
 Utilities for testing.
@@ -8,10 +8,10 @@
 from datetime import datetime
 from pangalactic.utils import oid
 from pangalactic.utils import sql
-from pangalactic.repo.chronosynclastic import Infundibulum
+from pangalactic.meta.factory import PanGalacticFactory
 import psycopg
 
-inf = Infundibulum()
+fac = PanGalacticFactory()
 
 t = datetime.now()
 
@@ -69,18 +69,18 @@
     @type  instcnt:  C{int}
     """
     # TODO:  use instcnt ...
-    schemas = inf._registry.object_schemas.values()
-    classes = inf._registry.classes
+    
+    classes = fac.classes
     if not runid:
         runid = '.'.join([str(i) for i in
                          [t.month, t.day, t.hour, t.minute, t.second]])
     parmdicts = dict([(schema.id, dict([(a, genVal(schema, a, testid, runid))
                                         for a in schema]))
-                      for schema in schemas])
-    objs = [classes[id](**parmdicts[id]) for id in classes]
+                      for schema in fac.object_schemas.values()])
+    objs = [klass(**parmdicts[id]) for klass in fac.classes.values()]
     for o in objs:
         o.id_ns='http://pangalactic.us/test/'
-        inf._registry.popTestData(o)
+        popTestData(o)
     return objs
 
 def popTestData(obj):
@@ -93,7 +93,7 @@
     obj.id = obj.id or "idthis"
     obj.id_ns = obj.id_ns or "TEST"
     dtstamp = DateTime.now()
-    testperson = inf._registry.classes['Person'](
+    testperson = fac.classes['Person'](
                      pgef_oid='Fester.Bestertester@earth.milkyway.univ',
                      id='Fester Bestertester',
                      id_ns='http://pangalactic.us/test/',

Index: PanGalactic/pangalactic/utils/localdb.py
diff -u PanGalactic/pangalactic/utils/localdb.py:1.130 PanGalactic/pangalactic/utils/localdb.py:1.131
--- PanGalactic/pangalactic/utils/localdb.py:1.130	Wed May 11 03:07:50 2005
+++ PanGalactic/pangalactic/utils/localdb.py	Sat May 14 01:49:07 2005
@@ -1,9 +1,9 @@
 """
 Local object cache manager
 
-@version: $Revision: 1.130 $
+@version: $Revision: 1.131 $
 """
-__version__ = "$Revision: 1.130 $"[11:-2]
+__version__ = "$Revision: 1.131 $"[11:-2]
 
 import os
 import glob
@@ -40,18 +40,17 @@
     wf_names = ["WfActivity", "WfProcessInstance", "WfTransition",
                 "WfEventAudit"]
 
-    def __init__(self, _registry):
+    def __init__(self, factory):
         """
         Initialize a LocalStorage instance.
 
-        @param _registry:  the PanGalacticRegistry instance (singleton)
-        @type  _registry:  L{pangalactic.meta.registry.PanGalacticRegistry}
+        @param factory:  the PanGalacticFactory instance (singleton)
+        @type  factory:  L{pangalactic.meta.factory.PanGalacticFactory}
         """
         # If modifying this stuff, be careful:  order is important
         if not os.path.exists("data"):
             os.makedirs("data")
-        self._registry = _registry
-        self.core_names = _registry.object_schemas.keys()
+        self.core_names = factory.object_schemas.keys()
         self.domain_names = Set(self.core_names + self.wf_names)
         domainlist = [(n, 1, USER) for n in self.domain_names]
         specials = [(n, 1, ADMIN) for n in self.special_names]

Index: PanGalactic/pangalactic/test/test_chronosynclastic_transactionalInsert.py
diff -u PanGalactic/pangalactic/test/test_chronosynclastic_transactionalInsert.py:1.9 PanGalactic/pangalactic/test/test_chronosynclastic_transactionalInsert.py:1.10
--- PanGalactic/pangalactic/test/test_chronosynclastic_transactionalInsert.py:1.9	Tue Apr 26 00:53:51 2005
+++ PanGalactic/pangalactic/test/test_chronosynclastic_transactionalInsert.py	Sat May 14 01:49:06 2005
@@ -1,4 +1,4 @@
-# $Id: test_chronosynclastic_transactionalInsert.py,v 1.9 2005/04/26 04:53:51 waterbug Exp $
+# $Id: test_chronosynclastic_transactionalInsert.py,v 1.10 2005/05/14 05:49:06 waterbug Exp $
 
 """
 Test for inserting rows using transactionalInsert()
@@ -24,8 +24,8 @@
 tmpid = utils4test.tmpid
 testval = utils4test.testval
 
-schemas = inf._registry.object_schemas.values()
-classes = inf._registry.classes
+schemas = inf.object_schemas.values()
+classes = inf.classes
 
 parmdicts = dict([(schema.id, dict([(a, testval(schema, a)) for a in schema]))
                   for schema in schemas])
@@ -34,7 +34,7 @@
  
 for o in objs:
     o.id_ns='http://pangalactic.us/test/'
-    inf._registry.popTestData(o)
+    utils4test.popTestData(o)
 
 extrs = [inf.extract(o) for o in objs]
 # pprint(extr)

Index: PanGalactic/pangalactic/meta/names.py
diff -u PanGalactic/pangalactic/meta/names.py:1.15 PanGalactic/pangalactic/meta/names.py:1.16
--- PanGalactic/pangalactic/meta/names.py:1.15	Tue Apr 26 00:53:50 2005
+++ PanGalactic/pangalactic/meta/names.py	Sat May 14 01:49:02 2005
@@ -1,12 +1,12 @@
-# $Id: names.py,v 1.15 2005/04/26 04:53:50 waterbug Exp $
+# $Id: names.py,v 1.16 2005/05/14 05:49:02 waterbug Exp $
 """
 Classes, functions, and services for handling identifiers, addresses, and
 namespaces.
 
-@version: $Revision: 1.15 $
+@version: $Revision: 1.16 $
 """
 
-__version__ = "$Revision: 1.15 $"[11:-2]
+__version__ = "$Revision: 1.16 $"[11:-2]
 
 from sets import Set
 from pangalactic.utils import utils
@@ -150,28 +150,3 @@
         return ''.join([LOCALSPACE.uri, identifier])
 
 
-class NameService(object):
-    """
-    The PanGalactic Name Service will define interfaces and adapters that
-    provide name lookup and resolution.  Its purpose is to enable
-    identifier strings (local names and qualified names) that are known to
-    the namespace registry (names.allspace) to be used in any role that
-    will ultimately require a globally unique address (a URI or pgef_oid,
-    for example).
-    """
-    def __init__(self, _registry, namespaces=None):
-        """
-        Initialize a NameService.
-
-        @param _registry:  the PanGalacticRegistry singleton
-        @type  _registry:  L{pangalactic.meta.registry.PanGalacticRegistry}
-
-        @param nsdict:  a {prefix:ns} dictionary of Namespaces
-        @type  nsdict:  dict
-        """
-        self._registry = _registry
-        if namespaces:
-            for ns in namespaces:
-                registerNamespace(ns)
-
-

Index: PanGalactic/pangalactic/meta/objectschema.py
diff -u PanGalactic/pangalactic/meta/objectschema.py:1.2 PanGalactic/pangalactic/meta/objectschema.py:1.3
--- PanGalactic/pangalactic/meta/objectschema.py:1.2	Wed May  4 06:24:11 2005
+++ PanGalactic/pangalactic/meta/objectschema.py	Sat May 14 01:49:02 2005
@@ -1,4 +1,4 @@
-# $Id: objectschema.py,v 1.2 2005/05/04 10:24:11 waterbug Exp $
+# $Id: objectschema.py,v 1.3 2005/05/14 05:49:02 waterbug Exp $
 
 """
 This module defines the C{ObjectSchema} class, which specifies the
@@ -13,9 +13,9 @@
 assigned at initialization time to instances of a class that has an
 instance of C{ObjectSchema} as its C{_schema}.
 
-@version: $Revision: 1.2 $
+@version: $Revision: 1.3 $
 """
-__version__ = "$Revision: 1.2 $"[11:-2]
+__version__ = "$Revision: 1.3 $"[11:-2]
 
 from sets import Set
 from pangalactic.meta.utils import getDefault
@@ -180,11 +180,11 @@
         dictionary.
         """},
 
-        'properties'     : {'range'          :'Property',
+        'properties'     : {
                             'id'             :'id',
                             'id_ns'          :'http://pangalactic.us/pgef/',
                             'name'           :'ID',
-                            'range'          :'str',
+                            'range'          :'Property',
                             'property_type'  :'object',
                             'max_cardinality':0,
                             'description'    :"""

Index: PanGalactic/pangalactic/repo/pger.py
diff -u PanGalactic/pangalactic/repo/pger.py:1.98 PanGalactic/pangalactic/repo/pger.py:1.99
--- PanGalactic/pangalactic/repo/pger.py:1.98	Sun Apr 24 01:21:22 2005
+++ PanGalactic/pangalactic/repo/pger.py	Sat May 14 01:49:05 2005
@@ -1,10 +1,10 @@
-# $Id: pger.py,v 1.98 2005/04/24 05:21:22 waterbug Exp $
+# $Id: pger.py,v 1.99 2005/05/14 05:49:05 waterbug Exp $
 """
 Pan Galactic Entropy Reverser module
 
-@version: $Revision: 1.98 $
+@version: $Revision: 1.99 $
 """
-__version__ = "$Revision: 1.98 $"[11:-2]
+__version__ = "$Revision: 1.99 $"[11:-2]
 
 import sys
 import os
@@ -73,14 +73,14 @@
         """
         Change a password for a userid.
 
-        @type password:   string
+        @type password:   C{str}
         @param password:  new password
 
-        @type userid:   string
+        @type userid:   C{str}
         @param userid:  pgef_oid of the Person whose password
                           is to be changed
 
-        @type requestor:  string
+        @type requestor:  C{str}
         @param requestor: pgef_oid of the Person who is
                           requesting the change
         """
@@ -120,7 +120,7 @@
         log.msg(logmsg, system='%s:PGER' % requestor)
         return logmsg
 
-    def getObjects(self, requestor, schemaid, refs=0, subtypes=0,
+    def getObjects(self, requestor, schema_id, refs=0, subtypes=0,
                    ret='extracts', **kw):
         """
         An interface through which any set of PgefObject subclass instances
@@ -129,15 +129,15 @@
         matches, and is therefore usually quicker if the exact values of
         the attributes of the instances desired are known.
 
-        @type  requestor:  string
+        @type  requestor:  C{str}
         @param requestor:  the userid of the user making the request.
 
-        @type  schemaid:  string
-        @param schemaid:  the id of a
+        @type  schema_id:  C{str}
+        @param schema_id:  the id of a
             L{pangalactic.meta.objectschema.ObjectSchema} known to the
             PanGalacticRegistry.
 
-        @type  refs:  integer
+        @type  refs:  C{int}
         @param refs:  specifies whether to include the objects referenced
             by the specified class.
               
@@ -147,7 +147,7 @@
             (in future, refs may specify how many reference levels to
             follow ...)
 
-        @type  subtypes:  boolean
+        @type  subtypes:  C{bool}
         @param subtypes:  specifies whether to include only the specified
             class (the default) or all subtypes.
 
@@ -169,12 +169,12 @@
         @return:    list of results (type of items depends on value of
             'ret' param).
         """
-        logmsg = 'getObjects, %s, %s' % (schemaid, str(kw))
+        logmsg = 'getObjects, %s, %s' % (schema_id, str(kw))
         log.msg(logmsg, system='%s:PGER' % requestor)
-        return self.infum.getObjects(requestor, schemaid, refs, subtypes,
+        return self.infum.getObjects(requestor, schema_id, refs, subtypes,
                                      ret=ret, **kw)
 
-    def findObjects(self, requestor, schemaid, refs=1, subtypes=0,
+    def findObjects(self, requestor, schema_id, refs=1, subtypes=0,
                     ret='extracts', fulltext='', args=None):
         """
         Search for all instances that match the specified arguments for the
@@ -186,10 +186,10 @@
         of that function will be combined with the search results from
         other attributes using the _getIntersectionResults() function.
 
-        @type  schemaid:  string
-        @param schemaid:  schema id of the instances to search for.
+        @type  schema_id:  C{str}
+        @param schema_id:  schema id of the instances to search for.
 
-        @type  refs:  boolean
+        @type  refs:  C{bool}
         @param refs:  specifies whether to include the objects referenced
             by the specified class.
 
@@ -199,14 +199,14 @@
             (in future, refs may specify how many reference levels to
             follow ...)
 
-        @type  subtypes:  boolean
+        @type  subtypes:  C{bool}
         @param subtypes:  specifies whether to include only the specified
             class (the default) or all subtypes.
 
                 0:  (default) only this type
                 1:  include subtypes
 
-        @type  ret:  string ('object' or 'extract')
+        @type  ret:  C{str} ('object' or 'extract')
         @param ret:  specifies whether to return objects or extracts
             (default: 'extracts').
 
@@ -223,7 +223,7 @@
             attribute is a string, a case-independent search will be done,
             treating the search value as a substring.
 
-        @type  kw:  string or sequence
+        @type  kw:  C{str} or sequence
         @param kw:  (optional kw args) valid names are:
                     
             B{orderby}:  column(s) to be sorted on -- this can be either a
@@ -235,11 +235,11 @@
             L{pangalactic.core.pgefobject.PgefObject}
         @return:  deferred result of search
         """
-        logmsg = 'search, %s, %s' % (schemaid, str(args[0]))
+        logmsg = 'search, %s, %s' % (schema_id, str(args[0]))
         log.msg(logmsg, system='%s:PGER' % requestor)
         if args:
             return self.infum.findObjects(requestor=requestor,
-                                          schemaid=schemaid,
+                                          schema_id=schema_id,
                                           refs=refs,
                                           subtypes=subtypes,
                                           ret=ret,
@@ -259,10 +259,10 @@
            - NOTE:  any application objects referenced as an attribute of
              an object to be added must already exist in PGER.
 
-        @type  input:  string ('object' or 'extract')
+        @type  input:  C{str} ('object' or 'extract')
         @param input:  the form of the submitted objects
 
-        @type  ret:  string ('object' or 'extract')
+        @type  ret:  C{str} ('object' or 'extract')
         @param ret:  the form of the returned objects
 
         @type  objects:  list
@@ -289,7 +289,7 @@
            - NOTE:  any application objects referenced as an attribute of)
              an object to be added must already exist in PGER.
 
-        @type requestor:  string
+        @type requestor:  C{str}
         @param requestor: the pgef_oid (userid) of the user
                     attempting to execute the operation
 
@@ -297,7 +297,7 @@
             L{pangalactic.core.versionedobject.VersionedObject}
         @param objects:  a list of VersionedObjects to be committed
 
-        @type input:   string ('object' or 'extract')
+        @type input:   C{str} ('object' or 'extract')
         @param input:  the form of the submitted objects
 
         @rtype:     a list of deferreds
@@ -333,17 +333,17 @@
            - NOTE:  any application objects referenced as an attribute of)
              an object to be added must already exist in PGER.
 
-        @type  requestor:  string
+        @type  requestor:  C{str}
         @param requestor:  the pgef_oid (userid) of the user attempting to
             execute the operation
 
         @type  e:  dictionary
         @param e:  an extract of a VersionedObject instance
         """
-        schemaid = e['object_schema_id']
-        logmsg = 'addVersionExtract for a %s' % schemaid
+        schema_id = e['object_schema_id']
+        logmsg = 'addVersionExtract for a %s' % schema_id
         log.msg(logmsg, system='%s:PGER' % requestor)
-        res = self.infum.getObjects(schemaid,
+        res = self.infum.getObjects(schema_id,
                                     base_id=e['base_id'],
                                     is_head=True)
         res.addCallbacks(lambda x: x[0].iteration,
@@ -359,7 +359,7 @@
 
             - usage:  _setHeadFlags(list of VersionedObject extracts)
 
-        @type  requestor:  string
+        @type  requestor:  C{str}
         @param requestor:  the pgef_oid (userid) of the user attempting to
             execute the operation
 

Index: PanGalactic/pangalactic/utils/datamanager.py
diff -u PanGalactic/pangalactic/utils/datamanager.py:1.176 PanGalactic/pangalactic/utils/datamanager.py:1.177
--- PanGalactic/pangalactic/utils/datamanager.py:1.176	Thu May 12 20:29:51 2005
+++ PanGalactic/pangalactic/utils/datamanager.py	Sat May 14 01:49:07 2005
@@ -1,10 +1,10 @@
-# $Id: datamanager.py,v 1.176 2005/05/13 00:29:51 waterbug Exp $
+# $Id: datamanager.py,v 1.177 2005/05/14 05:49:07 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_datamanager -*-
 
 """
 PanGalaxian's local workspace manager.
 
-@version: $Revision: 1.176 $
+@version: $Revision: 1.177 $
 """
 # TODO:  move the transaction/interface stuff, like XmlrpcInterface, into a
 # separate module -- InterfaceManager, which will handle all client
@@ -15,7 +15,7 @@
 # came from (repository, file import, etc.) and what their state is
 # (committed/uncommitted, etc.)
 
-__version__ = "$Revision: 1.176 $"[11:-2]
+__version__ = "$Revision: 1.177 $"[11:-2]
 
 import time
 import mx.DateTime
@@ -26,12 +26,12 @@
 from pprint import pprint
 
 # PanGalactic imports
-from pangalactic.core.person     import Person
-from pangalactic.core.project    import Project
-from pangalactic.core.filelink   import FileLink
-from pangalactic.core.workflow   import wffactory
-from pangalactic.meta.registry   import PanGalacticRegistry
-from pangalactic.node.gui.state  import state, prefs, displaymaps
+from pangalactic.core.person    import Person
+from pangalactic.core.project   import Project
+from pangalactic.core.filelink  import FileLink
+from pangalactic.core.workflow  import wffactory
+from pangalactic.meta.factory   import PanGalacticFactory
+from pangalactic.node.gui.state import state, prefs, displaymaps
 from pangalactic.utils                 import localdb
 from pangalactic.utils.httpupload      import upload
 from pangalactic.utils.pgefexceptions  import LocalStorageError
@@ -45,12 +45,12 @@
     # TODO:  all fns having to do w/servers,ports,etc will move to
     # InterfaceManager.
 
-    def __init__(self, _registry=None, domains='PanGalactic', userid=None):
+    def __init__(self, factory=None, domains='PanGalactic', userid=None):
         """
         Initialize a DataManager instance.
 
-        @param _registry:  the PanGalacticRegistry instance (singleton)
-        @type  _registry:  L{pangalactic.meta.registry.PanGalacticRegistry}
+        @param factory:  the PanGalacticFactory instance (singleton)
+        @type  factory:  L{pangalactic.meta.factory.PanGalacticFactory}
 
         @param domains:  specifies which application domains to include
         @type  domains:  C{str}
@@ -58,9 +58,9 @@
         @param userid:  the id of the invoking user (a Person oid)
         @type  userid:  C{str}
         """
-        self._registry = _registry or PanGalacticRegistry()
+        self.factory = factory or PanGalacticFactory()
         try:
-            self.cache = localdb.LocalStorage(self._registry)
+            self.cache = localdb.LocalStorage(self.factory)
         except:
             raise LocalStorageError, "LocalStorageError"
         self.uncommittedobjs = self.cache.uncommittedobjs
@@ -80,7 +80,7 @@
         self.creatingWorkflow = False
         if not displaymaps:
             # initialize default display maps
-            for schema_id, schema in self._registry.object_schemas.items():
+            for schema_id, schema in self.factory.object_schemas.items():
                 displaymaps[schema_id] = schema._default_display_map
 
     def getServerHost(self):
@@ -132,7 +132,7 @@
                                password,
                                secure=secure,
                                domains=self.domains,
-                               _registry=self._registry)
+                               factory=self.factory)
 
     def getRoot(self):
         return self.cache.dbroot
@@ -167,23 +167,23 @@
     def getUser(self, userid):
         return self.cache.getLocalObject(userid)
 
-    def newObject(self, classname, **kw):
+    def newObject(self, schema, **kw):
         """
         Create a new object with id "NEW" and with the current project and
         id namespace as its 'project' and 'id_ns' attributes, respectively.
         """
         # print "dm.newobject"
-        if classname == "FileLink":
+        if schema == "FileLink":
             self.newFileLink(**kw)
         obj = None
-        if classname in ["VersionedObject", "Part", "Model", "Document",
+        if schema in ["VersionedObject", "Part", "Model", "Document",
                          "PartsList"]:
-            klass = self._registry.classes[classname]
-            obj = klass(id="NEW",
-                        id_ns=state['id_ns'],
-                        project=state['project'],
-                        owner=self.user.id,
-                        **kw)
+            obj = self.factory.make(schema,
+                                    id="NEW",
+                                    id_ns=state['id_ns'],
+                                    project=state['project'],
+                                    owner=self.user.id,
+                                    **kw)
         return obj
 
     def newFileLink(self, file_path='', dlabel='',

Index: PanGalactic/TODO
diff -u PanGalactic/TODO:1.23 PanGalactic/TODO:1.24
--- PanGalactic/TODO:1.23	Wed May  4 06:24:11 2005
+++ PanGalactic/TODO	Sat May 14 01:49:02 2005
@@ -8,6 +8,10 @@
 ---------------------------------------------------
 To Do Before Release (in rough order of precedence)
 ---------------------------------------------------
+[*] NEW!  PgefObjectGrid widget (very close to completion)
+    - draggable columns
+    - popup menu for selection of visible columns from object properties
+    - menu choice to set preferred displaymap for class from current config
 [-] NEW!  *REPLACE* ItemEditFrame with late-bound object viewer/editors
     - new editor concept for all objs:  use object viewer as the editor
     - 'links' to objects from object Properties (related objs may or may
@@ -25,16 +29,18 @@
       'Close' button should be activated so the user can close the window
       (don't really need 'Save' button -- that should be implicit, as in
       Mozilla bookmark editor)
-[-] right now, drop/drag assembly does not activate 'Save' button, does
-    not show up in main assembly tree, and does not show up next time
-    ItemEditFrame comes up
+[*] recreate PgefTree widget
+    - add mouse-over balloons to show info on node
+    - "all" tree view to show all objs assoc. with each node
+    - explicit assembly (reified acu's and interfaces, w/icons)
+    - drop/drag assembly should activate 'Save' button
 [*] debug commit function for objs with files
-[*] oseb import
+[-] get ExpressEngine process protocol working
+[*] complete STEP file import/mapping function
     - use oseb.py deserialize the result of an ExpressEngine mapping into
       PGEF objects and store them in PGER, along with appropriate DataSet
       collection objects to identify the source and target data sets.
-[-] get ExpressEngine process protocol working
-[-] create a test set-up script that populates test data, etc.
+[*] create a test set-up script that populates test data, etc.
 [-] create a 'demo mode' that creates a sandbox for the user to play in
 [-] write up and test demo scenario(s), runnable by users
     - p21 file upload / EE map / show assembly
@@ -50,21 +56,13 @@
     - XMI export (OWL? OSEB? [oseb of STEP "functional model"?])
 [-] fix Glimpse full-text search (make a glimpse process protocol)
 [-] PB demo with collaborative grids (power budget metaphor, etc.)
-[*] oseb export
 [*] OWL import/export
 [-] Modify cache browser to use choicebook with grids
 [-] Ontology modeling canvas (mainly for extending pgef core ontology)
 [*] XMI import/export
 [-] UML/OWL/Express MOF model (ODM)
 [-] change PartsList to PartsListItem (join object)
-[*] fix display map management
-    - use state for displayconfig persistence (for grids, etc.)
 [-] use Bob Ippolito's threadedselectreactor to add Twisted to Pangalaxian
-[*] recreate PgefGrid widget
-[*] recreate PgefTree widget
-    - add mouse-over balloons to show info on node
-    - "all" tree view to show all objs assoc. with each node
-    - explicit assembly (reified acu's and interfaces, w/icons)
 [-] schemas for WfActivity, WfEvent, WfProcess, WfTransition
     - also look at Envisage's process modeling module
 [-] implement notifications, pub/sub (either PyDispatcher or Traits)
@@ -80,8 +78,19 @@
 --------------------------------------------
 To Do After Release (in no particular order)
 --------------------------------------------
-[-] COM interface to ST-Viewer
-[-] use oseb for PanGalaxian state serialization
+[-] implement INameService in PanGalacticRegistry, providing name lookup
+    and resolution.  The purpose is to enable identifier strings (local
+    names and qualified names) that are known to the namespace registry
+    (pangalactic.meta.names.allspace) to be used in any role that will
+    ultimately require a globally unique address (a URI or pgef_oid, for
+    example).  Note:  from there, it's not a huge jump to being able to
+    import an ontology from somewhere and create domain objects that have
+    schemas based on its Classes (not that I have a use-case for that yet!
+    ;).
+[-] add 'class_id' to extracts, so that serialized objects can specify
+    that their host class was not the default one for their 'object_schema'
+    (it will still have to be a class known to the registry).  Haven't
+    thought through the use-cases or implications of this ...
 [-] onProjectClick should make sure that cell (0,0) is visible
 [-] add nodetype to tree data (and type-specific icons to tree)
 [-] modify upload to differentiate between filetypes
@@ -99,11 +108,14 @@
 ----
 DONE
 ----
+[+] fix display map management
+    - use state for displayconfig persistence (for grids, etc.)
+[+] simplified OSEB import/export
 [+] fix model.of_part:  should be many-to-many (PartModel obj)
 [+] fix one-many and many-many mappings
     - many-many requires reifying the relationship as a "join object"
     - one-many (aggregate attrs)
 
 --------------------------------------------------------------------------
-# $Id: TODO,v 1.23 2005/05/04 10:24:11 waterbug Exp $
+# $Id: TODO,v 1.24 2005/05/14 05:49:02 waterbug Exp $
 

Index: PanGalactic/pangalactic/meta/factory.py
diff -u PanGalactic/pangalactic/meta/factory.py:1.17 PanGalactic/pangalactic/meta/factory.py:1.18
--- PanGalactic/pangalactic/meta/factory.py:1.17	Sun Apr 10 23:31:25 2005
+++ PanGalactic/pangalactic/meta/factory.py	Sat May 14 01:49:02 2005
@@ -1,13 +1,13 @@
-# $Id: factory.py,v 1.17 2005/04/11 03:31:25 waterbug Exp $
+# $Id: factory.py,v 1.18 2005/05/14 05:49:02 waterbug Exp $
 
 """
 The PanGalacticFactory provides functions to marshall and unmarshall
 subclasses of L{pangalactic.core.pgefobject.PgefObject}.
 
-@version: $Revision: 1.17 $
+@version: $Revision: 1.18 $
 """
 
-__version__ = "$Revision: 1.17 $"[11:-2]
+__version__ = "$Revision: 1.18 $"[11:-2]
 
 from pprint import pprint
 from mx.DateTime.ISO import ParseDateTime
@@ -15,16 +15,43 @@
 from pangalactic.meta.registry import PanGalacticRegistry
 
 
-class PanGalacticFactory:
+class PanGalacticFactory(PanGalacticRegistry):
     """
     The PanGalacticFactory provides functions to marshall and unmarshall
     subclasses of L{pangalactic.core.pgefobject.PgefObject}.
+
+    Instance variables used here that were inherited from
+    L{pangalactic.meta.registry.PanGalacticRegistry}:
+
+    @ivar object_schemas:  dictionary of registered C{ObjectSchema}s by id
+    @type object_schemas:  C{dict}
+
+    @ivar schema_base_order:  a list of C{ObjectSchema} ids in which no
+        C{ObjectSchema}'s id occurs before the id of its base
+        C{ObjectSchema}.
+    @type schema_base_order:  C{list}
     """
-    def __init__(self, _registry=None, domains='PanGalactic'):
-        if _registry:
-            self._registry = _registry
-        else:
-            self._registry = PanGalacticRegistry(domains=domains)
+    def __init__(self, domains='PanGalactic'):
+        PanGalacticRegistry.__init__(self, domains=domains)
+
+    def make(self, schema_id, _class=None, **kw):
+        """
+        Create an object that has the C{ObjectSchema} with an id of
+        C{schema_id} as its C{_schema}.  If no C{_class} is supplied, one
+        will be selected by the C{getClassForSchemaId} algorithm (see
+        L{pangalactic.meta.registry.PanGalacticRegistry}).
+
+        @param schema_id:  the id of a registered instance of
+            L{pangalactic.meta.objectschema.ObjectSchema}
+        @type  schema_id:  C{str}
+
+        @param _class:  an instance of C{PgefObject} or subclass
+        @type  _class:  L{pangalactic.core.pgefobject.PgefObject}
+        """
+        schema = self.object_schemas[schema_id]
+        if not _class:
+            _class = self.getClassForSchemaId(schema_id)
+        return _class(_schema=schema, **kw)
 
     def cook(self, value, prop):
         """
@@ -55,7 +82,7 @@
                 retvalue = 'True'
             else:
                 retvalue = ''
-        elif prop.range in self._registry.object_schemas:
+        elif prop.range in self.object_schemas:
             if prop.max_cardinality == 1:
                 if type(value) is str or type(value) is unicode:
                     retvalue = value
@@ -161,17 +188,17 @@
         referenced objects are found) and return all the resulting extracts
         in a list.
 
-        @type objs:   list of instances of subtypes of
-                      L{pangalactic.core.pgefobject.PgefObject}
         @param objs:  the list of objects from which _schema instance data
             is to be extracted
+        @type  objs:  C{list} of instances of subtypes of
+            L{pangalactic.core.pgefobject.PgefObject}
 
+        @param object_schemas:  limits the schemas to be extracted ([],
+            which is the default, indicates all schemas)
         @type object_schemas:   list of obj._schema.id's
-        @param object_schemas:  limits the classes to be extracted ([], which
-            is the default, indicates all classes)
 
-        @rtype:   list
         @return:  a list of extracts
+        @rtype:   C{list}
         """
         # DEBUGGING
         # print 'Begin: objs are %s' % str(objs)
@@ -181,8 +208,8 @@
         #     print '       all object_schemas will be extracted.'
         if object_schemas:
             for schema in object_schemas:
-                if schema not in self._registry.object_schemas:
-                    e = """Object schema "%s" is not known to the registry.""" % schema
+                if schema not in self.object_schemas:
+                    e = """Object schema "%s" is not known.""" % schema
                     raise ValueError, e
         extracts = []
         while objs:
@@ -211,7 +238,7 @@
                         for a in o._schema:
                             if getattr(o, a):
                                 if (o._schema[a].range
-                                    in self._registry.object_schemas):
+                                    in self.object_schemas):
                                     if o._schema[a].max_cardinality == 1:
                                         # check whether it's a pgef_oid
                                         if type(getattr(o, a)) is not str:
@@ -269,10 +296,10 @@
         # print 'remember:  extract ='
         # pprint(e)
         # print 'remember:  objs = %s' % str(objs)
-        schemaid = e['object_schema_id']
-        schema = self._registry.object_schemas[schemaid]
-        klass = self._registry.classes[
-                    self._registry.getClassForSchema(schemaid)]
+        # TODO:  add 'class_id' to extracts, so that extracts can specify
+        # that their host class was not the default one for that schema.
+        schema_id = e['object_schema_id']
+        schema = self.object_schemas[schema_id]
         obyoids = dict([(o.pgef_oid, o) for o in objs])
         kw = {}
         for a in schema:
@@ -300,7 +327,7 @@
         # up), add them to kw.
         # TODO:  look into optimizing this algorithm.
         for a in schema:
-            if schema[a].range in self._registry.object_schemas:
+            if schema[a].range in self.object_schemas:
                 # first look at non-aggregate attrs ...
                 if (schema[a].max_cardinality == 1
                     and e[a] in obyoids):
@@ -310,7 +337,7 @@
                     for item in kw[a]:
                         if item in obyoids:
                             kw[a][kw[a].index(item)] = obyoids[item]
-        obj = klass(**kw)
+        obj = self.make(schema_id, **kw)
         return [obj], objs
 
     def rememberAll(self, extracts, objs=None, hookusuptheobjects=0):
@@ -346,7 +373,6 @@
                 olist, nothing = self.remember(e)
                 remembered += olist
             return remembered, objs
-        object_schemas = self._registry.object_schemas
         # print 'rememberAll:  extracts = %s' % str(extracts)
         # print 'rememberAll:  objs = %s' % str(objs)
         # get rid of any null objects passed in
@@ -372,7 +398,7 @@
         # hook us up the objects!
         for o in remembered:
             for a in o._schema:
-                if o._schema[a].range in object_schemas:
+                if o._schema[a].range in self.object_schemas:
                     val = getattr(o, a, None)
                     if val:
                         # first look at non-aggregate attrs ...
@@ -405,11 +431,11 @@
         """
         parts = ename.split('_')
         i = 0
-        schemaid = ''
+        schema_id = ''
         while i < len(parts):
-            schemaid = schemaid + parts[i].capitalize()
+            schema_id = schema_id + parts[i].capitalize()
             i += 1
-        return schemaid
+        return schema_id
 
     def oseb2Objects(self, osebdataset):
         """
@@ -426,15 +452,12 @@
         objs = {}
         for xid in osebdataset['data']:
             entityname = osebdataset['data'][xid].pop('instance_type')
-            schemaid = self.getSchemaIdForEntityName(entityname)
-            schema = self._registry.object_schemas[schemaid]
-            classname = self._registry.getClassForSchema(schemaid)
+            schema_id = self.getSchemaIdForEntityName(entityname)
             # create objects, using xid's as temp oids (convenient since
             # they already use them to cross-ref each other)
-            objs[xid] = self._registry.classes[classname](
-                                               _schema=schema,
-                                               pgef_oid=xid,
-                                               **osebdataset['data'][xid])
+            objs[xid] = self.make(schema_id,
+                                  pgef_oid=xid,
+                                  **osebdataset['data'][xid])
         return objs
 
 

Index: PanGalactic/pangalactic/meta/registry.py
diff -u PanGalactic/pangalactic/meta/registry.py:1.29 PanGalactic/pangalactic/meta/registry.py:1.30
--- PanGalactic/pangalactic/meta/registry.py:1.29	Tue Apr 26 00:53:50 2005
+++ PanGalactic/pangalactic/meta/registry.py	Sat May 14 01:49:02 2005
@@ -1,9 +1,9 @@
-# $Id: registry.py,v 1.29 2005/04/26 04:53:50 waterbug Exp $
+# $Id: registry.py,v 1.30 2005/05/14 05:49:02 waterbug Exp $
 
 """
 Pan Galactic Engineering Framework Registry
 
-@version: $Revision: 1.29 $
+@version: $Revision: 1.30 $
 
 The C{PanGalacticRegistry} maintains an in-memory cache of the PanGalactic
 core ontology (the C{ObjectSchema} instances that are the C{_schema}s of
@@ -17,7 +17,7 @@
 L{pangalactic.core.pgefobject.PgefObject}), the class's module name must be
 the class name in lower-case.
 """
-__version__ = "$Revision: 1.29 $"[11:-2]
+__version__ = "$Revision: 1.30 $"[11:-2]
 
 import imp
 import re
@@ -55,24 +55,24 @@
         @ivar classes:
             A mapping of PanGalactic core class names to their class
             objects.
-        @type classes:  dict
+        @type classes:  C{dict}
 
         @ivar object_schemas:
             A mapping of the ids of C{ObjectSchema}s known to the registry to
             their instances.
-        @type object_schemas:  dict
+        @type object_schemas:  C{dict}
 
         @ivar refs:
             A mapping of the ids of C{ObjectSchema}s to the set of id's of
             C{ObjectSchema}s that they reference as the range of a
             property.
-        @type refs:  dict
+        @type refs:  C{dict}
 
         @ivar deps:
             A mapping of the ids of C{ObjectSchema}s to the
             C{ObjectSchema}s that they either reference as the range of a
             property or inherit from.
-        @type deps:  dict
+        @type deps:  C{dict}
         """
         self.classes = {}
         self.refs = {}
@@ -83,17 +83,16 @@
         if 'PanGalactic' not in domains:
             domains.append('PanGalactic')
         for domain in domains:
-            appclasses = self.getAppPkgClasses(domain)
-            self.classes.update(appclasses)
+            classes = self.getAppPkgClasses(domain)
+            self.classes.update(classes)
         # print 'classes are:'
         # pprint(self.classes)
         self.object_schemas = {}
         # add the ObjectSchemas of the PanGalactic core ontology to the
         # registry
-        for c in self.classes:
-            pcinst = self.classes[c]._schema
-            schemaid = pcinst.id
-            self.object_schemas[schemaid] = pcinst
+        for _class in self.classes.values():
+            schema = _class._schema
+            self.object_schemas[schema.id] = schema
         # add ObjectSchemas for the PanGalactic meta ontology to the
         # registry
         ################################################################
@@ -167,32 +166,32 @@
             )
         self.object_schemas['Property'] = pppc
         # build self.refs
-        for schemaid in self.object_schemas:
-            # print 'Building refs for', schemaid
-            self.refs[schemaid] = Set()
-            for a in self.object_schemas[schemaid]:
+        for schema_id in self.object_schemas:
+            # print 'Building refs for', schema_id
+            self.refs[schema_id] = Set()
+            for a in self.object_schemas[schema_id]:
                 # print 'Looking at attribute', a
-                if self.object_schemas[schemaid][a].range in self.object_schemas:
-                    self.refs[schemaid].add(self.object_schemas[schemaid][a].range)
+                if self.object_schemas[schema_id][a].range in self.object_schemas:
+                    self.refs[schema_id].add(self.object_schemas[schema_id][a].range)
         ### PROBABLY DON'T WANT MUCH, IF ANY, OF THIS CODE!!
         # build self.deps
 #         self.deps = Set()
 #         todo = self.object_schemas.copy()
-#         todoschemaids = todo.keys()[:]
-#         for schemaid in todoschemaids:
-#             if not self.refs[schemaid].keys():
-#                 self.deps_order.append(schemaid)
-#                 del todo[schemaid]
+#         todo_schema_ids = todo.keys()[:]
+#         for schema_id in todo_schema_ids:
+#             if not self.refs[schema_id].keys():
+#                 self.deps_order.append(schema_id)
+#                 del todo[schema_id]
 #         # print 'Got independent classes: '
 #         # print self.deps_order
 #         while 1:
-#             depschemaids = self.deps_order[:]
-#             todoschemaids = todo.keys()[:]
-#             for schemaid in todoschemaids:
-#                 refschemaids = self.refs[schemaid].values()
-#                 if Set(refschemaids) <= Set(depschemaids):
-#                     self.deps_order.append(schemaid)
-#                     del todo[schemaid]
+#             dep_schema_ids = self.deps_order[:]
+#             todo_schema_ids = todo.keys()[:]
+#             for schema_id in todo_schema_ids:
+#                 ref_schema_ids = self.refs[schema_id].values()
+#                 if Set(ref_schema_ids) <= Set(dep_schema_ids):
+#                     self.deps_order.append(schema_id)
+#                     del todo[schema_id]
 #             if not todo:
 #                 # print 'Got dependency order:'
 #                 # print self.deps_order
@@ -213,15 +212,15 @@
         """
         baseorder = []
         schemas  = self.object_schemas
-        for schemaid in schemas:
-            if not schemas[schemaid].base:
-                baseorder.append(schemaid)
+        for schema_id in schemas:
+            if not schemas[schema_id].base:
+                baseorder.append(schema_id)
         while 1:
-            for schemaid in schemas:
-                if (schemas[schemaid].base
-                    and schemas[schemaid].base.id in baseorder
-                    and schemaid not in baseorder):
-                    baseorder.append(schemaid)
+            for schema_id in schemas:
+                if (schemas[schema_id].base
+                    and schemas[schema_id].base.id in baseorder
+                    and schema_id not in baseorder):
+                    baseorder.append(schema_id)
                 if Set(baseorder) == Set(schemas.keys()):
                     return baseorder
 
@@ -280,7 +279,7 @@
             classdict[name] = self._importClass(modpath, name)
         return classdict
 
-    def getClassForSchema(self, schema_id):
+    def getClassForSchemaId(self, schema_id):
         """
         Return the name of the PgefObject subclass that can best accept
         this C{ObjectSchema} instance as its _schema.
@@ -297,22 +296,22 @@
             L{pangalactic.meta.objectschema.ObjectSchema}
         """
         if schema_id in self.classes:
-            return schema_id
+            return self.classes[schema_id]
         else:
             while 1:
-                baseid = self.object_schemas[schema_id].base.id
-                if (baseid in self.classes
+                base_id = self.object_schemas[schema_id].base.id
+                if (base_id in self.classes
                     or not getattr(base, 'base', None)):
-                    return baseid
+                    return self.classes[base_id]
                 else:
-                    schema_id = baseid
+                    schema_id = base_id
 
     def registerObjectSchema(self, schema):
         """
         Make an C{ObjectSchema} known to the registry.
         """
         # TODO:  may want to check base; running
-        # getClassForSchema might be enough.
+        # getClassForSchemaId might be enough.
         self.object_schemas[schema.id] = schema
 
     def report(self):
@@ -331,13 +330,13 @@
         # else:
         #     output += "    - None.\n"
         # output += '--------------------------------------------------\n'
-        for schemaid in self.schema_base_order:
-            pc = self.object_schemas[schemaid]
-            output += '\nObjectSchema ............. %s\n' % (schemaid)
+        for schema_id in self.schema_base_order:
+            pc = self.object_schemas[schema_id]
+            output += '\nObjectSchema ............. %s\n' % (schema_id)
             output += '  Base ObjectSchema ...... %s\n' % (
                                         getattr(pc.base, 'id', 'None'))
             output += '  PanGalactic core class ..... %s\n' % (
-                                  self.getClassForSchema(schemaid))
+                            self.getClassForSchemaId(schema_id).__name__)
             output += '  Abbreviation ............... %s\n' % (pc.abbrev)
             output += '  Description:\n'
             output += pc.description

Index: PanGalactic/pangalactic/repo/pgerxmlrpc.py
diff -u PanGalactic/pangalactic/repo/pgerxmlrpc.py:1.19 PanGalactic/pangalactic/repo/pgerxmlrpc.py:1.20
--- PanGalactic/pangalactic/repo/pgerxmlrpc.py:1.19	Thu Mar 24 01:51:39 2005
+++ PanGalactic/pangalactic/repo/pgerxmlrpc.py	Sat May 14 01:49:05 2005
@@ -1,10 +1,10 @@
 """
 PGER XML-RPC Interfaces module
-@version: $Revision: 1.19 $
+@version: $Revision: 1.20 $
 """
 
-__version__ = "$Revision: 1.19 $"[11:-2]
-# $Id: pgerxmlrpc.py,v 1.19 2005/03/24 06:51:39 waterbug Exp $
+__version__ = "$Revision: 1.20 $"[11:-2]
+# $Id: pgerxmlrpc.py,v 1.20 2005/05/14 05:49:05 waterbug Exp $
 
 from twisted.python import log
 from twisted.web.xmlrpc import XMLRPC
@@ -74,18 +74,17 @@
             s += """ya gotta have somethin' ...!"""
             return s
 
-    
     def xmlrpc_changePassword(self, password, userid=''):
         """
         Change password for a userid (default: for
         the authenticated user).
 
-        @type password:   string
         @param password:  new password
+        @type  password:  C{str}
 
-        @type userid:   string
         @param userid:  pgef_oid of the Person whose password is to be
             changed
+        @type  userid:  C{str}
         """
         return self.engine.changePassword(self.userid,
                                           userid,
@@ -97,27 +96,33 @@
         specified set of attribute-value pairs, returning the result as a
         list of "extracts" -- see L{pangalactic.utils.factory.extract})
 
-        @type typename:   string
         @param typename:  the name of a class that extends
-                          L{pangalactic.core.pgefobject.PgefObject}
+            L{pangalactic.core.pgefobject.PgefObject}
+        @type  typename:  C{str}
 
-        @type refs:   boolean
         @param refs:  whether to return all referenced objects or
-                      only the specified class
-                          0:  (default) only the specified class
-                          1:  include all reference objects
-
-        @type subtypes:   boolean
-        @param subtypes:  whether to return all subtypes of the
-                          requested type that match the criteria
-                              0:  (default) not
-                              1:  include all subtypes
-
-        @type criteria:   list or dictionary
-        @param criteria:  the selection criteria can take either
-                          of two forms:
-                              - list:  a list of [attr, value] pairs
-                              - dict:  a dictionary: {attr : value, ...}
+            only the specified class
+
+                0:  (default) only the specified class
+                1:  include all reference objects
+
+        @type  refs:  C{bool}
+
+        @param subtypes:  whether to return all subtypes of the requested
+            type that match the criteria
+
+                0:  (default) not
+                1:  include all subtypes
+
+        @type  subtypes:  C{bool}
+
+        @param criteria:  the selection criteria can take either of two
+            forms:
+
+                - list:  a list of [attr, value] pairs
+                - dict:  a dictionary: {attr : value, ...}
+
+        @type  criteria:  C{list} or C{dict}
         """
         if criteria:
             if isinstance(criteria, list):
@@ -125,7 +130,7 @@
             elif isinstance(criteria, dict):
                 kw = criteria
             res = self.engine.getObjects(requestor=self.userid,
-                                         schemaid=typename,
+                                         schema_id=typename,
                                          refs=refs,
                                          subtypes=subtypes,
                                          **kw)
@@ -133,66 +138,65 @@
         else:
             return """I'm sorry, Dave, I'm afraid I can't do that."""
 
-    def xmlrpc_search(self, schemaid, refs, subtypes, args):
+    def xmlrpc_search(self, schema_id, refs, subtypes, args):
         """
         Search for instances of the specified class.
 
-        @type schemaid:   string
-        @param schemaid:  the id of the class of objects to search for
+        @param schema_id:  the id of the class of objects to search for
             (i.e., a subtype of
             L{pangalactic.core.pgefobject.PgefObject})
+        @type  schema_id:  C{str}
 
-        @type  refs:  boolean
-        @param refs:  specifies whether to include objects
-                    referenced by the found objects (i.e.,
-                    the attributes whose types are classes in the
-                    ontology).
-                        0:  (default) do not get refs
-                        1:  get all references
-                    (in future, refs may specify how many
-                    reference levels to follow ...)
-
-        @type  subtypes:  boolean
-        @param subtypes:  specifies whether to include only the
-                    specified class (the default) or all
-                    subtypes.
+        @param refs:  specifies whether to include objects referenced by
+            the found objects (i.e., the attributes whose types are classes
+            in the ontology).
+
+                0:  (default) do not get refs
+                1:  get all references
+
+            (in future, refs may specify how many reference levels to
+            follow ...)
+        @type  refs:  C{bool}
+
+        @param subtypes:  specifies whether to include only the specified
+            class (the default) or all subtypes.
                         0:  (default) only this type
                         1:  include subtypes
+        @type  subtypes:  C{bool}
 
-        @type  objects:  boolean
-        @param objects:  specifies whether to return objects
-                    of the type specified or resultsets.
+        @param objects:  specifies whether to return objects of the type
+            specified or resultsets.
                         0:  resultsets
                         1:  objects
+        @type  objects:  C{bool}
+
+        @param args:  a list of query element tuples, in which each tuple
+            has the form:
 
-        @type args:   sequence
-        @param args:  a list of query element tuples, in which each
-                    tuple has the form:
-                        - element[0] = attribute name
-                        - element[1] = logical operator
-                        - element[2] = search value
-                    ... where operator can be any SQL operator,
-                    e.g.: 'LIKE', '=', '<', '>', etc.  Note that
-                    if the operator is 'LIKE' and the attribute
-                    is a string, a case-independent search will
-                    be done, treating the search value as a
-                    substring.
+                - element[0] = attribute name
+                - element[1] = logical operator
+                - element[2] = search value
+
+            ... where operator can be any SQL operator, e.g.: 'LIKE', '=',
+            '<', '>', etc.  Note that if the operator is 'LIKE' and the
+            attribute is a string, a case-independent search will be done,
+            treating the search value as a substring.
+        @type  args:  sequence
         """
-        return self.engine.findObjects(self.userid, schemaid, refs, subtypes,
+        return self.engine.findObjects(self.userid, schema_id, refs, subtypes,
                                        args=args)
 
     def xmlrpc_addObjects(self, extracts):
         """xmlrpc method to add objects.
 
-        @type extracts:   list
-        @param extracts:  a list of extracts (for the definition
-                          of extracts, see
-                          L{pangalactic.utils.factory.PgefFactory})
+        @param extracts:  a list of extracts (for the definition of
+            extracts, see L{pangalactic.utils.factory.PgefFactory})
+        @type  extracts:  C{list}
 
-        @rtype:   list
         @return:  a list of extracts:  the objects that were
                   added, with any relevant updates (e.g.,
                   timedate stamps)
+        @rtype:   C{list}
         """
         if extracts:
             return self.engine.addObjects(self.userid, extracts)
@@ -203,12 +207,11 @@
         """
         XML-RPC method to add objects.
 
-        @type extracts:   list
         @param extracts:  a list of extracts (for the definition
                           of extracts, see
                           L{pangalactic.utils.factory.PgefFactory})
+        @type extracts:   C{list}
 
-        @type blobs:  list
         @param blobs: a list of binary objects, which will be
                       saved to files on the server and referenced
                       from FileLink objects.  NOTE:  for each blob,
@@ -218,11 +221,12 @@
                       should occur in the same order in the
                       extracts as their blob occurs in the blobs
                       list.
+        @type blobs:  C{list}
 
-        @rtype:   list
         @return:  a list of extracts:  the objects that were
                   added, with any relevant updates (e.g.,
                   timedate stamps)
+        @rtype:   C{list}
         """
         if extracts and data:
             try:

Index: PanGalactic/pangalactic/repo/chronosynclastic.py
diff -u PanGalactic/pangalactic/repo/chronosynclastic.py:1.40 PanGalactic/pangalactic/repo/chronosynclastic.py:1.41
--- PanGalactic/pangalactic/repo/chronosynclastic.py:1.40	Sat Apr 30 00:52:39 2005
+++ PanGalactic/pangalactic/repo/chronosynclastic.py	Sat May 14 01:49:05 2005
@@ -1,4 +1,4 @@
-# $Id: chronosynclastic.py,v 1.40 2005/04/30 04:52:39 waterbug Exp $
+# $Id: chronosynclastic.py,v 1.41 2005/05/14 05:49:05 waterbug Exp $
 
 """
 The Chronosynclastic Infundibulum:  an asynchronous, ontology-driven
@@ -8,9 +8,9 @@
 (L{pangalactic.core.pgefobject.PgefObject} and its subclasses), the module
 name must be the class name in lower-case.
 
-@version: $Revision: 1.40 $
+@version: $Revision: 1.41 $
 """
-__version__ = "$Revision: 1.40 $"[11:-2]
+__version__ = "$Revision: 1.41 $"[11:-2]
 
 import imp
 import re
@@ -43,9 +43,6 @@
     ontology-driven object-relational mapping and database
     interface.
 
-    @ivar _registry:  A registry instance.
-    @type _registry:  L{pangalactic.meta.registry.PanGalacticRegistry}
-
     @ivar _db_type_map:
         A mapping of the names of PGEF types to their corresponding
         database type names
@@ -65,8 +62,8 @@
         @type  database:  C{str}
 
         @param domains:  names (in the form of a single, space-delimited
-            string) of packages containing domain classes to be added to
-            the registry
+            string) of packages containing domain classes of which the
+            Infundibulum needs to be aware.
         @type  domains:  C{str}
 
         @param init:  if true, and no tables are found, create them
@@ -101,19 +98,19 @@
                         ('r','') AND c.relname ~ '^_'""")
         return [item[0] for item in curs.fetchall()]
 
-    def _tableNameForSchemaId(self, schemaid):
+    def _tableNameForSchemaId(self, schema_id):
         """
         Convert a camelcase L{pangalactic.meta.objectschema.ObjectSchema}
         id into an underscore-delimited, lowercase table name.
 
-        @type schemaid:  string
-        @param schemaid: C{ObjectSchema} id
+        @type schema_id:  string
+        @param schema_id: C{ObjectSchema} id
 
         @rtype:  string
         @return: table name
         """
         patt = re.compile('([A-Z])')
-        l = re.split(patt, schemaid)
+        l = re.split(patt, schema_id)
         parts = l[1:]
         if 0 < len(parts) < 3:
             tname = string.lower(parts[0] + parts[1])
@@ -145,11 +142,11 @@
         tn = tname[1:] # drop initial '_'
         parts = tn.split('_')
         i = 0
-        schemaid = ''
+        schema_id = ''
         while i < len(parts):
-            schemaid = schemaid + parts[i].capitalize()
+            schema_id = schema_id + parts[i].capitalize()
             i += 1
-        return schemaid
+        return schema_id
 
     def killAllHumansErImeanTables(self):
         """
@@ -157,10 +154,10 @@
         L{pangalactic.meta.objectschema.ObjectSchema} instances.
         """
         dropcmds = []
-        invbaseorder = self._registry.schema_base_order
+        invbaseorder = self.schema_base_order
         invbaseorder.reverse()
-        for schemaid in invbaseorder:
-            tname = self._tableNameForSchemaId(schemaid)
+        for schema_id in invbaseorder:
+            tname = self._tableNameForSchemaId(schema_id)
             dropcmds.append("DROP TABLE %s CASCADE;" % tname)
         dropcmds.append("DROP TABLE _passwd CASCADE;")
         dropallcmd = '\n'.join(dropcmds)
@@ -170,12 +167,10 @@
     def createAllTables(self):
         """
         Build all tables of the repository schema (a collection of
-        L{pangalactic.meta.objectschema.ObjectSchema} instances) as
-        configured in the registry
-        (L{pangalactic.meta.registry.PanGalacticRegistry}).
+        L{pangalactic.meta.objectschema.ObjectSchema} instances).
         """
         creates = []
-        for schema_id in self._registry.schema_base_order:
+        for schema_id in self.schema_base_order:
             current_tables = self._getTableNames()
             if self._tableNameForSchemaId(schema_id) not in current_tables:
                 self.createTable(schema_id)
@@ -197,7 +192,7 @@
         curs.execute(cmd)
         return conn.commit()
 
-    def createTable(self, schemaid):
+    def createTable(self, schema_id):
         """
         Create a database table that will accomodate objects with the
         specified object schema.  In order to create a table for a given
@@ -207,9 +202,9 @@
         function takes care of that.  Basically, it finds the "closure" of
         the object schema within the PGEF core ontology.  :)
 
-        @param schemaid:  the id of a
+        @param schema_id:  the id of a
             L{pangalactic.meta.objectschema.ObjectSchema} instance
-        @type  schemaid:  C{str}
+        @type  schema_id:  C{str}
         """
         # Implementation of object schema inheritance of object properties
         # (i.e., object-object relationships) as FK relationships between
@@ -218,19 +213,21 @@
         # (1) create a dict of ALTER TABLE commands by table/schema
         # (2) when a new table is created, get the ALTER TABLE commands of
         # all its bases and modify them to apply to the new table
-        schema = self._registry.object_schemas[schemaid]
+        schema = self.object_schemas[schema_id]
         tname = self._tableNameForSchemaId(schema.id)
         current_tables = self._getTableNames()
         if tname in current_tables:
             return
-        required = Set([schemaid])
+        required = Set([schema_id])
+        print 'schema_id is:', schema_id
         # first check for other schemas referenced by this one, and those
         # referenced by the referenced schemas, etc. ...
         newstuff = Set()
         while 1:
             required = required.union(newstuff)
+            print 'required is:', required
             for id in required:
-                refs = self._registry.object_schemas[id].refd_obj_schemas
+                refs = self.object_schemas[id].refd_obj_schemas
                 newstuff = newstuff.union(refs)
             if required == required.union(newstuff):
                 break
@@ -238,7 +235,7 @@
         while 1:
             required = required.union(newstuff)
             for id in required:
-                baseid = getattr(self._registry.object_schemas[id].base,
+                baseid = getattr(self.object_schemas[id].base,
                                  'id', None)
                 if baseid:
                     newstuff.add(baseid)
@@ -246,10 +243,10 @@
                 break
         creates = []
         required_order = filter(lambda x: x in required,
-                                self._registry.schema_base_order)
+                                self.schema_base_order)
         for schema_id in required_order:
             if self._tableNameForSchemaId(schema_id) not in current_tables:
-                obj_schema = self._registry.object_schemas[schema_id]
+                obj_schema = self.object_schemas[schema_id]
                 create = self._genCreateTableCommands(obj_schema)
                 creates.append(create)
         cmd = '\n\n'.join(creates)
@@ -282,12 +279,13 @@
         # ONLY keyword is used, but we want to allow for cases in which all
         # tables are not created at once.)
         #
-        # To make the chronosynclastic infundibulum portable to databases
+        # To make the Chronosynclastic Infundibulum portable to databases
         # other than PostgreSQL, all that's needed is to implement the
         # inheritance-based query capability in Python as a fallback for
         # databases that don't offer it (shouldn't be that hard, since the
-        # registry already has all the inheritance info for the
-        # C{ObjectSchema} instances from which the tables are generated).
+        # Infundibulum (being a C{PanGalacticRegistry}) already has all the
+        # inheritance info for the C{ObjectSchema} instances from which the
+        # tables are generated).
         tname = self._tableNameForSchemaId(schema.id)
         # initialize the command strings to be returned
         createtable = ''
@@ -393,7 +391,7 @@
         """
         extracts = []
         for r in results:
-            schema = self._registry.object_schemas[r['_object_schema_id']]
+            schema = self.object_schemas[r['_object_schema_id']]
             extr = dict([(a, self._dbcook(r.get(''.join(['_', a]), ''),
                                          schema[a]))
                          for a in schema])
@@ -487,9 +485,9 @@
         """
         recs = []
         for e in extracts:
-            schemaid = e['object_schema_id']
-            schema = self._registry.object_schemas[schemaid]
-            table = self._tableNameForSchemaId(schemaid)
+            schema_id = e['object_schema_id']
+            schema = self.object_schemas[schema_id]
+            table = self._tableNameForSchemaId(schema_id)
             dbuncooked = {}
             for a in schema:
                 if e.get(a, None):
@@ -512,7 +510,7 @@
         """
         return [record[0], record[1]['_pgef_oid']]
 
-    def getObjects(self, requestor, schemaid, refs=0, subtypes=0,
+    def getObjects(self, requestor, schema_id, refs=0, subtypes=0,
                    ret='extracts', **kw):
         """
         An interface through which any set of PgefObject subclass instances
@@ -524,8 +522,8 @@
         @type  requestor:  string
         @param requestor:  the userid of the user making the request.
 
-        @type  schemaid:  string
-        @param schemaid:  the id of a registered
+        @type  schema_id:  string
+        @param schema_id:  the id of a registered
             L{pangalactic.meta.objectschema.ObjectSchema}.
 
         @type  refs:  integer
@@ -560,16 +558,16 @@
         @return:    list of results (type of items depends on value of
             'rtype' param).
         """
-        logmsg = 'getObjects, %s, %s' % (schemaid, str(kw))
+        logmsg = 'getObjects, %s, %s' % (schema_id, str(kw))
         log.msg(logmsg, system='%s:Chronosynclastic' % requestor)
         # for now, refs is "disabled"
         refs = 0
         if kw:
             dbargs = []
             for a in kw.keys():
-                if a in self._registry.object_schemas[schemaid]:
+                if a in self.object_schemas[schema_id]:
                     dbargs.append((a, '=', kw[a]))
-            dres = self._selectByObjectSchema(schemaid, subtypes, *dbargs)
+            dres = self._selectByObjectSchema(schema_id, subtypes, *dbargs)
             dres.addErrback(log.err)
             if refs:
                 dres.addCallback(self._getRefdRowKeys)
@@ -589,7 +587,7 @@
         if ret == 'objects':
             return dres.addCallback(lambda x:  self.rememberAll(x)[0])
 
-    def findObjects(self, requestor, schemaid, refs=1,
+    def findObjects(self, requestor, schema_id, refs=1,
                     subtypes=0, ret='extracts', args=None):
         """
         Search for all instances that match the specified arguments for the
@@ -604,8 +602,8 @@
         @type  requestor:  string
         @param requestor:  the userid of the user making the request.
 
-        @type schemaid:   string
-        @param schemaid:  the id of the class of objects to search for
+        @type schema_id:   string
+        @param schema_id:  the id of the class of objects to search for
             (i.e., a subtype of
             L{pangalactic.core.pgefobject.PgefObject})
 
@@ -651,7 +649,7 @@
             L{pangalactic.core.pgefobject.PgefObject}
         @return:    deferred result of search
         """
-        logmsg = 'search, %s, %s' % (schemaid, str(args[0]))
+        logmsg = 'search, %s, %s' % (schema_id, str(args[0]))
         log.msg(logmsg, system='%s:Chronosynclastic' % requestor)
         dbargs = []
         fulltext = 0
@@ -662,7 +660,7 @@
                     raise TypeError, e
                 elif a[0] == 'fulltext':
                     # do Glimpse search on fulltext string
-                    dft = self._searchFulltext(schemaid,
+                    dft = self._searchFulltext(schema_id,
                                                requestor, a[1])
                     fulltext = 1
                 else:
@@ -671,7 +669,7 @@
             if dbargs:
                 # TODO:  use appropriate views for searches
                 # TODO:  test dbargs and raise an exception if not well-formed.
-                dres = self._selectByObjectSchema(schemaid, subtypes, *dbargs)
+                dres = self._selectByObjectSchema(schema_id, subtypes, *dbargs)
                 dres.addErrback(log.err)
             if fulltext:
                 dres = defer.gatherResults([dres, dft], fireOnOneErrback=1)
@@ -691,13 +689,13 @@
         else:
             raise ValueError('Need some arguments!')
 
-    def _searchFulltext(self, requestor, schemaid, searchstring):
+    def _searchFulltext(self, requestor, schema_id, searchstring):
         """
         Search for all documents of a given type containing the specified
         string.  Default returntype is a unique document identifier string.
 
-        @type schemaid:   string
-        @param schemaid:  the id of a registered
+        @type schema_id:   string
+        @param schema_id:  the id of a registered
             L{pangalactic.meta.objectschema.ObjectSchema}
 
         @type searchstring:   string
@@ -706,7 +704,7 @@
         @rtype:     list of strings
         @return:    either basenames or paths, depending on I{returntype}
         """
-        gs = self._glimpseservers[schemaid]
+        gs = self._glimpseservers[schema_id]
         return gs.search(searchstring)
 
     def _getIntersectionResultSets(self, (resultsets, oids)):
@@ -724,9 +722,9 @@
         if rsets:
             rowkeys = []
             for rs in rsets:
-                schemaid = rs['_object_schema_id']
-                table = self._tableNameForSchemaId(schemaid)
-                schema = self._registry.object_schemas[schemaid]
+                schema_id = rs['_object_schema_id']
+                table = self._tableNameForSchemaId(schema_id)
+                schema = self.object_schemas[schema_id]
                 # first, max_cardinality == 1
                 refs = filter(lambda x:
                                 (x.property_type == 'object'
@@ -761,14 +759,14 @@
         else:
             return []
 
-    def _selectByObjectSchema(self, schemaid, subtypes, *args, **kw):
+    def _selectByObjectSchema(self, schema_id, subtypes, *args, **kw):
         """
         Select results from db by an
         L{pangalactic.meta.objectschema.ObjectSchema}-based set of search
         criteria.
 
-        @type schemaid:  string
-        @param schemaid: id of the C{ObjectSchema} of the instances to be
+        @type schema_id:  string
+        @param schema_id: id of the C{ObjectSchema} of the instances to be
             selected
 
         @type subtypes:  boolean
@@ -793,8 +791,8 @@
             [{colname:value,...}, {colname:value,...}, ...]
         """
         if args:
-            table = self._tableNameForSchemaId(schemaid)
-            logmsg = '_selectByObjectSchema [%s]' % schemaid
+            table = self._tableNameForSchemaId(schema_id)
+            logmsg = '_selectByObjectSchema [%s]' % schema_id
             log.msg(logmsg, system='Chronosynclastic')
             # convert obj attr names to col names
             dbargs = [(''.join(['_', x[0]]), x[1], x[2]) for x in args]
@@ -810,8 +808,8 @@
         @type pgef_oid:  string
         @param pgef_oid: a pgef_oid
 
-        @type schemaid:  string
-        @param schemaid: id of a registered
+        @type schema_id:  string
+        @param schema_id: id of a registered
             L{pangalactic.meta.objectschema.ObjectSchema}
 
         @rtype:   dict
@@ -955,15 +953,15 @@
         # want a list of lists (the r[0] works because there will
         # only be one resultset returned for each RowKey).
 
-    def updateObjects(self, requestor, schemaid, oids, updates,
+    def updateObjects(self, requestor, schema_id, oids, updates,
                       ret='extracts'):
         """
         Update the table for the instance of the specified
         L{pangalactic.meta.objectschema.ObjectSchema} with the specified
         pgef_oid.
 
-        @type schemaid:   string
-        @param schemaid:  id of the C{ObjectSchema} of the table to
+        @type schema_id:   string
+        @param schema_id:  id of the C{ObjectSchema} of the table to
             update.
 
         @type updates:   list or dictionary
@@ -975,7 +973,7 @@
         """
         if not updates or not oids:
             raise ValueError, "Both updates and oids must be non-null"
-        table = self._tableNameForSchemaId(schemaid)
+        table = self._tableNameForSchemaId(schema_id)
         if type(updates) is list:
             realupds = [(''.join(['_', a[0]]), a[1]) for a in updates]
         else:
@@ -990,13 +988,13 @@
         d = self.runOperation(sqlcmd, parms)
         logmsg = 'updateObjects:  %s instance(s) of %s updated.' % (
                                                             len(oids),
-                                                            schemaid)
+                                                            schema_id)
         d.addCallback(lambda x: self._updateObjectsDone(x, requestor, logmsg))
         d.addErrback(lambda e: self.operationError(e, requestor))
         # verify updates by returning updated objects
         d.addCallback(lambda x:
                       self.findObjects(requestor=requestor,
-                                       schemaid=schemaid,
+                                       schema_id=schema_id,
                                        refs=0,
                                        subtypes=0,
                                        ret='extracts',

Index: PanGalactic/pangalactic/utils/xmlrpcinterface.py
diff -u PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.79 PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.80
--- PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.79	Tue May  3 03:08:31 2005
+++ PanGalactic/pangalactic/utils/xmlrpcinterface.py	Sat May 14 01:49:07 2005
@@ -3,10 +3,10 @@
 """
 PanGalactic Client XML-RPC Interfaces
 
-@version: $Revision: 1.79 $
+@version: $Revision: 1.80 $
 """
 
-__version__ = "$Revision: 1.79 $"[11:-2]
+__version__ = "$Revision: 1.80 $"[11:-2]
 
 import base64
 import xmlrpclib
@@ -117,11 +117,13 @@
     """
 
     def __init__(self, host, port, username='', password='',
-                 secure=1, domains='PanGalactic', _registry=None): 
+                 secure=1, domains='PanGalactic', factory=None): 
         # proxyhost=None, proxyport=None ...
         # (we'll worry about proxies later :)
-        self._factory = PanGalacticFactory(_registry=_registry,
-                                           domains=domains)
+        if factory:
+            self.factory = factory
+        else:
+            self.factory = PanGalacticFactory(domains=domains)
         if secure:
             # not tested, according to xmlrpclib docs
             conns = 'https://'
@@ -184,16 +186,16 @@
             #for o in object_list:
             #    print "fileobj", o
             if type(object_list) is list:
-                # deporder = self._factory.getDependencyOrder()
+                # deporder = self.factory.getDependencyOrder()
                 # for o in object_list:
                 #     print o
-                extracts = [self._factory.extract(o) for o in object_list]
+                extracts = [self.factory.extract(o) for o in object_list]
                 newexts = self._RPC.addObjects(extracts)
-                newobjects, object_list = self._factory.rememberAll(newexts, objs)
+                newobjects, object_list = self.factory.rememberAll(newexts, objs)
             else:
-                extracts = [self._factory.extract(o)]
+                extracts = [self.factory.extract(o)]
                 newexts = self._RPC.addObjects(extracts)
-                newobjects, object_list = self._factory.rememberAll(newexts)
+                newobjects, object_list = self.factory.rememberAll(newexts)
         return newobjects
 
     def getObjects(self, classname, fields, refs=0, subtypes=0,
@@ -231,7 +233,7 @@
 
         data = self._RPC.getObjects(classname, refs, subtypes, fields)
         if data:
-            newobjs, objs = self._factory.rememberAll(data, objs)
+            newobjs, objs = self.factory.rememberAll(data, objs)
             return newobjs
         #else:
         #    print "no data"
@@ -243,7 +245,7 @@
         crit = {"id_ns" : context}
         data = self._RPC.getObjects("ObjectSchema", 0, 0, crit)
         if data:
-            newobjs, objs = self._factory.rememberAll(data, [])
+            newobjs, objs = self.factory.rememberAll(data, [])
             return newobjs
 
     def getOrganizations(self, context):
@@ -251,7 +253,7 @@
         crit = {"id_ns" : context}
         data = self._RPC.getObjects('Organization', 0, 0, crit)
         if data:
-            newobjs, objs = self._factory.rememberAll(data, [])
+            newobjs, objs = self.factory.rememberAll(data, [])
             return newobjs
 
     def getLinkedObjs(self, schema_id, criteria, objs=None):
@@ -259,7 +261,7 @@
         newobjs = []
         data = self._RPC.getObjects(schema_id, 1, 0, criteria)
         if data:
-            newobjs, objs = self._factory.rememberAll(data, objs)
+            newobjs, objs = self.factory.rememberAll(data, objs)
         return newobjs
 
     def approveUser(self, user_info):
@@ -297,7 +299,7 @@
                 #print "  #data found", len(data)
                 #for d in data:
                 #    print d["id"], d["description"]
-                objlist, localobjs = self._factory.rememberAll(data, localobjs)
+                objlist, localobjs = self.factory.rememberAll(data, localobjs)
                 #print "len objlist", len(objlist)
                 #print "len localobjs", len(localobjs)
                 for obj in objlist:
@@ -335,7 +337,7 @@
                 #for d in data:
                 #    print d["id"], d["description"]
 
-                objlist, localobjs = self._factory.rememberAll(data, localobjs)
+                objlist, localobjs = self.factory.rememberAll(data, localobjs)
                 for obj in objlist:
                     if obj.__class__.__name__ == classname:
                         retlist.append(obj)

Index: PanGalactic/src/sql/createPgerDbTables.py
diff -u PanGalactic/src/sql/createPgerDbTables.py:1.4 PanGalactic/src/sql/createPgerDbTables.py:1.5
--- PanGalactic/src/sql/createPgerDbTables.py:1.4	Mon Apr 11 00:34:48 2005
+++ PanGalactic/src/sql/createPgerDbTables.py	Sat May 14 01:49:08 2005
@@ -1,22 +1,5 @@
-from pangalactic.repo.chronosynclastic import Infundibulum as I
-# import psycopg
+from pangalactic.repo.chronosynclastic import Infundibulum as Fum
 
 # The Infundibulum now automatically creates all tables if it finds none ...
-i = I()
-
-# i.createAllTables()
-# createcmd = i.createAllTables()
-# dropcmd = i.killAllHumansErImeanTables()
-
-# # DEBUG
-# f = file('junk', 'w')
-# f.write(createcmd)
-# f.close()
-# 
-
-# conn = psycopg.connect(database='pgerdb')
-# curs = conn.cursor()
-# curs.execute(dropcmd)
-# curs.execute(createcmd)
-# conn.commit()
+fum = Fum()
 

From waterbug at step.nasa.gov  Sat May 14 02:03:58 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sat May 14 02:03:59 2005
Subject: [pangalactic-commits] Cruft removal.
Message-ID: <200505140603.j4E63wrN018160@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/utils/orggrid.py 1.4 None

Log message:
Cruft removal.

From waterbug at step.nasa.gov  Sun May 15 04:30:57 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sun May 15 04:30:59 2005
Subject: [pangalactic-commits] PgefObjectGrid is cookin' now!
Message-ID: <200505150830.j4F8UvTs030612@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/core/pgefobject.py 1.14 1.15
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.4 1.5
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.7 1.8
PanGalactic/pangalactic/test/IDTEST 1.114 1.115
PanGalactic/pangalactic/utils/__init__.py 1.17 1.18

Log message:
PgefObjectGrid is cookin' now!
* add/delete columns using grid menu
* drag and drop columns to change order
* save a display config as preference for object type
* reset to the saved preference or the default for that type
Yeehah!  :)

Index: PanGalactic/pangalactic/test/IDTEST
diff -u PanGalactic/pangalactic/test/IDTEST:1.114 PanGalactic/pangalactic/test/IDTEST:1.115
--- PanGalactic/pangalactic/test/IDTEST:1.114	Sat May 14 01:49:06 2005
+++ PanGalactic/pangalactic/test/IDTEST	Sun May 15 04:30:54 2005
@@ -1 +1 @@
-1650
\ No newline at end of file
+1658
\ No newline at end of file

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.4 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.5
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.4	Fri May 13 05:06:33 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Sun May 15 04:30:54 2005
@@ -1,10 +1,10 @@
-# $Id: pgefobjectgrid.py,v 1.4 2005/05/13 09:06:33 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.5 2005/05/15 08:30:54 waterbug Exp $
 """
-PGEF table-based, configurable, object-aware grid.
+The PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.4 $
+@version: $Revision: 1.5 $
 """
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 from pprint import pprint
 
@@ -13,9 +13,15 @@
 import wx.lib.gridmovers as gridmovers
 
 from pangalactic.node.gui.state import state, prefs, displaymaps
+from pangalactic.meta.factory import PanGalacticFactory as Factory
 
 class PgefObjectTable(gridlib.PyGridTableBase):
-    def __init__(self, objs=None):
+    """
+    An object container and configurator; the model underlying a
+    PgefObjectGrid.
+    """
+
+    def __init__(self, objs=None, factory=None):
         """
         Initialize a PgefDataTable.
 
@@ -24,12 +30,19 @@
             For now, the assumption is that all of these instances have the
             same _schema (L{pangalactic.meta.objectschema.ObjectSchema}).
         @type  objs:  C{list or Set}
+
+        @param factory:  the (usually singleton) object factory
+        @type  factory:  L{pangalactic.meta.factory.PanGalacticFactory}
         """
         # TODO:  add capability to handle multiple schemas.  User should be
         # able to pick whether to display them in one table (LCD display
         # mapping) or in multiple tables (possibly a notebook of tables).
         gridlib.PyGridTableBase.__init__(self)
+        self.fac = factory or Factory()
         self.objs = objs or []
+        # if there are preferred displaymaps, use them initially
+        if prefs.get('displaymaps', None):
+            displaymaps = prefs['displaymaps']
         self.setup()
         self._rows = self.GetNumberRows()
         self._cols = self.GetNumberCols()
@@ -38,31 +51,29 @@
         """
         Generate column labels and data based on the current set of objects.
         """
+        # print '- in PgefObjectTable.setup'
         if self.objs:
             self.row_labels = [str(i) for i in range(1, len(self.objs)+1)]
             # assumption that all objs have the same schema (see TODO)
             self.schema = self.objs[0]._schema
-            # if the current displaymap-state is not the default, use it
-            if displaymaps[self.schema.id] != self.schema._default_display_map:
+            # if there is a current displaymap set for the schema, use it
+            if displaymaps[self.schema.id]:
                 self.displaymap = displaymaps[self.schema.id]
-            # otherwise, if there is a preferred displaymap, use it
-            elif prefs.get('displaymaps', None):
-                if prefs['displaymaps'][self.schema.id]:
-                    self.displaymap = prefs['displaymaps'][self.schema.id]
-            # or if neither of these, use the default
+            # if not, use its default displaymap
             else:
                 self.displaymap = self.schema._default_display_map
-            print 'self.displaymap:'
-            pprint(self.displaymap)
+            # print '  - self.displaymap:'
+            # pprint(self.displaymap)
             self.identifiers = [x[0] for x in self.displaymap]
+            # print '  - self.identifiers:', self.identifiers
             self.col_labels = dict([(x[0], x[1]) for x in self.displaymap])
-            # TODO:  use types to determine 'data' to display
-            self.data = [dict([(i, getattr(o, i)) for i in self.identifiers])
-                         for o in self.objs]
-            print 'self.data:'
-            pprint(self.data)
-            print 'self.objs:'
-            print self.objs
+            extracts = [self.fac.extract(o) for o in self.objs]
+            self.data = [dict([(i, e.get(i, '')) for i in self.identifiers])
+                         for e in extracts]
+            # print '  - self.data:'
+            # pprint(self.data)
+            # print '  - self.objs:'
+            # print self.objs
         else:
             self.data = []
             self.schema = None
@@ -75,69 +86,76 @@
     # required methods for the wxPyGridTableBase interface
 
     def GetNumberRows(self):
+        """
+        Get the number of rows in the logical table.
+        """
         return len(self.data)
 
     def GetNumberCols(self):
+        """
+        Get the number of columns in the logical table.
+        """
         return len(self.identifiers)
 
     def IsEmptyCell(self, row, col):
+        """
+        Check whether a cell in the logical table is empty.
+        """
         id = self.identifiers[col]
         return not self.data[row][id]
 
     def GetValue(self, row, col):
+        """
+        Get the value from a cell in the logical table.
+        """
         id = self.identifiers[col]
         return self.data[row][id]
 
     def SetValue(self, row, col, value):
+        """
+        Set the value in a cell in the logical table.
+        """
         id = self.identifiers[col]
         self.data[row][id] = value
 
     def GetColLabelValue(self, col):
         """
-        Get row labels to display.
+        Get the logical table's column labels to display.
         """
         return self.col_labels[self.identifiers[col]]
 
     def GetRowLabelValue(self, row):
         """
-        Get row labels to display.
+        Get the logical table's row labels to display.
         """
         return self.row_labels[row]
 
     def MoveColumn(self, frm, to):
         """
-        Move the column
+        Move a column in the logical table.
         """
+        # print '- in PgefObjectTable.MoveColumn'
+        # print '  - self.identifiers:', self.identifiers
         grid = self.GetView()
         if grid:
-            # move the identifiers
-            old = self.identifiers[frm]
-            del self.identifiers[frm]
-            if to > frm:
-                self.identifiers.insert(to-1, old)
-            else:
-                self.identifiers.insert(to, old)
-            # notify the grid
-            grid.BeginBatch()
-            msg = gridlib.GridTableMessage(
-                    self, gridlib.GRIDTABLE_NOTIFY_COLS_DELETED, frm, 1)
-            grid.ProcessTableMessage(msg)
-            msg = gridlib.GridTableMessage(
-                    self, gridlib.GRIDTABLE_NOTIFY_COLS_INSERTED, to, 1)
-            grid.ProcessTableMessage(msg)
-            grid.EndBatch()
-            # adjust the displaymap
-            oldmap = self.displaymap[frm]
+            # adjust the current displaymap in displaymaps (state)
+            oldmap = displaymaps[self.schema.id][frm]
+            del displaymaps[self.schema.id][frm]
             if to > frm:
-                self.displaymap.insert(to-1, oldmap)
+                displaymaps[self.schema.id].insert(to-1, oldmap)
             else:
-                self.displaymap.insert(to, oldmap)
+                displaymaps[self.schema.id].insert(to, oldmap)
+            # recalculate the table identifiers, etc.
+            self.setup()
+            self.ResetView(grid)
 
     def ResetView(self, grid):
         """
-        (Grid) -> Reset the grid view.   Called to update the grid if
-        rows and/or columns have been added or deleted
+        (Grid) -> Reset the grid view.   Called to update the grid if rows
+        and/or columns have been added or deleted in the underlying model.
         """
+        # print '- in PgefObjectTable.ResetView'
+        # print '  - self.identifiers:', self.identifiers
         grid.BeginBatch()
         for current, new, delmsg, addmsg in [
             (self._rows, self.GetNumberRows(), gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED, gridlib.GRIDTABLE_NOTIFY_ROWS_APPENDED),
@@ -153,13 +171,16 @@
         grid.EndBatch()
         self._rows = self.GetNumberRows()
         self._cols = self.GetNumberCols()
+        grid.AutoSizeColumns(True)
+        grid.AutoSizeRows(True)
         # update the scrollbars and the displayed part of the grid
         grid.AdjustScrollbars()
         grid.ForceRefresh()
+        # print '  - (at end) self.identifiers:', self.identifiers
 
     def UpdateValues(self, grid):
         """
-        Update all displayed values.
+        Update all displayed values in the grid.
         """
         # This sends an event to the grid table to update all of the values
         msg = gridlib.GridTableMessage(self, gridlib.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
@@ -167,7 +188,7 @@
 
     def SortColumn(self, col):
         """
-        col -> sort the data based on the column indexed by col
+        Sort the data in the logical table based on the selected column.
         """
         id = self.identifiers[col]
         _data = []
@@ -185,8 +206,24 @@
 
 
 class PgefObjectGrid(gridlib.Grid):
-    def __init__(self, parent, objs=None):
-        gridlib.Grid.__init__(self, parent, -1)
+    """
+    The PGEF table-based, configurable, object-aware grid.
+    """
+
+    def __init__(self, parent, objs=None, **kw):
+        """
+        Initialize a PgefObjectGrid instance.
+
+        @param parent:  the parent widget
+        @type  parent:  C{wx.Something}
+
+        @param objs:  a collection (set or list) of instances of
+            L{pangalactic.core.pgefobject.PgefObject}
+            For now, the assumption is that all of these instances have the
+            same _schema (L{pangalactic.meta.objectschema.ObjectSchema}).
+        @type  objs:  C{list or Set}
+        """
+        gridlib.Grid.__init__(self, parent, -1, **kw)
         wx.ToolTip_Enable(True)
         self._table = PgefObjectTable(objs)
         # The second parameter means that the grid is to take ownership of the
@@ -195,9 +232,59 @@
         self.SetTable(self._table)
         self.objs = self._table.objs
         self.schema = self._table.schema
-        self.identifiers = self._table.identifiers
+        self.AutoSizeColumns(True)
+        self.AutoSizeRows(True)
         self.bindEvents()
 
+    # properties (for convenience)
+
+    def get_schema(self):
+        return self._table.schema
+
+    def set_schema(self, val):
+        self._table.schema = val
+
+    def del_schema(self):
+        raise TypeError, 'schema attribute cannot be deleted.'
+
+    schema = property(get_schema, set_schema, del_schema, 'schema')
+
+    def get_objs(self):
+        return self._table.objs
+
+    def set_objs(self, val):
+        self._table.objs = val
+
+    def del_objs(self):
+        raise TypeError, 'objs attribute cannot be deleted.'
+
+    objs = property(get_objs, set_objs, del_objs, 'objs')
+
+    def get_ids(self):
+        return self._table.identifiers
+
+    def set_ids(self, val):
+        self._table.identifiers = val
+
+    def del_ids(self):
+        raise TypeError, 'identifiers attribute cannot be deleted.'
+
+    def get_col_labels(self):
+        return self._table.col_labels
+
+    def set_col_labels(self, val):
+        raise TypeError, 'col_labels are read-only from grid.'
+
+    def del_col_labels(self):
+        raise TypeError, 'col_labels attribute cannot be deleted.'
+
+    col_labels = property(get_col_labels, set_col_labels,
+                          del_col_labels, 'col_labels')
+
+    # end of properties
+
+    identifiers = property(get_ids, set_ids, del_ids, 'identifiers')
+
     def reset(self):
         """
         Reset the view -- called when the current set of objects and/or the
@@ -207,9 +294,11 @@
         self._table.ResetView(self)
 
     def onLabelRightClick(self, evt):
-        # Did we click on a row, a column, or the upper left corner?
+        """
+        Select a grid popup menu or a column popup menu.
+        """
         if not self.objs:
-            print "No objects -- can't operate on empty grid."
+            print "No objects -- can't operate on an empty grid."
             return
         row, col = evt.GetRow(), evt.GetCol()
         if (row, col) == (-1,-1): self.gridPopup(evt)
@@ -222,11 +311,14 @@
         frm = evt.GetMoveColumn()       # Column being moved
         to = evt.GetBeforeColumn()      # Before which column to insert
         self._table.MoveColumn(frm,to)
+        self.reset()
 
     def gridPopup(self, evt):
         """
-        Show grid menu when upper left label area is right-clicked.
+        Display the grid popup menu when the upper left label area is
+        right-clicked.
         """
+        # print '- in PgefObjectGrid.gridPopup'
         self.grid_menu = wx.Menu()
         self.visible_cols_menu = wx.Menu()
         self.grid_menu.AppendMenu(-1, 'Visible Columns',
@@ -235,33 +327,54 @@
         self.visible_cols = {}
         labels = [self.schema[i].display_name for i in self.schema]
         labels.sort()
-        label_id = dict([(self.schema[i].display_name, i) for i in self.schema])
+        label_ids = dict([(self.schema[i].display_name, i) for i in self.schema])
+        # first, set checked menu items for visible columns
+        for id in self.identifiers:
+            # print '  - adding checked label:', label
+            label = self.schema[id].display_name
+            labels.remove(label)
+            self.visible_cols[label] = self.visible_cols_menu.Append(
+                                                       -1, label,
+                                                       label_ids[label],
+                                                        wx.ITEM_CHECK)
+            self.visible_cols[label].Check(True)
+            self.Bind(wx.EVT_MENU, self.onSetVisibleCols,
+                      self.visible_cols[label])
+        self.visible_cols_menu.AppendSeparator()
+        # then, set items for remaining (unchecked) attributes
         for label in labels:
+            # print '  - adding label:', label
             self.visible_cols[label] = self.visible_cols_menu.Append(
                                                        -1, label,
-                                                       label_id[label],
+                                                       label_ids[label],
                                                         wx.ITEM_CHECK)
-            if label_id[label] in self.identifiers:
-                self.visible_cols[label].Check(True)
-        self.set_pref = self.grid_menu.Append(-1, 'Set As Preference',
-                     'Set as your preferred columns to display for %s' % (
-                                                          self.schema.id),
-                     wx.ITEM_NORMAL)
-        all_labels = [self.schema[i].display_name
-                      for i in self.schema]
-        for label in all_labels:
             self.Bind(wx.EVT_MENU, self.onSetVisibleCols,
                       self.visible_cols[label])
-        self.Bind(wx.EVT_MENU, self.onSetPrefDisplaymap,
-                      self.set_pref)
+        self.save_pref = self.grid_menu.Append(-1, 'Save As Preference',
+              'Use the current column config as your preference for %s' % (
+                                                          self.schema.id),
+                     wx.ITEM_NORMAL)
+        self.Bind(wx.EVT_MENU, self.onSaveAsPrefDisplaymap,
+                      self.save_pref)
+        self.reset_pref = self.grid_menu.Append(-1, 'Reset To Preference',
+                     'Reset visible columns per your preference for %s' % (
+                                                          self.schema.id),
+                     wx.ITEM_NORMAL)
+        self.Bind(wx.EVT_MENU, self.onResetPerPrefDisplaymap,
+                      self.reset_pref)
+        self.reset_default = self.grid_menu.Append(-1, 'Reset To Default',
+                         'Reset visible columns per the default for %s' % (
+                                                          self.schema.id),
+                     wx.ITEM_NORMAL)
+        self.Bind(wx.EVT_MENU, self.onResetPerDefaultDisplaymap,
+                      self.reset_default)
         self.PopupMenu(self.grid_menu, evt.GetPosition())
         self.grid_menu.Destroy()
         self.reset()
 
     def colPopup(self, col, evt):
         """
-        (col, evt) -> display a popup menu when a column label is right
-        clicked.
+        Display the column popup menu when a column label is right clicked.
         """
         x = self.GetColSize(col)/2
         menu = wx.Menu()
@@ -283,47 +396,85 @@
 
     def bindEvents(self):
         """
-        Bind all events to handlers.
+        Bind misc events to handlers.
         """
-        # Enable Column moving
         gridmovers.GridColMover(self)
         self.Bind(gridmovers.EVT_GRID_COL_MOVE, self.onColMove, self)
         self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_CLICK, self.onLabelRightClick)
 
     def onSetVisibleCols(self, evt):
         """
-        Reset the choice of columns to be displayed in the grid.
+        Add or delete a column to/from the grid in response to a grid menu
+        selection.
         """
-        print ' - onSetVisibleCols'
-        displaymaps[self.schema.id] = []
+        # print ' - onSetVisibleCols'
         properties = dict([(self.schema[a].display_name, self.schema[a])
                             for a in self.schema])
+        # find out if a display name was just checked
+        dn_checked = ''
         for dn in properties:
-            if self.visible_cols[dn].IsChecked():
+            if (self.visible_cols[dn].IsChecked()
+                and not dn in self.col_labels.values()):
+                # add its column to the end (okay, might be better at the
+                # beginning ... we'll see what people say)
+                dn_checked = dn
                 displaymaps[self.schema.id].append(
                     [properties[dn].id,
                      properties[dn].display_name,
                      properties[dn].range])
+        # or if something was unchecked
+        if not dn_checked:
+            displaymaps[self.schema.id] = []
+            for dn in [self.col_labels[i] for i in self.identifiers]:
+                if self.visible_cols[dn].IsChecked():
+                    displaymaps[self.schema.id].append(
+                        [properties[dn].id,
+                         properties[dn].display_name,
+                         properties[dn].range])
 
-    def onSetPrefDisplaymap(self, evt):
+    def onSaveAsPrefDisplaymap(self, evt):
         """
-        Set the current displaymap as the user's preferred displaymap for
+        Save the current displaymap as the user's preferred displaymap for
         the current object schema.
         """
-        print ' - onSetPrefDisplaymap'
-        prefs['displaymaps'][self.schema.id] = self.displaymap
+        print ' - onSavePrefDisplaymap'
+        prefs['displaymaps'][self.schema.id] = list(displaymaps[self.schema.id])
+
+    def onResetPerPrefDisplaymap(self, evt):
+        """
+        Reset the current displaymap per the user's preferred displaymap
+        for the current object schema.
+        """
+        print ' - onResetPerPrefDisplaymap'
+        if prefs['displaymaps'].get(self.schema.id, None):
+            displaymaps[self.schema.id] = prefs['displaymaps'][self.schema.id]
+        else:
+            print 'No pref set for', self.schema.id
+
+    def onResetPerDefaultDisplaymap(self, evt):
+        """
+        Reset the current displaymap per the default displaymap for the
+        current object schema.
+        """
+        print ' - onResetPerDefaultDisplaymap'
+        displaymaps[self.schema.id] = self.schema._default_display_map
+
+###############
+# Testing stuff
+###############
 
+from pangalactic.core.pgefobject import PgefObject as PO
+from pangalactic.test.utils4test import popTestData
+testobjs = [PO(id='spam'), PO(id='eggs'), PO(id='ni'), PO(id='shrubbery'),
+            PO(id='Ekke ekke ekke ptang zoo boing')]
+for po in testobjs:  popTestData(po)
 
 class TestFrame(wx.Frame):
     def __init__(self, parent):
         wx.Frame.__init__(self, parent, -1,
                           "PgefGrid", size=(640,480))
         # make up an object for testing ...
-        from pangalactic.core.pgefobject import PgefObject as PO
-        from pangalactic.test.utils4test import popTestData
-        objs = [PO(id='foo'), PO(id='bar'), PO(id='baz')]
-        for po in objs:  popTestData(po)
-        grid = PgefObjectGrid(self, objs)
+        grid = PgefObjectGrid(self, testobjs)
 
 
 if __name__ == '__main__':

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.7 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.8
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.7	Sat Apr 30 14:45:25 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Sun May 15 04:30:54 2005
@@ -1,13 +1,14 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 
 import  wx
 from pangalactic.node.gui.widgets.pgeftree import PgefTree
+from pangalactic.node.gui.widgets.pgefobjectgrid import PgefObjectGrid, testobjs
 
 class PgxnPanes(wx.Panel):
     """
@@ -114,9 +115,9 @@
     def __init__(self, parent, id, views=None):
         wx.Notebook.__init__(self, parent, id=id, pos=wx.DefaultPosition,
                              size=wx.Size(600,600))
-        self.views = views
+        self.views = views or {'Models' : None}
         self.trees = {}
-        if not views:
+        if not self.views:
             win = wx.Panel(self)
             win.SetBackgroundColour('WHITE')
             st = wx.StaticText(win, -1, noviewstext,
@@ -125,8 +126,10 @@
         else:
             for view in self.views:
                 win = wx.Panel(self)
-                win.SetBackgroundColour('WHITE')
+                # win.SetBackgroundColour('WHITE')
                 # do stuff to add a plug-in view
+                self.views[view] = PgefObjectGrid(win, testobjs,
+                                                  size=(640,480))
                 self.AddPage(win, view)
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)

Index: PanGalactic/pangalactic/utils/__init__.py
diff -u PanGalactic/pangalactic/utils/__init__.py:1.17 PanGalactic/pangalactic/utils/__init__.py:1.18
--- PanGalactic/pangalactic/utils/__init__.py:1.17	Mon Mar 21 17:06:07 2005
+++ PanGalactic/pangalactic/utils/__init__.py	Sun May 15 04:30:55 2005
@@ -29,7 +29,6 @@
 "proxyclass",
 "proxydialog_wdr",
 "pystrptime",
-"registry",
 "reportfonts",
 "reportlab_blocks",
 "serverclass",
@@ -41,5 +40,4 @@
 "usersearchframe",
 "usersearch_wdr",
 "utils",
-"xmlrpcinterface",
-"xmltreewidget"]
+"xmlrpcinterface"]

Index: PanGalactic/pangalactic/core/pgefobject.py
diff -u PanGalactic/pangalactic/core/pgefobject.py:1.14 PanGalactic/pangalactic/core/pgefobject.py:1.15
--- PanGalactic/pangalactic/core/pgefobject.py:1.14	Sat Apr 30 14:45:23 2005
+++ PanGalactic/pangalactic/core/pgefobject.py	Sun May 15 04:30:53 2005
@@ -1,4 +1,4 @@
-# $Id: pgefobject.py,v 1.14 2005/04/30 18:45:23 waterbug Exp $
+# $Id: pgefobject.py,v 1.15 2005/05/15 08:30:53 waterbug Exp $
 
 """
 PgefObject is the Mother of all PanGalactic objects.
@@ -31,9 +31,9 @@
 Note that PgefObject and its subclasses do not (yet) implement all of these
 characteristics, but that is their ultimate goal.
 
-@version: $Revision: 1.14 $
+@version: $Revision: 1.15 $
 """
-__version__ = "$Revision: 1.14 $"[11:-2]
+__version__ = "$Revision: 1.15 $"[11:-2]
 
 import copy
 from mx import DateTime
@@ -300,7 +300,7 @@
         Property(
             id='owner',
             id_ns=PGEF_URI,
-            name='PGER Owner',
+            name='Owner',
             range='Person',
             property_type='object',
             description="""
@@ -329,7 +329,7 @@
         Property(
             id='create_datetime',
             id_ns=PGEF_URI,
-            name='Created',
+            name='Create Date-Time',
             range='DateTime',
             description="""
             [pgef:create_datetime] Date-time of creation of the object.
@@ -347,7 +347,7 @@
         Property(
             id='mod_datetime',
             id_ns=PGEF_URI,
-            name='Modified',
+            name='Last Mod Date-Time',
             range='DateTime',
             description="""
             [pgef:mod_datetime] Date-time of last modification of the

From waterbug at step.nasa.gov  Sun May 15 04:49:36 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sun May 15 04:49:38 2005
Subject: [pangalactic-commits] Small typos.
Message-ID: <200505150849.j4F8na9s030876@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.5 1.6

Log message:
Small typos.

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.5 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.6
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.5	Sun May 15 04:30:54 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Sun May 15 04:49:35 2005
@@ -1,10 +1,10 @@
-# $Id: pgefobjectgrid.py,v 1.5 2005/05/15 08:30:54 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.6 2005/05/15 08:49:35 waterbug Exp $
 """
 The PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 from pprint import pprint
 
@@ -269,6 +269,8 @@
     def del_ids(self):
         raise TypeError, 'identifiers attribute cannot be deleted.'
 
+    identifiers = property(get_ids, set_ids, del_ids, 'identifiers')
+
     def get_col_labels(self):
         return self._table.col_labels
 
@@ -283,8 +285,6 @@
 
     # end of properties
 
-    identifiers = property(get_ids, set_ids, del_ids, 'identifiers')
-
     def reset(self):
         """
         Reset the view -- called when the current set of objects and/or the
@@ -295,7 +295,7 @@
 
     def onLabelRightClick(self, evt):
         """
-        Select a grid popup menu or a column popup menu.
+        Select the grid popup menu or a column popup menu.
         """
         if not self.objs:
             print "No objects -- can't operate on an empty grid."

From waterbug at step.nasa.gov  Sun May 15 23:18:01 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sun May 15 23:18:03 2005
Subject: [pangalactic-commits] PgefObjectGrid now works with PanGalaxian (NG)
Message-ID: <200505160318.j4G3I1JX001055@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/TODO 1.24 1.25
PanGalactic/pangalactic/node/pangalaxian_new.py 1.8 1.9
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.6 1.7
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.8 1.9

Log message:
PgefObjectGrid now works with PanGalaxian (NG)

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.6 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.7
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.6	Sun May 15 04:49:35 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Sun May 15 23:18:00 2005
@@ -1,10 +1,10 @@
-# $Id: pgefobjectgrid.py,v 1.6 2005/05/15 08:49:35 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.7 2005/05/16 03:18:00 waterbug Exp $
 """
 The PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 from pprint import pprint
 
@@ -234,6 +234,7 @@
         self.schema = self._table.schema
         self.AutoSizeColumns(True)
         self.AutoSizeRows(True)
+        self.EnableEditing(False)
         self.bindEvents()
 
     # properties (for convenience)

Index: PanGalactic/TODO
diff -u PanGalactic/TODO:1.24 PanGalactic/TODO:1.25
--- PanGalactic/TODO:1.24	Sat May 14 01:49:02 2005
+++ PanGalactic/TODO	Sun May 15 23:17:58 2005
@@ -8,10 +8,6 @@
 ---------------------------------------------------
 To Do Before Release (in rough order of precedence)
 ---------------------------------------------------
-[*] NEW!  PgefObjectGrid widget (very close to completion)
-    - draggable columns
-    - popup menu for selection of visible columns from object properties
-    - menu choice to set preferred displaymap for class from current config
 [-] NEW!  *REPLACE* ItemEditFrame with late-bound object viewer/editors
     - new editor concept for all objs:  use object viewer as the editor
     - 'links' to objects from object Properties (related objs may or may
@@ -34,6 +30,9 @@
     - "all" tree view to show all objs assoc. with each node
     - explicit assembly (reified acu's and interfaces, w/icons)
     - drop/drag assembly should activate 'Save' button
+[-] PgefObjectGrid widget
+    - fix handling of object-valued columns
+    - enable saving of named displaymaps
 [*] debug commit function for objs with files
 [-] get ExpressEngine process protocol working
 [*] complete STEP file import/mapping function
@@ -108,6 +107,10 @@
 ----
 DONE
 ----
+[+] NEW!  PgefObjectGrid widget
+    - draggable columns
+    - popup menu for selection of visible columns from object properties
+    - menu choice to set preferred displaymap for class from current config
 [+] fix display map management
     - use state for displayconfig persistence (for grids, etc.)
 [+] simplified OSEB import/export
@@ -117,5 +120,5 @@
     - one-many (aggregate attrs)
 
 --------------------------------------------------------------------------
-# $Id: TODO,v 1.24 2005/05/14 05:49:02 waterbug Exp $
+# $Id: TODO,v 1.25 2005/05/16 03:17:58 waterbug Exp $
 

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.8 PanGalactic/pangalactic/node/pangalaxian_new.py:1.9
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.8	Thu May 12 20:29:50 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Sun May 15 23:17:59 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.8 2005/05/13 00:29:50 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.9 2005/05/16 03:17:59 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.8 $
+@version: $Revision: 1.9 $
 """
-__version__ = "$Revision: 1.8 $"[11:-2]
+__version__ = "$Revision: 1.9 $"[11:-2]
 
 # Python core modules
 import sys
@@ -253,6 +253,7 @@
         _icon = wx.EmptyIcon()
         _icon.CopyFromBitmap(toolkitimages.getPanGalacticon16Bitmap())
         self.SetIcon(_icon)
+        # add status bar, tool bar, and main window
         self.statusbar = PgxnStatusBar(self)
         self.SetStatusBar(self.statusbar)
         self.toolbar = PgxnToolBar(self)

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.8 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.9
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.8	Sun May 15 04:30:54 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Sun May 15 23:18:00 2005
@@ -1,9 +1,9 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.8 $
+@version: $Revision: 1.9 $
 """
-__version__ = "$Revision: 1.8 $"[11:-2]
+__version__ = "$Revision: 1.9 $"[11:-2]
 
 
 import  wx
@@ -31,12 +31,12 @@
         minor.treebook = PgxnTreeBook(minor, -1)
         minor.treebook.Fit()
         self.minorpane = minor
-        self.majorpane = wx.Panel(self, -1, style=wx.SUNKEN_BORDER)
-        # self.majorpane.SetBackgroundColour('GREEN')  # DEBUGGING
-        self.notebook = PgxnNotebook(self.majorpane, -1)
-        self.notebook.Fit()
+        # self.majorpane = wx.ScrolledWindow(self, -1, style=wx.SUNKEN_BORDER)
+        # self.majorpane.SetAutoLayout(True)
+        self.majorpane = PgxnNotebook(self, -1)
         self.Bind(wx.EVT_SASH_DRAGGED, self.onSashDrag, self.minorpane)
         self.Bind(wx.EVT_SIZE, self.onSize)
+        self.sizeChanged = True
 
     def onSashDrag(self, event):
         self.minorpane.SetDefaultSize((event.GetDragRect().width, 1000))
@@ -115,8 +115,10 @@
     def __init__(self, parent, id, views=None):
         wx.Notebook.__init__(self, parent, id=id, pos=wx.DefaultPosition,
                              size=wx.Size(600,600))
-        self.views = views or {'Models' : None}
-        self.trees = {}
+        # TODO:  views should come from names of object types (schemas)
+        # used by the current project
+        self.views = views or ['Models']
+        self.grids = {}
         if not self.views:
             win = wx.Panel(self)
             win.SetBackgroundColour('WHITE')
@@ -125,12 +127,12 @@
             self.AddPage(win, '[system views]')
         else:
             for view in self.views:
-                win = wx.Panel(self)
-                # win.SetBackgroundColour('WHITE')
-                # do stuff to add a plug-in view
-                self.views[view] = PgefObjectGrid(win, testobjs,
+                self.grids[view] = PgefObjectGrid(self, testobjs,
                                                   size=(640,480))
-                self.AddPage(win, view)
+                box = wx.BoxSizer(wx.HORIZONTAL)
+                box.Add(self.grids[view], 0, wx.ALL)
+                self.AddPage(self.grids[view], view)
+                # self.grids[view].Fit()
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
 

From waterbug at step.nasa.gov  Sun May 15 23:23:27 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sun May 15 23:23:30 2005
Subject: [pangalactic-commits] Pretty things up a bit.
Message-ID: <200505160323.j4G3NRCo001085@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.9 1.10

Log message:
Pretty things up a bit.

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.9 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.10
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.9	Sun May 15 23:18:00 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Sun May 15 23:23:26 2005
@@ -1,9 +1,9 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.9 $
+@version: $Revision: 1.10 $
 """
-__version__ = "$Revision: 1.9 $"[11:-2]
+__version__ = "$Revision: 1.10 $"[11:-2]
 
 
 import  wx
@@ -26,13 +26,9 @@
         minor.SetOrientation(wx.LAYOUT_VERTICAL)
         minor.SetAlignment(wx.LAYOUT_LEFT)
         minor.SetSashVisible(wx.SASH_RIGHT, True)
-        # add a trees panel where decomp trees will live
-#         minor.treespanel = PgxnTreesPanel(minor)
         minor.treebook = PgxnTreeBook(minor, -1)
         minor.treebook.Fit()
         self.minorpane = minor
-        # self.majorpane = wx.ScrolledWindow(self, -1, style=wx.SUNKEN_BORDER)
-        # self.majorpane.SetAutoLayout(True)
         self.majorpane = PgxnNotebook(self, -1)
         self.Bind(wx.EVT_SASH_DRAGGED, self.onSashDrag, self.minorpane)
         self.Bind(wx.EVT_SIZE, self.onSize)
@@ -80,7 +76,9 @@
             for view in self.views:
                 win = wx.Panel(self)
                 win.SetBackgroundColour('WHITE')
-                self.trees[view] = PgefTree(win, -1, datamanager=None, allowdragndrop=False)
+                self.trees[view] = PgefTree(win, -1,
+                                            datamanager=None,
+                                            allowdragndrop=False)
                 self.AddPage(win, view)
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
@@ -104,7 +102,8 @@
 This notebook holds various views of a system.
 
 The names of the views available for a given system are found
-on the labels of the notebook's tabs."""
+on the labels of the notebook's tabs.
+"""
 
 
 class PgxnNotebook(wx.Notebook):
@@ -116,7 +115,7 @@
         wx.Notebook.__init__(self, parent, id=id, pos=wx.DefaultPosition,
                              size=wx.Size(600,600))
         # TODO:  views should come from names of object types (schemas)
-        # used by the current project
+        # used by the current project ... or something.
         self.views = views or ['Models']
         self.grids = {}
         if not self.views:
@@ -129,10 +128,7 @@
             for view in self.views:
                 self.grids[view] = PgefObjectGrid(self, testobjs,
                                                   size=(640,480))
-                box = wx.BoxSizer(wx.HORIZONTAL)
-                box.Add(self.grids[view], 0, wx.ALL)
                 self.AddPage(self.grids[view], view)
-                # self.grids[view].Fit()
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
 

From waterbug at step.nasa.gov  Mon May 16 04:07:32 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 16 04:07:34 2005
Subject: [pangalactic-commits] Set ToolTips off by default
Message-ID: <200505160807.j4G87W6b005073@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.9 1.10

Log message:
Set ToolTips off by default

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.9 PanGalactic/pangalactic/node/pangalaxian_new.py:1.10
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.9	Sun May 15 23:17:59 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Mon May 16 04:07:30 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.9 2005/05/16 03:17:59 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.10 2005/05/16 08:07:30 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.9 $
+@version: $Revision: 1.10 $
 """
-__version__ = "$Revision: 1.9 $"[11:-2]
+__version__ = "$Revision: 1.10 $"[11:-2]
 
 # Python core modules
 import sys
@@ -138,7 +138,6 @@
         self.__do_layout()
         # end wxGlade
         ###################################################
-        # Read saved state and prefs from files
         wx.InitAllImageHandlers()
         # Make sure there's a tmp dir here
         if not os.path.exists('tmp'):
@@ -234,7 +233,7 @@
         # self.GodMode = None
         showloginconfirm = prefs.get('ShowLoginConfirmed', True)
         self.options_loginconfirm.Check(bool(int(showloginconfirm)))
-        show_tooltips = prefs.get("ShowToolTips", True)
+        show_tooltips = prefs.get("ShowToolTips", False)
         if show_tooltips:
             wx.ToolTip_Enable(True)
             self.options_tooltips.Check(True)

From waterbug at step.nasa.gov  Mon May 16 04:12:45 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 16 04:12:46 2005
Subject: [pangalactic-commits] Incremental improvements to PgefObjectGrid ...
Message-ID: <200505160812.j4G8Cjux005283@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.7 1.8

Log message:
Incremental improvements to PgefObjectGrid ...
* right click on column label pops up its definition
* left double-click on column label sorts on that column
* grid pop-up menu pops up closer to mouse position

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.7 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.8
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.7	Sun May 15 23:18:00 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Mon May 16 04:12:44 2005
@@ -1,10 +1,10 @@
-# $Id: pgefobjectgrid.py,v 1.7 2005/05/16 03:18:00 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.8 2005/05/16 08:12:44 waterbug Exp $
 """
 The PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 from pprint import pprint
 
@@ -186,7 +186,7 @@
         msg = gridlib.GridTableMessage(self, gridlib.GRIDTABLE_REQUEST_VIEW_GET_VALUES)
         grid.ProcessTableMessage(msg)
 
-    def SortColumn(self, col):
+    def SortOnColumn(self, col):
         """
         Sort the data in the logical table based on the selected column.
         """
@@ -224,7 +224,6 @@
         @type  objs:  C{list or Set}
         """
         gridlib.Grid.__init__(self, parent, -1, **kw)
-        wx.ToolTip_Enable(True)
         self._table = PgefObjectTable(objs)
         # The second parameter means that the grid is to take ownership of the
         # table and will destroy it when done.  Otherwise you would need to keep
@@ -236,6 +235,21 @@
         self.AutoSizeRows(True)
         self.EnableEditing(False)
         self.bindEvents()
+        tooltip = '\n'.join(['This is a PGEF Object Grid',
+                  '- each row in the table represents an object.',
+                  '- right-click in the upper left corner for a menu',
+                  '  that can be used to add or delete columns.'])
+        self.SetToolTip(wx.ToolTip(tooltip))
+
+    def bindEvents(self):
+        """
+        Bind misc events to handlers.
+        """
+        gridmovers.GridColMover(self)
+        self.Bind(gridmovers.EVT_GRID_COL_MOVE, self.onColMove, self)
+        self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_CLICK, self.onLabelRightClick)
+        self.Bind(gridlib.EVT_GRID_LABEL_LEFT_DCLICK, self.sortOnColumn)
+        self.Bind(gridlib.EVT_GRID_LABEL_LEFT_CLICK, self.noSelect)
 
     # properties (for convenience)
 
@@ -294,6 +308,12 @@
         self._table.setup()
         self._table.ResetView(self)
 
+    def noSelect(self, evt):
+        """
+        Deselect any current selection.
+        """
+        self.ClearSelection()
+
     def onLabelRightClick(self, evt):
         """
         Select the grid popup menu or a column popup menu.
@@ -303,7 +323,7 @@
             return
         row, col = evt.GetRow(), evt.GetCol()
         if (row, col) == (-1,-1): self.gridPopup(evt)
-        elif row == -1: self.colPopup(col, evt)
+        elif row == -1: self.colPopupHelp(col, evt)
 
     def onColMove(self,evt):
         """
@@ -369,39 +389,32 @@
                      wx.ITEM_NORMAL)
         self.Bind(wx.EVT_MENU, self.onResetPerDefaultDisplaymap,
                       self.reset_default)
-        self.PopupMenu(self.grid_menu, evt.GetPosition())
+        print 'position:', evt.GetPosition()
+        epos = evt.GetPosition()
+        pos = (epos[0] - 80, epos[1] - 30)
+        self.PopupMenu(self.grid_menu, pos)
         self.grid_menu.Destroy()
         self.reset()
 
-    def colPopup(self, col, evt):
+    def colPopupHelp(self, col, evt):
         """
-        Display the column popup menu when a column label is right clicked.
-        """
-        x = self.GetColSize(col)/2
-        menu = wx.Menu()
-        id1 = wx.NewId()
-        sortID = wx.NewId()
-        xo, yo = evt.GetPosition()
-        self.SelectCol(col)
-        cols = self.GetSelectedCols()
-        self.Refresh()
-        menu.Append(sortID, "Sort Column")
-        def sort(event, self=self, col=col):
-            self._table.SortColumn(col)
-            self.reset()
-        if len(cols) == 1:
-            self.Bind(wx.EVT_MENU, sort, id=sortID)
-        self.PopupMenu(menu, (xo, 0))
-        menu.Destroy()
-        return
-
-    def bindEvents(self):
+        Display the column popup help when a column label is right clicked.
         """
-        Bind misc events to handlers.
-        """
-        gridmovers.GridColMover(self)
-        self.Bind(gridmovers.EVT_GRID_COL_MOVE, self.onColMove, self)
-        self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_CLICK, self.onLabelRightClick)
+        id = self.identifiers[col]
+        prop = self.schema[id]
+        helptext = '\n'.join(['* '+prop.display_name+' *',
+                              prop.description])
+        helpwin = ColHelpPopup(self, helptext)
+        obj = evt.GetEventObject()
+        pos = obj.ClientToScreen((0, 0))
+        helpwin.Position(pos, (50, 50))
+        helpwin.Popup()
+
+    def sortOnColumn(self, evt):
+        col = evt.GetCol()
+        self._table.SortOnColumn(col)
+        self.reset()
+        self.ClearSelection()
 
     def onSetVisibleCols(self, evt):
         """
@@ -438,7 +451,6 @@
         Save the current displaymap as the user's preferred displaymap for
         the current object schema.
         """
-        print ' - onSavePrefDisplaymap'
         prefs['displaymaps'][self.schema.id] = list(displaymaps[self.schema.id])
 
     def onResetPerPrefDisplaymap(self, evt):
@@ -460,6 +472,25 @@
         print ' - onResetPerDefaultDisplaymap'
         displaymaps[self.schema.id] = self.schema._default_display_map
 
+
+class ColHelpPopup(wx.PopupTransientWindow):
+    """
+    Popup help window containing the definition of the property shown in
+    the selected column.
+    """
+    def __init__(self, parent, helptext):
+        wx.PopupTransientWindow.__init__(self, parent, wx.SIMPLE_BORDER)
+        panel = wx.Panel(self, -1)
+        panel.SetBackgroundColour(wx.WHITE)
+        st = wx.StaticText(panel, -1, helptext, pos=(10,10))
+        sz = st.GetBestSize()
+        panel.SetSize((sz.width+20, sz.height+20))
+        self.SetSize(panel.GetSize())
+
+    def ProcessLeftDown(self, evt):
+        return False
+
+
 ###############
 # Testing stuff
 ###############

From waterbug at step.nasa.gov  Mon May 16 04:13:22 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 16 04:13:24 2005
Subject: [pangalactic-commits] Improvements to definitions.
Message-ID: <200505160813.j4G8DM8j005323@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/core/pgefobject.py 1.15 1.16

Log message:
Improvements to definitions.

Index: PanGalactic/pangalactic/core/pgefobject.py
diff -u PanGalactic/pangalactic/core/pgefobject.py:1.15 PanGalactic/pangalactic/core/pgefobject.py:1.16
--- PanGalactic/pangalactic/core/pgefobject.py:1.15	Sun May 15 04:30:53 2005
+++ PanGalactic/pangalactic/core/pgefobject.py	Mon May 16 04:13:20 2005
@@ -1,4 +1,4 @@
-# $Id: pgefobject.py,v 1.15 2005/05/15 08:30:53 waterbug Exp $
+# $Id: pgefobject.py,v 1.16 2005/05/16 08:13:20 waterbug Exp $
 
 """
 PgefObject is the Mother of all PanGalactic objects.
@@ -31,9 +31,9 @@
 Note that PgefObject and its subclasses do not (yet) implement all of these
 characteristics, but that is their ultimate goal.
 
-@version: $Revision: 1.15 $
+@version: $Revision: 1.16 $
 """
-__version__ = "$Revision: 1.15 $"[11:-2]
+__version__ = "$Revision: 1.16 $"[11:-2]
 
 import copy
 from mx import DateTime
@@ -128,27 +128,28 @@
         All PgefObjects are assigned a unique pgef_oid.  The pgef_oid is
         intended to be unique within the entire Galaxy -- er, scope of a
         Pan Galactic Engineering Framework (PGEF) application, as opposed
-        to being unique only within PGER.  It is created at the time of
-        creation of the PgefObject in the application and is applicable to
-        local PgefObjects as well as those stored in PGER.
+        to being unique only within the repository.  It is created at the
+        time of creation of the PgefObject in the application and is
+        applicable to local PgefObjects as well as those stored in the
+        repository.
 
         Every PgefObject is manageable within the context of PGER -- it has
-        time-date stamps for its instantiation and last modification in
-        PGER, required references to its creator in PGER (record_creator)
-        and last modifier in PGER (record_modifier), and an optional
-        reference to its PGER owner (record_owner), if different from its
-        PGER creator.
-
-        The vast majority of objects stored in PGER will be initially
-        instantiated, and probably also managed, outside of PGER by some
-        engineering software tool, and therefore may have creation and
-        modification datetimes (create_datetime and mod_datetime) different
-        from their creation and modification time-date stamps in PGER
-        (record_create_datetime and record_mod_datetime), so unless an
-        entity is *only* created in PGER, the external creator ("creator"
-        attribute), modifier ("modifier" attribute) and owner ("owner"
-        attribute) and the create_datetime and mod_datetime (if known)
-        should be populated.
+        time-date stamps for its instantiation and last modification in the
+        repository, required references to its creator in the repository
+        (record_creator) and last modifier in the repository
+        (record_modifier), and an optional reference to its PGER owner
+        (record_owner), if different from its PGER creator.
+
+        The vast majority of objects stored in the repository will be
+        initially instantiated, and probably also managed, outside of the
+        repository by some engineering software tool, and therefore may
+        have creation and modification datetimes (create_datetime and
+        mod_datetime) different from their creation and modification
+        time-date stamps in the repository (record_create_datetime and
+        record_mod_datetime), so unless an entity is *only* created in the
+        repository, the external creator ("creator" attribute), modifier
+        ("modifier" attribute) and owner ("owner" attribute) and the
+        create_datetime and mod_datetime (if known) should be populated.
         """,
         properties=[
         Property(
@@ -157,10 +158,10 @@
             name='OID',
             range='str',
             description="""
-            [pgef:pgef_oid] 'pgef_oid' is an object identifier that is
-            intended to be unique across all PGEF application instances in
-            all PGEF applications, whether they are in communication or
-            not.  It is usually constructed as the concatenation of the
+            [pgef:pgef_oid]  In PGEF, an OID is an object identifier that
+            is intended to be unique across all PGEF application instances
+            in all PGEF applications, whether they are in communication or
+            not.  By default, it is constructed as the concatenation of the
             object creator's id, which is typically their email address
             (hence a URI for a Person), with the timestamp of the object's
             creation in Universal Time.  However, in cases in which an
@@ -176,12 +177,11 @@
             range='str',
             default_display='True',
             description="""
-            [step:id] [rdf:ID] Id is an identifier that is unique within
-            some specified namespace (the id_ns).  There are no constraints
-            on the population of id/id_ns; however, in a canonical data
-            definition scheme, id should be a local name and id_ns should
-            be a namespace, and the combination of the two should form a
-            URI.
+            [step:id] [rdf:ID] An ID is an identifier that is unique within
+            a specified namespace.  In a canonical data definition scheme,
+            id should be a 'local name', its namespace should be specified
+            as a valid URI or locally unique prefix, and the combination of
+            the two should form a globally unique Qualified Name.
             """),
         Property(
             id='id_ns',
@@ -190,8 +190,9 @@
             range='str',
             default='NOCONTEXT',
             description="""
-            [xml:base] 'id_ns' is the context, base URI, or namespace
-            within which the id is unique.
+            [xml:base]  An ID Namespace is the context within which an
+            identifier (ID) is unique.  (Customarily, a namespace is
+            formulated as a URI.)
             """),
         Property(
             id='security_mask',
@@ -200,10 +201,11 @@
             range='int',
             default='0',
             description="""
-            [pgef:security_mask] Support for instance-level customizable
-            access control.  Accessibility of each entity instance (row)
-            will be governed by testing its security_mask against the
-            security_mask assigned to the user.  Details TBD.
+            [pgef:security_mask]  In PGEF, a Security Mask is used to
+            implement instance-level customizable access control.
+            Accessibility of each entity instance (row) will be governed by
+            testing its security_mask against the security_mask assigned to
+            the user.  Details TBD.
             """),
         Property(
             id='name',
@@ -212,12 +214,12 @@
             range='str',
             default_display='True',
             description="""
-            [rdfs:label] A presentation name or human-readable name for the
-            object -- usually the name by which the object is known to an
-            end-user, but may be used for any type of appellation or
-            identification, including aliases and local nomenclatures.  Its
-            meaning is application context-dependent.  This 'name' concept
-            is analogous to a person's given name.
+            [rdfs:label]  A Name is a human-readable identifier for an
+            object -- usually the one by which the object is known to the
+            end-user, but it may be used for any type of identification,
+            including aliases and local nomenclatures.  Its meaning is
+            dependent on the application context.  This concept of Name is
+            analogous to a person's given name.
             """),
         Property(
             id='description',
@@ -225,8 +227,8 @@
             name='Description',
             range='str',
             description="""
-            [rdf:Description] A narrative about the characteristics and
-            identifying features of the object.
+            [rdf:Description]  A Description is a narrative about the
+            characteristics and identifying features of an object.
             """),
         Property(
             id='comment',
@@ -234,10 +236,10 @@
             name='Comment',
             range='str',
             description="""
-            [rdfs:comment] Provides information about the object that may
-            be incidental, temporal, or contextual, and is usually in
-            addition to the information in 'description'.  The meaning of
-            'comment' is determined by the application context.
+            [rdfs:comment]  A Comment provides information about an object
+            that may be incidental, temporal, or contextual, and is usually
+            in addition to the information in 'description'.  The meaning
+            of Comment is determined by the application context.
             """),
         # TODO:  this should be a list of Persons
         Property(
@@ -247,16 +249,16 @@
             range='Person',
             property_type='object',
             description="""
-            [pgef:record_owner] The user who owns the object's record in
-            PGER.
-            (1) record_owner and record_creator are both provided in case
-            the owner and creator of the PgefObject are different.  The
-            default is for them to be the same.
-            (2) The default is record_owner == record_creator.  (This will
-            be enforced by PGER.)
-            (3) The owner always has the privilege of modifying the
-            PgefObject (or deleting it, if deletion is allowed for that
-            entity type).
+            [pgef:record_owner] The PGER Owner is the user who owns the
+            object's record in the repository.
+            (1) PGER Owner and PGER Creator are both provided in case the
+            owner and creator of the record of the object in the repository
+            are different.  The default is for them to be the same.
+            (2) The default is PGER Owner == PGER Creator.  (This will
+            be enforced by the repository.)
+            (3) The PGER Owner always has the privilege of modifying the
+            record of the object in the repository (or deleting it, if
+            deletion is allowed for that entity type).
             """),
         Property(
             id='record_creator',
@@ -266,7 +268,7 @@
             property_type='object',
             description="""
             [pgef:record_creator] The user who first added the object's
-            record to PGER.
+            record to the repository.
             """),
         Property(
             id='record_create_datetime',
@@ -275,7 +277,7 @@
             range='DateTime',
             description="""
             [pgef:record_create_datetime] Date-time of addition of the
-            object's record to PGER.
+            object's record to the repository.
             """),
         Property(
             id='record_modifier',
@@ -285,7 +287,7 @@
             property_type='object',
             description="""
             [pgef:record_modifier] The user who last modified the object's
-            record in PGER.
+            record in the repository.
             """),
         Property(
             id='record_mod_datetime',
@@ -294,7 +296,7 @@
             range='DateTime',
             description="""
             [pgef:record_mod_datetime] Date-time of last modification of
-            the object's record in PGER.
+            the object's record in the repository.
             """),
         # TODO:  this should be a list of Persons
         Property(
@@ -351,7 +353,7 @@
             range='DateTime',
             description="""
             [pgef:mod_datetime] Date-time of last modification of the
-            object's record in PGER.
+            object.
             """),
         Property(
             id='reps',
@@ -363,15 +365,18 @@
             min_cardinality=0,
             max_cardinality=0,
             description="""
-            [pgef:reps] Representation(s) either created from this object
-            (generable=True) or from which this object can be created
-            (composable=True).  The representation from which the object
-            was originally imported (if any) will have its
-            'is_object_source' attribute set to True.  Representations
+            [pgef:reps]  A Representation is any artifact used to
+            communicate or display information about a computational object
+            or its real-world counterpart.  Representation(s) can be either
+            generated from a computational object (generable=True) or can
+            used to create an instance of a computational object
+            (composable=True).  The representation from which the
+            computational object was originally imported (if any) will have
+            its 'is_object_source' attribute set to True.  Representations
             include both "presentations", such as PDF or HTML for a
             document, and more general representations such as
-            serializations (e.g., for an engineering model:  STEP Part 21,
-            UML, OWL, etc.).
+            serializations or data sets for exchange (e.g., for an
+            engineering model:  STEP Part 21, UML, OWL, etc.).
             """)
         ]) # end of _schema
 

From waterbug at step.nasa.gov  Mon May 16 17:32:19 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 16 17:32:20 2005
Subject: [pangalactic-commits] Doc reform!  All are one:  PgefManual!
Message-ID: <200505162132.j4GLWJlR023477@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/doc/PgefManual.html None 1.1
PanGalactic/doc/PgefManual.txt None 1.1
PanGalactic/doc/PgefAdminGuide.txt 1.1 None
PanGalactic/doc/PgefDevGuide.txt 1.10 None
PanGalactic/doc/PgefReference.txt 1.21 None
PanGalactic/doc/PgefRoadmap.txt 1.6 None
PanGalactic/doc/PgefTutorial.txt 1.1 None
PanGalactic/doc/PgefUsersGuide.txt 1.3 None

Log message:
Doc reform!  All are one:  PgefManual!
Basically, they all needed so much work that I decided to
smoosh them all into one and just try to make that one decent.
Lots of editing done, plus now the doc is ReST-conformant --
which is how this html version is generated.

From waterbug at step.nasa.gov  Mon May 16 17:34:45 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 16 17:34:47 2005
Subject: [pangalactic-commits] Tweaking and pruning ...
Message-ID: <200505162134.j4GLYj15023771@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/TODO 1.25 1.26
PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py 1.7 1.8
PanGalactic/pangalactic/node/gui/psm/pgeftree.py 1.9 1.10
PanGalactic/pangalactic/node/gui/psm/psmtool.py 1.31 1.32
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.8 1.9
PanGalactic/pangalactic/node/gui/widgets/pgeftree.py 1.6 1.7
PanGalactic/pangalactic/node/io/treereport.py 1.7 None
PanGalactic/pangalactic/repo/chronosynclastic.py 1.41 1.42
PanGalactic/pangalactic/test/IDTEST 1.115 1.116

Log message:
Tweaking and pruning ...

Index: PanGalactic/TODO
diff -u PanGalactic/TODO:1.25 PanGalactic/TODO:1.26
--- PanGalactic/TODO:1.25	Sun May 15 23:17:58 2005
+++ PanGalactic/TODO	Mon May 16 17:34:40 2005
@@ -8,6 +8,11 @@
 ---------------------------------------------------
 To Do Before Release (in rough order of precedence)
 ---------------------------------------------------
+[*] recreate PgefTree widget
+    - add right-click pop-up windows to show info on node
+    - "all" tree view to show all objs assoc. with each node
+    - explicit assembly view (reified acu's and interfaces, w/icons)
+    - drop/drag assembly should activate 'Save' button
 [-] NEW!  *REPLACE* ItemEditFrame with late-bound object viewer/editors
     - new editor concept for all objs:  use object viewer as the editor
     - 'links' to objects from object Properties (related objs may or may
@@ -25,11 +30,6 @@
       'Close' button should be activated so the user can close the window
       (don't really need 'Save' button -- that should be implicit, as in
       Mozilla bookmark editor)
-[*] recreate PgefTree widget
-    - add mouse-over balloons to show info on node
-    - "all" tree view to show all objs assoc. with each node
-    - explicit assembly (reified acu's and interfaces, w/icons)
-    - drop/drag assembly should activate 'Save' button
 [-] PgefObjectGrid widget
     - fix handling of object-valued columns
     - enable saving of named displaymaps
@@ -120,5 +120,5 @@
     - one-many (aggregate attrs)
 
 --------------------------------------------------------------------------
-# $Id: TODO,v 1.25 2005/05/16 03:17:58 waterbug Exp $
+# $Id: TODO,v 1.26 2005/05/16 21:34:40 waterbug Exp $
 

Index: PanGalactic/pangalactic/node/gui/psm/pgeftree.py
diff -u PanGalactic/pangalactic/node/gui/psm/pgeftree.py:1.9 PanGalactic/pangalactic/node/gui/psm/pgeftree.py:1.10
--- PanGalactic/pangalactic/node/gui/psm/pgeftree.py:1.9	Wed May 11 03:07:48 2005
+++ PanGalactic/pangalactic/node/gui/psm/pgeftree.py	Mon May 16 17:34:41 2005
@@ -1,10 +1,10 @@
-# $Id: pgeftree.py,v 1.9 2005/05/11 07:07:48 waterbug Exp $
+# $Id: pgeftree.py,v 1.10 2005/05/16 21:34:41 waterbug Exp $
 """
 Base class for PanGalaxian's trees
 
-@version: $Revision: 1.9 $
+@version: $Revision: 1.10 $
 """
-__version__ = "$Revision: 1.9 $"[11:-2]
+__version__ = "$Revision: 1.10 $"[11:-2]
 
 import wx
 import cPickle, types
@@ -19,9 +19,8 @@
 from pangalactic.utils            import pgefevents
 from pangalactic.node.gui.state  import state
 from pangalactic.node.gui.psm     import itemdroptarget
-from pangalactic.node.io          import treereport
 
-__version__ = "$Revision: 1.9 $"[11:-2]
+__version__ = "$Revision: 1.10 $"[11:-2]
 
 
 class PgefTree(wx.TreeCtrl):
@@ -170,33 +169,6 @@
                 self.SetItemHasChildren(treeid, True)            
         self.SortChildren(rootnode)
 
-    def DumpToPdf(self, event = None):
-        dlg = pdfoptions.PDFOptions(self)
-        dlg.showall.Show(1)
-        dlg.showvisible.Show(1)
-        result = dlg.ShowModal()
-        if result == wx.ID_OK:
-            temproot = self.GetRootItem()
-            templist = []
-            
-            if dlg.showall.GetValue():
-                showflag = 1
-            elif dlg.showvisible.GetValue():
-                showflag = 0
-                
-            self.WalkNodes(temproot, currentindent = 0, returnlist = templist, showall = showflag)
-            newtemplist = self.CreatePDFObjectList(templist)
-            
-            filename = dlg.filename.GetValue()
-            if filename.find('.pdf') == -1:
-                filename += '.pdf'
-                
-            temp = treereport.TreeReport(filename,
-                                         dlg.pdftitle.GetValue(),
-                                         dlg.footertext.GetValue(),
-                                         newtemplist)
-            temp.generate()
-            
     def WalkNodes(self, startnode, currentindent = None, returnlist = None, showall = None):
         #print '%s - %i' % (self.GetItemText(startnode), currentindent)
         labels = ['ROOT']
@@ -226,18 +198,6 @@
         if child.IsOk():
             self.WalkNodes(child, currentindent, returnlist, showall)
             
-    def CreatePDFObjectList(self, objlist):
-        #print objlist
-        returnlist = []
-        for entry in objlist:
-            obj = self.dm.getLocalObject(entry[0])
-            if obj == None:
-                returnlist.append(entry)
-                #print 'no item -  appending <%s>' % entry
-            else:
-                returnlist.append((obj, entry[1]))
-        return returnlist
-
         
 class PgefMainTree(PgefTree):
     """

Index: PanGalactic/pangalactic/node/gui/psm/psmtool.py
diff -u PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.31 PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.32
--- PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.31	Wed May 11 03:07:48 2005
+++ PanGalactic/pangalactic/node/gui/psm/psmtool.py	Mon May 16 17:34:41 2005
@@ -1,10 +1,10 @@
-# $Id: psmtool.py,v 1.31 2005/05/11 07:07:48 waterbug Exp $
+# $Id: psmtool.py,v 1.32 2005/05/16 21:34:41 waterbug Exp $
 # Originally Created 04/05/2001
 """
 PSM Tool is the Product Structure Manager.  It handles visualization,
 navigation, and editing of product structures.
 """
-__version__ = "$Revision: 1.31 $"[11:-2]
+__version__ = "$Revision: 1.32 $"[11:-2]
 
 import os
 import sys
@@ -53,7 +53,6 @@
 ID_EDITFRAME_PARTS = wx.NewId()
 ID_TREE_RIGHTPOPUP_EDIT = wx.NewId()
 ID_TREE_RIGHTPOPUP_SHOWPROJECT = wx.NewId()
-ID_TREE_RIGHTPOPUP_DUMPTOPDF = wx.NewId()
 
 ID_LEFT_PANEL = wx.NewId()
 ID_CHOICE_VIEW = wx.NewId()
@@ -212,9 +211,6 @@
         wx.EVT_MENU(self,
                  ID_TREE_RIGHTPOPUP_SHOWPROJECT,
                  self.OnShowProjectFrame)
-        wx.EVT_MENU(self,
-                 ID_TREE_RIGHTPOPUP_DUMPTOPDF,
-                 self.tree.DumpToPdf)
         wx.EVT_CHOICE(self,
                    toolbarpanel.ID_PROJECT,
                    self.OnSelectProject)
@@ -410,8 +406,6 @@
                     'Edit...', "Edit this Part")
         menu.Append(ID_TREE_RIGHTPOPUP_SHOWPROJECT,
                     'View Project Data...', "View project data")
-        menu.Append(ID_TREE_RIGHTPOPUP_DUMPTOPDF,
-                    'Generate PDF...', 'Show the PDF creation options')
         menu.SetHelpString(ID_TREE_RIGHTPOPUP_EDIT,
                            "Edit this Part")
         menu.SetHelpString(ID_TREE_RIGHTPOPUP_SHOWPROJECT,

Index: PanGalactic/pangalactic/test/IDTEST
diff -u PanGalactic/pangalactic/test/IDTEST:1.115 PanGalactic/pangalactic/test/IDTEST:1.116
--- PanGalactic/pangalactic/test/IDTEST:1.115	Sun May 15 04:30:54 2005
+++ PanGalactic/pangalactic/test/IDTEST	Mon May 16 17:34:43 2005
@@ -1 +1 @@
-1658
\ No newline at end of file
+1674
\ No newline at end of file

Index: PanGalactic/pangalactic/repo/chronosynclastic.py
diff -u PanGalactic/pangalactic/repo/chronosynclastic.py:1.41 PanGalactic/pangalactic/repo/chronosynclastic.py:1.42
--- PanGalactic/pangalactic/repo/chronosynclastic.py:1.41	Sat May 14 01:49:05 2005
+++ PanGalactic/pangalactic/repo/chronosynclastic.py	Mon May 16 17:34:43 2005
@@ -1,4 +1,4 @@
-# $Id: chronosynclastic.py,v 1.41 2005/05/14 05:49:05 waterbug Exp $
+# $Id: chronosynclastic.py,v 1.42 2005/05/16 21:34:43 waterbug Exp $
 
 """
 The Chronosynclastic Infundibulum:  an asynchronous, ontology-driven
@@ -8,9 +8,9 @@
 (L{pangalactic.core.pgefobject.PgefObject} and its subclasses), the module
 name must be the class name in lower-case.
 
-@version: $Revision: 1.41 $
+@version: $Revision: 1.42 $
 """
-__version__ = "$Revision: 1.41 $"[11:-2]
+__version__ = "$Revision: 1.42 $"[11:-2]
 
 import imp
 import re
@@ -219,13 +219,11 @@
         if tname in current_tables:
             return
         required = Set([schema_id])
-        print 'schema_id is:', schema_id
         # first check for other schemas referenced by this one, and those
         # referenced by the referenced schemas, etc. ...
         newstuff = Set()
         while 1:
             required = required.union(newstuff)
-            print 'required is:', required
             for id in required:
                 refs = self.object_schemas[id].refd_obj_schemas
                 newstuff = newstuff.union(refs)

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.8 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.9
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.8	Mon May 16 04:12:44 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Mon May 16 17:34:41 2005
@@ -1,10 +1,10 @@
-# $Id: pgefobjectgrid.py,v 1.8 2005/05/16 08:12:44 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.9 2005/05/16 21:34:41 waterbug Exp $
 """
 The PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.8 $
+@version: $Revision: 1.9 $
 """
-__version__ = "$Revision: 1.8 $"[11:-2]
+__version__ = "$Revision: 1.9 $"[11:-2]
 
 from pprint import pprint
 
@@ -498,7 +498,7 @@
 from pangalactic.core.pgefobject import PgefObject as PO
 from pangalactic.test.utils4test import popTestData
 testobjs = [PO(id='spam'), PO(id='eggs'), PO(id='ni'), PO(id='shrubbery'),
-            PO(id='Ekke ekke ekke ptang zoo boing')]
+            PO(id='Ekke ekke ekke ptang zoom boing')]
 for po in testobjs:  popTestData(po)
 
 class TestFrame(wx.Frame):

Index: PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py
diff -u PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py:1.7 PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py:1.8
--- PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py:1.7	Wed May 11 03:07:48 2005
+++ PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py	Mon May 16 17:34:41 2005
@@ -1,4 +1,4 @@
-# $Id: itemdroptarget.py,v 1.7 2005/05/11 07:07:48 waterbug Exp $
+# $Id: itemdroptarget.py,v 1.8 2005/05/16 21:34:41 waterbug Exp $
 
 import cPickle
 
@@ -10,13 +10,15 @@
 from wxPython.wx import wxPoint, wxTreeItemIcon_Selected
 
 
-__version__ = "$Revision: 1.7 $"[11:-2]
-
-#constants
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 
 class ItemDropTarget(wxPyDropTarget):
-    """This class wraps the DropTarget functionality that is used in the tree"""
+    """
+    This class is used by the C{PgefTree} to identify and find the drop
+    target in a drag and drop operation.  (And it needs to be completely
+    rewritten!)
+    """
 
     def __init__(self, tree, datamanager=None):
         wxPyDropTarget.__init__(self)
@@ -71,13 +73,13 @@
                 #print "moving within tree"
                 moving_within_tree = True
 
-            # If there is no nauoid, set the dropnauoobj to None
+            # If there is no acuid, set the dropacuobj to None
             try:
-                dropnauoobj = self.dm.getLocalObject(dropdata[0])
-                #print "have dropnauo", dropnauoobj
+                dropacuobj = self.dm.getLocalObject(dropdata[0])
+                #print "have dropacu", dropacuobj
             except KeyError:
                 print "keyerror on drop"
-                dropnauoobj = None
+                dropacuobj = None
 
             # get the object for the item being dropped from local storage
             dropitem = None
@@ -104,7 +106,7 @@
 
             # Get the target data
             targetdata = self.tree.GetPyData(targetnode)
-            targetnauo = None
+            targetacu = None
             targetitem = None
             #print 'targetdata is', targetdata            
             
@@ -122,36 +124,24 @@
                     self.dm.topLevelItemIDs.append(dropitem.pgef_oid)
                 else:
                     return d
-                targetnauo = "ROOT"
-
-            # check for toplevel item
-            elif targetdata[0] == 'TOPLEVEL':
-                #print "drop on toplevel"
-                #not used.. so commenting for now
-                #havetoplevelnode = True
-                # we are dropping a node onto a toplevel node. Are we us?
-                if self.tree.GetPyData(targetnode)[1] == dropitem.pgef_oid:
-                    return d
-                targetitem = self.dm.getLocalObject(targetdata[1])
-                #print 'targetnauo is ', targetnauo
-                if targetnauo == None:
-                    targetnauo = "TOPLEVEL"
+                targetacu = "ROOT"
 
             elif DragFromGrid:
                 #print "drag from grid"
                 targetitem = self.dm.getLocalObject(targetdata[1])
                 #print 'project is: ', state['project']
                 #print '******** targetitem is', targetitem.id
-                #print '******** targetnauo is', targetnauo
-                if targetnauo == None:
-                    targetnauo = "TOPLEVEL"
+                #print '******** targetacu is', targetacu
+                if targetacu == None:
+                    print "no drop target"
+                    return
 
             elif targetdata[0]:
                 #print "drop with targetdata[0]"
                 #print "targetdata", targetdata
                 #print 'DragFromGrid is ', DragFromGrid
                 targetitem = self.dm.getLocalObject(targetdata[1])
-                targetnauo = self.dm.getLocalObject(targetdata[0])
+                targetacu = self.dm.getLocalObject(targetdata[0])
             else:
                 print "wtf"
                 return d
@@ -159,27 +149,26 @@
             if moving_within_tree:
                 #print "moving within tree - delete"
                 try:    
-                    self.dm.removeAcu(dropnauoobj.pgef_oid)
-                    self.dm.removeLocalAcu(dropnauoobj)
+                    self.dm.removeAcu(dropacuobj.pgef_oid)
+                    self.dm.removeLocalAcu(dropacuobj)
                 except KeyError:
-                    print 'had trouble deleting the nauo'
-            # create new nauo
-            #print "create new nauo"
-            newnauo = Acu(subtype = 'nauo')
-            newnauo.component = dropitem
-            newnauo.state = 'ADD'
-            newnauo.owner = newnauo.creator = newnauo.modifier = self.dm.user.id
+                    print 'had trouble deleting the acu'
+            # create new acu
+            #print "create new acu"
+            newacu = Acu()
+            newacu.component = dropitem
+            newacu.state = 'ADD'
+            newacu.owner = newacu.creator = newacu.modifier = self.dm.user.id
             if haverootnode:
                 #print "haverootnode; assembly is TOPLEVEL"
                 tlobj = Model(project = state['project'])
-                #tlobj.pgef_oid = "TOPLEVEL"   ## wtf???? vwk
-                newnauo.assembly = tlobj
+                newacu.assembly = tlobj
             else: 
                 #print "havenode; assembly is oid"
-                newnauo.assembly = targetitem
-            #print "newnauo", newnauo.id, newnauo.assembly.id, newnauo.component.id
+                newacu.assembly = targetitem
+            #print "newacu", newacu.id, newacu.assembly.id, newacu.component.id
             # add new acu
-            self.dm.addAcu(newnauo, targetnauo)
+            self.dm.addAcu(newacu, targetacu)
             try:
                 # if isinstance(targetitem, Model):
                 #     targetitem.has_parts_flag = 1
@@ -194,7 +183,7 @@
                 #print "itemdroptarget: 2b: expand"
                 self.tree.Expand(targetnode)
             # create the new tree node
-            dropobj = [newnauo.pgef_oid, dropitem.pgef_oid]
+            dropobj = [newacu.pgef_oid, dropitem.pgef_oid]
             id = self.tree.AppendItem(targetnode, dropitem.id)
             self.tree.SetItemImage(id, self.tree.itemicon)
             self.tree.SetItemImage(id, self.tree.itemicon, wxTreeItemIcon_Selected)
@@ -211,7 +200,7 @@
                 #print "itemdroptarget: 3b: expand"
                 self.tree.Expand(targetnode)
 
-            # delete the old nauo from the tree
+            # delete the old acu from the tree
             if moving_within_tree:
                 if self.tree.GetSelection() <> self.tree.GetRootItem():
                     delnode = self.tree.GetSelection()

Index: PanGalactic/pangalactic/node/gui/widgets/pgeftree.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgeftree.py:1.6 PanGalactic/pangalactic/node/gui/widgets/pgeftree.py:1.7
--- PanGalactic/pangalactic/node/gui/widgets/pgeftree.py:1.6	Wed May 11 03:07:49 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgeftree.py	Mon May 16 17:34:41 2005
@@ -1,10 +1,10 @@
-# $Id: pgeftree.py,v 1.6 2005/05/11 07:07:49 waterbug Exp $
+# $Id: pgeftree.py,v 1.7 2005/05/16 21:34:41 waterbug Exp $
 """
 Base class for PanGalaxian's trees
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 import wx
 import cPickle, types
@@ -14,9 +14,8 @@
 from pangalactic.utils            import pgefevents
 from pangalactic.node.gui.state  import state
 from pangalactic.node.gui.psm     import itemdroptarget
-from pangalactic.node.io          import treereport
 
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 
 class PgefTree(wx.TreeCtrl):
@@ -34,6 +33,9 @@
         self.dropOnNode = True
         self.il = None
         self.LoadImageLIst()
+        # forget about dnd for now ... itemdroptarget badly needs a
+        # total rewrite!!
+        allowdragndrop = False
         if allowdragndrop:
             self.dt = itemdroptarget.ItemDropTarget(self, datamanager)
             self.SetDropTarget(self.dt)
@@ -88,33 +90,8 @@
             event.Skip()
             
     def StartDragOperation(self):
-        if self.dt == None:
-            return
-
-        # print "pgeftree.startdragoperation"
-
-        # if the following print code executes,
-        # it will print info about the node
-        # being dragged.  quite useful, on occasion
-        selectednode = self.GetSelection()
-        nauo_item = self.GetPyData(selectednode)
-        item = self.dm.getLocalObject(nauo_item[1])
-        if item:
-            print "item: " + item.name # + "; parts: " + str(item.has_parts_flag) + \
-                  #"; plflag: " + str(item.has_parts_lists_flag) + \
-                  #"; state: " + str(item.state) + " (" + nauo_item[0] + ", " + nauo_item[1] + ")"
-        #else:
-        #    print "dragging the project root is pointless"
-        #    return
-
-        data = [nauo_item[0], nauo_item[1], self.__class__]
-        treeitempickle = cPickle.dumps(data, 1)
-        treeitem = wx.CustomDataObject(wx.CustomDataFormat("PGEF_Item"))
-        treeitem.SetData(treeitempickle)
-        dropSource = wx.DropSource(self)
-        dropSource.SetData(treeitem)
-        #result = dropSource.DoDragDrop(True)    
-        dropSource.DoDragDrop(True)    
+        # dnd is deactivated for now
+        pass
 
     def LoadTreefromObjects(self, dm, rootobj, parentnode=None):
         """
@@ -152,29 +129,6 @@
                 self.SetItemHasChildren(treeid, True)            
         self.SortChildren(rootnode)
 
-    def DumpToPdf(self, event = None):
-        dlg = pdfoptions.PDFOptions(self)
-        dlg.showall.Show(1)
-        dlg.showvisible.Show(1)
-        result = dlg.ShowModal()
-        if result == wx.ID_OK:
-            temproot = self.GetRootItem()
-            templist = []
-            if dlg.showall.GetValue():
-                showflag = 1
-            elif dlg.showvisible.GetValue():
-                showflag = 0
-            self.WalkNodes(temproot, currentindent = 0, returnlist = templist, showall = showflag)
-            newtemplist = self.CreatePDFObjectList(templist)
-            filename = dlg.filename.GetValue()
-            if filename.find('.pdf') == -1:
-                filename += '.pdf'
-            temp = treereport.TreeReport(filename,
-                                         dlg.pdftitle.GetValue(),
-                                         dlg.footertext.GetValue(),
-                                         newtemplist)
-            temp.generate()
-
     def WalkNodes(self, startnode, currentindent = None, returnlist = None, showall = None):
         #print '%s - %i' % (self.GetItemText(startnode), currentindent)
         labels = ['ROOT']
@@ -204,15 +158,4 @@
         if child.IsOk():
             self.WalkNodes(child, currentindent, returnlist, showall)
 
-    def CreatePDFObjectList(self, objlist):
-        #print objlist
-        returnlist = []
-        for entry in objlist:
-            obj = self.dm.getLocalObject(entry[0])
-            if obj == None:
-                returnlist.append(entry)
-                #print 'no item -  appending <%s>' % entry
-            else:
-                returnlist.append((obj, entry[1]))
-        return returnlist
 

From waterbug at step.nasa.gov  Mon May 16 22:03:21 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 16 22:03:25 2005
Subject: [pangalactic-commits] Many improvements.
Message-ID: <200505170203.j4H23LVF025932@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/doc/PgefManual.txt 1.1 1.2
PanGalactic/doc/PgefManual.html 1.1 1.2

Log message:
Many improvements.

Index: PanGalactic/doc/PgefManual.html
diff -u PanGalactic/doc/PgefManual.html:1.1 PanGalactic/doc/PgefManual.html:1.2
--- PanGalactic/doc/PgefManual.html:1.1	Mon May 16 17:32:17 2005
+++ PanGalactic/doc/PgefManual.html	Mon May 16 22:03:19 2005
@@ -5,9 +5,9 @@
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <meta name="generator" content="Docutils 0.3.7: http://docutils.sourceforge.net/" />
 <title>The PGEF Manual</title>
-<meta name="author" content="Stephen Waterbury &lt;stephen.c.waterbury at nasa.gov&gt;" />
+<meta name="author" content="Stephen Waterbury &lt;stephen dot c dot waterbury at nasa dot gov&gt;" />
 <meta name="author" content="Ginny Keech" />
-<meta name="date" content="2005-04-04" />
+<meta name="date" content="2005-05-16" />
 <link rel="stylesheet" href="default.css" type="text/css" />
 </head>
 <body>
@@ -19,17 +19,18 @@
 <col class="docinfo-content" />
 <tbody valign="top">
 <tr><th class="docinfo-name">Author:</th>
-<td>Stephen Waterbury &lt;stephen.c.waterbury at nasa.gov&gt;</td></tr>
+<td>Stephen Waterbury &lt;stephen dot c dot waterbury at nasa dot gov&gt;</td></tr>
 <tr><th class="docinfo-name">Author:</th>
 <td>Ginny Keech</td></tr>
 <tr><th class="docinfo-name">Version:</th>
-<td>1.21</td></tr>
+<td>1.1</td></tr>
 <tr><th class="docinfo-name">Date:</th>
-<td>2005-04-04</td></tr>
+<td>2005-05-16</td></tr>
 </tbody>
 </table>
-<div class="section" id="don-t-panic">
-<h1><a name="don-t-panic">Don't Panic!</a></h1>
+<div class="section" id="foreword">
+<h1><a name="foreword">Foreword</a></h1>
+<p><strong>Don't Panic!</strong>  :)</p>
 <p>This document provides both general and specific information on the current
 release of PGEF.  Its intended audience is PGEF application developers,
 PGEF node administrators, computer-literate end-users, contributors to
@@ -69,17 +70,17 @@
 <h1><a name="scope-requirements-and-use-cases">Scope, Requirements, and Use Cases</a></h1>
 <div class="section" id="scope">
 <h2><a name="scope">Scope</a></h2>
-<blockquote>
 <ul class="simple">
 <li>In Scope<ul>
 <li>General<ul>
-<li>GUI functions</li>
-<li>Plug-in architecture</li>
+<li>GUI module supporting both user and admin views</li>
+<li>Nekkid objects architecture</li>
 <li>Services (repository, etc.)</li>
 <li>Authentication</li>
 <li>Role-based access control</li>
+<li>Secure (asymmetric-key encrypted) connections</li>
 <li>API's accessible via multiple protocols/transports</li>
-<li>STEP/Express data I/O and management<ul>
+<li>STEP/Express/OWL/XML/UML/XMI data I/O and management<ul>
 <li>STEP Part 21 (ISO 10303-21) file input/output</li>
 <li>STEP XML (ISO 10303-28/OSEB XML format) input/output</li>
 <li>Validation of STEP/Express  (ISO 10303-11) schemas
@@ -90,15 +91,15 @@
 </li>
 </ul>
 </li>
-<li>GUI<ul>
-<li>Interface to repository services</li>
-<li>Interface to local persistence</li>
+<li>GUI functions<ul>
+<li>Interface to repository services (search, get, commit)</li>
+<li>Interface to local persistence (cache browser)</li>
 <li>Rendering of structure trees (assemblies, etc.)</li>
 <li>Structured product document creation, maintenance</li>
-<li>Workflow interfaces</li>
+<li>Workflow</li>
 </ul>
 </li>
-<li>Infrastructure Services / API's (used by plug-ins)<ul>
+<li>Infrastructure Services / API's<ul>
 <li>Security and Access Control<ul>
 <li>Encryption</li>
 <li>Authentication</li>
@@ -119,32 +120,32 @@
 </li>
 </ul>
 </li>
-<li>Core Plug-ins (custom app plug-ins will build on these)<ul>
-<li>PGPDM (Structured Product Document Production and Management)<ul>
+<li>Core applications<ul>
+<li>Structured Product Document Production and Management<ul>
 <li>status:  almost there</li>
 </ul>
 </li>
-<li>PGKM  (Ontology, Dictionary, and Rules Production and Management)<ul>
+<li>Ontology, Dictionary, and Rules Production and Management<ul>
 <li>status:  some infrastructure</li>
 </ul>
 </li>
-<li>PGX   (PG Transformer -- Model and Data Mapping and Xformation/Xlation)<ul>
+<li>Model and Data Mapping and Xformation/Xlation<ul>
 <li>status:  first implementation will use Express Engine</li>
 </ul>
 </li>
-<li>PGWFM (PG Flow -- Enterprise Process and Workflow Design and Management)<ul>
+<li>Workflow Design and Management<ul>
 <li>status:  very simple workflows</li>
 </ul>
 </li>
-<li>PGSci (Scientific and Mathematical Libraries)<ul>
+<li>Scientific and Mathematical Libraries<ul>
 <li>status:  nothing yet (will interface to SciPy/Numeric)</li>
 </ul>
 </li>
-<li>PGPL  (PG Parts Library -- CAX Model Library and Archive Management)<ul>
+<li>Parts Library -- CAX Model Library and Archive Management<ul>
 <li>status:  not started</li>
 </ul>
 </li>
-<li>PGCAX (CAX Tools)<ul>
+<li>CAX Tools<ul>
 <li>status:  not started</li>
 </ul>
 </li>
@@ -152,20 +153,15 @@
 </li>
 </ul>
 </li>
-<li>Out of Scope<ul>
-<li>General<ul>
-<li>Death ray</li>
+<li>Definitely Out of Scope<ul>
 <li>Virtual sex toys</li>
+<li>Death ray</li>
 </ul>
 </li>
 </ul>
-</li>
-</ul>
-</blockquote>
 </div>
 <div class="section" id="security-and-access-control-requirements">
 <h2><a name="security-and-access-control-requirements">Security and Access Control Requirements</a></h2>
-<blockquote>
 <ul class="simple">
 <li>Access control shall be based upon a combination of security
 masks and user roles.</li>
@@ -181,41 +177,29 @@
 modify new (custom) roles within specified domains and to assign
 standard and/or custom roles to other users.</li>
 </ul>
-</blockquote>
 </div>
 <div class="section" id="use-case-sketches">
 <h2><a name="use-case-sketches">Use Case Sketches</a></h2>
-<p>[ Flesh these out, and include the ones in your slides ... ]</p>
-<blockquote>
-<ul>
-<li><p class="first">Repository and Client (thick or thin)</p>
-<ul>
-<li><p class="first">Implement a STEP-mappable high level information model
-(ontology) for parts, models, docs, and systems engineering
-concepts</p>
-</li>
-<li><p class="first">Retrieve model/doc ref(s) from repository</p>
-<blockquote>
+<p>[TODO:  flesh these out, and include the ones in the slides.]</p>
 <ul class="simple">
+<li>Repository and Client (thick or thin)<ul>
+<li>Implement a STEP-mappable high level information model
+(ontology) for parts, models, docs, and systems engineering
+concepts</li>
+<li>Retrieve model/doc ref(s) from repository<ul>
 <li>&quot;Get&quot; (by Id/Oid)</li>
 <li>&quot;Search&quot; (by parameters)</li>
 </ul>
-</blockquote>
 </li>
-<li><p class="first">Add model(s)/doc(s) (including files) to repository</p>
-<blockquote>
-<ul class="simple">
+<li>Add model(s)/doc(s) (including files) to repository<ul>
 <li>&quot;Add&quot; (by Id/Oid)</li>
 </ul>
-</blockquote>
-</li>
-<li><p class="first">Save workflow templates, instances, and states to
-repository</p>
 </li>
+<li>Save workflow templates, instances, and states to
+repository</li>
 </ul>
 </li>
-<li><p class="first">Client (thick)</p>
-<ul class="simple">
+<li>Client (thick)<ul>
 <li>Wizard for creating structured product documents</li>
 <li>Wizard for creating workflow templates and instances</li>
 <li>Interface for managing/viewing workflow items and their
@@ -223,28 +207,29 @@
 </ul>
 </li>
 </ul>
-</blockquote>
 </div>
 </div>
-<div class="section" id="the-pgef-ontology">
-<h1><a name="the-pgef-ontology">The PGEF Ontology</a></h1>
+<div class="section" id="the-pgef-core-ontology">
+<h1><a name="the-pgef-core-ontology">The PGEF Core Ontology</a></h1>
 <div class="section" id="id1">
 <h2><a name="id1">Scope</a></h2>
-<p>The scope of the Pan Galactic Ontology is intended to include all
-information relevant to products and product models throughout
-the product life cycle.</p>
-<p>PGEF's principal domain is the &quot;manufacturing&quot; enterprise, in the broadest
-possible sense of &quot;manufacturing&quot; -- i.e., any type of &quot;product&quot;
-development, where a &quot;product&quot; is any artifact that is or includes one or
-more of the following:  software, firmware, hardware, materials, and
+<p>The scope of the Pan Galactic Core Ontology is intended to
+include all information relevant to products and product models
+throughout the product life cycle.</p>
+<p>PGEF's principal domain is the &quot;manufacturing&quot; enterprise, in the
+broadest possible sense of &quot;manufacturing&quot; -- i.e., any type of
+&quot;product&quot; life cycle support (as the current buzz words go) where
+a &quot;product&quot; is any artifact that is or includes one or more of
+the following:  software, firmware, hardware, materials, and
 documents.</p>
 <p>Consequently, one of PGEF's principal goals is to collect, integrate, and
-manage information about products (known in the PGEF Ontology as &quot;parts&quot;),
+manage information about products (known in the PGEF Core Ontology as &quot;parts&quot;),
 models, and documents created and used by the enterprise.  To define the
 objects of its domain, PGEF implements a simple core ontology of the most
 basic classes of things that occur in enterprises that develop products.</p>
-<p>[ TODO: generate the PGEF Ontology into PanGalactic/home/pgef.owl and
-reference it from this section as the PGEF Core Ontology. ]</p>
+<p>[TODO: generate the PGEF Core Ontology into
+PanGalactic/home/pgef.owl and reference it from this section as
+the PGEF Core Ontology. ]</p>
 </div>
 <div class="section" id="the-pgef-meta-object-facility">
 <h2><a name="the-pgef-meta-object-facility">The PGEF Meta Object Facility</a></h2>
@@ -253,33 +238,30 @@
 Its principal classes are:</p>
 <blockquote>
 <ul>
-<li><p class="first">PgefObjectSchema</p>
-<p>The PgefObjectSchema class represents an ontological class, and defines
-a set of associated attributes (Property instances; 'Properties' in
+<li><p class="first"><strong>ObjectSchema</strong></p>
+<p>The ObjectSchema class represents an ontological class, and defines a
+set of associated attributes (Property instances; 'Properties' in
 ontological parlance) for which that class is the domain.  [Link to the
-PgefObjectSchema API documentation here:
-L{pangalactic.meta.pgefobjectschema.PgefObjectSchema}]</p>
+ObjectSchema API documentation here:
+L{pangalactic.meta.objectschema.ObjectSchema}]</p>
 </li>
-<li><p class="first">Property</p>
-<p>The Property class represents an ontological Property.
-In PGEF, an ontological Property is represented as an
-attribute of its domain class.  Thus, Property
-instances used to define the attributes of PgefObjectSchema
-instances.  [Link to the Property API documentation
-here: L{pangalactic.meta.pgefproperty.Property}]</p>
+<li><p class="first"><strong>Property</strong></p>
+<p>The Property class represents an ontological Property.  In PGEF, an
+ontological Property is represented as an attribute of its domain
+class.  Thus, Property instances used to define the attributes of
+ObjectSchema instances.  [Link to the Property API documentation here:
+L{pangalactic.meta.pgefproperty.Property}]</p>
 <ul>
 <li><p class="first">Every Property has a 'pgef_datatype' (default value:
-'str'), which must be one of: 'str', 'int', 'bool', 'DateTime',
-or the id of a registered PgefObjectSchema (in which case its
-'property_type' must be set to 'object').  If the
-Property's value is an aggregate of objects, then
-'max_cardinality' must be either an integer greater than 1 or
-(if the aggregate is unlimited in size) 0.</p>
+'str'), which must be one of: 'str', 'int', 'bool', 'DateTime', or
+the id of a registered ObjectSchema (in which case its
+'property_type' must be set to 'object').  If the Property's value is
+an aggregate of objects, then 'max_cardinality' must be either an
+integer greater than 1 or (if the aggregate is unlimited in size) 0.</p>
 </li>
 <li><p class="first">An Property can have a default value, which is specified in
 the 'default' attribute and must be encoded as a string.  The
 &quot;default default&quot; values are the null of each type:</p>
-<blockquote>
 <ul>
 <li><p class="first">Strings:  are literal (default default: '')</p>
 </li>
@@ -292,7 +274,7 @@
 </dl>
 </li>
 <li><dl class="first docutils">
-<dt>DateTime: DateTime-valued PgefProperties have a default of</dt>
+<dt>DateTime: DateTime-valued Properties have a default of</dt>
 <dd><p class="first last">None.  [Note that this does not pertain to
 &quot;initialization&quot; values -- e.g., the
 initialization value for 'create_datetime' is
@@ -301,7 +283,7 @@
 </dl>
 </li>
 <li><dl class="first docutils">
-<dt>Classes:  object-valued PgefProperties (cf.</dt>
+<dt>Classes:  object-valued Properties (cf.</dt>
 <dd><p class="first last">owl:ObjectProperty) have a default of None if
 their max_cardinality == 1; otherwise, the
 default is an empty list ([]).</p>
@@ -309,7 +291,6 @@
 </dl>
 </li>
 </ul>
-</blockquote>
 </li>
 </ul>
 </li>
@@ -323,36 +304,33 @@
 software classes that represent ontological classes are sometimes referred
 to as domain objects:  &quot;a domain object is a logical container of purely
 domain information, [and] usually represents a logical entity in the
-problem domain space&quot; [<a class="reference" href="http://c2.com/cgi/wiki?DomainObject">http://c2.com/cgi/wiki?DomainObject</a>].</p>
+problem domain space&quot; (source: <a class="reference" href="http://c2.com/cgi/wiki?DomainObject">The Wiki</a>).</p>
 <p>PgefObject is the root class of the PGEF Core Classes, so hereafter
-'PgefObject' will be used to refer to any PGEF Core Class.</p>
+the term <em>PgefObject</em> will be used to refer to any PGEF Core Class.</p>
 <p>In PGEF, the concept of an ontological class is represented by the
-PgefObjectSchema class.  Each PgefObject instance is assigned at creation
-time an instance of PgefObjectSchema as its '_schema'.  The '_schema'
-defines the set of attributes of that instance that will be stored when and
-if the instance is committed to the repository, PGER.</p>
+ObjectSchema class.  Each PgefObject instance is assigned at creation time
+an instance of ObjectSchema as its '_schema'.  The '_schema' defines the
+set of attributes of that instance that will be stored when and if the
+instance is committed to the repository, PGER.</p>
 <p>Note that a PgefObject instance can have other attributes for various
 purposes (local state, etc.), and these can be persisted locally (in the
 PanGalaxian client's ZODB cache, e.g.), but they will not be known to the
 repository and will not be shared or synchronized with other proxies of
 that instance in a distributed application unless that is done by way of an
 application protocol that is not part of the state of the domain object.</p>
-<p>Although the PGEF core ontology is fairly broad in scope, its focus is the
-domain of Systems Engineering.</p>
+<p>Although the PGEF core ontology is fairly broad in scope, its primary focus
+is the domain of Systems Engineering.</p>
 </div>
 </div>
 <div class="section" id="the-pgef-architecture">
 <h1><a name="the-pgef-architecture">The PGEF Architecture</a></h1>
-<div class="section" id="major-components">
-<h2><a name="major-components">Major Components</a></h2>
-</div>
 <div class="section" id="software-components-of-pgef">
 <h2><a name="software-components-of-pgef">Software Components of PGEF</a></h2>
 <ul>
-<li><p class="first">PGER -- the Pan Galactic Engineering Repository</p>
+<li><p class="first"><strong>PGER</strong> -- the Pan Galactic Engineering Repository</p>
 <blockquote>
-<p>(see <a class="reference" href="#the-pan-galactic-engineering-repository-pger">The Pan Galactic Engineering Repository (PGER)</a>, for
-more detail.)</p>
+<p>[see <a class="reference" href="#the-pan-galactic-engineering-repository-pger">The Pan Galactic Engineering Repository (PGER)</a>, for
+more detail.]</p>
 <ul>
 <li><p class="first">provides a logical interface layer above the object-relational
 hyperdatabase (the Chronosynclastic Infundibulum)</p>
@@ -366,8 +344,8 @@
 </li>
 <li><p class="first">PgerXmlrpc -- the PGER XML-RPC interface</p>
 <blockquote>
-<p>(see <a class="reference" href="#notes-on-the-pger-xml-rpc-search-interface">Notes on the PGER XML-RPC search interface</a>, for more
-detail.)</p>
+<p>[see <a class="reference" href="#notes-on-the-pger-xml-rpc-search-interface">Notes on the PGER XML-RPC search interface</a>, for more
+detail.]</p>
 <ul class="simple">
 <li>uses the XML-RPC 'struct' idiom to transmit serialized
 object states</li>
@@ -378,25 +356,25 @@
 </ul>
 </blockquote>
 </li>
-<li><p class="first">Chronosynclastic -- the PGER Object-Relational Backend</p>
+<li><p class="first"><strong>Chronosynclastic</strong> -- the PGER Object-Relational Backend</p>
 <blockquote>
-<p>(see <a class="reference" href="#o-r-mapping-the-chronosynclastic-infundibulum">O-R Mapping:  The Chronosynclastic Infundibulum</a>, for
-more detail.)</p>
+<p>[see <a class="reference" href="#o-r-mapping-the-chronosynclastic-infundibulum">O-R Mapping:  The Chronosynclastic Infundibulum</a>, for
+more detail.]</p>
 <ul class="simple">
-<li>uses Twisted's adbapi, which provides a non-blocking database
-API that returns &quot;deferred&quot; place-holders that are called
-back with results when they become available.</li>
-<li>generates its database schema from the application ontology.
-The default schema is generated from the PGEF Core Ontology,
-which application can extend by adding other ontologies
-and/or ontological classes (PgefObjectSchema instances).</li>
+<li>uses Twisted's adbapi, which provides a non-blocking database API
+that returns &quot;deferred&quot; place-holders that are called back with
+results when they become available.</li>
+<li>generates its database schema from the application ontology.  The
+default schema is generated from the PGEF Core Ontology, which
+application can extend by adding other ontologies and/or ontological
+classes (ObjectSchema instances).</li>
 <li>provides a flexible O-R mapping</li>
 </ul>
 </blockquote>
 </li>
-<li><p class="first">PanGalaxian -- the PGEF GUI</p>
+<li><p class="first"><strong>PanGalaxian</strong> -- the PGEF GUI</p>
 <blockquote>
-<p>(see <a class="reference" href="#the-pgef-gui-pangalaxian">The PGEF GUI:  PanGalaxian</a>, for more detail.)</p>
+<p>[see <a class="reference" href="#the-pgef-gui-pangalaxian">The PGEF GUI:  PanGalaxian</a>, for more detail.]</p>
 <ul class="simple">
 <li>Provides a graphical desktop environment for managing engineering
 objects (e.g., CAD/CAE models, documents, etc.)</li>
@@ -407,9 +385,9 @@
 </ul>
 </blockquote>
 </li>
-<li><p class="first">PanGalactic Communications Hub -- the PGEF Hub</p>
+<li><p class="first"><strong>PanGalactic Communications Hub</strong> -- the PGEF Hub</p>
 <blockquote>
-<p>(not implemented yet)</p>
+<p>[Not implemented yet.]</p>
 <ul class="simple">
 <li>Acts as the controller and mediator between all PGEF components,
 local and remote</li>
@@ -424,59 +402,24 @@
 </li>
 </ul>
 </div>
-<div class="section" id="pgef-oid-s-unique-object-identifiers">
-<h2><a name="pgef-oid-s-unique-object-identifiers">PGEF OID's:  Unique Object Identifiers</a></h2>
-<p>Each PGEF application object is assigned a unique identifier, the 'oid'.
-The preferred form for the oid is a URI, if one is available or can be
-constructed canonically.  Otherwise, an arbitrary (but unique) one will be
-generated as follows:</p>
+<div class="section" id="odds-and-ends">
+<h2><a name="odds-and-ends">Odds and Ends</a></h2>
+<p>Miscellaneous notes on architectural features.</p>
+<ul>
+<li><p class="first"><strong>PGEF OID's</strong>:  Unique Object Identifiers</p>
+<blockquote>
+<p>Each PGEF application object is assigned a unique identifier, the
+'oid'.  The preferred form for the oid is a URI, if one is
+available or can be constructed canonically.  Otherwise, an
+arbitrary (but unique) one will be generated as follows:</p>
 <p><cite>[canonical userid of object creator] + [time-date stamp of creation-time]</cite></p>
-<p>where the canonical userid is the user's email address and the time-date stamp
-is in Universal Time.</p>
-</div>
-<div class="section" id="pgef-application-services-architecture-and-twisted">
-<h2><a name="pgef-application-services-architecture-and-twisted">PGEF Application/Services Architecture and Twisted</a></h2>
-<p>PGEF consists of a set of functions that are implemented as &quot;services&quot;.  A PGEF
-application can combine these services and specialize them (e.g. with security
-constraints, convenience functions, etc.).</p>
-<p>In Twisted, an application is a &quot;plugin&quot; that is run by the Twisted framework.
-The PGEF services, such as the PGEF repository (PGER), are implemented as
-services within the PGEF Twisted application plugin.</p>
-<p>An application of PGEF is also implemented as a Twisted plugin with services.</p>
-<p>Commentary about how this is done, from Moshe Zadka in the twisted mailing list
-archives:</p>
-<pre class="literal-block">
-The idiomatic way is:
-
-    class SomeOtherService
-        # .... do something interesting here
-        def registry(self):
-            return self.parent.getServiceNamed('registry')
-
-    def makeService(config):
-        s = RegistryService()
-        s.setName('registry')
-        anotherS = SomeOtherService()
-        m = service.MultiService()
-        s.setServiceParent(m)
-        anotherS.setServiceParent(m)
-        return m
-
-The trick is to have 's' and 'anotherS' completely symmetrical,
-and allow them to access each other.
-</pre>
-</div>
-<div class="section" id="pgef-application-templates">
-<h2><a name="pgef-application-templates">PGEF Application Templates</a></h2>
-<blockquote>
-<ul class="simple">
-<li>Structured Product Document Publishing</li>
-<li>Model Management and Collaboration</li>
-</ul>
+<p>where the canonical userid is the user's email address and the
+time-date stamp is in Universal Time.</p>
 </blockquote>
-</div>
-<div class="section" id="distributed-architecture-vger">
-<h2><a name="distributed-architecture-vger">Distributed Architecture (VGER)</a></h2>
+</li>
+<li><p class="first"><strong>VGER</strong>:  Distributed Architecture</p>
+<blockquote>
+<p>[Not implemented yet.]</p>
 <p>The PGEF repository, PGER, will be configurable either as a
 single node or as a distributed set of peer nodes forming a
 Virtual Galactic Repository (VGER).  In either configuration, a
@@ -496,60 +439,65 @@
 service it is managing.  For example, a PGER node may only
 include data about personnel who own models or who are working on
 a project that exists in the context of that node.</p>
+</blockquote>
+</li>
+</ul>
 </div>
 </div>
 <div class="section" id="the-pan-galactic-engineering-repository-pger">
 <h1><a name="the-pan-galactic-engineering-repository-pger">The Pan Galactic Engineering Repository (PGER)</a></h1>
-<p>The PGEF Ontology provides the basis for the database structures of the PGEF
-Repository (PGER).</p>
+<p>The PGEF Core Ontology provides the basis for the database
+structures of the PGEF Repository (PGER).  The layer that
+translates the domain Classes and Properties of the ontology to
+the structure of the database is the Chronosynclastic
+Infundibulum.</p>
 <div class="section" id="o-r-mapping-the-chronosynclastic-infundibulum">
 <h2><a name="o-r-mapping-the-chronosynclastic-infundibulum">O-R Mapping:  The Chronosynclastic Infundibulum</a></h2>
 <p>The O-R Mapping used by the PGEF Repository (PGER) is implemented in the
 Chronosynclastic Infundibulum (the <cite>pangalactic.repo.chronosynclastic</cite>
-module).</p>
-<p>To recap, the default _schema of a PGEF Core Class is a
-PgefObjectSchema instance whose id is the same as the __name__ of
-the class.</p>
-<p>Each PgefObjectSchema known to the registry (initially, the ones
-corresponding to the core classes) has a corresponding database table in
-the repository.  The name of the database table is the name of the core
-class converted from studly caps ('StudlyCaps') to lower-case
+module).  Chronosynclastic makes extensive use of the PGEF Meta Object
+Facility.  To recap, the default _schema of a PGEF Core Class is a
+ObjectSchema instance whose id is the same as the __name__ of the class.</p>
+<p>Each ObjectSchema known to the registry (initially, just the ones
+corresponding to the PGEF core ontology) has a corresponding database table
+in the repository.  The name of the database table is the name of the core
+class converted from studly caps (<cite>StudlyCaps</cite>) to lower-case
 underscore-delimited format, with a leading underscore added
-('_studly_caps') to avoid name clashes.  The table's column names are
-generated from the PgefObjectSchema instance's Property id's (also with
-leading underscores added).</p>
-<p>The database's table relationships and constraints are determined
-by other attributes of the PgefObjectSchemas and PgefProperties.</p>
+(<cite>_studly_caps</cite>) to avoid name clashes.  The table's column names are
+generated from the ObjectSchema instance's Property id's (also with leading
+underscores added).</p>
+<p>The database's table relationships and constraints are determined by other
+attributes of the ObjectSchemas and Properties.</p>
 <blockquote>
 <ul>
 <li><p class="first">required attributes</p>
-<p>A Property with a min_cardinality &gt; 0 signifies a &quot;required&quot;
+<p>A Property with a min_cardinality &gt; 0 signifies a required
 attribute, and the corresponding column is declared 'NOT NULL'.</p>
 </li>
 <li><p class="first">one-to-many relationships</p>
 <p>A one-to-many relationship can be represented either by an
 aggregate-valued property or by reifying the relationship
 (i.e., making it an object).</p>
-<p>If the objects on the 'many' side of a one-to-many
+<p>If the objects on the <em>many</em> side of a one-to-many
 relationship are owned by (or existence-dependent on) the
-object on the 'one' side, an aggregate-valued property
-whose domain is the 'one' side and whose range is the
-'many' side is used to represent the relationship.</p>
-<p>If the objects on the 'many' side are independent of the
-object on the 'one' side, the relationship is probably
+object on the <em>one</em> side, an aggregate-valued property
+whose domain is the <em>one</em> side and whose range is the
+<em>many</em> side is used to represent the relationship.</p>
+<p>If the objects on the <em>many</em> side are independent of the
+object on the <em>one</em> side, the relationship is probably
 actually a many-to-many relationship (anyway, it will be
 treated in the Chronosynclastic O-R mapping as if it were
 many-to-many:  i.e., the relationship will be reified).
 This case is discussed in detail in the next section
 (many-to-many relationships).</p>
 <p>An aggregate-valued Property corresponds to a one-to-many
-relationship.  A Property is aggregate-valued if either:</p>
-<blockquote>
-<ul class="simple">
-<li>max_cardinality == 0 (meaning no limit) or</li>
-<li>max_cardinality &gt; 1</li>
-</ul>
-</blockquote>
+relationship.  The fact that a Property is aggregate-valued is
+represented in one of two ways:</p>
+<pre class="literal-block">
+max_cardinality == 0 (meaning no limit) or
+
+max_cardinality == n (where n &gt; 1)
+</pre>
 <p>The aggregate-valued property will be represented as a
 list-valued attribute in the Python object that receives it
 in a schema (i.e., a Python object that represents an
@@ -564,8 +512,8 @@
 is done explicitly in the PanGalactic core ontology by
 reifying (representing as an object) all many-to-many
 relationships (or one-to-many relationships in which the
-object on the 'many' side is not existence-dependent on the
-object on the 'one' side).</p>
+object on the <em>many</em> side is not existence-dependent on the
+object on the <em>one</em> side).</p>
 <p>An example is the Assembly Component Usage (Acu) class,
 which represents the &quot;part of&quot; relationship between a part
 and an assembly in which it is used.  Reifying the
@@ -598,70 +546,63 @@
 </div>
 <div class="section" id="notes-on-the-pger-xml-rpc-search-interface">
 <h2><a name="notes-on-the-pger-xml-rpc-search-interface">Notes on the PGER XML-RPC search interface</a></h2>
-<p>search(schemaid, refs, subtypes, args)</p>
-<blockquote>
-<p>... where:</p>
-<dl class="docutils">
-<dt>schemaid  = id (name) of the PgefObjectSchema whose instances</dt>
-<dd>are being searched for</dd>
-<dt>refs      = 0 -&gt; don't get 1st level of referenced objects</dt>
-<dd>1 -&gt; do     &quot;   &quot;    &quot;    &quot;     &quot;         &quot;</dd>
-<dt>subtypes  = 0 -&gt; don't get subtypes</dt>
-<dd>1 -&gt; get subtypes</dd>
-<dt>args      = a list of 3-tuples of the form</dt>
-<dd><p class="first">(attrname, logical-operator, value)</p>
-<ul class="last simple">
-<li>logical-operator can be anything usable in
-an SQL query, such as '=', '&lt;=', 'like', etc.</li>
-<li>for a strings, '=' means exact match, and
-'like' means a case-insensitive match
-on the value as a substring</li>
-</ul>
-</dd>
-</dl>
-</blockquote>
+<p><strong>Syntax</strong>:</p>
+<pre class="literal-block">
+search(schemaid, refs, subtypes, args)
+
+... where:
+
+schemaid  = id (name) of the ObjectSchema whose instances
+            are being searched for
+
+refs      = 0 -&gt; don't get 1st level of referenced objects
+            1 -&gt; do     &quot;   &quot;    &quot;    &quot;     &quot;         &quot;
+
+subtypes  = 0 -&gt; don't get subtypes
+            1 -&gt; get subtypes
+
+args      = a list of 3-tuples of the form
+            (attrname, logical-operator, value)
+
+            - logical-operator can be anything usable in
+              an SQL query, such as '=', '&lt;=', 'like', etc.
+
+            - for strings, '=' means exact match, and
+              'like' means case-insensitive match
+              on the value as a substring
+</pre>
 <p>Some examples of valid 'args' lists:</p>
-<ul>
-<li><p class="first">[('pgef_oid', '=', 'admin')]</p>
-</li>
-<li><p class="first">[('pgef_oid', 'like', 'smallberries')]</p>
-</li>
-<li><p class="first">[('create_datetime', '&lt;', '2004-02-02')]</p>
-<p>Note:  for datetime searches, dates must be in ISO format:
-YYYY-MM-DD [HH:MM:SS]</p>
-</li>
-<li><dl class="first docutils">
-<dt>[('publish_date', 'is', 'null'),</dt>
-<dd><p class="first last">('pger_create_datetime', 'is not', 'null')]</p>
-</dd>
-</dl>
-<p>Note:  for null searches, the operator <em>must</em> be 'is' or 'is
-not' and the value <em>must</em> be 'null' (they are both
-case-insensitive).</p>
-</li>
-<li><dl class="first docutils">
-<dt>[('change_flag', 'boolean', 1),</dt>
-<dd><p class="first last">('validated_flag', 'boolean', 0)]</p>
-</dd>
-</dl>
-<p>Note:  for boolean searches, the operator must be 'boolean'
-(case-insensitive) and the value must be 1 or 0.</p>
-</li>
-<li><dl class="first docutils">
-<dt>[('parent_oid', 'in',</dt>
-<dd><dl class="first last docutils">
-<dt>['admin.1086874967.03', 'admin.1086874967.16',</dt>
-<dd><p class="first last">'admin.1086874967.57', 'admin.1086874967.72',
-'admin.1086874967.87', 'admin.1086874968.16',
-'admin.1086874966.9'])]</p>
-</dd>
-</dl>
-</dd>
-</dl>
-<p>Note:  in searches of lists of values, the operator can be
-either 'in' or 'not in'.</p>
-</li>
-</ul>
+<pre class="literal-block">
+[('pgef_oid', '=', 'admin')]
+
+[('pgef_oid', 'like', 'smallberries')]
+
+[('create_datetime', '&lt;', '2004-02-02')]
+
+    Note:  for datetime searches, dates must be in ISO format:
+    YYYY-MM-DD [HH:MM:SS]
+
+[('publish_date', 'is', 'null'),
+ ('pger_create_datetime', 'is not', 'null')]
+
+    Note:  for null searches, the operator *must* be 'is' or 'is not'
+    and the value *must* be 'null' (they are both case-insensitive).
+
+[('change_flag', 'boolean', 1),
+ ('validated_flag', 'boolean', 0)]
+
+    Note:  for boolean searches, the operator must be 'boolean'
+    (case-insensitive) and the value must be 1 or 0. 
+
+[('parent_oid', 'in',
+  ['admin.1086874967.03', 'admin.1086874967.16',
+   'admin.1086874967.57', 'admin.1086874967.72',
+   'admin.1086874967.87', 'admin.1086874968.16',
+   'admin.1086874966.9'])]
+
+    Note:  in searches of lists of values, the operator can be
+    either 'in' or 'not in'.
+</pre>
 </div>
 </div>
 <div class="section" id="the-pgef-gui-pangalaxian">
@@ -670,34 +611,39 @@
 <div class="section" id="building-a-self-extracting-executable-of-pangalaxian">
 <h2><a name="building-a-self-extracting-executable-of-pangalaxian">Building a self-extracting executable of PanGalaxian</a></h2>
 <p>Build the executable on a Windows W2K machine.</p>
-<p>You must have the following software installed in order to build an executable.
-This is in addition to any software required to run the application from source.</p>
-<p>py2exe     - creates the &lt;appname&gt;.exe
-Inno Setup - creates the setup.exe</p>
-<p>If you have not already done so, there are a few steps to take prior to building
-an executable.</p>
-<p>First, find POSException.py and copy it to the Python23 directory; it should be
-in the ZODB subdirectory of site-packages.</p>
-<p>Next, unzip the rl_win32_2_3.zip archive into the reportlab subdirectory of
-site-packages.  If you don't have this archive, you can get it from the
-ReportLab site.  Otherwise, you'll have many more undefined symbols, and some of
-them actually _need_ to be defined.</p>
-<p>Finally, make sure you have freshly installed your application in site-packages.
-You can accomplish this by first deleting the build subdirectory under your main
-application directory (in this case, PanGalactic), and then running &quot;python
-setup.py install&quot; from the command line.</p>
+<p>You must have the following software installed in order to build an
+executable:</p>
+<ul class="simple">
+<li><cite>py2exe</cite> (creates the <cite>&lt;appname&gt;.exe</cite>)</li>
+<li><cite>Inno Setup</cite> (creates the <cite>setup.exe</cite>)</li>
+</ul>
+<p>(This is in addition to any software required to run the application from
+source.)</p>
+<p>If you have not already done so, there are a few steps to take prior to
+building an executable.</p>
+<p>First, find POSException.py and copy it to the Python23 directory; it
+should be in the ZODB subdirectory of site-packages.</p>
+<p>Next, unzip the <cite>rl_win32_2_3.zip</cite> archive into the reportlab subdirectory
+of site-packages.  If you don't have this archive, you can get it from the
+<a class="reference" href="http://www.reportlab.org">ReportLab</a> site.  Otherwise, you'll have many more undefined symbols, and
+some of them actually <em>need</em> to be defined.</p>
+<p>Finally, make sure you have freshly installed your application in
+site-packages.  You can accomplish this by first deleting the build
+subdirectory under your main application directory (in this case,
+PanGalactic), and then running <cite>python setup.py install</cite> from the command
+line.</p>
 <p>The steps are:</p>
 <blockquote>
 <ul>
-<li><p class="first">Create a pangalaxian.exe</p>
+<li><p class="first">Create a <cite>pangalaxian.exe</cite></p>
 </li>
 <li><p class="first">Test Test Test</p>
 </li>
-<li><p class="first">Create a setup.exe</p>
+<li><p class="first">Create a <cite>setup.exe</cite></p>
 </li>
 <li><p class="first">Test this, too</p>
 </li>
-<li><p class="first">Copy the setup.exe to the download area on the server as:</p>
+<li><p class="first">Copy the <cite>setup.exe</cite> to the download area on the server as:</p>
 <pre class="literal-block">
 pangalactic_xxx_setup.exe
 </pre>
@@ -705,19 +651,28 @@
 </ul>
 </blockquote>
 <ol class="loweralpha simple">
-<li>Create a pangalaxian.exe</li>
+<li>Create a <cite>pangalaxian.exe</cite></li>
 </ol>
 <p>There is a setup.py located in the client directory
-(<cite>PanGalacticpangalacticclient</cite>).  Edit the pangalaxian.py file and
-modify the variable VERSION (automation RSN).  The command to enter at a
+(<cite>PanGalacticpangalacticclient</cite>).  Edit the <cite>pangalaxian.py</cite> file and
+modify the variable <cite>VERSION</cite> (automation RSN).  The command to enter at a
 DOS prompt is:</p>
-<p><cite>DOS&gt; python setup.py py2exe -i &quot;POSException&quot; -d c:nasaPanGalacticpangalacticclientdistpangalaxian --ignores &quot;Persistence.Persistent, initgroups, intSet, jarray, java.awt.image, javax.imageio, logger, mxDateTime.__version__, yaml, _rl_accel, Crypto.Cipher, Interface, OpenSSL, java.io.IOException, java.io.InterruptedIOException, java.net, resource, wxPython.lib.PyCrust.version, Crypto.Util&quot;</cite></p>
+<pre class="literal-block">
+DOS&gt; python setup.py py2exe -i &quot;POSException&quot; -d \
+c:\nasa\PanGalactic\pangalactic\client\dist\pangalaxian \
+--ignores &quot;Persistence.Persistent, initgroups, intSet, \
+jarray, java.awt.image, javax.imageio, logger, \
+mxDateTime.__version__, yaml, _rl_accel, Crypto.Cipher, \
+Interface, OpenSSL, java.io.IOException, \
+java.io.InterruptedIOException, java.net, resource, \
+wxPython.lib.PyCrust.version, Crypto.Util&quot;
+</pre>
 <p>This command is also at the top of the <cite>setup.py</cite> file.</p>
 <p>When you run this command, any undefined symbols will be listed at the end of
 the output.  The --ignore option takes a list of symbols to ignore.  The
 executable is generated in the directory specified by the -d parameter.
-Currently, pangalaxian.exe is generated in a subdirectory of client, namely:
-.distpangalaxian</p>
+Currently, <cite>pangalaxian.exe</cite> is generated in a subdirectory of client, namely:
+<cite>.\dist\pangalaxian\</cite></p>
 <p>On to the next step...</p>
 <ol class="loweralpha simple" start="2">
 <li>Test Test Test</li>
@@ -726,207 +681,199 @@
 are not yet comprehensive, you also need to test connection, download, editting,
 upload, and anything else that doesn't yet have a test case.</p>
 <ol class="loweralpha simple" start="3">
-<li>Create a setup.exe</li>
-</ol>
-<p>Start the Inno Setup application.  Open the pangalaxian.iss script.  Modify the
-variable AppVerName to match the variable VERSION in pangalaxian.py.</p>
-<ol class="loweralpha simple" start="4">
+<li>Create a <cite>setup.exe</cite><ul>
+<li>Start the Inno Setup application.</li>
+<li>Open the <cite>pangalaxian.iss</cite> script.</li>
+<li>Modify the variable AppVerName to match the variable VERSION in
+<cite>pangalaxian.py</cite>.</li>
+</ul>
+</li>
 <li>Test Test Test</li>
 </ol>
-<p>Install setup.exe to the default location.  Run all the same tests that you did
-for pangalaxian.exe.  Uninstall it, and reinstall it to a non-default location.
+<p>Install <cite>setup.exe</cite> to the default location.  Run all the same tests that you did
+for <cite>pangalaxian.exe</cite>.  Uninstall it, and reinstall it to a non-default location.
 Run those tests again.</p>
-<p>If you're completely satisfied, rename setup.exe to
+<p>If you're completely satisfied, rename <cite>setup.exe</cite> to
 <cite>pangalactic_xxx_setup.exe</cite>, where xxx corresponds to the variable
 <cite>VERSION</cite>.</p>
 <ol class="loweralpha simple" start="5">
 <li>Copy the <cite>pangalactic_xxx_setup.exe</cite> to the download area on the server</li>
 </ol>
 <p>Open an sftp session to the server, and copy <cite>pangalactic_xxx_setup.exe</cite> to:
-/usr/local/apps/ned/www/beta</p>
+<cite>/usr/local/apps/ned/www/beta</cite></p>
 </div>
 </div>
 <div class="section" id="troubleshooting">
 <h1><a name="troubleshooting">Troubleshooting</a></h1>
 <p>Problem: Invoking Acrobat Reader on linux using version 5.0.8 aborts.</p>
-<dl class="docutils">
-<dt>Workaround: Edit the acroread script, which should be   </dt>
-<dd><p class="first">&lt;wherever you installed it&gt;/bin/acroread.</p>
-<p>Right after the line which begins:</p>
-<p>install_dir=&lt;wherever you installed it&gt;</p>
+<p>Workaround:</p>
+<ul>
+<li><p class="first">Edit the acroread script, which should be:</p>
+<pre class="literal-block">
+&lt;wherever you installed it&gt;/bin/acroread. 
+</pre>
+</li>
+<li><p class="first">Right after the line which begins:</p>
+<pre class="literal-block">
+install_dir=&lt;wherever you installed it&gt;
+</pre>
 <p>add:</p>
-<p>export LANG=C</p>
-<p class="last">This fix assumes you are running bash.  Modify the 
+<pre class="literal-block">
+export LANG=C
+</pre>
+</li>
+</ul>
+<p>This fix assumes you are running bash.  Modify the 
 line appropriately for other shells.</p>
-</dd>
-</dl>
 </div>
-<div class="section" id="testing-pangalaxian">
-<h1><a name="testing-pangalaxian">Testing PanGalaxian</a></h1>
-<p>There are a handful of existing tests that are up-to-date.  (If
-any!)  Before you start testing, make sure you have removed any
-client data (in the <cite>pangalactic/node</cite> dir, execute <cite>'rm data/*'</cite>),
-and remove the state file, 'state.json', from the node directory.</p>
+<div class="section" id="manually-testing-pangalaxian">
+<h1><a name="manually-testing-pangalaxian">Manually &quot;Testing&quot; PanGalaxian</a></h1>
+<p>There are a handful of PanGalaxian unit existing tests that are up-to-date
+(okay, maybe None!).  Before you start this simple form of &quot;testing&quot;, make
+sure you have removed any client data (in the <cite>pangalactic/node</cite> dir,
+execute <cite>'rm data/*'</cite>), and remove the state file, <cite>state.json</cite>, from the
+node directory.</p>
 <blockquote>
-<ul>
-<li><p class="first">Start the application</p>
+<ul class="simple">
+<li>Start the application</li>
+<li>Select your repository</li>
+<li>Enter your username and email in the window</li>
+<li>Login</li>
+<li>Select the H2G2 project<ul>
+<li>See all the data show up</li>
+</ul>
 </li>
-<li><p class="first">Select your repository</p>
+<li>Select a model.  Preferable HOG.1-CAD<ul>
+<li>See the pretty tree</li>
+</ul>
 </li>
-<li><p class="first">Enter your username and email in the window</p>
+<li>Double-click on HOG.1-CAD in the tree<ul>
+<li>See the pretty editor</li>
+<li>Close the editor window</li>
+</ul>
 </li>
-<li><p class="first">Login</p>
+<li>Double-click on the HOG.1-CAD in the grid<ul>
+<li>See the editor again</li>
+<li>Close it again</li>
+</ul>
 </li>
-<li><p class="first">Select the H2G2 project</p>
-<blockquote>
-<p>See all the data show up</p>
-</blockquote>
+<li>Click on a plus in the tree<ul>
+<li>See the tree expand</li>
+<li>The plus disappears if there are no children</li>
+</ul>
 </li>
-<li><p class="first">Select a model.  Preferable HOG.1-CAD</p>
-<blockquote>
-<p>See the pretty tree</p>
-</blockquote>
+<li>Select Tools-&gt;Search...<ul>
+<li>The Search window appears</li>
+<li>Specify at least 1 search criterion</li>
+<li>Click [Search]</li>
+<li>if successful<ul>
+<li>See the Summary page with result counts</li>
+<li>Click on the tabs of each result type (e.g., Part, Model)<ul>
+<li>See an overview of each result type</li>
+</ul>
 </li>
-<li><p class="first">Double-click on HOG.1-CAD in the tree</p>
-<blockquote>
-<p>See the pretty editor
-Close the editor window</p>
-</blockquote>
+<li>Click on the Criteria tab</li>
+</ul>
 </li>
-<li><p class="first">Double-click on the HOG.1-CAD in the grid</p>
-<blockquote>
-<p>See the editor again
-Close it again</p>
-</blockquote>
+<li>else<ul>
+<li>Click [OK] on the Search Error window</li>
+</ul>
 </li>
-<li><p class="first">Click on a plus in the tree</p>
-<blockquote>
-<p>See the tree expand
-The plus disappears if there are no children</p>
-</blockquote>
+<li>Repeat as many times as you like</li>
+<li>Close the window</li>
+</ul>
 </li>
-<li><p class="first">Select Tools-&gt;Search...</p>
-<blockquote>
-<p>The Search window appears
-Specify at least 1 search criterion
-Click [Search]
-if successful</p>
-<blockquote>
-<p>See the Summary page with result counts
-Click on the tabs of each result type (e.g., Part, Model)</p>
-<blockquote>
-<p>See an overview of each result type</p>
-</blockquote>
-<p>Click on the Criteria tab</p>
-</blockquote>
-<p>else</p>
-<blockquote>
-<p>Click [OK] on the Search Error window</p>
-</blockquote>
-<p>Repeat as many times as you like
-Close the window</p>
-</blockquote>
+<li>Select File-&gt;New-&gt;Part...<ul>
+<li>See the Part wizard</li>
+<li>Enter a part number at least</li>
+<li>Enter any additional data you wish</li>
+<li>Click [Save]</li>
+<li>The tree is rebuilt, showing your new part</li>
+<li>Close this window</li>
+<li>Your part is at the bottom of the Part tab in the main window (grey</li>
+<li>background)</li>
+</ul>
 </li>
-<li><p class="first">Select File-&gt;New-&gt;Part...</p>
-<blockquote>
-<p>See the Part wizard
-Enter a part number at least
-Enter any additional data you wish
-Click [Save]
-The tree is rebuilt, showing your new part
-Close this window
-Your part is at the bottom of the Part tab in the main window (grey
-background)</p>
-</blockquote>
+<li>Select File-&gt;New-&gt;Model...<ul>
+<li>See the Model wizard</li>
+<li>Enter a model identifier and model name at least</li>
+<li>Enter any additional data you wish</li>
+<li>Click [Save]</li>
+<li>The tree is rebuilt, showing your new model</li>
+<li>Close this window</li>
+<li>Your model is at the bottom of the Model tab in the main window (grey</li>
+<li>background)</li>
+</ul>
 </li>
-<li><p class="first">Select File-&gt;New-&gt;Model...</p>
-<blockquote>
-<p>See the Model wizard
-Enter a model identifier and model name at least
-Enter any additional data you wish
-Click [Save]
-The tree is rebuilt, showing your new model
-Close this window
-Your model is at the bottom of the Model tab in the main window (grey
-background)</p>
-</blockquote>
+<li>Select File-&gt;New-&gt;Parts List...<ul>
+<li>See the Parts List wizard</li>
+<li>If running on Windows<ul>
+<li>tbd</li>
+</ul>
 </li>
-<li><p class="first">Select File-&gt;New-&gt;Parts List...</p>
-<blockquote>
-<p>See the Parts List wizard
-If running on Windows</p>
-<blockquote>
-<p>tbd</p>
-</blockquote>
-<p>Else</p>
-<blockquote>
-<p>Click [Save]
-Your parts list is added to the tree</p>
-</blockquote>
-<p>Close this window</p>
-</blockquote>
+<li>Else<ul>
+<li>Click [Save]</li>
+<li>Your parts list is added to the tree</li>
+</ul>
 </li>
-<li><p class="first">Select File-&gt;New-&gt;Document...</p>
-<blockquote>
-<p>See the Document wizard
-Enter as much data as you wish
-Click [Save]
-Your document is added to the tree
-Close this window</p>
-</blockquote>
+<li>Close this window</li>
+</ul>
 </li>
-<li><p class="first">Select File-&gt;Export-&gt;Properties...</p>
-<blockquote>
-<p>tbd</p>
-</blockquote>
+<li>Select File-&gt;New-&gt;Document...<ul>
+<li>See the Document wizard</li>
+<li>Enter as much data as you wish</li>
+<li>Click [Save]</li>
+<li>Your document is added to the tree</li>
+<li>Close this window</li>
+</ul>
 </li>
-<li><p class="first">Select File-&gt;Export-&gt;Table Data...</p>
-<blockquote>
-<p>See the PDF creation window   
-Select [Generate PDF for the table]
-Specify the output filename
-Enter the header and footer lines, if any
-Specify any additional options
-Click [Create]
-Click [OK] on the message window</p>
-</blockquote>
+<li>Select File-&gt;Export-&gt;Properties...<ul>
+<li>tbd</li>
+</ul>
 </li>
-<li><p class="first">Right-click on the Model grid</p>
-<blockquote>
-<p>See the PDF creation window   
-Select [Generate PDF for the table]
-Specify the output filename
-Enter the header and footer lines, if any
-Specify any additional options
-Click [Create]
-Click [OK] on the message window</p>
-</blockquote>
+<li>Select File-&gt;Export-&gt;Table Data...<ul>
+<li>See the PDF creation window</li>
+<li>Select [Generate PDF for the table]</li>
+<li>Specify the output filename</li>
+<li>Enter the header and footer lines, if any</li>
+<li>Specify any additional options</li>
+<li>Click [Create]</li>
+<li>Click [OK] on the message window</li>
+</ul>
 </li>
-<li><p class="first">Select Tools-&gt;Local Database Browser...</p>
-<blockquote>
-<p>See the local browser
-Select an entry in the list
-See the grid fill with data
-Repeat for as many as you like
-Close this window</p>
-</blockquote>
+<li>Right-click on the Model grid<ul>
+<li>See the PDF creation window</li>
+<li>Select [Generate PDF for the table]</li>
+<li>Specify the output filename</li>
+<li>Enter the header and footer lines, if any</li>
+<li>Specify any additional options</li>
+<li>Click [Create]</li>
+<li>Click [OK] on the message window</li>
+</ul>
 </li>
-<li><p class="first">Select Repository-&gt;View My Stuff...</p>
-<blockquote>
-<p>if you have created anything that is on the server</p>
-<blockquote>
-<p>See the Search window with the Summary results page</p>
-</blockquote>
-<p>else</p>
-<blockquote>
-<p>Click [OK] on the Search Error window</p>
-</blockquote>
-<p>Close the Search window</p>
-</blockquote>
+<li>Select Tools-&gt;Local Database Browser...<ul>
+<li>See the local browser</li>
+<li>Select an entry in the list</li>
+<li>See the grid fill with data</li>
+<li>Repeat for as many as you like</li>
+<li>Close this window</li>
+</ul>
+</li>
+<li>Select Repository-&gt;View My Stuff...<ul>
+<li>if you have created anything that is on the server<ul>
+<li>See the Search window with the Summary results page</li>
+</ul>
+</li>
+<li>else<ul>
+<li>Click [OK] on the Search Error window</li>
+</ul>
+</li>
+<li>Close the Search window</li>
+</ul>
 </li>
 </ul>
 </blockquote>
-<p>$Id: PgefManual.html,v 1.1 2005/05/16 21:32:17 waterbug Exp $</p>
+<p>$Id: PgefManual.html,v 1.2 2005/05/17 02:03:19 waterbug Exp $</p>
 </div>
 </div>
 </body>

Index: PanGalactic/doc/PgefManual.txt
diff -u PanGalactic/doc/PgefManual.txt:1.1 PanGalactic/doc/PgefManual.txt:1.2
--- PanGalactic/doc/PgefManual.txt:1.1	Mon May 16 17:32:17 2005
+++ PanGalactic/doc/PgefManual.txt	Mon May 16 22:03:19 2005
@@ -5,15 +5,17 @@
 a.k.a. The Hacker's Guide to PanGalactic
 ----------------------------------------
 
-:Author: Stephen Waterbury <stephen.c.waterbury at nasa.gov>
+:Author: Stephen Waterbury <stephen dot c dot waterbury at nasa dot gov>
 :Author: Ginny Keech
-:Version: $Revision: 1.1 $
-:Date: $Date: 2005/05/16 21:32:17 $
+:Version: $Revision: 1.2 $
+:Date: $Date: 2005/05/17 02:03:19 $
 
 
-------------
-Don't Panic!
-------------
+--------
+Foreword
+--------
+
+**Don't Panic!**  :)
 
 This document provides both general and specific information on the current
 release of PGEF.  Its intended audience is PGEF application developers,
@@ -64,168 +66,172 @@
 Scope
 =====
 
-  * In Scope
+* In Scope
+
+  - General
 
-    - General
+    + GUI module supporting both user and admin views
+    + Nekkid objects architecture
+    + Services (repository, etc.)
+    + Authentication
+    + Role-based access control
+    + Secure (asymmetric-key encrypted) connections
+    + API's accessible via multiple protocols/transports
+    + STEP/Express/OWL/XML/UML/XMI data I/O and management
 
-      + GUI functions
-      + Plug-in architecture
-      + Services (repository, etc.)
-      + Authentication
-      + Role-based access control
-      + API's accessible via multiple protocols/transports
-      + STEP/Express data I/O and management
+      * STEP Part 21 (ISO 10303-21) file input/output
+      * STEP XML (ISO 10303-28/OSEB XML format) input/output
+      * Validation of STEP/Express  (ISO 10303-11) schemas
+        and data sets
+      * Mapping and transformation of STEP/Express data sets
+        using Express-X (ISO 10303-14)
 
-        * STEP Part 21 (ISO 10303-21) file input/output
-        * STEP XML (ISO 10303-28/OSEB XML format) input/output
-        * Validation of STEP/Express  (ISO 10303-11) schemas
-          and data sets
-        * Mapping and transformation of STEP/Express data sets
-          using Express-X (ISO 10303-14)
+  - GUI functions
 
-    - GUI
+    + Interface to repository services (search, get, commit)
+    + Interface to local persistence (cache browser)
+    + Rendering of structure trees (assemblies, etc.)
+    + Structured product document creation, maintenance
+    + Workflow
 
-      + Interface to repository services
-      + Interface to local persistence
-      + Rendering of structure trees (assemblies, etc.)
-      + Structured product document creation, maintenance
-      + Workflow interfaces
+  - Infrastructure Services / API's
 
-    - Infrastructure Services / API's (used by plug-ins)
+    + Security and Access Control
 
-      + Security and Access Control
+      * Encryption
+      * Authentication
+      * Authorization (role-based access)
 
-        * Encryption
-        * Authentication
-        * Authorization (role-based access)
+    + Messaging and Subscription/Notification
+    + Organization Directory
+    + Project Directory
+    + Application and Service Directory
+    + Workflow Management
+    + Repository
 
-      + Messaging and Subscription/Notification
-      + Organization Directory
-      + Project Directory
-      + Application and Service Directory
-      + Workflow Management
-      + Repository
+      * Versioned objects (Documents, Models, Parts)
+      * Data/file upload
+      * Access to objects by high-level attributes
+      * Search by attributes and text content
 
-        * Versioned objects (Documents, Models, Parts)
-        * Data/file upload
-        * Access to objects by high-level attributes
-        * Search by attributes and text content
+  - Core applications
 
-    - Core Plug-ins (custom app plug-ins will build on these)
+    + Structured Product Document Production and Management
 
-      + PGPDM (Structured Product Document Production and Management)
+      * status:  almost there
 
-        * status:  almost there
+    + Ontology, Dictionary, and Rules Production and Management
 
-      + PGKM  (Ontology, Dictionary, and Rules Production and Management)
+      * status:  some infrastructure
 
-        * status:  some infrastructure
+    + Model and Data Mapping and Xformation/Xlation
 
-      + PGX   (PG Transformer -- Model and Data Mapping and Xformation/Xlation)
+      * status:  first implementation will use Express Engine
 
-        * status:  first implementation will use Express Engine
+    + Workflow Design and Management
 
-      + PGWFM (PG Flow -- Enterprise Process and Workflow Design and Management)
+      * status:  very simple workflows
 
-        * status:  very simple workflows
+    + Scientific and Mathematical Libraries
 
-      + PGSci (Scientific and Mathematical Libraries)
+      * status:  nothing yet (will interface to SciPy/Numeric)
 
-        * status:  nothing yet (will interface to SciPy/Numeric)
+    + Parts Library -- CAX Model Library and Archive Management
 
-      + PGPL  (PG Parts Library -- CAX Model Library and Archive Management)
+      * status:  not started
 
-        * status:  not started
+    + CAX Tools
 
-      + PGCAX (CAX Tools)
+      * status:  not started
 
-        * status:  not started
 
+* Definitely Out of Scope
 
-  * Out of Scope
+  - Virtual sex toys
 
-    - General
+  - Death ray
 
-      + Death ray
-      + Virtual sex toys
 
 
 Security and Access Control Requirements
 ========================================
 
-  * Access control shall be based upon a combination of security
-    masks and user roles.  
+* Access control shall be based upon a combination of security
+  masks and user roles.  
 
-  * Security masks shall be able to be assigned to:
+* Security masks shall be able to be assigned to:
 
-    - Base classes (subtypes of PgefObject)
-    - Application classes (OntoClasses)
-    - Application class instances 
+  - Base classes (subtypes of PgefObject)
+  - Application classes (OntoClasses)
+  - Application class instances 
 
-  * A set of standard PGEF roles shall be defined, each of which will
-    have a specified set of permissions.
+* A set of standard PGEF roles shall be defined, each of which will
+  have a specified set of permissions.
 
-  * Some standard roles will include permissions to add, delete, and
-    modify new (custom) roles within specified domains and to assign
-    standard and/or custom roles to other users.
+* Some standard roles will include permissions to add, delete, and
+  modify new (custom) roles within specified domains and to assign
+  standard and/or custom roles to other users.
 
 
 Use Case Sketches
 =================
 
-[ Flesh these out, and include the ones in your slides ... ]
+[TODO:  flesh these out, and include the ones in the slides.]
 
-  * Repository and Client (thick or thin)
+* Repository and Client (thick or thin)
 
-    - Implement a STEP-mappable high level information model
-      (ontology) for parts, models, docs, and systems engineering
-      concepts
-    - Retrieve model/doc ref(s) from repository
+  - Implement a STEP-mappable high level information model
+    (ontology) for parts, models, docs, and systems engineering
+    concepts
 
-        + "Get" (by Id/Oid)
-        + "Search" (by parameters)
+  - Retrieve model/doc ref(s) from repository
 
-    - Add model(s)/doc(s) (including files) to repository
+    + "Get" (by Id/Oid)
+    + "Search" (by parameters)
 
-        + "Add" (by Id/Oid)
+  - Add model(s)/doc(s) (including files) to repository
 
-    - Save workflow templates, instances, and states to
-      repository
+    + "Add" (by Id/Oid)
 
-  * Client (thick)
+  - Save workflow templates, instances, and states to
+    repository
 
-    - Wizard for creating structured product documents
-    - Wizard for creating workflow templates and instances
-    - Interface for managing/viewing workflow items and their
-      states
+* Client (thick)
 
+  - Wizard for creating structured product documents
+  - Wizard for creating workflow templates and instances
+  - Interface for managing/viewing workflow items and their
+    states
 
------------------
-The PGEF Ontology
------------------
+
+----------------------
+The PGEF Core Ontology
+----------------------
 
 Scope
 =====
 
-The scope of the Pan Galactic Ontology is intended to include all
-information relevant to products and product models throughout
-the product life cycle.
+The scope of the Pan Galactic Core Ontology is intended to
+include all information relevant to products and product models
+throughout the product life cycle.
 
 
-PGEF's principal domain is the "manufacturing" enterprise, in the broadest
-possible sense of "manufacturing" -- i.e., any type of "product"
-development, where a "product" is any artifact that is or includes one or
-more of the following:  software, firmware, hardware, materials, and
+PGEF's principal domain is the "manufacturing" enterprise, in the
+broadest possible sense of "manufacturing" -- i.e., any type of
+"product" life cycle support (as the current buzz words go) where
+a "product" is any artifact that is or includes one or more of
+the following:  software, firmware, hardware, materials, and
 documents.
 
 Consequently, one of PGEF's principal goals is to collect, integrate, and
-manage information about products (known in the PGEF Ontology as "parts"),
+manage information about products (known in the PGEF Core Ontology as "parts"),
 models, and documents created and used by the enterprise.  To define the
 objects of its domain, PGEF implements a simple core ontology of the most
 basic classes of things that occur in enterprises that develop products.
 
-[ TODO: generate the PGEF Ontology into PanGalactic/home/pgef.owl and
-reference it from this section as the PGEF Core Ontology. ]
+[TODO: generate the PGEF Core Ontology into
+PanGalactic/home/pgef.owl and reference it from this section as
+the PGEF Core Ontology. ]
 
 
 The PGEF Meta Object Facility
@@ -235,48 +241,46 @@
 not implement the OMG Meta Object Facility but has a very similar intent.  
 Its principal classes are:
 
-  - PgefObjectSchema
+  - **ObjectSchema**
 
-    The PgefObjectSchema class represents an ontological class, and defines
-    a set of associated attributes (Property instances; 'Properties' in
+    The ObjectSchema class represents an ontological class, and defines a
+    set of associated attributes (Property instances; 'Properties' in
     ontological parlance) for which that class is the domain.  [Link to the
-    PgefObjectSchema API documentation here:
-    L{pangalactic.meta.pgefobjectschema.PgefObjectSchema}]
+    ObjectSchema API documentation here:
+    L{pangalactic.meta.objectschema.ObjectSchema}]
 
-  - Property
+  - **Property**
 
-    The Property class represents an ontological Property.
-    In PGEF, an ontological Property is represented as an
-    attribute of its domain class.  Thus, Property
-    instances used to define the attributes of PgefObjectSchema
-    instances.  [Link to the Property API documentation
-    here: L{pangalactic.meta.pgefproperty.Property}]
+    The Property class represents an ontological Property.  In PGEF, an
+    ontological Property is represented as an attribute of its domain
+    class.  Thus, Property instances used to define the attributes of
+    ObjectSchema instances.  [Link to the Property API documentation here:
+    L{pangalactic.meta.pgefproperty.Property}]
 
     * Every Property has a 'pgef_datatype' (default value:
-      'str'), which must be one of: 'str', 'int', 'bool', 'DateTime',
-      or the id of a registered PgefObjectSchema (in which case its
-      'property_type' must be set to 'object').  If the
-      Property's value is an aggregate of objects, then
-      'max_cardinality' must be either an integer greater than 1 or
-      (if the aggregate is unlimited in size) 0.
+      'str'), which must be one of: 'str', 'int', 'bool', 'DateTime', or
+      the id of a registered ObjectSchema (in which case its
+      'property_type' must be set to 'object').  If the Property's value is
+      an aggregate of objects, then 'max_cardinality' must be either an
+      integer greater than 1 or (if the aggregate is unlimited in size) 0.
 
     * An Property can have a default value, which is specified in
       the 'default' attribute and must be encoded as a string.  The
       "default default" values are the null of each type:
 
-        - Strings:  are literal (default default: '')
-        - Integers: are cast to int (default default: 0)
-        - Booleans: '' == False; any non-empty string == True
-                    (default default: False)
-        - DateTime: DateTime-valued PgefProperties have a default of
-                    None.  [Note that this does not pertain to
-                    "initialization" values -- e.g., the
-                    initialization value for 'create_datetime' is
-                    DateTime.now().]
-        - Classes:  object-valued PgefProperties (cf.
-                    owl:ObjectProperty) have a default of None if
-                    their max_cardinality == 1; otherwise, the
-                    default is an empty list ([]).
+      - Strings:  are literal (default default: '')
+      - Integers: are cast to int (default default: 0)
+      - Booleans: '' == False; any non-empty string == True
+                  (default default: False)
+      - DateTime: DateTime-valued Properties have a default of
+                  None.  [Note that this does not pertain to
+                  "initialization" values -- e.g., the
+                  initialization value for 'create_datetime' is
+                  DateTime.now().]
+      - Classes:  object-valued Properties (cf.
+                  owl:ObjectProperty) have a default of None if
+                  their max_cardinality == 1; otherwise, the
+                  default is an empty list ([]).
 
 
 The PGEF Core Classes
@@ -287,16 +291,18 @@
 software classes that represent ontological classes are sometimes referred
 to as domain objects:  "a domain object is a logical container of purely
 domain information, [and] usually represents a logical entity in the
-problem domain space" [http://c2.com/cgi/wiki?DomainObject].
+problem domain space" (source: `The Wiki`_).
+
+.. _The Wiki:  http://c2.com/cgi/wiki?DomainObject
 
 PgefObject is the root class of the PGEF Core Classes, so hereafter
-'PgefObject' will be used to refer to any PGEF Core Class.
+the term *PgefObject* will be used to refer to any PGEF Core Class.
 
 In PGEF, the concept of an ontological class is represented by the
-PgefObjectSchema class.  Each PgefObject instance is assigned at creation
-time an instance of PgefObjectSchema as its '_schema'.  The '_schema'
-defines the set of attributes of that instance that will be stored when and
-if the instance is committed to the repository, PGER.
+ObjectSchema class.  Each PgefObject instance is assigned at creation time
+an instance of ObjectSchema as its '_schema'.  The '_schema' defines the
+set of attributes of that instance that will be stored when and if the
+instance is committed to the repository, PGER.
 
 Note that a PgefObject instance can have other attributes for various
 purposes (local state, etc.), and these can be persisted locally (in the
@@ -305,8 +311,8 @@
 that instance in a distributed application unless that is done by way of an
 application protocol that is not part of the state of the domain object.
 
-Although the PGEF core ontology is fairly broad in scope, its focus is the
-domain of Systems Engineering.
+Although the PGEF core ontology is fairly broad in scope, its primary focus
+is the domain of Systems Engineering.
 
 
 ---------------------
@@ -317,7 +323,7 @@
 Software Components of PGEF
 ===========================
 
-* PGER -- the Pan Galactic Engineering Repository
+* **PGER** -- the Pan Galactic Engineering Repository
 
     [see `The Pan Galactic Engineering Repository (PGER)`_, for
     more detail.]
@@ -342,23 +348,23 @@
 
         + implements the XML-RPC representation of the PGER API
 
-* Chronosynclastic -- the PGER Object-Relational Backend
+* **Chronosynclastic** -- the PGER Object-Relational Backend
 
     [see `O-R Mapping:  The Chronosynclastic Infundibulum`_, for
     more detail.]
 
-    - uses Twisted's adbapi, which provides a non-blocking database
-      API that returns "deferred" place-holders that are called
-      back with results when they become available.
-
-    - generates its database schema from the application ontology.
-      The default schema is generated from the PGEF Core Ontology,
-      which application can extend by adding other ontologies
-      and/or ontological classes (PgefObjectSchema instances).
+    - uses Twisted's adbapi, which provides a non-blocking database API
+      that returns "deferred" place-holders that are called back with
+      results when they become available.
+
+    - generates its database schema from the application ontology.  The
+      default schema is generated from the PGEF Core Ontology, which
+      application can extend by adding other ontologies and/or ontological
+      classes (ObjectSchema instances).
 
     - provides a flexible O-R mapping
 
-* PanGalaxian -- the PGEF GUI
+* **PanGalaxian** -- the PGEF GUI
 
     [see `The PGEF GUI:  PanGalaxian`_, for more detail.]
 
@@ -371,7 +377,7 @@
     - Includes tools for creating, validating, and managing Structured
       Product Documents
 
-* PanGalactic Communications Hub -- the PGEF Hub
+* **PanGalactic Communications Hub** -- the PGEF Hub
 
     [Not implemented yet.]
 
@@ -393,57 +399,46 @@
 
 Miscellaneous notes on architectural features.
 
-PGEF OID's:  Unique Object Identifiers
---------------------------------------
 
-Each PGEF application object is assigned a unique identifier, the 'oid'.
-The preferred form for the oid is a URI, if one is available or can be
-constructed canonically.  Otherwise, an arbitrary (but unique) one will be
-generated as follows:
+* **PGEF OID's**:  Unique Object Identifiers
 
-`[canonical userid of object creator] + [time-date stamp of creation-time]`
+    Each PGEF application object is assigned a unique identifier, the
+    'oid'.  The preferred form for the oid is a URI, if one is
+    available or can be constructed canonically.  Otherwise, an
+    arbitrary (but unique) one will be generated as follows:
+
+    `[canonical userid of object creator] + [time-date stamp of creation-time]`
+     
+    where the canonical userid is the user's email address and the
+    time-date stamp is in Universal Time.
  
-where the canonical userid is the user's email address and the time-date stamp
-is in Universal Time.
- 
-
-PGEF Application Templates
---------------------------
-
-[This section is obviously in need of some fleshing out.]
-
-    * Structured Product Document Publishing
-
-    * Model Management and Collaboration
-
-
-Distributed Architecture (VGER)
--------------------------------
-
-[Not implemented yet.]
-
-The PGEF repository, PGER, will be configurable either as a
-single node or as a distributed set of peer nodes forming a
-Virtual Galactic Repository (VGER).  In either configuration, a
-PGER node will manage some objects locally and obtain references
-to others from authoritative sources, possibly caching them with
-a reference to their source.
 
-In the VGER configuration, some of the PGER nodes may be
-specialized, perhaps providing a single PGEF service, e.g., a
-project directory service, a workflow management service, an
-ontology and dictionary management service, etc.
+* **VGER**:  Distributed Architecture 
 
-Some of these PGER nodes may be essentially mirrors or wrappers
-of authoritative data sources, possibly with some locally-created
-items that will be maintained independently of updates of
-mirrored data.
+    [Not implemented yet.]
 
-A particular PGER node may opt to cache only that portion of a
-peer service's data that applies to the instance data of the
-service it is managing.  For example, a PGER node may only
-include data about personnel who own models or who are working on
-a project that exists in the context of that node.
+    The PGEF repository, PGER, will be configurable either as a
+    single node or as a distributed set of peer nodes forming a
+    Virtual Galactic Repository (VGER).  In either configuration, a
+    PGER node will manage some objects locally and obtain references
+    to others from authoritative sources, possibly caching them with
+    a reference to their source.
+
+    In the VGER configuration, some of the PGER nodes may be
+    specialized, perhaps providing a single PGEF service, e.g., a
+    project directory service, a workflow management service, an
+    ontology and dictionary management service, etc.
+
+    Some of these PGER nodes may be essentially mirrors or wrappers
+    of authoritative data sources, possibly with some locally-created
+    items that will be maintained independently of updates of
+    mirrored data.
+
+    A particular PGER node may opt to cache only that portion of a
+    peer service's data that applies to the instance data of the
+    service it is managing.  For example, a PGER node may only
+    include data about personnel who own models or who are working on
+    a project that exists in the context of that node.
 
 
 
@@ -451,10 +446,11 @@
 The Pan Galactic Engineering Repository (PGER)
 ----------------------------------------------
 
-The PGEF Ontology provides the basis for the database structures of the
-PGEF Repository (PGER).  The layer that translates the domain Classes and
-Properties of the ontology to the structure of the database is the
-Chronosynclastic Infundibulum.
+The PGEF Core Ontology provides the basis for the database
+structures of the PGEF Repository (PGER).  The layer that
+translates the domain Classes and Properties of the ontology to
+the structure of the database is the Chronosynclastic
+Infundibulum.
 
 
 O-R Mapping:  The Chronosynclastic Infundibulum
@@ -464,24 +460,23 @@
 Chronosynclastic Infundibulum (the `pangalactic.repo.chronosynclastic`
 module).  Chronosynclastic makes extensive use of the PGEF Meta Object
 Facility.  To recap, the default _schema of a PGEF Core Class is a
-PgefObjectSchema instance whose id is the same as the __name__ of
-the class.
+ObjectSchema instance whose id is the same as the __name__ of the class.
 
-Each PgefObjectSchema known to the registry (initially, just the ones
+Each ObjectSchema known to the registry (initially, just the ones
 corresponding to the PGEF core ontology) has a corresponding database table
 in the repository.  The name of the database table is the name of the core
-class converted from studly caps ('StudlyCaps') to lower-case
+class converted from studly caps (`StudlyCaps`) to lower-case
 underscore-delimited format, with a leading underscore added
-('_studly_caps') to avoid name clashes.  The table's column names are
-generated from the PgefObjectSchema instance's Property id's (also with
-leading underscores added).
+(`_studly_caps`) to avoid name clashes.  The table's column names are
+generated from the ObjectSchema instance's Property id's (also with leading
+underscores added).
 
-The database's table relationships and constraints are determined
-by other attributes of the PgefObjectSchemas and PgefProperties.
+The database's table relationships and constraints are determined by other
+attributes of the ObjectSchemas and Properties.
 
     * required attributes
 
-      A Property with a min_cardinality > 0 signifies a "required"
+      A Property with a min_cardinality > 0 signifies a required
       attribute, and the corresponding column is declared 'NOT NULL'.
 
     * one-to-many relationships
@@ -490,14 +485,14 @@
       aggregate-valued property or by reifying the relationship
       (i.e., making it an object).
 
-      If the objects on the 'many' side of a one-to-many
+      If the objects on the *many* side of a one-to-many
       relationship are owned by (or existence-dependent on) the
-      object on the 'one' side, an aggregate-valued property
-      whose domain is the 'one' side and whose range is the
-      'many' side is used to represent the relationship.
+      object on the *one* side, an aggregate-valued property
+      whose domain is the *one* side and whose range is the
+      *many* side is used to represent the relationship.
 
-      If the objects on the 'many' side are independent of the
-      object on the 'one' side, the relationship is probably
+      If the objects on the *many* side are independent of the
+      object on the *one* side, the relationship is probably
       actually a many-to-many relationship (anyway, it will be
       treated in the Chronosynclastic O-R mapping as if it were
       many-to-many:  i.e., the relationship will be reified).
@@ -506,11 +501,11 @@
 
       An aggregate-valued Property corresponds to a one-to-many
       relationship.  The fact that a Property is aggregate-valued is
-      represented in one of two ways:
+      represented in one of two ways::
 
-        - max_cardinality == 0 (meaning no limit) or
+        max_cardinality == 0 (meaning no limit) or
 
-        - max_cardinality == n (where n > 1)
+        max_cardinality == n (where n > 1)
 
       The aggregate-valued property will be represented as a
       list-valued attribute in the Python object that receives it
@@ -527,8 +522,8 @@
       is done explicitly in the PanGalactic core ontology by
       reifying (representing as an object) all many-to-many
       relationships (or one-to-many relationships in which the
-      object on the 'many' side is not existence-dependent on the
-      object on the 'one' side).
+      object on the *many* side is not existence-dependent on the
+      object on the *one* side).
 
       An example is the Assembly Component Usage (Acu) class,
       which represents the "part of" relationship between a part
@@ -563,60 +558,62 @@
 Notes on the PGER XML-RPC search interface
 ==========================================
 
-search(schemaid, refs, subtypes, args)
-
-  ... where:
+**Syntax**::
 
-  schemaid  = id (name) of the PgefObjectSchema whose instances
-              are being searched for
+    search(schemaid, refs, subtypes, args)
 
-  refs      = 0 -> don't get 1st level of referenced objects
-              1 -> do     "   "    "    "     "         "
+    ... where:
 
-  subtypes  = 0 -> don't get subtypes
-              1 -> get subtypes
-
-  args      = a list of 3-tuples of the form
-              (attrname, logical-operator, value)
+    schemaid  = id (name) of the ObjectSchema whose instances
+                are being searched for
+ 
+    refs      = 0 -> don't get 1st level of referenced objects
+                1 -> do     "   "    "    "     "         "
+ 
+    subtypes  = 0 -> don't get subtypes
+                1 -> get subtypes
+ 
+    args      = a list of 3-tuples of the form
+                (attrname, logical-operator, value)
+ 
+                - logical-operator can be anything usable in
+                  an SQL query, such as '=', '<=', 'like', etc.
 
-              - logical-operator can be anything usable in
-                an SQL query, such as '=', '<=', 'like', etc.
-              - for a strings, '=' means exact match, and
-                'like' means a case-insensitive match
-                on the value as a substring
+                - for strings, '=' means exact match, and
+                  'like' means case-insensitive match
+                  on the value as a substring
 
-Some examples of valid 'args' lists:
+Some examples of valid 'args' lists::
 
-*  [('pgef_oid', '=', 'admin')]
+    [('pgef_oid', '=', 'admin')]
 
-*  [('pgef_oid', 'like', 'smallberries')]
+    [('pgef_oid', 'like', 'smallberries')]
 
-*  [('create_datetime', '<', '2004-02-02')]
+    [('create_datetime', '<', '2004-02-02')]
 
-   Note:  for datetime searches, dates must be in ISO format:
-   YYYY-MM-DD [HH:MM:SS]
+        Note:  for datetime searches, dates must be in ISO format:
+        YYYY-MM-DD [HH:MM:SS]
 
-*  [('publish_date', 'is', 'null'),
-    ('pger_create_datetime', 'is not', 'null')]
+    [('publish_date', 'is', 'null'),
+     ('pger_create_datetime', 'is not', 'null')]
 
-   Note:  for null searches, the operator *must* be 'is' or 'is
-   not' and the value *must* be 'null' (they are both
-   case-insensitive).
+        Note:  for null searches, the operator *must* be 'is' or 'is not'
+        and the value *must* be 'null' (they are both case-insensitive).
 
-*  [('change_flag', 'boolean', 1),
-    ('validated_flag', 'boolean', 0)]
+    [('change_flag', 'boolean', 1),
+     ('validated_flag', 'boolean', 0)]
 
-   Note:  for boolean searches, the operator must be 'boolean'
-   (case-insensitive) and the value must be 1 or 0. 
+        Note:  for boolean searches, the operator must be 'boolean'
+        (case-insensitive) and the value must be 1 or 0. 
 
-*  [('parent_oid', 'in',
-     ['admin.1086874967.03', 'admin.1086874967.16',
-      'admin.1086874967.57', 'admin.1086874967.72',
-      'admin.1086874967.87', 'admin.1086874968.16',
-      'admin.1086874966.9'])]
+    [('parent_oid', 'in',
+      ['admin.1086874967.03', 'admin.1086874967.16',
+       'admin.1086874967.57', 'admin.1086874967.72',
+       'admin.1086874967.87', 'admin.1086874968.16',
+       'admin.1086874966.9'])]
 
-   Note:  in searches of lists of values, the operator can be
-   either 'in' or 'not in'.
+        Note:  in searches of lists of values, the operator can be
+        either 'in' or 'not in'.
 
 
 --------------------------
@@ -631,59 +628,70 @@
 
 Build the executable on a Windows W2K machine.
 
-You must have the following software installed in order to build an executable.
-This is in addition to any software required to run the application from source.
+You must have the following software installed in order to build an
+executable:
 
-py2exe     - creates the <appname>.exe
-Inno Setup - creates the setup.exe
+* `py2exe` (creates the `<appname>.exe`)
+* `Inno Setup` (creates the `setup.exe`)
 
-If you have not already done so, there are a few steps to take prior to building
-an executable.
+(This is in addition to any software required to run the application from
+source.)
 
-First, find POSException.py and copy it to the Python23 directory; it should be
-in the ZODB subdirectory of site-packages.
-
-Next, unzip the rl_win32_2_3.zip archive into the reportlab subdirectory of
-site-packages.  If you don't have this archive, you can get it from the
-ReportLab site.  Otherwise, you'll have many more undefined symbols, and some of
-them actually _need_ to be defined.
-
-Finally, make sure you have freshly installed your application in site-packages.
-You can accomplish this by first deleting the build subdirectory under your main
-application directory (in this case, PanGalactic), and then running "python
-setup.py install" from the command line.
+If you have not already done so, there are a few steps to take prior to
+building an executable.
+
+First, find POSException.py and copy it to the Python23 directory; it
+should be in the ZODB subdirectory of site-packages.
+
+Next, unzip the `rl_win32_2_3.zip` archive into the reportlab subdirectory
+of site-packages.  If you don't have this archive, you can get it from the
+ReportLab_ site.  Otherwise, you'll have many more undefined symbols, and
+some of them actually *need* to be defined.
+
+Finally, make sure you have freshly installed your application in
+site-packages.  You can accomplish this by first deleting the build
+subdirectory under your main application directory (in this case,
+PanGalactic), and then running `python setup.py install` from the command
+line.
 
 The steps are:
 
-    - Create a pangalaxian.exe
+  - Create a `pangalaxian.exe`
 
-    - Test Test Test
+  - Test Test Test
 
-    - Create a setup.exe
+  - Create a `setup.exe`
 
-    - Test this, too
+  - Test this, too
 
-    - Copy the setup.exe to the download area on the server as::
+  - Copy the `setup.exe` to the download area on the server as::
 
-         pangalactic_xxx_setup.exe
+       pangalactic_xxx_setup.exe
 
 
-a. Create a pangalaxian.exe
+a. Create a `pangalaxian.exe`
 
 There is a setup.py located in the client directory
-(`PanGalactic\pangalactic\client`).  Edit the pangalaxian.py file and
-modify the variable VERSION (automation RSN).  The command to enter at a
-DOS prompt is:
-
-`DOS> python setup.py py2exe -i "POSException" -d c:\nasa\PanGalactic\pangalactic\client\dist\pangalaxian --ignores "Persistence.Persistent, initgroups, intSet, jarray, java.awt.image, javax.imageio, logger, mxDateTime.__version__, yaml, _rl_accel, Crypto.Cipher, Interface, OpenSSL, java.io.IOException, java.io.InterruptedIOException, java.net, resource, wxPython.lib.PyCrust.version, Crypto.Util"`
+(`PanGalactic\pangalactic\client`).  Edit the `pangalaxian.py` file and
+modify the variable `VERSION` (automation RSN).  The command to enter at a
+DOS prompt is::
+
+    DOS> python setup.py py2exe -i "POSException" -d \
+    c:\nasa\PanGalactic\pangalactic\client\dist\pangalaxian \
+    --ignores "Persistence.Persistent, initgroups, intSet, \
+    jarray, java.awt.image, javax.imageio, logger, \
+    mxDateTime.__version__, yaml, _rl_accel, Crypto.Cipher, \
+    Interface, OpenSSL, java.io.IOException, \
+    java.io.InterruptedIOException, java.net, resource, \
+    wxPython.lib.PyCrust.version, Crypto.Util"
 
 This command is also at the top of the `setup.py` file.
 
 When you run this command, any undefined symbols will be listed at the end of
 the output.  The --ignore option takes a list of symbols to ignore.  The
 executable is generated in the directory specified by the -d parameter.
-Currently, pangalaxian.exe is generated in a subdirectory of client, namely:
-.\dist\pangalaxian\
+Currently, `pangalaxian.exe` is generated in a subdirectory of client, namely:
+`.\\dist\\pangalaxian\\`
 
 On to the next step...
 
@@ -695,19 +703,20 @@
 upload, and anything else that doesn't yet have a test case.
 
 
-c. Create a setup.exe
-
-Start the Inno Setup application.  Open the pangalaxian.iss script.  Modify the
-variable AppVerName to match the variable VERSION in pangalaxian.py.
+c. Create a `setup.exe`
 
+   * Start the Inno Setup application.
+   * Open the `pangalaxian.iss` script.
+   * Modify the variable AppVerName to match the variable VERSION in
+     `pangalaxian.py`.
 
 d. Test Test Test
 
-Install setup.exe to the default location.  Run all the same tests that you did
-for pangalaxian.exe.  Uninstall it, and reinstall it to a non-default location.
+Install `setup.exe` to the default location.  Run all the same tests that you did
+for `pangalaxian.exe`.  Uninstall it, and reinstall it to a non-default location.
 Run those tests again.
 
-If you're completely satisfied, rename setup.exe to
+If you're completely satisfied, rename `setup.exe` to
 `pangalactic_xxx_setup.exe`, where xxx corresponds to the variable
 `VERSION`.
 
@@ -715,7 +724,7 @@
 e. Copy the `pangalactic_xxx_setup.exe` to the download area on the server
 
 Open an sftp session to the server, and copy `pangalactic_xxx_setup.exe` to:
-/usr/local/apps/ned/www/beta
+`/usr/local/apps/ned/www/beta`
 
 
 
@@ -725,169 +734,170 @@
 
 Problem: Invoking Acrobat Reader on linux using version 5.0.8 aborts.
 
-Workaround: Edit the acroread script, which should be   
-            <wherever you installed it>/bin/acroread. 
+Workaround:
 
-            Right after the line which begins: 
+* Edit the acroread script, which should be::
 
-            install_dir=<wherever you installed it>
+    <wherever you installed it>/bin/acroread. 
 
-            add: 
+* Right after the line which begins::
 
-            export LANG=C
+    install_dir=<wherever you installed it>
 
-            This fix assumes you are running bash.  Modify the 
-            line appropriately for other shells.
+  add:: 
 
+    export LANG=C
 
--------------------
-Testing PanGalaxian
--------------------
+This fix assumes you are running bash.  Modify the 
+line appropriately for other shells.
 
-There are a handful of existing tests that are up-to-date.  (If
-any!)  Before you start testing, make sure you have removed any
-client data (in the `pangalactic/node` dir, execute `'rm data/*'`),
-and remove the state file, 'state.json', from the node directory.
 
-    - Start the application  
+------------------------------
+Manually "Testing" PanGalaxian
+------------------------------
 
-    - Select your repository  
+There are a handful of PanGalaxian unit existing tests that are up-to-date
+(okay, maybe None!).  Before you start this simple form of "testing", make
+sure you have removed any client data (in the `pangalactic/node` dir,
+execute `'rm data/*'`), and remove the state file, `state.json`, from the
+node directory.
 
+    - Start the application  
+    - Select your repository  
     - Enter your username and email in the window
-
     - Login
-
     - Select the H2G2 project
 
-       See all the data show up
+      + See all the data show up
 
     - Select a model.  Preferable HOG.1-CAD
 
-       See the pretty tree
+      + See the pretty tree
 
     - Double-click on HOG.1-CAD in the tree
 
-       See the pretty editor
-       Close the editor window
+      + See the pretty editor
+      + Close the editor window
 
     - Double-click on the HOG.1-CAD in the grid
 
-       See the editor again
-       Close it again
+      + See the editor again
+      + Close it again
 
     - Click on a plus in the tree
 
-       See the tree expand
-       The plus disappears if there are no children
+      + See the tree expand
+      + The plus disappears if there are no children
 
     - Select Tools->Search...
 
-       The Search window appears
-       Specify at least 1 search criterion
-       Click [Search]
-       if successful
+      + The Search window appears
+      + Specify at least 1 search criterion
+      + Click [Search]
+      + if successful
 
-          See the Summary page with result counts
-          Click on the tabs of each result type (e.g., Part, Model)
+        * See the Summary page with result counts
+        * Click on the tabs of each result type (e.g., Part, Model)
 
-             See an overview of each result type
+          - See an overview of each result type
 
-          Click on the Criteria tab
+        * Click on the Criteria tab
 
-       else
+      + else
 
-          Click [OK] on the Search Error window
+        * Click [OK] on the Search Error window
 
-       Repeat as many times as you like
-       Close the window
+      + Repeat as many times as you like
+      + Close the window
 
     - Select File->New->Part...
 
-       See the Part wizard
-       Enter a part number at least
-       Enter any additional data you wish
-       Click [Save]
-       The tree is rebuilt, showing your new part
-       Close this window
-       Your part is at the bottom of the Part tab in the main window (grey
-       background)
+      + See the Part wizard
+      + Enter a part number at least
+      + Enter any additional data you wish
+      + Click [Save]
+      + The tree is rebuilt, showing your new part
+      + Close this window
+      + Your part is at the bottom of the Part tab in the main window (grey
+      + background)
 
     - Select File->New->Model...
 
-       See the Model wizard
-       Enter a model identifier and model name at least
-       Enter any additional data you wish
-       Click [Save]
-       The tree is rebuilt, showing your new model
-       Close this window
-       Your model is at the bottom of the Model tab in the main window (grey
-       background)
+      + See the Model wizard
+      + Enter a model identifier and model name at least
+      + Enter any additional data you wish
+      + Click [Save]
+      + The tree is rebuilt, showing your new model
+      + Close this window
+      + Your model is at the bottom of the Model tab in the main window (grey
+      + background)
 
     - Select File->New->Parts List...
 
-       See the Parts List wizard
-       If running on Windows
+      + See the Parts List wizard
+      + If running on Windows
 
-          tbd
+        * tbd
 
-       Else
+      + Else
 
-          Click [Save]
-          Your parts list is added to the tree
+        * Click [Save]
+        * Your parts list is added to the tree
 
-       Close this window
+      + Close this window
 
     - Select File->New->Document...
 
-       See the Document wizard
-       Enter as much data as you wish
-       Click [Save]
-       Your document is added to the tree
-       Close this window
+      + See the Document wizard
+      + Enter as much data as you wish
+      + Click [Save]
+      + Your document is added to the tree
+      + Close this window
 
     - Select File->Export->Properties...
 
-       tbd
+      + tbd
 
     - Select File->Export->Table Data...
 
-       See the PDF creation window   
-       Select [Generate PDF for the table]
-       Specify the output filename
-       Enter the header and footer lines, if any
-       Specify any additional options
-       Click [Create]
-       Click [OK] on the message window
+      + See the PDF creation window   
+      + Select [Generate PDF for the table]
+      + Specify the output filename
+      + Enter the header and footer lines, if any
+      + Specify any additional options
+      + Click [Create]
+      + Click [OK] on the message window
 
     - Right-click on the Model grid
 
-       See the PDF creation window   
-       Select [Generate PDF for the table]
-       Specify the output filename
-       Enter the header and footer lines, if any
-       Specify any additional options
-       Click [Create]
-       Click [OK] on the message window
+      + See the PDF creation window   
+      + Select [Generate PDF for the table]
+      + Specify the output filename
+      + Enter the header and footer lines, if any
+      + Specify any additional options
+      + Click [Create]
+      + Click [OK] on the message window
 
     - Select Tools->Local Database Browser...
 
-       See the local browser
-       Select an entry in the list
-       See the grid fill with data
-       Repeat for as many as you like
-       Close this window
+      + See the local browser
+      + Select an entry in the list
+      + See the grid fill with data
+      + Repeat for as many as you like
+      + Close this window
 
     - Select Repository->View My Stuff...
 
-       if you have created anything that is on the server
+      + if you have created anything that is on the server
 
-          See the Search window with the Summary results page
+        * See the Search window with the Summary results page
 
-       else
+      + else
 
-          Click [OK] on the Search Error window
+        * Click [OK] on the Search Error window
 
-       Close the Search window
+      + Close the Search window
 
+.. _ReportLab:  http://www.reportlab.org
 
-$Id: PgefManual.txt,v 1.1 2005/05/16 21:32:17 waterbug Exp $
+$Id: PgefManual.txt,v 1.2 2005/05/17 02:03:19 waterbug Exp $

From waterbug at step.nasa.gov  Tue May 17 04:00:08 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May 17 04:00:10 2005
Subject: [pangalactic-commits] Mo betta docs.
Message-ID: <200505170800.j4H8088q027993@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/admin/epyrun 1.8 1.9
PanGalactic/doc/PgefManual.html 1.2 1.3
PanGalactic/doc/PgefManual.txt 1.2 1.3
PanGalactic/pangalactic/core/pgefobject.py 1.16 1.17
PanGalactic/pangalactic/meta/factory.py 1.18 1.19
PanGalactic/pangalactic/meta/objectschema.py 1.3 1.4
PanGalactic/pangalactic/meta/registry.py 1.30 1.31
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.9 1.10
PanGalactic/pangalactic/repo/chronosynclastic.py 1.42 1.43
PanGalactic/pangalactic/repo/pgersoap.py 1.7 1.8
PanGalactic/pangalactic/repo/pgerxmlrpc.py 1.20 1.21
PanGalactic/pangalactic/utils/twistlets.py 1.1 1.2

Log message:
Mo betta docs.

Index: PanGalactic/pangalactic/meta/registry.py
diff -u PanGalactic/pangalactic/meta/registry.py:1.30 PanGalactic/pangalactic/meta/registry.py:1.31
--- PanGalactic/pangalactic/meta/registry.py:1.30	Sat May 14 01:49:02 2005
+++ PanGalactic/pangalactic/meta/registry.py	Tue May 17 04:00:04 2005
@@ -1,9 +1,9 @@
-# $Id: registry.py,v 1.30 2005/05/14 05:49:02 waterbug Exp $
+# $Id: registry.py,v 1.31 2005/05/17 08:00:04 waterbug Exp $
 
 """
 Pan Galactic Engineering Framework Registry
 
-@version: $Revision: 1.30 $
+@version: $Revision: 1.31 $
 
 The C{PanGalacticRegistry} maintains an in-memory cache of the PanGalactic
 core ontology (the C{ObjectSchema} instances that are the C{_schema}s of
@@ -17,7 +17,7 @@
 L{pangalactic.core.pgefobject.PgefObject}), the class's module name must be
 the class name in lower-case.
 """
-__version__ = "$Revision: 1.30 $"[11:-2]
+__version__ = "$Revision: 1.31 $"[11:-2]
 
 import imp
 import re
@@ -46,33 +46,36 @@
     convention will be followed:  for PanGalactic core Python classes
     (subclasses of L{pangalactic.core.pgefobject.PgefObject}), the class's
     module name must be the class name in lower-case.
+
+    @ivar classes:
+        A mapping of PanGalactic core class names to their class
+        objects.
+    @type classes:  C{dict}
+
+    @ivar object_schemas:
+        A mapping of the ids of C{ObjectSchema}s known to the registry to
+        their instances.
+    @type object_schemas:  C{dict}
+
+    @ivar refs:
+        A mapping of the ids of C{ObjectSchema}s to the set of id's of
+        C{ObjectSchema}s that they reference as the range of a
+        property.
+    @type refs:  C{dict}
+
+    @ivar deps:
+        A mapping of the ids of C{ObjectSchema}s to the
+        C{ObjectSchema}s that they either reference as the range of a
+        property or inherit from.
+    @type deps:  C{dict}
     """
 
     def __init__(self, domains='PanGalactic'):
         """
         Initialize the registry.
 
-        @ivar classes:
-            A mapping of PanGalactic core class names to their class
-            objects.
-        @type classes:  C{dict}
-
-        @ivar object_schemas:
-            A mapping of the ids of C{ObjectSchema}s known to the registry to
-            their instances.
-        @type object_schemas:  C{dict}
-
-        @ivar refs:
-            A mapping of the ids of C{ObjectSchema}s to the set of id's of
-            C{ObjectSchema}s that they reference as the range of a
-            property.
-        @type refs:  C{dict}
-
-        @ivar deps:
-            A mapping of the ids of C{ObjectSchema}s to the
-            C{ObjectSchema}s that they either reference as the range of a
-            property or inherit from.
-        @type deps:  C{dict}
+        @param domains:  a comma-delimited list of ontological domains
+        @type  domains:  C{str}
         """
         self.classes = {}
         self.refs = {}

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.9 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.10
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.9	Mon May 16 17:34:41 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Tue May 17 04:00:04 2005
@@ -1,10 +1,10 @@
-# $Id: pgefobjectgrid.py,v 1.9 2005/05/16 21:34:41 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.10 2005/05/17 08:00:04 waterbug Exp $
 """
 The PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.9 $
+@version: $Revision: 1.10 $
 """
-__version__ = "$Revision: 1.9 $"[11:-2]
+__version__ = "$Revision: 1.10 $"[11:-2]
 
 from pprint import pprint
 
@@ -310,9 +310,9 @@
 
     def noSelect(self, evt):
         """
-        Deselect any current selection.
+        Do not select a column.
         """
-        self.ClearSelection()
+        pass
 
     def onLabelRightClick(self, evt):
         """

Index: PanGalactic/pangalactic/core/pgefobject.py
diff -u PanGalactic/pangalactic/core/pgefobject.py:1.16 PanGalactic/pangalactic/core/pgefobject.py:1.17
--- PanGalactic/pangalactic/core/pgefobject.py:1.16	Mon May 16 04:13:20 2005
+++ PanGalactic/pangalactic/core/pgefobject.py	Tue May 17 04:00:03 2005
@@ -1,11 +1,11 @@
-# $Id: pgefobject.py,v 1.16 2005/05/16 08:13:20 waterbug Exp $
+# $Id: pgefobject.py,v 1.17 2005/05/17 08:00:03 waterbug Exp $
 
 """
 PgefObject is the Mother of all PanGalactic objects.
 
 More prosaically, PgefObject is the base class for all PanGalactic domain
 classes (generic domain objects).  To quote from "The Wiki"
-(http://www.c2.com/cgi/wiki):
+U{http://www.c2.com/cgi/wiki}:
 
     A domain object is a logical container of purely domain information
     [and] usually represents a logical entity in the problem domain space
@@ -31,9 +31,9 @@
 Note that PgefObject and its subclasses do not (yet) implement all of these
 characteristics, but that is their ultimate goal.
 
-@version: $Revision: 1.16 $
+@version: $Revision: 1.17 $
 """
-__version__ = "$Revision: 1.16 $"[11:-2]
+__version__ = "$Revision: 1.17 $"[11:-2]
 
 import copy
 from mx import DateTime
@@ -48,9 +48,11 @@
 
 class PgefObject(object):
     """
-    PgefObject is the base class for all of the PanGalactic domain
-    classes (generic domain objects).  From "The Wiki"
-    (http://www.c2.com/cgi/wiki):
+    PgefObject is the Mother of all PanGalactic objects.
+
+    More prosaically, PgefObject is the base class for all PanGalactic
+    domain classes (generic domain objects).  From "The Wiki"
+    U{http://www.c2.com/cgi/wiki}:
 
         A domain object is a logical container of purely domain information
         [and] usually represents a logical entity in the problem domain

Index: PanGalactic/pangalactic/meta/objectschema.py
diff -u PanGalactic/pangalactic/meta/objectschema.py:1.3 PanGalactic/pangalactic/meta/objectschema.py:1.4
--- PanGalactic/pangalactic/meta/objectschema.py:1.3	Sat May 14 01:49:02 2005
+++ PanGalactic/pangalactic/meta/objectschema.py	Tue May 17 04:00:04 2005
@@ -1,4 +1,4 @@
-# $Id: objectschema.py,v 1.3 2005/05/14 05:49:02 waterbug Exp $
+# $Id: objectschema.py,v 1.4 2005/05/17 08:00:04 waterbug Exp $
 
 """
 This module defines the C{ObjectSchema} class, which specifies the
@@ -13,9 +13,9 @@
 assigned at initialization time to instances of a class that has an
 instance of C{ObjectSchema} as its C{_schema}.
 
-@version: $Revision: 1.3 $
+@version: $Revision: 1.4 $
 """
-__version__ = "$Revision: 1.3 $"[11:-2]
+__version__ = "$Revision: 1.4 $"[11:-2]
 
 from sets import Set
 from pangalactic.meta.utils import getDefault
@@ -65,7 +65,7 @@
         _default_display_order, _default_display_names, and
         _default_display_types.)
 
-            - C{[[attr_name, range], [attr_name, range], ... }}
+            - C{[[attr_name, range], [attr_name, range], ... ]}
     """
     # TODO:  generate ivar documentation for __doc__ from _schema.
     _schema = {

Index: PanGalactic/pangalactic/meta/factory.py
diff -u PanGalactic/pangalactic/meta/factory.py:1.18 PanGalactic/pangalactic/meta/factory.py:1.19
--- PanGalactic/pangalactic/meta/factory.py:1.18	Sat May 14 01:49:02 2005
+++ PanGalactic/pangalactic/meta/factory.py	Tue May 17 04:00:04 2005
@@ -1,13 +1,13 @@
-# $Id: factory.py,v 1.18 2005/05/14 05:49:02 waterbug Exp $
+# $Id: factory.py,v 1.19 2005/05/17 08:00:04 waterbug Exp $
 
 """
 The PanGalacticFactory provides functions to marshall and unmarshall
 subclasses of L{pangalactic.core.pgefobject.PgefObject}.
 
-@version: $Revision: 1.18 $
+@version: $Revision: 1.19 $
 """
 
-__version__ = "$Revision: 1.18 $"[11:-2]
+__version__ = "$Revision: 1.19 $"[11:-2]
 
 from pprint import pprint
 from mx.DateTime.ISO import ParseDateTime
@@ -156,15 +156,14 @@
         cast into clear-text encoding formats suitable for transmission in
         a text-based protocol), plus the id of the object's _schema.
 
-            C{{'object_schema_id' : obj._schema.id,
-               attrname           : cooked_attr_value, ...}}
-
         @type obj:   an instance of a subclass of
-                     L{pangalactic.core.pgefobject.PgefObject}
+            L{pangalactic.core.pgefobject.PgefObject}
         @param obj:  the object from which _schema instance data is to be
             extracted
 
         @rtype:      dictionary
+            C{{'object_schema_id' : obj._schema.id,
+               attrname           : cooked_attr_value, ...}}
         @return:     a dictionary mapping the attribute names in the
             object's '_schema' attribute to their cooked values.
         """
@@ -261,15 +260,15 @@
         The 'objs' argument is a list of objects.  It may contain any
         number of objects, and remember() will look in it for:
 
-        * A clone of the object that the extract represents (i.e., same
-          class and pgef_oid).  If a clone is found, it will be returned
-          unchanged unless the extract's record_mod_datetime is later than
-          the clone's, in which case the clone will first be synchronized
-          with the extract and then returned.
-
-        * Objects referenced by the object that the extract represents.  If
-          found, these objects will be referenced by the remembered object
-          (the deserialized extract).
+            * A clone of the object that the extract represents (i.e., same
+              class and pgef_oid).  If a clone is found, it will be
+              returned unchanged unless the extract's record_mod_datetime
+              is later than the clone's, in which case the clone will first
+              be synchronized with the extract and then returned.
+
+            * Objects referenced by the object that the extract represents.
+              If found, these objects will be referenced by the remembered
+              object (the deserialized extract).
 
         One use case:  update of an object, which may reference other local
         objects.  In this scenario, the objs list only needs to include the

Index: PanGalactic/pangalactic/repo/pgersoap.py
diff -u PanGalactic/pangalactic/repo/pgersoap.py:1.7 PanGalactic/pangalactic/repo/pgersoap.py:1.8
--- PanGalactic/pangalactic/repo/pgersoap.py:1.7	Thu Mar 24 02:18:27 2005
+++ PanGalactic/pangalactic/repo/pgersoap.py	Tue May 17 04:00:05 2005
@@ -1,10 +1,10 @@
 """
 PGER SOAP Interfaces module
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
 
-__version__ = "$Revision: 1.7 $"[11:-2]
-# $Id: pgersoap.py,v 1.7 2005/03/24 07:18:27 waterbug Exp $
+__version__ = "$Revision: 1.8 $"[11:-2]
+# $Id: pgersoap.py,v 1.8 2005/05/17 08:00:05 waterbug Exp $
 
 from twisted.web import soap
 from twisted.internet.defer import succeed, fail
@@ -71,7 +71,7 @@
         XMLRPC getObjects:  get the set of objects that exactly
         match a specified set of attribute-value pairs, returning
         the result as a list of "extracts" -- see
-        L{pangalactic.utils.factory.extract})
+        L{pangalactic.meta.factory.extract})
 
         @type typename:   string
         @param typename:  the name of a class that extends
@@ -128,7 +128,7 @@
         @type extracts:   list
         @param extracts:  a list of extracts (for the definition
                           of extracts, see
-                          L{pangalactic.utils.factory.PgefFactory})
+                          L{pangalactic.meta.factory.PanGalacticFactory})
 
         @rtype:   list
         @return:  a list of extracts:  the objects that were
@@ -146,7 +146,7 @@
         @type extracts:   list
         @param extracts:  a list of extracts (for the definition
                           of extracts, see
-                          L{pangalactic.utils.factory.PgefFactory})
+                          L{pangalactic.meta.factory.PanGalacticFactory})
 
         @type blobs:  list
         @param blobs: a list of binary objects, which will be

Index: PanGalactic/admin/epyrun
diff -u PanGalactic/admin/epyrun:1.8 PanGalactic/admin/epyrun:1.9
--- PanGalactic/admin/epyrun:1.8	Thu Feb 17 23:20:34 2005
+++ PanGalactic/admin/epyrun	Tue May 17 04:00:02 2005
@@ -4,7 +4,7 @@
 # This makes sure that users don't have to set up their environment
 # specially in order to run these programs from bin/.
 import sys, os, string, shutil
-if string.find(os.path.abspath(sys.argv[0]), os.sep+'PanGalactic') != -1:
+if string.find(os.path.abspath(sys.argv[0]), os.sep+'Twisted') != -1:
     sys.path.insert(0, os.path.normpath(os.path.join(os.path.abspath(sys.argv[0]
 ), os.pardir, os.pardir)))
 sys.path.insert(0, os.curdir)
@@ -65,23 +65,28 @@
 fakeOut("gnome.ui")
 fakeOut("pygtk")
 fakeOut("gtk")
-fakeOut("wx")
+fakeOut("wxPython.wx")
+sys.modules["zope.interface._zope_interface_coptimizations"] = None
 
-# HACK: make Twisted Interfaces not use __metaclass__ =
-# MetaInterface. Epydoc barfs on any classes whose type isn't
-# TypeType.
-
-from twisted.python import components
-
-class Interface:
-    pass
-
-Interface.__module__ = 'twisted.python.components'
-Interface.__doc__ = components.Interface.__doc__
-components.Interface = Interface
+## HACK: This is a nasty one! Replace TypeType with (TypeType,
+## InterfaceClass), and dir with something that makes Interfaces look like 
+## classes so epydoc will try to document Interfaces.
+from zope.interface.interface import InterfaceClass, Method
+import types
+types.TypeType = (types.TypeType, InterfaceClass)
+_marker = object()
+def epydir(obj=_marker, dir=dir):
+    if obj is _marker:
+        return sys._getframe(1).f_locals.keys()
+    elif isinstance(obj, InterfaceClass):
+        return obj.names(all=True)
+    else:
+        return dir(obj)
+import __builtin__
+__builtin__.dir = epydir
 
 # initial twisted
-from twisted.python import reflect
+from twisted.python import reflect, util
 from twisted.internet import reactor
 # epydoc
 import epydoc
@@ -91,6 +96,29 @@
 from epydoc import uid
 import epydoc.html
 
+# HACK: unsplit moduleMovedForSplit
+def moduleMovedForSplit(origModuleName, newModuleName, moduleDesc,
+                        projectName, projectURL, globDict):
+    modoc = """
+%(moduleDesc)s
+
+This module is DEPRECATED. It has been split off into a third party
+package, Twisted %(projectName)s. Please see %(projectURL)s.
+
+This is just a place-holder that imports from the third-party %(projectName)s
+package for backwards compatibility. To use it, you need to install
+that package.
+
+This module has moved to %(newModuleName)s.
+
+""" % {'moduleDesc': moduleDesc,
+       'projectName': projectName,
+       'projectURL': projectURL,
+       'newModuleName': newModuleName}
+
+    globDict['__doc__'] = modoc
+util.moduleMovedForSplit = moduleMovedForSplit
+
 # HACK: Force everything to be public.
 
 def is_private(self):
@@ -101,6 +129,53 @@
 uid.UID.is_private = is_private
 uid.UID.is_public = is_public
 
+# HACK: More zope.interface hackery -- zope.interface.interface.Methods are
+# methods too!
+is_method_orig = uid.ObjectUID.is_method
+def is_method(self):
+    return is_method_orig(self) or isinstance(self._obj, Method)
+uid.ObjectUID.is_method = is_method
+is_routine_orig = uid.ObjectUID.is_routine
+def is_routine(self):
+    return is_routine_orig(self) or isinstance(self._obj, Method)
+uid.ObjectUID.is_routine = is_routine
+_findname_orig = uid.ObjectUID._findname
+def _findname(self):
+    if isinstance(self._obj, Method):
+        return '%s.%s' % (self.cls(), self._obj.__name__)
+    else:
+        return _findname_orig(self)
+uid.ObjectUID._findname = _findname
+cls_orig = uid.ObjectUID.cls
+def cls(self):
+    if isinstance(self._obj, Method):
+        return uid.ObjectUID(self._obj.interface)
+    else:
+        return cls_orig(self)
+uid.ObjectUID.cls = cls
+module_orig = uid.ObjectUID.module
+def module(self):
+    if isinstance(self._obj, Method):
+        return uid.ObjectUID(self._obj.interface).module()
+    else:
+        return module_orig(self)
+uid.ObjectUID.module = module
+make_uid_orig = uid.make_uid
+def make_uid(obj, base_uid=None, shortname=None):
+    if isinstance(obj, Method):
+        key = (id(obj), id(obj.interface))
+        obj_uid = uid._object_uids.get(key)
+        if obj_uid is not None: return obj_uid
+        obj_uid = uid.ObjectUID(obj)
+        uid._object_uids[key] = obj_uid
+        return obj_uid
+    else:
+        return make_uid_orig(obj, base_uid, shortname)
+uid.make_uid = make_uid
+#from twisted.cred.portal import IRealm
+#print uid.ObjectUID(IRealm.requestAvatar).is_routine()
+#sys.exit()
+
 # HACK: Don't append -module and -class to the filenames, and generate
 # redirecty-files for all methods.
 
@@ -170,15 +245,48 @@
 
 from epydoc import objdoc
 
-orig_add = objdoc.DocMap._add
-
-def _add(self, objID):
-    m = objID.module()
-    if m and m.name() not in modnames: # see below for where modnames is defined
-        return
-    return orig_add(self, objID)
-
-objdoc.DocMap._add = _add
+# HACK: objdoc directly imports make_uid, so our monkeypatch to make_uid needs
+# to happen here too:
+objdoc.make_uid = make_uid
+
+# HACK: add dummy im_func attr to Method to make epydoc happy
+Method.im_func = property(lambda s: s)
+
+# HACK: teach inspect.getargspec how to extract info from Methods
+import inspect
+getargspec_orig = inspect.getargspec
+def getargspec(func):
+    if isinstance(func, Method):
+        spec = func.getSignatureInfo()
+        defaults = [spec['optional'][arg] 
+                    for arg in spec['positional'] 
+                    if arg in spec['optional']]
+        return (spec['positional'], spec['varargs'], spec['kwargs'], defaults)
+    else:
+        return getargspec_orig(func)
+inspect.getargspec = getargspec
+
+# HACK: Make FuncDoc DTRT with Methods
+_init_signature_orig = objdoc.FuncDoc._init_signature
+# This one is for epydoc CVS
+def _init_signature(self, func):
+    if isinstance(func, Method):
+        docstring = objdoc._getdoc(func)
+        self._init_signature_from_argspec(*inspect.getargspec(func))
+        return docstring
+    else:
+        return _init_signature_orig(self, func)
+objdoc.FuncDoc._init_signature = _init_signature
+
+# This one is for epydoc 2.1
+_init_builtin_signature_orig = objdoc.FuncDoc._init_builtin_signature
+def _init_builtin_signature(self, func):
+    if isinstance(func, Method):
+        _init_signature_orig(self, func)
+        return False
+    else:
+        return _init_builtin_signature_orig(self, func)
+objdoc.FuncDoc._init_builtin_signature = _init_builtin_signature
 
 # HACK: Another "only doc what we tell you". We don't want epydoc to
 # automatically recurse into subdirectories: "twisted"'s presence was
@@ -224,12 +332,17 @@
 imports.find_modules = find_modules
 
 
+
 # Now, set up the list of modules for epydoc to document
 modnames = []
 def addMod(arg, path, files):
+    if 'test' in files:
+        files.remove('test')
+    if 'topfiles' in files:
+        files.remove('topfiles')
     for fn in files:
         file = os.path.join(path, fn).replace('%s__init__'%os.sep, '')
-        if file[-3:] == '.py' and not file.count('%stest%s' % (os.sep,os.sep)):
+        if file[-3:] == '.py':
             modName = file[:-3].replace(os.sep,'.')
             try:
                 #print 'pre-loading', modName
@@ -242,7 +355,7 @@
                 modnames.append(modName)
 
 document_all = True # are we doing a full build?
-names = ['pangalactic/'] # default, may be overriden below
+names = ['pangalactic/'] #default, may be overriden below
 
 #get list of modules/pkgs on cmd-line
 try:
@@ -265,11 +378,12 @@
             #from TwistedEmacs
             names[i] = names[i][j:]
 
+    old_out_dir = "html"
     #if -o was specified, we need to change it to point to a tmp dir
     #otherwise add our own -o option
     try:
         i = sys.argv.index('-o')
-        out_dir = sys.argv[i+1]
+        old_out_dir = sys.argv[i+1]
         try:
             os.mkdir(tmp_dir)
         except OSError:
@@ -278,7 +392,6 @@
     except ValueError:
         sys.argv[1:1] = ['-o', tmp_dir]
 
-
 osrv = sys.argv
 sys.argv=["IGNORE"]
 im = __import__
@@ -302,6 +415,9 @@
 __builtins__.__import__ = im
 sys.argv = osrv
 
+
+
+
 if 'pangalactic.test' in modnames:
     modnames.remove('pangalactic.test')
 ##if 'pangalactic' in modnames:
@@ -309,7 +425,7 @@
 
 sys.argv.extend(modnames)
 
-sys.argv[1:1] = ['-n', 'PanGalactic', '-u', 'http://pangalactic.us/', '--no-private']
+sys.argv[1:1] = ['-n', 'The Pan Galactic Engineering Framework', '-u', 'http://pangalactic.us/', '--no-private']
 
 # Make it easy to profile epyrun
 if 0:
@@ -325,20 +441,13 @@
 def moveFilesOut(arg, dirname, fnames):
     for fn in fnames:
         if fn.startswith('pangalactic.'):
-            shutil.move('%s%s%s' % (tmp_dir, os.sep, fn), out_dir)
-
+            shutil.move('%s%s%s' % (tmp_dir, os.sep, fn), old_out_dir)
+        
 if not document_all:
-    print "Updating files in %s" % out_dir
+    print "Updating files in %s" % old_out_dir
     #move the right html files in to place
     os.path.walk(tmp_dir, moveFilesOut, None)
     #clean up
     shutil.rmtree(tmp_dir)
 
-# ifile = open('doc/html/pgef_api_index.html')
-# icontent = ifile.read()
-# ifile.close()
-# ifilecp = open('doc/api/html/index.html', 'w')
-# ifilecp.write(icontent)
-# ifilecp.close()
-
 print 'Done!'

Index: PanGalactic/doc/PgefManual.txt
diff -u PanGalactic/doc/PgefManual.txt:1.2 PanGalactic/doc/PgefManual.txt:1.3
--- PanGalactic/doc/PgefManual.txt:1.2	Mon May 16 22:03:19 2005
+++ PanGalactic/doc/PgefManual.txt	Tue May 17 04:00:03 2005
@@ -7,8 +7,8 @@
 
 :Author: Stephen Waterbury <stephen dot c dot waterbury at nasa dot gov>
 :Author: Ginny Keech
-:Version: $Revision: 1.2 $
-:Date: $Date: 2005/05/17 02:03:19 $
+:Version: $Revision: 1.3 $
+:Date: $Date: 2005/05/17 08:00:03 $
 
 
 --------
@@ -156,21 +156,21 @@
 Security and Access Control Requirements
 ========================================
 
-* Access control shall be based upon a combination of security
-  masks and user roles.  
+* Access control shall be based upon a combination of security masks and
+  user roles.  
 
 * Security masks shall be able to be assigned to:
 
-  - Base classes (subtypes of PgefObject)
-  - Application classes (OntoClasses)
-  - Application class instances 
-
-* A set of standard PGEF roles shall be defined, each of which will
-  have a specified set of permissions.
-
-* Some standard roles will include permissions to add, delete, and
-  modify new (custom) roles within specified domains and to assign
-  standard and/or custom roles to other users.
+  - `PGEF Core Classes`_
+  - Application Classes (classes derived from `PGEF Core Classes`_)
+  - Instances of either of these
+
+* A set of standard PGEF roles shall be defined, each of which will have a
+  specified set of permissions.
+
+* Some standard permissions will include permissions to add, delete, and
+  modify new (custom) roles within specified domains and to assign standard
+  and/or custom roles to other users.
 
 
 Use Case Sketches
@@ -180,21 +180,19 @@
 
 * Repository and Client (thick or thin)
 
-  - Implement a STEP-mappable high level information model
-    (ontology) for parts, models, docs, and systems engineering
-    concepts
+  - Implement a STEP-mappable high level information model (ontology) for a
+    specific engineering problem domain
 
-  - Retrieve model/doc ref(s) from repository
+  - Retrieve model/doc ref(s) from the repository
 
-    + "Get" (by Id/Oid)
-    + "Search" (by parameters)
+    + `Get` (by Id/Oid)
+    + `Search` (by parameters)
 
-  - Add model(s)/doc(s) (including files) to repository
+  - Add model(s)/doc(s) (including files) to the repository
 
-    + "Add" (by Id/Oid)
+    + `Add` (by Id/Oid)
 
-  - Save workflow templates, instances, and states to
-    repository
+  - Save workflow templates, instances, and states to the repository
 
 * Client (thick)
 
@@ -211,105 +209,109 @@
 Scope
 =====
 
-The scope of the Pan Galactic Core Ontology is intended to
-include all information relevant to products and product models
-throughout the product life cycle.
+The scope of the Pan Galactic Core Ontology is intended to include all
+information relevant to products and product models throughout the product
+life cycle.
 
 
-PGEF's principal domain is the "manufacturing" enterprise, in the
-broadest possible sense of "manufacturing" -- i.e., any type of
-"product" life cycle support (as the current buzz words go) where
-a "product" is any artifact that is or includes one or more of
-the following:  software, firmware, hardware, materials, and
-documents.
+PGEF's principal domain is the "manufacturing" enterprise, in the broadest
+possible sense of "manufacturing" -- i.e., any type of "product" life cycle
+support (as the current buzz words go) where a "product" is any artifact
+that is or includes one or more of the following:  software, firmware,
+hardware, materials, and documents.
 
 Consequently, one of PGEF's principal goals is to collect, integrate, and
-manage information about products (known in the PGEF Core Ontology as "parts"),
-models, and documents created and used by the enterprise.  To define the
-objects of its domain, PGEF implements a simple core ontology of the most
-basic classes of things that occur in enterprises that develop products.
-
-[TODO: generate the PGEF Core Ontology into
-PanGalactic/home/pgef.owl and reference it from this section as
-the PGEF Core Ontology. ]
+manage information about products (known in the PGEF Core Ontology as
+"parts"), models, and documents created and used by the enterprise.  To
+define the objects of its domain, PGEF implements a simple core ontology of
+the most basic classes of things that occur in enterprises that develop
+products.
+
+[**TODO**: generate the PGEF Core Ontology into `PanGalactic/home/pgef.owl`
+and reference it from this section as the PGEF Core Ontology. ]
 
 
 The PGEF Meta Object Facility
 =============================
 
-The PGEF Meta Object Facility (MOF) (the `pangalactic.meta` module) does
-not implement the OMG Meta Object Facility but has a very similar intent.  
-Its principal classes are:
+The `PGEF Meta Object Facility`_ (PMOF) (the `pangalactic.meta` module)
+does not implement the OMG Meta Object Facility (MOF), but it has much
+in common with it.  Its principal classes are:
 
   - **ObjectSchema**
 
-    The ObjectSchema class represents an ontological class, and defines a
-    set of associated attributes (Property instances; 'Properties' in
-    ontological parlance) for which that class is the domain.  [Link to the
-    ObjectSchema API documentation here:
-    L{pangalactic.meta.objectschema.ObjectSchema}]
+    The ObjectSchema_ class represents an ontological class, and defines a
+    set of associated attributes (Property_ instances; `Properties` in
+    ontological parlance) for which that class is the domain.
 
   - **Property**
 
-    The Property class represents an ontological Property.  In PGEF, an
-    ontological Property is represented as an attribute of its domain
-    class.  Thus, Property instances used to define the attributes of
-    ObjectSchema instances.  [Link to the Property API documentation here:
-    L{pangalactic.meta.pgefproperty.Property}]
-
-    * Every Property has a 'pgef_datatype' (default value:
-      'str'), which must be one of: 'str', 'int', 'bool', 'DateTime', or
-      the id of a registered ObjectSchema (in which case its
-      'property_type' must be set to 'object').  If the Property's value is
-      an aggregate of objects, then 'max_cardinality' must be either an
-      integer greater than 1 or (if the aggregate is unlimited in size) 0.
-
-    * An Property can have a default value, which is specified in
-      the 'default' attribute and must be encoded as a string.  The
-      "default default" values are the null of each type:
-
-      - Strings:  are literal (default default: '')
-      - Integers: are cast to int (default default: 0)
-      - Booleans: '' == False; any non-empty string == True
-                  (default default: False)
-      - DateTime: DateTime-valued Properties have a default of
-                  None.  [Note that this does not pertain to
-                  "initialization" values -- e.g., the
-                  initialization value for 'create_datetime' is
-                  DateTime.now().]
-      - Classes:  object-valued Properties (cf.
-                  owl:ObjectProperty) have a default of None if
-                  their max_cardinality == 1; otherwise, the
-                  default is an empty list ([]).
+    The Property_ class represents an ontological Property_.  In PGEF, an
+    ontological Property_ is represented as an attribute of its domain
+    class.  Thus, Property_ instances used to define the attributes of
+    ObjectSchema_ instances.
+
+    Property_ has the following important attributes:
+
+    * **domain** -- the type of the ObjectSchema_ that owns it.  (Maps to
+      rdfs:domain.)
+
+    * **property_type** (default value: `datatype`) -- values of
+      `property_type` can be::
+
+          `datatype` (maps to `owl:DatatypeProperty`) 
+          `object`   (maps to `owl:ObjectProperty`)
+
+    * **range** (default value: `str`) -- if the Property_ is a
+      `DatatypeProperty`, its `range` must be one of `str`, `int`, `bool`,
+      `DateTime`.  If it is an `ObjectProperty`, its range must be the id
+      of a registered ObjectSchema_ (in which case its `property_type` must
+      be set to `object`).  If the Property_'s value is an aggregate of
+      objects, then its `max_cardinality` must be either an integer greater
+      than 1 or (if the aggregate is unlimited in size) 0.
+
+    * **default** -- a default value for the Property_.  The default values
+      for `default` are the null of each type:
+
+      - **Strings** (`str`):  are literal (default default: `''`)
+      - **Integers** (`int`): are cast to int (default default: `0`)
+      - **Booleans** (`bool`): empty string (`''`) == False; any
+        non-empty string == True (default default: False)
+      - **DateTime** (`DateTime`): DateTime-valued Properties have a default of
+        None.  [Note that this does not pertain to
+        "initialization" values -- e.g., the
+        initialization value for `create_datetime` is
+        DateTime.now().]
+      - **Classes** (`classname`):  object-valued Properties (cf.
+        owl:ObjectProperty) have a default of None if their max_cardinality
+        == 1; otherwise, the default is an empty list ([]).
 
 
 The PGEF Core Classes
 =====================
 
-The PGEF Core Classes are a set of Python classes corresponding to (and
+The `PGEF Core Classes`_ are a set of Python classes corresponding to (and
 named after) the PGEF ontology's (ontological) classes.  Instances of
 software classes that represent ontological classes are sometimes referred
-to as domain objects:  "a domain object is a logical container of purely
+to as domain objects:  "a `domain object`_ is a logical container of purely
 domain information, [and] usually represents a logical entity in the
 problem domain space" (source: `The Wiki`_).
 
-.. _The Wiki:  http://c2.com/cgi/wiki?DomainObject
-
-PgefObject is the root class of the PGEF Core Classes, so hereafter
-the term *PgefObject* will be used to refer to any PGEF Core Class.
+PgefObject_ is the root class of the `PGEF Core Classes`_, so hereafter
+the term *PgefObject_* will be used to refer to any PGEF Core Class.
 
 In PGEF, the concept of an ontological class is represented by the
-ObjectSchema class.  Each PgefObject instance is assigned at creation time
-an instance of ObjectSchema as its '_schema'.  The '_schema' defines the
-set of attributes of that instance that will be stored when and if the
+ObjectSchema_ class.  Each PgefObject_ instance is assigned at creation
+time an instance of ObjectSchema_ as its `_schema`.  The `_schema` defines
+the set of attributes of that instance that will be stored when and if the
 instance is committed to the repository, PGER.
 
-Note that a PgefObject instance can have other attributes for various
+Note that a PgefObject_ instance can have other attributes for various
 purposes (local state, etc.), and these can be persisted locally (in the
 PanGalaxian client's ZODB cache, e.g.), but they will not be known to the
 repository and will not be shared or synchronized with other proxies of
 that instance in a distributed application unless that is done by way of an
-application protocol that is not part of the state of the domain object.
+application protocol that is not part of the state of the `domain object`_.
 
 Although the PGEF core ontology is fairly broad in scope, its primary focus
 is the domain of Systems Engineering.
@@ -329,7 +331,7 @@
     more detail.]
 
     - provides a logical interface layer above the object-relational
-      hyperdatabase (the Chronosynclastic Infundibulum)
+      hyperdatabase (the `Chronosynclastic Infundibulum`_)
 
     - contains a Registry in which lives the core PGEF ontology and
       any application-specific ontologies
@@ -338,12 +340,12 @@
 
     - drives all external interfaces (XML-RPC, SOAP, etc.)
 
-    - PgerXmlrpc -- the PGER XML-RPC interface
+    - PgerXmlrpcService_ -- the PGER XML-RPC Service interface
 
-        [see `Notes on the PGER XML-RPC search interface`_, for more
+        [see `Notes on the PGER XML-RPC Service interface`_, for more
         detail.]
 
-        + uses the XML-RPC 'struct' idiom to transmit serialized
+        + uses the XML-RPC `struct` idiom to transmit serialized
           object states
 
         + implements the XML-RPC representation of the PGER API
@@ -360,7 +362,7 @@
     - generates its database schema from the application ontology.  The
       default schema is generated from the PGEF Core Ontology, which
       application can extend by adding other ontologies and/or ontological
-      classes (ObjectSchema instances).
+      classes (ObjectSchema_ instances).
 
     - provides a flexible O-R mapping
 
@@ -403,7 +405,7 @@
 * **PGEF OID's**:  Unique Object Identifiers
 
     Each PGEF application object is assigned a unique identifier, the
-    'oid'.  The preferred form for the oid is a URI, if one is
+    `oid`.  The preferred form for the oid is a URI, if one is
     available or can be constructed canonically.  Otherwise, an
     arbitrary (but unique) one will be generated as follows:
 
@@ -449,35 +451,35 @@
 The PGEF Core Ontology provides the basis for the database
 structures of the PGEF Repository (PGER).  The layer that
 translates the domain Classes and Properties of the ontology to
-the structure of the database is the Chronosynclastic
-Infundibulum.
+the structure of the database is the `Chronosynclastic
+Infundibulum`_.
 
 
-O-R Mapping:  The Chronosynclastic Infundibulum
-===============================================
+O-R Mapping:  The `Chronosynclastic Infundibulum`_
+==================================================
 
 The O-R Mapping used by the PGEF Repository (PGER) is implemented in the
-Chronosynclastic Infundibulum (the `pangalactic.repo.chronosynclastic`
-module).  Chronosynclastic makes extensive use of the PGEF Meta Object
-Facility.  To recap, the default _schema of a PGEF Core Class is a
-ObjectSchema instance whose id is the same as the __name__ of the class.
+`Chronosynclastic Infundibulum` (the `pangalactic.repo.chronosynclastic`
+module).  `Chronosynclastic` makes extensive use of the `PGEF Meta Object
+Facility`_.  To recap, the default _schema of a PGEF Core Class is a
+ObjectSchema_ instance whose id is the same as the __name__ of the class.
 
-Each ObjectSchema known to the registry (initially, just the ones
+Each ObjectSchema_ known to the registry (initially, just the ones
 corresponding to the PGEF core ontology) has a corresponding database table
 in the repository.  The name of the database table is the name of the core
 class converted from studly caps (`StudlyCaps`) to lower-case
 underscore-delimited format, with a leading underscore added
 (`_studly_caps`) to avoid name clashes.  The table's column names are
-generated from the ObjectSchema instance's Property id's (also with leading
-underscores added).
+generated from the ObjectSchema_ instance's Property_ id's (also with
+leading underscores added).
 
 The database's table relationships and constraints are determined by other
-attributes of the ObjectSchemas and Properties.
+attributes of the ObjectSchema_s and Properties.
 
     * required attributes
 
-      A Property with a min_cardinality > 0 signifies a required
-      attribute, and the corresponding column is declared 'NOT NULL'.
+      A Property_ with a min_cardinality > 0 signifies a required
+      attribute, and the corresponding column is declared `NOT NULL`.
 
     * one-to-many relationships
 
@@ -499,8 +501,8 @@
       This case is discussed in detail in the next section
       (many-to-many relationships).
 
-      An aggregate-valued Property corresponds to a one-to-many
-      relationship.  The fact that a Property is aggregate-valued is
+      An aggregate-valued Property_ corresponds to a one-to-many
+      relationship.  The fact that a Property_ is aggregate-valued is
       represented in one of two ways::
 
         max_cardinality == 0 (meaning no limit) or
@@ -530,10 +532,10 @@
       and an assembly in which it is used.  Reifying the
       relationship not only enables database normalization, but
       also supports assigning attributes to the relationship
-      itself.  In the case of Acu, 'reference_designator' (a
+      itself.  In the case of Acu, `reference_designator` (a
       commonly used identifier of the role of a particular
       component in an assembly) is an attribute of the Acu
-      object.  E.g., the reference_designator 'R10' might refer
+      object.  E.g., the reference_designator `R10` might refer
       to a specific component role in an electronic circuit,
       which may be fulfilled by various specific components in
       different versions of the circuit, but the role it
@@ -555,8 +557,11 @@
       searching for relationship objects that point to it.
 
 
-Notes on the PGER XML-RPC search interface
-==========================================
+Notes on the PGER XML-RPC Service Interface
+===========================================
+
+[Only the `search` interface is discussed here ... see
+PgerXmlrpcService_ API documentation for more info.]
 
 **Syntax**::
 
@@ -898,6 +903,16 @@
 
       + Close the Search window
 
+
+.. _Chronosynclastic Infundibulum: http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.repo.chronosynclastic.Infundibulum.html
+.. _domain object:  http://c2.com/cgi/wiki?DomainObject
+.. _ObjectSchema: http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.objectschema.ObjectSchema.html
+.. _PGEF Core Classes: http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.core.html
+.. _PGEF Meta Object Facility: http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.html
+.. _PgefObject: http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.core.pgefobject.PgefObject.html
+.. _PgerXmlrpcService: http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.repo.pgerxmlrpc.PgerXmlrpcService.html
+.. _Property: http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html
 .. _ReportLab:  http://www.reportlab.org
+.. _The Wiki:  http://c2.com/cgi/wiki
 
-$Id: PgefManual.txt,v 1.2 2005/05/17 02:03:19 waterbug Exp $
+$Id: PgefManual.txt,v 1.3 2005/05/17 08:00:03 waterbug Exp $

Index: PanGalactic/pangalactic/repo/chronosynclastic.py
diff -u PanGalactic/pangalactic/repo/chronosynclastic.py:1.42 PanGalactic/pangalactic/repo/chronosynclastic.py:1.43
--- PanGalactic/pangalactic/repo/chronosynclastic.py:1.42	Mon May 16 17:34:43 2005
+++ PanGalactic/pangalactic/repo/chronosynclastic.py	Tue May 17 04:00:05 2005
@@ -1,4 +1,4 @@
-# $Id: chronosynclastic.py,v 1.42 2005/05/16 21:34:43 waterbug Exp $
+# $Id: chronosynclastic.py,v 1.43 2005/05/17 08:00:05 waterbug Exp $
 
 """
 The Chronosynclastic Infundibulum:  an asynchronous, ontology-driven
@@ -8,9 +8,9 @@
 (L{pangalactic.core.pgefobject.PgefObject} and its subclasses), the module
 name must be the class name in lower-case.
 
-@version: $Revision: 1.42 $
+@version: $Revision: 1.43 $
 """
-__version__ = "$Revision: 1.42 $"[11:-2]
+__version__ = "$Revision: 1.43 $"[11:-2]
 
 import imp
 import re
@@ -43,10 +43,8 @@
     ontology-driven object-relational mapping and database
     interface.
 
-    @ivar _db_type_map:
-        A mapping of the names of PGEF types to their corresponding
-        database type names
-    @type _db_type_map:  dict
+    @ivar _db_type_map:  A C{dict} mapping the names of PGEF types to their
+        corresponding database type names
     """
 
     def __init__(self,
@@ -55,19 +53,16 @@
                  domains='PanGalactic',
                  init=True):
         """
-        @param dbapiname:  name of the DBAPI adapter to use
-        @type  dbapiname:  C{str}
+        @param dbapiname:  name (a C{str}) of the DBAPI adapter to use
 
-        @param database:  name of the database to use
-        @type  database:  C{str}
+        @param database:  name (a C{str}) of the database to use
 
         @param domains:  names (in the form of a single, space-delimited
-            string) of packages containing domain classes of which the
+            C{str}) of packages containing domain classes of which the
             Infundibulum needs to be aware.
-        @type  domains:  C{str}
 
-        @param init:  if true, and no tables are found, create them
-        @type  init:  C{bool}
+        @param init:  (C{bool}) -- if True, and no tables are found, create
+            them
         """
         # TODO:  check if db exists; if not, create one
         self.database = database
@@ -87,7 +82,7 @@
 
     def _getTableNames(self):
         """
-        Get a list of all current PGERDB table names.  (This is implemented
+        Get a C{list} of all current PGERDB table names.  (This is implemented
         as a blocking function because it is only used for db admin
         functions, which intentionally block.)
         """
@@ -103,11 +98,9 @@
         Convert a camelcase L{pangalactic.meta.objectschema.ObjectSchema}
         id into an underscore-delimited, lowercase table name.
 
-        @type schema_id:  string
-        @param schema_id: C{ObjectSchema} id
+        @param schema_id: C{ObjectSchema} id (a C{str})
 
-        @rtype:  string
-        @return: table name
+        @return: table name (a C{str})
         """
         patt = re.compile('([A-Z])')
         l = re.split(patt, schema_id)
@@ -133,11 +126,9 @@
         Convert an underscore-delimited, lowercase table name into a
         camelcase L{pangalactic.meta.objectschema.ObjectSchema} id.
 
-        @type tname:  C{str}
-        @param tname: table name
+        @param tname: table name (a C{str})
 
-        @rtype:  C{str}
-        @return: C{ObjectSchema} id
+        @return: C{ObjectSchema} id (a C{str})
         """
         tn = tname[1:] # drop initial '_'
         parts = tn.split('_')
@@ -202,9 +193,8 @@
         function takes care of that.  Basically, it finds the "closure" of
         the object schema within the PGEF core ontology.  :)
 
-        @param schema_id:  the id of a
+        @param schema_id:  the id (a C{str}) of a
             L{pangalactic.meta.objectschema.ObjectSchema} instance
-        @type  schema_id:  C{str}
         """
         # Implementation of object schema inheritance of object properties
         # (i.e., object-object relationships) as FK relationships between
@@ -261,10 +251,9 @@
 
         @param schema:  a L{pangalactic.meta.objectschema.ObjectSchema}
             instance
-        @type  schema:  C{str}
 
-        @return:  the commands (C{str}s) for creating this table
-        @rtype:   C{tuple}
+        @return:  the commands (a C{tuple} of C{str}s) for creating this
+            table
         """
         # Note:  _genCreateTableCommands now does not rely on PostgreSQL
         # inheritance for propagation of columns by inheritance, but it
@@ -356,19 +345,17 @@
         Get the resultset of a dbapi query as a dictionary of the
         form {colname : value}.
 
-        @rtype:   dict
-        @return:  the result set.
+        @return:  the result set (a C{dict})
         """
         return self.runInteraction(self._mapQuery, *sqlargs)
 
     def _mapQuery(self, curs, *args, **kwargs):
         """
-        Transform the result of a dbapi query into a list of
+        Transform the result of a dbapi query into a C{list} of
         dictionaries of the form {colname : value}.  This
         function is designed to be used by _runQueryMapped.
 
-        @rtype:   list
-        @return:  a list of dictionaries of the form
+        @return:  a C{list} of dictionaries of the form
                   {colname : value}
         """
         curs.execute(*args, **kwargs)
@@ -383,8 +370,7 @@
         mapping underscore-prefixed database column names to
         their corresultsponding schema attribute names.
 
-        @rtype:   list
-        @return:  a list of extracts (see:
+        @return:  a C{list} of extracts (see:
             L{pangalactic.meta.factory.PanGalacticFactory.extract}
         """
         extracts = []
@@ -402,11 +388,10 @@
         Encode a result value as a plain text string (typically for
         transmission in a text-based protocol, such as XML-RPC or SOAP).
 
-        @type value:    any type
         @param value:   a value to be converted
 
-        @type prop:   L{pangalactic.meta.pgefproperty.Property}
-        @param prop:  the Property whose value is to be converted
+        @param prop:  the L{pangalactic.meta.pgefproperty.Property} whose
+            value is to be converted
         """
         if value is None:
             # print "%s is None -- setting it to an empty string." % value
@@ -438,11 +423,10 @@
         Convert a value from a cooked type to a DBAPI-compatible type in
         preparation for using it in a DBAPI call.
 
-        @type value:   string or list
-        @param value:  value to be converted
+        @param value:  value (C{str} or C{list}) to be converted
 
-        @type prop:   L{pangalactic.meta.pgefproperty.Property}
-        @param prop:  the Property whose value is to be dbuncooked
+        @param prop:  the L{pangalactic.meta.pgefproperty.Property} whose
+            value is to be dbuncooked
         """
         if prop.range == 'bool':
             if value:
@@ -470,16 +454,14 @@
 
     def _extracts2Records(self, extracts):
         """
-        Convert a list of extracts to a list of "records" for use
+        Convert a C{list} of extracts to a C{list} of "records" for use
         in the addObjects() method.
 
-        @type e:   list
         @param e:  an extract -- see
-                   L{pangalactic.meta.factory.PgefFactory.extract}
+            L{pangalactic.meta.factory.PanGalacticFactory.extract}
 
-        @rtype:  list
         @return: a "record", which has the following structure:
-                 [tablename, dict of "dbuncooked" attrs]
+            C{[tablename, dict of "dbuncooked" attrs]}
         """
         recs = []
         for e in extracts:
@@ -498,13 +480,11 @@
         """
         Create a rowkey from a record.
 
-        @type record:   list
         @param record:  a "record" has the following structure:
-                        [tablename, {colname : value, ...}]
+            C{[tablename, {colname : value, ...}]}
 
-        @rtype:  list
-        @return: a "rowkey".  A rowkey has the following
-                 structure:  [tablename, pgef_oid]
+        @return: a "rowkey".  A rowkey has the following structure:
+            C{[tablename, pgef_oid]}
         """
         return [record[0], record[1]['_pgef_oid']]
 
@@ -517,44 +497,39 @@
         matches, and is therefore usually quicker -- should be used if the
         exact values of the attributes being searched are known.
 
-        @type  requestor:  string
-        @param requestor:  the userid of the user making the request.
+        @param requestor:  the userid (a C{str}) of the user making the
+            request.
 
-        @type  schema_id:  string
-        @param schema_id:  the id of a registered
+        @param schema_id:  the id (a C{str}) of a registered
             L{pangalactic.meta.objectschema.ObjectSchema}.
 
-        @type  refs:  integer
         @param refs:  specifies whether to include the objects referenced
             by the specified class.
-                      
-                0:  (default) do not get refs
-                1:  get all directly referenced objects
+
+                - C{0}:  (default) do not get refs
+                - C{1}:  get all directly referenced objects
 
             (in future, refs may specify how many reference levels to
             follow ...)
 
-        @type  subtypes:  boolean
         @param subtypes:  specifies whether to include only the specified
             class (the default) or all subtypes.
 
-                0:  (default) only this type
-                1:  include subtypes
+                - C{0}:  (default) only this type
+                - C{1}:  include subtypes
 
-        @type  ret:  str
         @param ret:  specifies in what form to return the results.
 
-                'extracts':  (default) extracts
-                'objects':   objects
+                - C{extracts}:  (default) extracts
+                - C{objects}:   objects
 
         @param kw:  keyword arguments of the form:
 
-                key:   an attribute of the object
-                value: the value to be selected by
+                - C{key}:   an attribute of the object
+                - C{value}: the value to be selected by
 
-        @rtype:     list
-        @return:    list of results (type of items depends on value of
-            'rtype' param).
+        @return:  C{list} of results (type of items depends on value of
+            C{ret} param).
         """
         logmsg = 'getObjects, %s, %s' % (schema_id, str(kw))
         log.msg(logmsg, system='%s:Chronosynclastic' % requestor)
@@ -597,55 +572,49 @@
         of that function will be combined with the search results from
         other attributes using the _getIntersectionResults() function.
 
-        @type  requestor:  string
         @param requestor:  the userid of the user making the request.
 
-        @type schema_id:   string
         @param schema_id:  the id of the class of objects to search for
             (i.e., a subtype of
             L{pangalactic.core.pgefobject.PgefObject})
 
-        @type  refs:  boolean
         @param refs:  specifies whether to include the objects referenced
             by the specified class.
 
-                0:  (default) do not get refs
-                1:  get all references
+                - C{0}:  (default) do not get refs
+                - C{1}:  get all references
 
             (in future, refs may specify how many reference levels to
             follow, or what types to include in the results ...)
 
-        @type  subtypes:  boolean
         @param subtypes:  specifies whether to include only the specified
             class (the default) or all subtypes.
 
-                0:  (default) only this type
-                1:  include subtypes
+                - C{0}:  (default) only this type
+                - C{1}:  include subtypes
 
-        @type  ret:  string
         @param ret:  specifies whether to return objects of the type
             specified or resultsets.
 
-                'extracts':  extracts
-                'objects':   Python objects
+                - C{extracts}:  extracts
+                - C{objects}:   Python objects
 
-        @type args:   sequence
-        @param args:  a list of query element tuples, in which each tuple
+        @param args:  a C{list} of query element tuples, in which each tuple
             has the form:
 
-                - element[0] = attribute name
-                - element[1] = logical operator
-                - element[2] = search value
+                - C{element[0] = attribute name}
+                - C{element[1] = logical operator}
+                - C{element[2] = search value}
 
             ... where operator can be any SQL operator, e.g.: 'LIKE', '=',
             '<', '>', 'IN', etc.  Note that if the operator is 'LIKE' and
             the attribute is a string, a case-independent search will be
             done, treating the search value as a substring.
 
-        @rtype:     L{twisted.internet.defer.Deferred} sequence of
-            resultsets or sequence of instances of subtypes of
+        @return:  result of the search as a
+            L{twisted.internet.defer.Deferred} sequence of resultsets or
+            sequence of instances of subtypes of
             L{pangalactic.core.pgefobject.PgefObject}
-        @return:    deferred result of search
         """
         logmsg = 'search, %s, %s' % (schema_id, str(args[0]))
         log.msg(logmsg, system='%s:Chronosynclastic' % requestor)
@@ -692,30 +661,39 @@
         Search for all documents of a given type containing the specified
         string.  Default returntype is a unique document identifier string.
 
-        @type schema_id:   string
         @param schema_id:  the id of a registered
             L{pangalactic.meta.objectschema.ObjectSchema}
 
-        @type searchstring:   string
-        @param searchstring:  the string to be searched for
+        @param searchstring:  the C{str} to be searched for
 
-        @rtype:     list of strings
-        @return:    either basenames or paths, depending on I{returntype}
+        @return:  a C{list} of paths to files whose contents contain the
+            searchstring
         """
         gs = self._glimpseservers[schema_id]
         return gs.search(searchstring)
 
     def _getIntersectionResultSets(self, (resultsets, oids)):
         """
-        Get all results whose pgef_oids are in a supplied list.
+        Get all results whose pgef_oids are in a supplied C{list}.
+
+        @param (resultsets, oids):  a C{tuple} containing the resultsets
+            and oids to be matched up.
+
+        @return:  the matching resultsets
         """
         return filter(lambda x: x['_pgef_oid'] in oids, resultsets)
 
     def _getRefdRowKeys(self, rsets):
         """
-        Get all rowkeys of objects referenced by a list of resultsets
+        Get all rowkeys of objects referenced by a C{list} of resultsets
         (including rowkeys of the objects represented in the resultsets
-        themselves).  A rowkey is just a list: [tablename, pgef_oid].
+        themselves).  A rowkey is just a C{list}: [tablename, pgef_oid].
+
+        @param (resultsets, oids):  a C{tuple} containing the resultsets
+            and oids to be matched up.
+
+        @return: a C{list} of rowkeys.  A rowkey has the following
+            structure:  C{[tablename, pgef_oid]}
         """
         if rsets:
             rowkeys = []
@@ -763,30 +741,27 @@
         L{pangalactic.meta.objectschema.ObjectSchema}-based set of search
         criteria.
 
-        @type schema_id:  string
         @param schema_id: id of the C{ObjectSchema} of the instances to be
             selected
 
-        @type subtypes:  boolean
         @param subtypes: whether to search only the specified
-            C{ObjectSchema} (False) or to include all subtypes (True)
+            C{ObjectSchema} (if C{False}) or to include all subtypes (if
+            C{True})
 
-        @type args:   list of tuples
-        @param args:  a list of tuples, in which each tuple has the form:
+        @param args:  a C{list} of tuples, in which each tuple has the form:
 
-                - element[0] = C{ObjectSchema} property id
-                - element[1] = search value
-                - element[2] = operator
+                - C{element[0] = ObjectSchema property id}
+                - C{element[1] = search value}
+                - C{element[2] = operator}
 
             where I{operator} can be any SQL binary operator.
 
         @param kw:    (optional kw args)
 
-        @rtype:       L{twisted.internet.deferred.Deferred}
-        @return:      (deferred) list of dictionaries of the form (return
-            type of _runQueryMapped):
+        @return:  L{twisted.internet.defer.Deferred} C{list} of dictionaries
+            of the form (return type of _runQueryMapped):
 
-            [{colname:value,...}, {colname:value,...}, ...]
+                - C{[{colname:value,...}, {colname:value,...}, ...]}
         """
         if args:
             table = self._tableNameForSchemaId(schema_id)
@@ -803,15 +778,12 @@
         """
         Get the object with this rowkey.
 
-        @type pgef_oid:  string
         @param pgef_oid: a pgef_oid
 
-        @type schema_id:  string
         @param schema_id: id of a registered
             L{pangalactic.meta.objectschema.ObjectSchema}
 
-        @rtype:   dict
-        @return:  a result set with one item.
+        @return:  a result set (C{dict}) with one item.
         """
         sqlargs = sql.buildSelectFromRowKey(rowkey)
         return self._runQueryMapped(*sqlargs)
@@ -819,7 +791,7 @@
     def addObjects(self, requestor, objects,
                    input='extracts', ret='extracts'):
         """
-        Add a list of extracts of PGEF objects to PGER.  Procedure:
+        Add a C{list} of extracts of PGEF objects to PGER.  Procedure:
 
             - add a row to the appropriate PGER table for each object
 
@@ -831,14 +803,11 @@
             - return a datetime stamp that is the record_create_datetime
               and record_mod_datetime for all the committed objects
 
-        @type objects:  list
-        @param objects: list of objects or extracts to be added
+        @param objects: C{list} of objects or extracts to be added
              L{pangalactic.core.pgefobject.PgefObject}
 
-        @type requestor:  string (userid)
         @param requestor: user who requested the operation
 
-        @type input:  string
         @param input: format of objects to be added
 
             'extracts':  see
@@ -846,11 +815,9 @@
 
             'objects':  Python objects
 
-        @type ret:  string
         @param ret: format of objects to be returned (see input)
 
-        @rtype:  list of deferreds
-        @return: list of deferred objects (or extracts)
+        @return: C{list} of deferred objects (or extracts)
             L{pangalactic.core.pgefobject.PgefObject} that were added
         """
         if input == 'objects':
@@ -894,9 +861,7 @@
         """
         Callback for error in addObjects.
 
-        @type error:   a deferred error
-        @param error:  the error propagated by failure of a
-                    deferred 
+        @param error:  the error propagated by failure of a deferred 
         """
         log.msg("addObjects failed: %s" % (error), system='Chronosynclastic')
         log.err(error)
@@ -904,12 +869,12 @@
     def _addRecords(self, records, requestor):
         """
         Add a series of rows, in a single transaction, from a
-        list of records.
+        C{list} of records.
 
-        @type records:  list
-        @param records: a list of records
+        @param records: a C{list} of records
+
+        @param requestor:  the userid of the user making the request.
 
-        @rtype:  deferred
         @return: a deferred (with no payload)
         """
         tables = utils.unique([rec[0] for rec in records])
@@ -931,15 +896,13 @@
 
     def _verifyAddRecords(self, recs):
         """
-        Verify that a list of records have been added to PGER by doing a
+        Verify that a C{list} of records have been added to PGER by doing a
         query on their rowkeys.
 
-        @type recs:   list
-        @param recs:  a list of records, which look like:
+        @param recs:  a C{list} of records, which look like:
                       [tablename, {colname : value, ...}]
 
-        @rtype:  list
-        @return: list of mapped results (dicts), one for each record added
+        @return: C{list} of mapped results (dicts), one for each record added
         """
         d = defer.gatherResults(
             [self._getResultByRowKey(
@@ -958,16 +921,16 @@
         L{pangalactic.meta.objectschema.ObjectSchema} with the specified
         pgef_oid.
 
-        @type schema_id:   string
+        @param requestor:  the userid (a C{str}) of the user making the
+            request.
+
         @param schema_id:  id of the C{ObjectSchema} of the table to
             update.
 
-        @type updates:   list or dictionary
         @param updates:  colname/value pairs to be updated (can be either a
-            dictionary or a list of 2-item lists)
+            dictionary or a C{list} of 2-item C{list}s)
 
-        @type pgef_oid:   list or tuple
-        @param pgef_oid:  a list or tuple of pgef_oids.
+        @param oids:  a C{list} or tuple of pgef_oids.
         """
         if not updates or not oids:
             raise ValueError, "Both updates and oids must be non-null"

Index: PanGalactic/doc/PgefManual.html
diff -u PanGalactic/doc/PgefManual.html:1.2 PanGalactic/doc/PgefManual.html:1.3
--- PanGalactic/doc/PgefManual.html:1.2	Mon May 16 22:03:19 2005
+++ PanGalactic/doc/PgefManual.html	Tue May 17 04:00:03 2005
@@ -7,7 +7,7 @@
 <title>The PGEF Manual</title>
 <meta name="author" content="Stephen Waterbury &lt;stephen dot c dot waterbury at nasa dot gov&gt;" />
 <meta name="author" content="Ginny Keech" />
-<meta name="date" content="2005-05-16" />
+<meta name="date" content="2005-05-17" />
 <link rel="stylesheet" href="default.css" type="text/css" />
 </head>
 <body>
@@ -23,9 +23,9 @@
 <tr><th class="docinfo-name">Author:</th>
 <td>Ginny Keech</td></tr>
 <tr><th class="docinfo-name">Version:</th>
-<td>1.1</td></tr>
+<td>1.2</td></tr>
 <tr><th class="docinfo-name">Date:</th>
-<td>2005-05-16</td></tr>
+<td>2005-05-17</td></tr>
 </tbody>
 </table>
 <div class="section" id="foreword">
@@ -163,19 +163,19 @@
 <div class="section" id="security-and-access-control-requirements">
 <h2><a name="security-and-access-control-requirements">Security and Access Control Requirements</a></h2>
 <ul class="simple">
-<li>Access control shall be based upon a combination of security
-masks and user roles.</li>
+<li>Access control shall be based upon a combination of security masks and
+user roles.</li>
 <li>Security masks shall be able to be assigned to:<ul>
-<li>Base classes (subtypes of PgefObject)</li>
-<li>Application classes (OntoClasses)</li>
-<li>Application class instances</li>
+<li><a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.core.html">PGEF Core Classes</a></li>
+<li>Application Classes (classes derived from <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.core.html">PGEF Core Classes</a>)</li>
+<li>Instances of either of these</li>
 </ul>
 </li>
-<li>A set of standard PGEF roles shall be defined, each of which will
-have a specified set of permissions.</li>
-<li>Some standard roles will include permissions to add, delete, and
-modify new (custom) roles within specified domains and to assign
-standard and/or custom roles to other users.</li>
+<li>A set of standard PGEF roles shall be defined, each of which will have a
+specified set of permissions.</li>
+<li>Some standard permissions will include permissions to add, delete, and
+modify new (custom) roles within specified domains and to assign standard
+and/or custom roles to other users.</li>
 </ul>
 </div>
 <div class="section" id="use-case-sketches">
@@ -183,20 +183,18 @@
 <p>[TODO:  flesh these out, and include the ones in the slides.]</p>
 <ul class="simple">
 <li>Repository and Client (thick or thin)<ul>
-<li>Implement a STEP-mappable high level information model
-(ontology) for parts, models, docs, and systems engineering
-concepts</li>
-<li>Retrieve model/doc ref(s) from repository<ul>
-<li>&quot;Get&quot; (by Id/Oid)</li>
-<li>&quot;Search&quot; (by parameters)</li>
+<li>Implement a STEP-mappable high level information model (ontology) for a
+specific engineering problem domain</li>
+<li>Retrieve model/doc ref(s) from the repository<ul>
+<li><cite>Get</cite> (by Id/Oid)</li>
+<li><cite>Search</cite> (by parameters)</li>
 </ul>
 </li>
-<li>Add model(s)/doc(s) (including files) to repository<ul>
-<li>&quot;Add&quot; (by Id/Oid)</li>
+<li>Add model(s)/doc(s) (including files) to the repository<ul>
+<li><cite>Add</cite> (by Id/Oid)</li>
 </ul>
 </li>
-<li>Save workflow templates, instances, and states to
-repository</li>
+<li>Save workflow templates, instances, and states to the repository</li>
 </ul>
 </li>
 <li>Client (thick)<ul>
@@ -213,83 +211,75 @@
 <h1><a name="the-pgef-core-ontology">The PGEF Core Ontology</a></h1>
 <div class="section" id="id1">
 <h2><a name="id1">Scope</a></h2>
-<p>The scope of the Pan Galactic Core Ontology is intended to
-include all information relevant to products and product models
-throughout the product life cycle.</p>
-<p>PGEF's principal domain is the &quot;manufacturing&quot; enterprise, in the
-broadest possible sense of &quot;manufacturing&quot; -- i.e., any type of
-&quot;product&quot; life cycle support (as the current buzz words go) where
-a &quot;product&quot; is any artifact that is or includes one or more of
-the following:  software, firmware, hardware, materials, and
-documents.</p>
+<p>The scope of the Pan Galactic Core Ontology is intended to include all
+information relevant to products and product models throughout the product
+life cycle.</p>
+<p>PGEF's principal domain is the &quot;manufacturing&quot; enterprise, in the broadest
+possible sense of &quot;manufacturing&quot; -- i.e., any type of &quot;product&quot; life cycle
+support (as the current buzz words go) where a &quot;product&quot; is any artifact
+that is or includes one or more of the following:  software, firmware,
+hardware, materials, and documents.</p>
 <p>Consequently, one of PGEF's principal goals is to collect, integrate, and
-manage information about products (known in the PGEF Core Ontology as &quot;parts&quot;),
-models, and documents created and used by the enterprise.  To define the
-objects of its domain, PGEF implements a simple core ontology of the most
-basic classes of things that occur in enterprises that develop products.</p>
-<p>[TODO: generate the PGEF Core Ontology into
-PanGalactic/home/pgef.owl and reference it from this section as
-the PGEF Core Ontology. ]</p>
+manage information about products (known in the PGEF Core Ontology as
+&quot;parts&quot;), models, and documents created and used by the enterprise.  To
+define the objects of its domain, PGEF implements a simple core ontology of
+the most basic classes of things that occur in enterprises that develop
+products.</p>
+<p>[<strong>TODO</strong>: generate the PGEF Core Ontology into <cite>PanGalactic/home/pgef.owl</cite>
+and reference it from this section as the PGEF Core Ontology. ]</p>
 </div>
 <div class="section" id="the-pgef-meta-object-facility">
 <h2><a name="the-pgef-meta-object-facility">The PGEF Meta Object Facility</a></h2>
-<p>The PGEF Meta Object Facility (MOF) (the <cite>pangalactic.meta</cite> module) does
-not implement the OMG Meta Object Facility but has a very similar intent.  
-Its principal classes are:</p>
+<p>The <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.html">PGEF Meta Object Facility</a> (PMOF) (the <cite>pangalactic.meta</cite> module)
+does not implement the OMG Meta Object Facility (MOF), but it has much
+in common with it.  Its principal classes are:</p>
 <blockquote>
 <ul>
 <li><p class="first"><strong>ObjectSchema</strong></p>
-<p>The ObjectSchema class represents an ontological class, and defines a
-set of associated attributes (Property instances; 'Properties' in
-ontological parlance) for which that class is the domain.  [Link to the
-ObjectSchema API documentation here:
-L{pangalactic.meta.objectschema.ObjectSchema}]</p>
+<p>The <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.objectschema.ObjectSchema.html">ObjectSchema</a> class represents an ontological class, and defines a
+set of associated attributes (<a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a> instances; <cite>Properties</cite> in
+ontological parlance) for which that class is the domain.</p>
 </li>
 <li><p class="first"><strong>Property</strong></p>
-<p>The Property class represents an ontological Property.  In PGEF, an
-ontological Property is represented as an attribute of its domain
-class.  Thus, Property instances used to define the attributes of
-ObjectSchema instances.  [Link to the Property API documentation here:
-L{pangalactic.meta.pgefproperty.Property}]</p>
+<p>The <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a> class represents an ontological <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a>.  In PGEF, an
+ontological <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a> is represented as an attribute of its domain
+class.  Thus, <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a> instances used to define the attributes of
+<a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.objectschema.ObjectSchema.html">ObjectSchema</a> instances.</p>
+<p><a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a> has the following important attributes:</p>
 <ul>
-<li><p class="first">Every Property has a 'pgef_datatype' (default value:
-'str'), which must be one of: 'str', 'int', 'bool', 'DateTime', or
-the id of a registered ObjectSchema (in which case its
-'property_type' must be set to 'object').  If the Property's value is
-an aggregate of objects, then 'max_cardinality' must be either an
-integer greater than 1 or (if the aggregate is unlimited in size) 0.</p>
-</li>
-<li><p class="first">An Property can have a default value, which is specified in
-the 'default' attribute and must be encoded as a string.  The
-&quot;default default&quot; values are the null of each type:</p>
-<ul>
-<li><p class="first">Strings:  are literal (default default: '')</p>
+<li><p class="first"><strong>domain</strong> -- the type of the <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.objectschema.ObjectSchema.html">ObjectSchema</a> that owns it.  (Maps to
+rdfs:domain.)</p>
+</li>
+<li><p class="first"><strong>property_type</strong> (default value: <cite>datatype</cite>) -- values of
+<cite>property_type</cite> can be:</p>
+<pre class="literal-block">
+`datatype` (maps to `owl:DatatypeProperty`) 
+`object`   (maps to `owl:ObjectProperty`)
+</pre>
 </li>
-<li><p class="first">Integers: are cast to int (default default: 0)</p>
+<li><p class="first"><strong>range</strong> (default value: <cite>str</cite>) -- if the <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a> is a
+<cite>DatatypeProperty</cite>, its <cite>range</cite> must be one of <cite>str</cite>, <cite>int</cite>, <cite>bool</cite>,
+<cite>DateTime</cite>.  If it is an <cite>ObjectProperty</cite>, its range must be the id
+of a registered <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.objectschema.ObjectSchema.html">ObjectSchema</a> (in which case its <cite>property_type</cite> must
+be set to <cite>object</cite>).  If the <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a>'s value is an aggregate of
+objects, then its <cite>max_cardinality</cite> must be either an integer greater
+than 1 or (if the aggregate is unlimited in size) 0.</p>
 </li>
-<li><dl class="first docutils">
-<dt>Booleans: '' == False; any non-empty string == True</dt>
-<dd><p class="first last">(default default: False)</p>
-</dd>
-</dl>
-</li>
-<li><dl class="first docutils">
-<dt>DateTime: DateTime-valued Properties have a default of</dt>
-<dd><p class="first last">None.  [Note that this does not pertain to
+<li><p class="first"><strong>default</strong> -- a default value for the <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a>.  The default values
+for <cite>default</cite> are the null of each type:</p>
+<ul class="simple">
+<li><strong>Strings</strong> (<cite>str</cite>):  are literal (default default: <cite>''</cite>)</li>
+<li><strong>Integers</strong> (<cite>int</cite>): are cast to int (default default: <cite>0</cite>)</li>
+<li><strong>Booleans</strong> (<cite>bool</cite>): empty string (<cite>''</cite>) == False; any
+non-empty string == True (default default: False)</li>
+<li><strong>DateTime</strong> (<cite>DateTime</cite>): DateTime-valued Properties have a default of
+None.  [Note that this does not pertain to
 &quot;initialization&quot; values -- e.g., the
-initialization value for 'create_datetime' is
-DateTime.now().]</p>
-</dd>
-</dl>
-</li>
-<li><dl class="first docutils">
-<dt>Classes:  object-valued Properties (cf.</dt>
-<dd><p class="first last">owl:ObjectProperty) have a default of None if
-their max_cardinality == 1; otherwise, the
-default is an empty list ([]).</p>
-</dd>
-</dl>
-</li>
+initialization value for <cite>create_datetime</cite> is
+DateTime.now().]</li>
+<li><strong>Classes</strong> (<cite>classname</cite>):  object-valued Properties (cf.
+owl:ObjectProperty) have a default of None if their max_cardinality
+== 1; otherwise, the default is an empty list ([]).</li>
 </ul>
 </li>
 </ul>
@@ -299,25 +289,25 @@
 </div>
 <div class="section" id="the-pgef-core-classes">
 <h2><a name="the-pgef-core-classes">The PGEF Core Classes</a></h2>
-<p>The PGEF Core Classes are a set of Python classes corresponding to (and
+<p>The <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.core.html">PGEF Core Classes</a> are a set of Python classes corresponding to (and
 named after) the PGEF ontology's (ontological) classes.  Instances of
 software classes that represent ontological classes are sometimes referred
-to as domain objects:  &quot;a domain object is a logical container of purely
+to as domain objects:  &quot;a <a class="reference" href="http://c2.com/cgi/wiki?DomainObject">domain object</a> is a logical container of purely
 domain information, [and] usually represents a logical entity in the
-problem domain space&quot; (source: <a class="reference" href="http://c2.com/cgi/wiki?DomainObject">The Wiki</a>).</p>
-<p>PgefObject is the root class of the PGEF Core Classes, so hereafter
-the term <em>PgefObject</em> will be used to refer to any PGEF Core Class.</p>
+problem domain space&quot; (source: <a class="reference" href="http://c2.com/cgi/wiki">The Wiki</a>).</p>
+<p><a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.core.pgefobject.PgefObject.html">PgefObject</a> is the root class of the <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.core.html">PGEF Core Classes</a>, so hereafter
+the term <em>PgefObject_</em> will be used to refer to any PGEF Core Class.</p>
 <p>In PGEF, the concept of an ontological class is represented by the
-ObjectSchema class.  Each PgefObject instance is assigned at creation time
-an instance of ObjectSchema as its '_schema'.  The '_schema' defines the
-set of attributes of that instance that will be stored when and if the
+<a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.objectschema.ObjectSchema.html">ObjectSchema</a> class.  Each <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.core.pgefobject.PgefObject.html">PgefObject</a> instance is assigned at creation
+time an instance of <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.objectschema.ObjectSchema.html">ObjectSchema</a> as its <cite>_schema</cite>.  The <cite>_schema</cite> defines
+the set of attributes of that instance that will be stored when and if the
 instance is committed to the repository, PGER.</p>
-<p>Note that a PgefObject instance can have other attributes for various
+<p>Note that a <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.core.pgefobject.PgefObject.html">PgefObject</a> instance can have other attributes for various
 purposes (local state, etc.), and these can be persisted locally (in the
 PanGalaxian client's ZODB cache, e.g.), but they will not be known to the
 repository and will not be shared or synchronized with other proxies of
 that instance in a distributed application unless that is done by way of an
-application protocol that is not part of the state of the domain object.</p>
+application protocol that is not part of the state of the <a class="reference" href="http://c2.com/cgi/wiki?DomainObject">domain object</a>.</p>
 <p>Although the PGEF core ontology is fairly broad in scope, its primary focus
 is the domain of Systems Engineering.</p>
 </div>
@@ -333,7 +323,7 @@
 more detail.]</p>
 <ul>
 <li><p class="first">provides a logical interface layer above the object-relational
-hyperdatabase (the Chronosynclastic Infundibulum)</p>
+hyperdatabase (the <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.repo.chronosynclastic.Infundibulum.html">Chronosynclastic Infundibulum</a>)</p>
 </li>
 <li><p class="first">contains a Registry in which lives the core PGEF ontology and
 any application-specific ontologies</p>
@@ -342,12 +332,12 @@
 </li>
 <li><p class="first">drives all external interfaces (XML-RPC, SOAP, etc.)</p>
 </li>
-<li><p class="first">PgerXmlrpc -- the PGER XML-RPC interface</p>
+<li><p class="first"><a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.repo.pgerxmlrpc.PgerXmlrpcService.html">PgerXmlrpcService</a> -- the PGER XML-RPC Service interface</p>
 <blockquote>
-<p>[see <a class="reference" href="#notes-on-the-pger-xml-rpc-search-interface">Notes on the PGER XML-RPC search interface</a>, for more
+<p>[see <a class="reference" href="#notes-on-the-pger-xml-rpc-service-interface">Notes on the PGER XML-RPC Service interface</a>, for more
 detail.]</p>
 <ul class="simple">
-<li>uses the XML-RPC 'struct' idiom to transmit serialized
+<li>uses the XML-RPC <cite>struct</cite> idiom to transmit serialized
 object states</li>
 <li>implements the XML-RPC representation of the PGER API</li>
 </ul>
@@ -367,7 +357,7 @@
 <li>generates its database schema from the application ontology.  The
 default schema is generated from the PGEF Core Ontology, which
 application can extend by adding other ontologies and/or ontological
-classes (ObjectSchema instances).</li>
+classes (<a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.objectschema.ObjectSchema.html">ObjectSchema</a> instances).</li>
 <li>provides a flexible O-R mapping</li>
 </ul>
 </blockquote>
@@ -409,7 +399,7 @@
 <li><p class="first"><strong>PGEF OID's</strong>:  Unique Object Identifiers</p>
 <blockquote>
 <p>Each PGEF application object is assigned a unique identifier, the
-'oid'.  The preferred form for the oid is a URI, if one is
+<cite>oid</cite>.  The preferred form for the oid is a URI, if one is
 available or can be constructed canonically.  Otherwise, an
 arbitrary (but unique) one will be generated as follows:</p>
 <p><cite>[canonical userid of object creator] + [time-date stamp of creation-time]</cite></p>
@@ -449,30 +439,30 @@
 <p>The PGEF Core Ontology provides the basis for the database
 structures of the PGEF Repository (PGER).  The layer that
 translates the domain Classes and Properties of the ontology to
-the structure of the database is the Chronosynclastic
-Infundibulum.</p>
+the structure of the database is the <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.repo.chronosynclastic.Infundibulum.html">Chronosynclastic
+Infundibulum</a>.</p>
 <div class="section" id="o-r-mapping-the-chronosynclastic-infundibulum">
-<h2><a name="o-r-mapping-the-chronosynclastic-infundibulum">O-R Mapping:  The Chronosynclastic Infundibulum</a></h2>
+<h2><a name="o-r-mapping-the-chronosynclastic-infundibulum">O-R Mapping:  The <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.repo.chronosynclastic.Infundibulum.html">Chronosynclastic Infundibulum</a></a></h2>
 <p>The O-R Mapping used by the PGEF Repository (PGER) is implemented in the
-Chronosynclastic Infundibulum (the <cite>pangalactic.repo.chronosynclastic</cite>
-module).  Chronosynclastic makes extensive use of the PGEF Meta Object
-Facility.  To recap, the default _schema of a PGEF Core Class is a
-ObjectSchema instance whose id is the same as the __name__ of the class.</p>
-<p>Each ObjectSchema known to the registry (initially, just the ones
+<cite>Chronosynclastic Infundibulum</cite> (the <cite>pangalactic.repo.chronosynclastic</cite>
+module).  <cite>Chronosynclastic</cite> makes extensive use of the <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.html">PGEF Meta Object
+Facility</a>.  To recap, the default _schema of a PGEF Core Class is a
+<a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.objectschema.ObjectSchema.html">ObjectSchema</a> instance whose id is the same as the __name__ of the class.</p>
+<p>Each <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.objectschema.ObjectSchema.html">ObjectSchema</a> known to the registry (initially, just the ones
 corresponding to the PGEF core ontology) has a corresponding database table
 in the repository.  The name of the database table is the name of the core
 class converted from studly caps (<cite>StudlyCaps</cite>) to lower-case
 underscore-delimited format, with a leading underscore added
 (<cite>_studly_caps</cite>) to avoid name clashes.  The table's column names are
-generated from the ObjectSchema instance's Property id's (also with leading
-underscores added).</p>
+generated from the <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.objectschema.ObjectSchema.html">ObjectSchema</a> instance's <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a> id's (also with
+leading underscores added).</p>
 <p>The database's table relationships and constraints are determined by other
-attributes of the ObjectSchemas and Properties.</p>
+attributes of the ObjectSchema_s and Properties.</p>
 <blockquote>
 <ul>
 <li><p class="first">required attributes</p>
-<p>A Property with a min_cardinality &gt; 0 signifies a required
-attribute, and the corresponding column is declared 'NOT NULL'.</p>
+<p>A <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a> with a min_cardinality &gt; 0 signifies a required
+attribute, and the corresponding column is declared <cite>NOT NULL</cite>.</p>
 </li>
 <li><p class="first">one-to-many relationships</p>
 <p>A one-to-many relationship can be represented either by an
@@ -490,8 +480,8 @@
 many-to-many:  i.e., the relationship will be reified).
 This case is discussed in detail in the next section
 (many-to-many relationships).</p>
-<p>An aggregate-valued Property corresponds to a one-to-many
-relationship.  The fact that a Property is aggregate-valued is
+<p>An aggregate-valued <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a> corresponds to a one-to-many
+relationship.  The fact that a <a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.meta.pgefproperty.Property.html">Property</a> is aggregate-valued is
 represented in one of two ways:</p>
 <pre class="literal-block">
 max_cardinality == 0 (meaning no limit) or
@@ -519,10 +509,10 @@
 and an assembly in which it is used.  Reifying the
 relationship not only enables database normalization, but
 also supports assigning attributes to the relationship
-itself.  In the case of Acu, 'reference_designator' (a
+itself.  In the case of Acu, <cite>reference_designator</cite> (a
 commonly used identifier of the role of a particular
 component in an assembly) is an attribute of the Acu
-object.  E.g., the reference_designator 'R10' might refer
+object.  E.g., the reference_designator <cite>R10</cite> might refer
 to a specific component role in an electronic circuit,
 which may be fulfilled by various specific components in
 different versions of the circuit, but the role it
@@ -544,8 +534,10 @@
 </ul>
 </blockquote>
 </div>
-<div class="section" id="notes-on-the-pger-xml-rpc-search-interface">
-<h2><a name="notes-on-the-pger-xml-rpc-search-interface">Notes on the PGER XML-RPC search interface</a></h2>
+<div class="section" id="notes-on-the-pger-xml-rpc-service-interface">
+<h2><a name="notes-on-the-pger-xml-rpc-service-interface">Notes on the PGER XML-RPC Service Interface</a></h2>
+<p>[Only the <cite>search</cite> interface is discussed here ... see
+<a class="reference" href="http://ned.gsfc.nasa.gov/pangalapidoc/pangalactic.repo.pgerxmlrpc.PgerXmlrpcService.html">PgerXmlrpcService</a> API documentation for more info.]</p>
 <p><strong>Syntax</strong>:</p>
 <pre class="literal-block">
 search(schemaid, refs, subtypes, args)
@@ -873,7 +865,7 @@
 </li>
 </ul>
 </blockquote>
-<p>$Id: PgefManual.html,v 1.2 2005/05/17 02:03:19 waterbug Exp $</p>
+<p>$Id: PgefManual.html,v 1.3 2005/05/17 08:00:03 waterbug Exp $</p>
 </div>
 </div>
 </body>

Index: PanGalactic/pangalactic/repo/pgerxmlrpc.py
diff -u PanGalactic/pangalactic/repo/pgerxmlrpc.py:1.20 PanGalactic/pangalactic/repo/pgerxmlrpc.py:1.21
--- PanGalactic/pangalactic/repo/pgerxmlrpc.py:1.20	Sat May 14 01:49:05 2005
+++ PanGalactic/pangalactic/repo/pgerxmlrpc.py	Tue May 17 04:00:05 2005
@@ -1,10 +1,10 @@
 """
 PGER XML-RPC Interfaces module
-@version: $Revision: 1.20 $
+@version: $Revision: 1.21 $
 """
 
-__version__ = "$Revision: 1.20 $"[11:-2]
-# $Id: pgerxmlrpc.py,v 1.20 2005/05/14 05:49:05 waterbug Exp $
+__version__ = "$Revision: 1.21 $"[11:-2]
+# $Id: pgerxmlrpc.py,v 1.21 2005/05/17 08:00:05 waterbug Exp $
 
 from twisted.python import log
 from twisted.web.xmlrpc import XMLRPC
@@ -90,39 +90,31 @@
                                           userid,
                                           password)
 
-    def xmlrpc_getObjects(self, typename, refs, subtypes, criteria):
+    def xmlrpc_getObjects(self, schema_id, refs, subtypes, criteria):
         """
         XMLRPC getObjects:  get the set of objects that exactly match a
         specified set of attribute-value pairs, returning the result as a
-        list of "extracts" -- see L{pangalactic.utils.factory.extract})
+        list of "extracts" -- see L{pangalactic.meta.factory.extract})
 
-        @param typename:  the name of a class that extends
-            L{pangalactic.core.pgefobject.PgefObject}
-        @type  typename:  C{str}
+        @param schema_id:  the _schema.id of the objects to get (a C{str})
 
-        @param refs:  whether to return all referenced objects or
-            only the specified class
-
-                0:  (default) only the specified class
-                1:  include all reference objects
-
-        @type  refs:  C{bool}
+        @param refs:  specifies whether to return only the objects matching
+            the criteria or to include all objects that they directly
+            reference.
+                - C{0}:  (default) only the specified class
+                - C{1}:  include all reference objects
 
         @param subtypes:  whether to return all subtypes of the requested
             type that match the criteria
-
-                0:  (default) not
-                1:  include all subtypes
-
-        @type  subtypes:  C{bool}
+                - C{0}:  (default) not
+                - C{1}:  include all subtypes
 
         @param criteria:  the selection criteria can take either of two
             forms:
+                - C{list}:  a list of [attr, value] pairs
+                - C{dict}:  a dictionary: {attr : value, ...}
 
-                - list:  a list of [attr, value] pairs
-                - dict:  a dictionary: {attr : value, ...}
-
-        @type  criteria:  C{list} or C{dict}
+        @return:  a C{list} of extracts of the objects that were found
         """
         if criteria:
             if isinstance(criteria, list):
@@ -142,46 +134,37 @@
         """
         Search for instances of the specified class.
 
-        @param schema_id:  the id of the class of objects to search for
-            (i.e., a subtype of
-            L{pangalactic.core.pgefobject.PgefObject})
-        @type  schema_id:  C{str}
+        @param schema_id:  the _schema.id of the objects to search for
+            (a C{str})
 
         @param refs:  specifies whether to include objects referenced by
-            the found objects (i.e., the attributes whose types are classes
-            in the ontology).
-
-                0:  (default) do not get refs
-                1:  get all references
-
+            the found objects (i.e., ObjectProperties).
+                - C{0}:  (default) do not get referenced objects
+                - C{1}:  get all references
             (in future, refs may specify how many reference levels to
             follow ...)
-        @type  refs:  C{bool}
 
         @param subtypes:  specifies whether to include only the specified
             class (the default) or all subtypes.
-                        0:  (default) only this type
-                        1:  include subtypes
-        @type  subtypes:  C{bool}
+                - C{0}:  (default) only this type
+                - C{1}:  include subtypes
 
         @param objects:  specifies whether to return objects of the type
             specified or resultsets.
-                        0:  resultsets
-                        1:  objects
-        @type  objects:  C{bool}
-
-        @param args:  a list of query element tuples, in which each tuple
-            has the form:
-
-                - element[0] = attribute name
-                - element[1] = logical operator
-                - element[2] = search value
+                - C{0}:  resultsets
+                - C{1}:  objects
 
-            ... where operator can be any SQL operator, e.g.: 'LIKE', '=',
+        @param args:  a C{list} of query element tuples, in which each
+            tuple has the form:
+                - C{element[0] = attribute name}
+                - C{element[1] = logical operator}
+                - C{element[2] = search value}
+            where the operator can be any SQL operator, e.g.: 'LIKE', '=',
             '<', '>', etc.  Note that if the operator is 'LIKE' and the
             attribute is a string, a case-independent search will be done,
             treating the search value as a substring.
-        @type  args:  sequence
+
+        @return:  a C{list} of extracts of the objects that were found
         """
         return self.engine.findObjects(self.userid, schema_id, refs, subtypes,
                                        args=args)
@@ -189,14 +172,11 @@
     def xmlrpc_addObjects(self, extracts):
         """xmlrpc method to add objects.
 
-        @param extracts:  a list of extracts (for the definition of
-            extracts, see L{pangalactic.utils.factory.PgefFactory})
-        @type  extracts:  C{list}
-
-        @return:  a list of extracts:  the objects that were
-                  added, with any relevant updates (e.g.,
-                  timedate stamps)
-        @rtype:   C{list}
+        @param extracts:  a C{list} of extracts (for the definition of
+            extracts, see L{pangalactic.meta.factory.PanGalacticFactory})
+
+        @return:  a C{list} of extracts:  the objects that were added, with
+            any relevant updates (e.g., timedate stamps)
         """
         if extracts:
             return self.engine.addObjects(self.userid, extracts)
@@ -207,26 +187,18 @@
         """
         XML-RPC method to add objects.
 
-        @param extracts:  a list of extracts (for the definition
-                          of extracts, see
-                          L{pangalactic.utils.factory.PgefFactory})
-        @type extracts:   C{list}
-
-        @param blobs: a list of binary objects, which will be
-                      saved to files on the server and referenced
-                      from FileLink objects.  NOTE:  for each blob,
-                      there should be a corresponding
-                      L{pangalactic.core.filelink.FileLink}
-                      instance in the list of extracts, and they
-                      should occur in the same order in the
-                      extracts as their blob occurs in the blobs
-                      list.
-        @type blobs:  C{list}
-
-        @return:  a list of extracts:  the objects that were
-                  added, with any relevant updates (e.g.,
-                  timedate stamps)
-        @rtype:   C{list}
+        @param extracts:  a C{list} of extracts (for the definition of
+            extracts, see L{pangalactic.meta.factory.PanGalacticFactory})
+
+        @param blobs: a C{list} of binary objects, which will be saved to
+            files on the server and referenced from FileLink objects.
+            NOTE: for each blob, there should be a corresponding
+            L{pangalactic.core.filelink.FileLink} instance in the list of
+            extracts, and they should occur in the same order in the
+            extracts as their blob occurs in the blobs list.
+
+        @return:  a C{list} of extracts:  the objects that were added, with
+            any relevant updates (e.g., timedate stamps)
         """
         if extracts and data:
             try:

Index: PanGalactic/pangalactic/utils/twistlets.py
diff -u PanGalactic/pangalactic/utils/twistlets.py:1.1 PanGalactic/pangalactic/utils/twistlets.py:1.2
--- PanGalactic/pangalactic/utils/twistlets.py:1.1	Mon Oct 11 16:23:47 2004
+++ PanGalactic/pangalactic/utils/twistlets.py	Tue May 17 04:00:05 2005
@@ -2,7 +2,7 @@
 Little twisted helpers
 """
 
-# $Id: twistlets.py,v 1.1 2004/10/11 20:23:47 waterbug Exp $
+# $Id: twistlets.py,v 1.2 2005/05/17 08:00:05 waterbug Exp $
 
 from urlparse import urlparse, urlunparse
 from twisted.internet import reactor
@@ -13,7 +13,7 @@
     """
     Make a deferred call into a blocking call.
 
-    @type d:    L{twisted.internet.defer.Deferred
+    @type d:    L{twisted.internet.defer.Deferred}
     @param d:   a deferred call
 
     @rtype:     any

From waterbug at step.nasa.gov  Tue May 17 16:05:26 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May 17 16:05:29 2005
Subject: [pangalactic-commits] Pangalaxian-NG blasting -- hard hat area!
Message-ID: <200505172005.j4HK5QsN006529@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.10 1.11
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.10 1.11
PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py 1.3 1.4

Log message:
Pangalaxian-NG blasting -- hard hat area!

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.10 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.11
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.10	Sun May 15 23:23:26 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Tue May 17 16:05:24 2005
@@ -1,9 +1,9 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.10 $
+@version: $Revision: 1.11 $
 """
-__version__ = "$Revision: 1.10 $"[11:-2]
+__version__ = "$Revision: 1.11 $"[11:-2]
 
 
 import  wx
@@ -14,7 +14,7 @@
     """
     PgxnPanes is the sash window widget in the middle of the PanGalaxian
     main window, which contains a small pane ('minorpane') on the left,
-    mainly for trees, and a larger one ('majorpane') on the right for
+    mainly for trees, and a larger one ('gridbook') on the right for
     grids, canvases, etc.
     """
 
@@ -26,21 +26,21 @@
         minor.SetOrientation(wx.LAYOUT_VERTICAL)
         minor.SetAlignment(wx.LAYOUT_LEFT)
         minor.SetSashVisible(wx.SASH_RIGHT, True)
-        minor.treebook = PgxnTreeBook(minor, -1)
-        minor.treebook.Fit()
+        self.treebook = PgxnTreeBook(minor, -1)
+        self.treebook.Fit()
         self.minorpane = minor
-        self.majorpane = PgxnNotebook(self, -1)
+        self.gridbook = PgxnNotebook(self, -1)
         self.Bind(wx.EVT_SASH_DRAGGED, self.onSashDrag, self.minorpane)
         self.Bind(wx.EVT_SIZE, self.onSize)
         self.sizeChanged = True
 
     def onSashDrag(self, event):
         self.minorpane.SetDefaultSize((event.GetDragRect().width, 1000))
-        wx.LayoutAlgorithm().LayoutWindow(self, self.majorpane)
-        self.majorpane.Refresh()
+        wx.LayoutAlgorithm().LayoutWindow(self, self.gridbook)
+        self.gridbook.Refresh()
 
     def onSize(self, event):
-        wx.LayoutAlgorithm().LayoutWindow(self, self.majorpane)
+        wx.LayoutAlgorithm().LayoutWindow(self, self.gridbook)
         self.Refresh()
 
 notreestext = """

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.10 PanGalactic/pangalactic/node/pangalaxian_new.py:1.11
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.10	Mon May 16 04:07:30 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Tue May 17 16:05:24 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.10 2005/05/16 08:07:30 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.11 2005/05/17 20:05:24 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.10 $
+@version: $Revision: 1.11 $
 """
-__version__ = "$Revision: 1.10 $"[11:-2]
+__version__ = "$Revision: 1.11 $"[11:-2]
 
 # Python core modules
 import sys
@@ -63,6 +63,18 @@
     PanGalaxian's internal model, plugin API, and the GUI elements of its
     main window, including a menu bar, a status bar, and sash window with a
     tree pane on the left and a grid/canvas notebook pane on the right.
+
+    ivar toolbar:  an instance of
+        L{pangalactic.node.gui.widgets.pgxntoolbar.PgxnToolBar}
+
+    ivar statusbar:  an instance of
+        L{pangalactic.node.gui.widgets.pgxnstatusbar.PgxnStatusBar}
+
+    ivar treebook:  a choicebook containing trees (an instance of
+        L{pangalactic.node.gui.widgets.pgxntreebook.PgxnTreeBook})
+
+    ivar gridbook:  a notebook containing grids (an instance of
+        L{pangalactic.node.gui.widgets.pgxngridbook.PgxnGridBook})
     """
 
     def __init__(self, *args, **kwds):
@@ -71,10 +83,10 @@
         wx.Frame.__init__(self, *args, **kwds)
         
         # Menu Bar
-        self.pgxn_menubar = wx.MenuBar()
-        self.SetMenuBar(self.pgxn_menubar)
+        self.menubar = wx.MenuBar()
+        self.SetMenuBar(self.menubar)
         self.file_menu = wx.Menu()
-        self.pgxn_menubar.Append(self.file_menu, "&File")
+        self.menubar.Append(self.file_menu, "&File")
         self.file_new_menu = wx.Menu()
         self.file_menu.AppendMenu(-1, "&New", self.file_new_menu, "")
         self.file_new_part      = self.file_new_menu.Append(-1, "&Part...", "Create a Part ...", wx.ITEM_NORMAL)
@@ -109,18 +121,18 @@
         self.tools_menu.AppendSeparator()
         self.tools_search = self.tools_menu.Append(-1, "&Search...", "Search repository ...", wx.ITEM_NORMAL)
         self.tools_report = self.tools_menu.Append(-1, "&Report...", "Generate a PDF report from the grid contents ...", wx.ITEM_NORMAL)
-        self.pgxn_menubar.Append(self.tools_menu, "&Tools")
+        self.menubar.Append(self.tools_menu, "&Tools")
         self.repository_menu = wx.Menu()
-        self.pgxn_menubar.Append(self.repository_menu, "&Repository")
+        self.menubar.Append(self.repository_menu, "&Repository")
         self.repo_commit     = self.repository_menu.Append(-1, "&Commit ...", "Commit local changes to repository ...", wx.ITEM_NORMAL)
         self.repo_getmystuff = self.repository_menu.Append(-1, "&Get My Stuff...", "Get objects owned by me ...", wx.ITEM_NORMAL)
         self.repo_selectrepo = self.repository_menu.Append(-1, "Select &Repository...", "Select a Repository ...", wx.ITEM_NORMAL)
         self.cache_menu = wx.Menu()
-        self.pgxn_menubar.Append(self.cache_menu, "&Cache")
+        self.menubar.Append(self.cache_menu, "&Cache")
         self.cache_browse = self.cache_menu.Append(-1, "&Browse Local Objects...", "Browse locally cached objects ...", wx.ITEM_NORMAL)
         self.cache_clear  = self.cache_menu.Append(-1, "&Clear Local Objects...", "Remove objects from local cache", wx.ITEM_NORMAL)
         self.options_menu = wx.Menu()
-        self.pgxn_menubar.Append(self.options_menu, "&Options")
+        self.menubar.Append(self.options_menu, "&Options")
         self.options_userid       = self.options_menu.Append(-1, "&Userid...", "Set userid ...", wx.ITEM_NORMAL)
         self.options_passwd       = self.options_menu.Append(-1, "Change &Password...", "Change your password ...", wx.ITEM_NORMAL)
         self.options_outputdir    = self.options_menu.Append(-1, "Set Output &Directory...", "Select a directory to write files to ...", wx.ITEM_NORMAL)
@@ -129,7 +141,7 @@
         self.options_loginconfirm = self.options_menu.Append(-1, "Show Login &Confirmation", "Confirm when login succeeds ...", wx.ITEM_NORMAL)
         self.options_tooltips     = self.options_menu.Append(-1, "Show &Tooltips", "Allow tooltip pop-up messages", wx.ITEM_CHECK)
         self.help_menu = wx.Menu()
-        self.pgxn_menubar.Append(self.help_menu, "&Help")
+        self.menubar.Append(self.help_menu, "&Help")
         self.help_about    = self.help_menu.Append(-1, "&About", "Info about PanGalaxian ...", wx.ITEM_NORMAL)
         self.help_contents = self.help_menu.Append(-1, "&Contents", "Contents of help docs ...", wx.ITEM_NORMAL)
         # Menu Bar end
@@ -257,6 +269,8 @@
         self.SetStatusBar(self.statusbar)
         self.toolbar = PgxnToolBar(self)
         self.mainwin = PgxnPanes(self)
+        self.treebook = self.mainwin.treebook
+        self.gridbook = self.mainwin.gridbook
 
     def __do_layout(self):
         box = wx.BoxSizer(wx.VERTICAL)
@@ -285,7 +299,7 @@
         # self.Bind(wx.EVT_MENU, self.onNewModel, self.file_new_model)
         # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.file_new_partslist)
         # self.Bind(wx.EVT_MENU, self.onNewDocument, self.file_new_document)
-        # self.Bind(wx.EVT_MENU, self.onLogin, self.file_login)
+        self.Bind(wx.EVT_MENU, self.onLogin, self.file_login)
         # self.Bind(wx.EVT_MENU, self.onLogout, self.file_logout)
         # self.Bind(wx.EVT_MENU, self.onExport, self.file_export)
         self.Bind(wx.EVT_MENU, self.onExit, self.file_exit)
@@ -347,9 +361,83 @@
         self.Layout()
 
     def onNewPart(self, event):
+        """
+        Create a new instance of Part.
+        """
+        # TODO:  think about "New Object" instead of hard-coded special cases
         print "PanGalaxian.onNewPart"
-        metadata = ["MENU", None, "Part"]
-        self.psmplugin.OnNewPart(metadata)
+
+    def onLogin(self, event):
+        """
+        Login to a service (repository is it, for now).
+        """
+        print "PanGalaxian.OnLogin"
+        loginconfirm = prefs.get('ShowLoginConfirmed', None)
+        if loginconfirm is None:
+            loginconfirm = 1
+        # logindlg = LoginClass(self, -1, "PGEF Login" )
+        logindlg = LoginDialog(self, -1)
+        logindlg.login_confirm_checkbox.SetValue(bool(int(loginconfirm)))
+        logindlg.ssl_checkbox.SetValue(int(self.secure))
+        logindlg.repo_choice.Clear()
+        for entry in state['serverlist']:
+            logindlg.repo_choice.Append(entry)
+        i = state['serverlist'].index(state['server'])
+        logindlg.repo_choice.SetSelection(i)
+        logindlg.CentreOnParent()
+        userid = prefs.get('userid', None) or state.get('userid', '')
+        logindlg.userid_text_ctrl.SetValue(userid)
+        if userid:
+            logindlg.passwd_text_ctrl.SetFocus()
+        still_trying = True
+        while still_trying:
+            logindlg.passwd_text_ctrl.SetValue("")
+            logindlg.passwd_text_ctrl.SetFocus()
+            result = logindlg.ShowModal()
+            if result == wx.ID_CANCEL:
+                logindlg.Destroy()
+                still_trying = False
+            elif result == wx.ID_OK:
+                prefs['ShowLoginConfirmed'] = int(
+                                    logindlg.login_confirm_checkbox.GetValue())
+                self.options_loginconfirm.Check(
+                                    logindlg.login_confirm_checkbox.GetValue())
+                self.secure = logindlg.ssl_checkbox.GetValue()
+                hostport    = logindlg.repo_choice.GetStringSelection()
+                loginid     = logindlg.userid_text_ctrl.GetValue()
+                loginpasswd = logindlg.passwd_text_ctrl.GetValue()
+                state['server'] = state['serverlist'][
+                                          logindlg.repo_choice.GetSelection()]
+                print '  - loginid: ', loginid
+                print '  - server: ', state['server']
+                if (prefs.get('userid', None)
+                    and loginid == prefs['userid']):
+                    self.dm.user._password = loginpasswd
+                print 'self.secure: ', self.secure
+                if self.dm.login(loginid, loginpasswd, secure=self.secure):
+                    dlg = wx.Dialog(self, -1, "A Message from PGEF",
+                                   wx.DefaultPosition, wx.Size(400, 75),
+                                   wx.THICK_FRAME)
+                    msg = wx.StaticText(dlg, -1,
+                          "Please wait while PGEF validates your login...",
+                          wx.Point (10, 10), wx.DefaultSize, wx.ALIGN_CENTRE)
+                    dlg.CentreOnParent()
+                    dlg.Show(True)
+                    dlg.Destroy()
+                    logindlg.Destroy()
+                    still_trying = False
+                    state['loggedin'] = '1'
+                    state['userid'] = loginid
+                    self.onStateChange()
+                    if prefs.get('ShowLoginConfirmed', 0):
+                        sdlg = wx.MessageDialog(self,
+                                   "Login successful.",
+                                   "Yay!", wx.OK)
+                        sdlg.CentreOnParent()
+                        sdlg.ShowModal() 
+                        sdlg.Destroy()
+                else:
+                    logindlg.SetTitle("Try Again?")
 
     def onExit(self, event):
         """
@@ -368,6 +456,14 @@
             prefs["ShowToolTips"] = False
         event.Skip()
 
+    def onShowLoginConfirmed(self, event):
+        print "PanGalaxian.onShowLoginConfirmed"
+        if self.options_loginconfirm.IsChecked():
+            prefs["ShowLoginConfirmed"] = True
+        else:
+            prefs["ShowLoginConfirmed"] = False
+        event.Skip()
+
     def onHelpAbout(self, event):
         dlg = AboutBox(self, -1,
                        "About " + APP_NAME,
@@ -388,6 +484,53 @@
                                wx.OK|wx.CENTRE|wx.ICON_EXCLAMATION)
         dlg.ShowModal()
 
+    def onStateChange(self, event=None):
+        """
+        Trigger local/remote-mode state changes for PanGalaxian
+        (propagating the call to the onStateChange() methods for
+        DataManager, and PSMTool).
+        """
+        # blab about my state
+        print "PanGalaxian.onStateChange"
+        print "  - prefs:"
+        pprint(prefs)
+        print "  - state:"
+        for s in state:
+            if s != 'displaymaps':
+                print "    * %s" % s
+                pprint(state[s])
+        # actually do stuff ...
+        self.dm.onStateChange()
+        if state['loggedin']:
+            print "\n  *** logged in (non-local mode) ***\n"
+            # GUI state changes
+            if state['userid'] != 'admin':
+                self.removeSpecialMenus(state['userid'])
+            self.options_repo.Enable(0)
+            self.options_proxy.Enable(0)
+            self.options_user.Enable(0)
+            self.options_passwd.Enable(0)
+            self.file_login.Enable(0)
+            self.file_logout.Enable(1)
+            self.repo_commit.Enable(1)
+            self.repo_getmystuff.Enable(1)
+            self.repo_selectrepo.Enable(0)
+            self.tools_search.Enable(1)
+        else:
+            self.options_repo.Enable(1)
+            self.options_proxy.Enable(1)
+            self.options_user.Enable(1)
+            self.options_passwd.Enable(1)
+            self.file_login.Enable(1)
+            self.file_logout.Enable(0)
+            self.repo_commit.Enable(0)
+            self.repo_getmystuff.Enable(0)
+            self.repo_selectrepo.Enable(1)
+            self.tools_search.Enable(0)
+            print "\n  *** not logged in (local mode) ***\n"
+            # GUI state changes
+        self.statusbar.onStateChange()
+
 
 # end of class PgxnFrame
 

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.3 PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.4
--- PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.3	Wed May 11 03:07:49 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py	Tue May 17 16:05:24 2005
@@ -1,11 +1,11 @@
-# $Id: pgxnstatusbar.py,v 1.3 2005/05/11 07:07:49 waterbug Exp $
+# $Id: pgxnstatusbar.py,v 1.4 2005/05/17 20:05:24 waterbug Exp $
 
 """
 Custom status bar for PanGalaxian (the PGEF desktop client).
 
-@version: $Revision: 1.3 $
+@version: $Revision: 1.4 $
 """
-__version__ = "$Revision: 1.3 $"[11:-2]
+__version__ = "$Revision: 1.4 $"[11:-2]
 
 # Python core modules
 from pprint import pprint
@@ -27,6 +27,7 @@
     """
     def __init__(self, parent):
         wx.StatusBar.__init__(self, parent, -1)
+        self.parent = parent
         self.sizechanged = False
         self.Bind(wx.EVT_SIZE, self.onSize)
         self.Bind(wx.EVT_IDLE, self.onIdle)
@@ -40,20 +41,22 @@
         self.SetStatusWidths([-4, -1, 50, 25, 25])
         self.SetStatusText("", 1)  # placeholder for field 1
         # online/offline image (field 2):
-        bmpol = toolkitimages.getOfflineBitmap()
+        self.bmpon = toolkitimages.getOnlineBitmap()
+        self.bmpoff = toolkitimages.getOfflineBitmap()
         rect = self.GetFieldRect(2)
-        self.olbutton = wx.BitmapButton(self, -1, bmpol,
+        self.onbutton = wx.BitmapButton(self, -1, self.bmpoff,
                                         (rect.x+1, rect.y+1),
                                         (rect.width-2, rect.height))
-        # TODO:  give olbutton a TipWindow (instead of Tooltip)
-        self.olbutton.SetToolTipString('You are offline ... to log on, click the icon')
-        self.Bind(wx.EVT_BUTTON, self.onClick, self.olbutton)
-        """
-        # simple bitmap for field 2 instead ...
-        # online/offline image (field 2):
-        bmpol = toolkitimages.getOfflineBitmap()
-        self.onlinebitmap = wx.StaticBitmap(self, -1, bmpol)
-        """
+        # TODO:  give on/off buttons a TipWindow (instead of Tooltip)
+        self.onbutton.Show()
+        self.onbutton.Enable(True)
+        self.Bind(wx.EVT_BUTTON, self.onClick, self.onbutton)
+        self.offbutton = wx.BitmapButton(self, -1, self.bmpon,
+                                        (rect.x+1, rect.y+1),
+                                        (rect.width-2, rect.height))
+        self.Bind(wx.EVT_BUTTON, self.onClick, self.offbutton)
+        self.offbutton.Hide()
+        self.offbutton.Enable(False)
         # secure/insecure image (field 3):
         bmplk = toolkitimages.getLockInsecureBitmap()
         self.lockbitmap = wx.StaticBitmap(self, -1, bmplk)
@@ -64,8 +67,8 @@
         Reposition widgets within their fields (call this when resized).
         """
         rect = self.GetFieldRect(2)
-        self.olbutton.SetPosition((rect.x+1, rect.y+1))
-        self.olbutton.SetSize((rect.width-2, rect.height))
+        self.onbutton.SetPosition((rect.x+1, rect.y+1))
+        self.onbutton.SetSize((rect.width-2, rect.height))
         rect = self.GetFieldRect(3)
         self.lockbitmap.SetPosition((rect.x+2, rect.y+2))
         self.lockbitmap.SetSize((rect.width-4, rect.height-4))
@@ -80,5 +83,26 @@
             self.reposition()
 
     def onClick(self, evt):
-        print "PanGalaxian.onLogin"
+        print "PgxnStatusBar.onClick"
+        if state['loggedin']:
+            self.parent.onLogout()
+        else:
+            self.parent.onLogin()
+
+    def onStateChange(self):
+        """
+        Check state and set things accordingly.
+        """
+        if state['loggedin']:
+            self.onbutton.Hide()
+            self.onbutton.Enable(False)
+            self.offbutton.Show()
+            self.offbutton.Enable(True)
+            self.offbutton.SetToolTipString('To log off, click the icon')
+        else:
+            self.onbutton.Show()
+            self.onbutton.Enable(True)
+            self.onbutton.SetToolTipString('To log on, click the icon')
+            self.offbutton.Hide()
+            self.offbutton.Enable(False)
 

From waterbug at step.nasa.gov  Wed May 18 01:19:51 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May 18 01:19:54 2005
Subject: [pangalactic-commits] Login workin nice,
	little button in status bar and all!
Message-ID: <200505180519.j4I5Jp8a010602@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian.py 1.55 1.56
PanGalactic/pangalactic/node/pangalaxian_new.py 1.11 1.12
PanGalactic/pangalactic/node/gui/dialogs/login.py 1.1 1.2
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.10 1.11
PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py 1.4 1.5
PanGalactic/pangalactic/repo/pgerxmlrpc.py 1.21 1.22
PanGalactic/pangalactic/utils/datamanager.py 1.177 1.178

Log message:
Login workin nice, little button in status bar and all!

Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.55 PanGalactic/pangalactic/node/pangalaxian.py:1.56
--- PanGalactic/pangalactic/node/pangalaxian.py:1.55	Wed May 11 03:07:45 2005
+++ PanGalactic/pangalactic/node/pangalaxian.py	Wed May 18 01:19:46 2005
@@ -1,13 +1,13 @@
 #!/usr/bin/env python 
 
-# $Id: pangalaxian.py,v 1.55 2005/05/11 07:07:45 waterbug Exp $
+# $Id: pangalaxian.py,v 1.56 2005/05/18 05:19:46 waterbug Exp $
 
 """
 Main application module for the PGEF desktop client.
 
-@version: $Revision: 1.55 $
+@version: $Revision: 1.56 $
 """
-__version__ = "$Revision: 1.55 $"[11:-2]
+__version__ = "$Revision: 1.56 $"[11:-2]
 
 import sys
 import os
@@ -505,7 +505,6 @@
         else:
             print "\n  *** not logged in (local mode) ***\n"
             # GUI state changes
-            self.addSpecialMenus(state['userid'])
             self.menuBar.Enable(ID_FILE_LOGIN, 1)
             self.menuBar.Enable(ID_PREF_PROXY, 1)
             self.menuBar.Enable(ID_PREF_SERVER1, 1)
@@ -547,7 +546,7 @@
 
 
     def OnClearLocalDB(self, event):
-        if self.dm.uncommittedData():
+        if self.dm.has_uncommitted_data:
             msg = """
             You have uncommitted changes.  Really clear the local cache?"""
         else:
@@ -623,48 +622,21 @@
         if not userid:
             dlg = ChangePasswd(self, -1, "Change Your Password")
             dlg.CentreOnParent()
-            login_passwd = self.dm.getPasswd("login")
-            curr_passwd = self.dm.getPasswd("current")
-            # print "passwd", login_passwd, curr_passwd
-
+            old_passwd = self.passwd
             still_trying = True
             while still_trying:
                 # print dlg.GetTitle()
                 if dlg.ShowModal() == wx.ID_OK:
-                    # print "passwds", dlg.getOldPasswd(), dlg.getNewPasswd(), dlg.getConfirmPasswd()
-
-                    if dlg.getOldPasswd() == curr_passwd and \
+                    if dlg.getOldPasswd() == old_passwd and \
                         dlg.getNewPasswd() == dlg.getConfirmPasswd():
                         # print "changed"
                         still_trying = False
                         new_password = dlg.getConfirmPasswd()
-                        self.dm.changePassword(login_passwd,
+                        self.dm.changePassword(old_passwd,
                                                new_password,
-                                               self.dm.user.id,
-                                               secure=self.secure)
-                    else:
-                        dlg.clearFields()
-                        dlg.SetTitle("Try Again?")
-                else:
-                    still_trying = False
-            dlg.Destroy()
-
-        elif self.dm.user.god:
-            dlg = ChangePasswd(self, -1, "Change Admin Password")
-            dlg.CentreOnParent()
-            still_trying = True
-            while still_trying:
-                # print dlg.GetTitle()
-                if dlg.ShowModal() == wx.ID_OK:
-                    # print "passwds", dlg.getOldPasswd(), dlg.getNewPasswd(), dlg.getConfirmPasswd()
-                    if dlg.getNewPasswd() == dlg.getConfirmPasswd():
-                        # print "changed"
-                        still_trying = False
-                        new_password = dlg.getConfirmPasswd()
-                        self.dm.changePassword(new_password,
-                                               login_passwd,
-                                               userid,
+                                               state['userid'],
                                                secure=self.secure)
+                        self.passwd = new_passwd
                     else:
                         dlg.clearFields()
                         dlg.SetTitle("Try Again?")
@@ -813,17 +785,6 @@
         dlg.ShowModal()
 
 
-    def addSpecialMenus(self, user_info):
-        if (state['loggedin']
-            and state['userid'] == 'admin'
-            and self.adminmenu == None):
-            self.AddAdminMenu(self.dm.user)  
-        #########
-        # GodMenu is temporarily disabled
-        # if self.dm.user.god:
-        #     self.AddGodMenu(self.dm.user)
-
-
     def removeSpecialMenus(self, user_info):
         if not userinfo.id == "admin" and self.adminmenu:
             self.RemoveAdminMenu(user_info)
@@ -911,16 +872,13 @@
                 self.secure = logindlg.ssl_checkbox.GetValue()
                 hostport    = logindlg.repo_choice.GetStringSelection()
                 loginid     = logindlg.userid_text_ctrl.GetValue()
-                loginpasswd = logindlg.passwd_text_ctrl.GetValue()
+                self.passwd = logindlg.passwd_text_ctrl.GetValue()
                 state['server'] = state['serverlist'][
                                           logindlg.repo_choice.GetSelection()]
                 print '  - loginid: ', loginid
                 print '  - server: ', state['server']
-                if (prefs.get('userid', None)
-                    and loginid == prefs['userid']):
-                    self.dm.user._password = loginpasswd
                 print 'self.secure: ', self.secure
-                if self.dm.login(loginid, loginpasswd, secure=self.secure):
+                if self.dm.login(loginid, self.passwd, secure=self.secure):
                     dlg = wx.Dialog(self, -1, "A Message from PGEF",
                                    wx.DefaultPosition, wx.Size(400, 75),
                                    wx.THICK_FRAME)
@@ -974,7 +932,7 @@
                             os.remove(tmpfn)
                         except:
                             pass
-            if self.dm.uncommittedData():
+            if self.dm.has_uncommitted_data:
                 text = """Commit work now?  (If "No", your work will be saved in the Cache.) """
                 dlg = wx.MessageDialog(self, text,
                           "PanGalaxian:  Uncommitted Work",
@@ -1027,127 +985,6 @@
         """
         pass
 
-#    def onSelectMode(self, event):
-
-#        id = event.GetId()
-#
-#        if id <> ID_PGTEST_ITEM:
-#            self.menuBar.Check(ID_PGTEST_ITEM, 0)
-#        if id <> ID_PGTEST_ITEM:
-#            self.menuBar.Check(ID_PGTEST_ITEM, 0)
-#        if id <> ID_PGDEV_ITEM:
-#            self.menuBar.Check(ID_PGDEV_ITEM, 0)
-#        if id <> ID_PGPROD_ITEM:
-#            self.menuBar.Check(ID_PGPROD_ITEM, 0)
-#        if id <> ID_PGPLAY_ITEM:
-#            self.menuBar.Check(ID_PGPLAY_ITEM, 0)
-#        if id <> ID_PGDEMO_ITEM:
-#            self.menuBar.Check(ID_PGDEMO_ITEM, 0)
-#
-#        event.Skip()
-
-#    def onAdminEditUser(self, event):
-#        self.searchUser(mode = userinfo.EDIT_MODE)
-
-#    def onAdminDisableUser(self, event):
-#        self.searchUser(mode = userinfo.DISABLE_MODE)
-
-#    def onAdminEnableUser(self, event):
-#        self.searchUser(mode = userinfo.ENABLE_MODE)
-
-##    def onAdminPasswd(self, event):
-##        print "hook up pythoncard window here.  TBD RSN"
-##        self.onPasswd(event)
-
-##    def onPasswd(self, event):
-##        login_passwd = self.dm.getPasswd("login")
-##        curr_passwd = self.dm.getPasswd("current")
-##        # print "passwd", login_passwd, curr_passwd
-##        dlg = ChangePasswd(self, -1, "Change Password")
-##        dlg.CentreOnParent()
-
-##        still_trying = True
-##        while still_trying:
-##            if dlg.ShowModal() == wx.ID_OK:
-##                # print "passwds", dlg.getOldPasswd(), dlg.getNewPasswd(), dlg.getConfirmPasswd()
-
-##                if dlg.getOldPasswd() == curr_passwd and \
-##                    dlg.getNewPasswd() == dlg.getConfirmPasswd():
-##                    still_trying = False
-##                    new_password = dlg.getConfirmPasswd()
-##                    self.dm.changePassword(login_passwd, new_password,
-##                                           secure=self.secure)
-
-##                else:
-##                    dlg.clearFields()
-##                    dlg.SetTitle("Try Again?")
-##            else:
-##                still_trying = False
-
-##        dlg.Destroy()
-
-
-
-##    def showUser(self, mode):
-##        tmpsize = wx.Size(650, 500)
-##        user_frame = toolframe.ToolFrame(self, -1, "User Data", wx.DefaultPosition, tmpsize)
-##        user_frame.menuBar.SetLabel(toolframe.ID_FILE_EXIT, "&Close")
-##        user_frame.menuBar.SetHelpString(toolframe.ID_FILE_EXIT, "Close this window")
-##        user_frame.mainpanel = userinfo.UserInfo(user_frame, -1, mode = mode, datamgr = self.dm)
-##        user_frame.CentreOnParent()
-##        user_frame.Show(True)
-
-
-##    def onAdminAddUser(self, event):
-##        self.showUser(mode = userinfo.ADD_MODE)
-
-##    def onAdminEditUser(self, event):
-##        self.searchUser(mode = userinfo.EDIT_MODE)
-
-##    def onAdminDisableUser(self, event):
-##        self.searchUser(mode = userinfo.DISABLE_MODE)
-
-##    def onAdminEnableUser(self, event):
-##        self.searchUser(mode = userinfo.ENABLE_MODE)
-
-##    def searchUser(self, mode):
-##        tmpsize = wx.Size(600, 350)
-##        user_frame = UserSearchFrame(self, -1, "User Data", self.dm, tmpsize)
-##        user_frame.CentreOnParent()
-##        user_frame.Show(True)
-
-
-
-######### GodMenu is temporarily disabled
-#
-#     def RemoveGodMenu(self, user_info):
-#         self.menuBar.Remove(self.specialmenupos) # the admin menu
-#         self.menuBar.Refresh()
-#         self.GodMenu = None
-# 
-# 
-#     def AddGodMenu(self, user_info): 
-#         """
-#         This method inserts the God menu on the main menubar, 
-#         just to the right of the Options Menu.  This only should happen 
-#         if the user logged in has God access.
-#         """
-#         if self.GodMenu == None:
-#             self.GodMenu = wx.Menu()
-#             self.GodMenu.Append(ID_ADMIN_PASSWD,
-#                                 "Change &Password...",
-#                                 "Change Administrator Password")
-#             AdminMenu = self.createAdminMenu()
-#             self.GodMenu.AppendMenu(ID_SPECIAL_ADMIN,
-#                                     '&Administrator',
-#                                     AdminMenu)
-#         self.menuBar.Insert(self.specialmenupos, self.GodMenu, "God") 
-#         # self.menuBar.Check(ID_PGDEV_ITEM, 1)
-#         self.menuBar.Refresh()
-
-
-#----------------------------------------------------------------------------
-
 class MyApp(wx.App):
 
     def OnInit(self):

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.11 PanGalactic/pangalactic/node/pangalaxian_new.py:1.12
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.11	Tue May 17 16:05:24 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Wed May 18 01:19:46 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.11 2005/05/17 20:05:24 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.12 2005/05/18 05:19:46 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.11 $
+@version: $Revision: 1.12 $
 """
-__version__ = "$Revision: 1.11 $"[11:-2]
+__version__ = "$Revision: 1.12 $"[11:-2]
 
 # Python core modules
 import sys
@@ -23,6 +23,7 @@
 import wxversion
 wxversion.select("2.5")
 import wx
+from wx.lib.dialogs import MultipleChoiceDialog
 
 # PyDispatch module
 import dispatch
@@ -151,10 +152,12 @@
         # end wxGlade
         ###################################################
         wx.InitAllImageHandlers()
-        # Make sure there's a tmp dir here
+        # make sure there's a tmp dir here
         if not os.path.exists('tmp'):
             os.makedirs('tmp')
-        # Look for a userid ... if none, run first-time dialog/wizard
+        # by default, this client instance will hold a passwd
+        self.hold_passwd = True
+        # look for a userid ... if none, run first-time dialog/wizard
         if not prefs.get('userid', None):
             # TODO:  make first-time dialog a conf wizard for prefs, etc.
             # TODO:  make conf wiz usable any time (alt.: dlg for expt. users)
@@ -209,7 +212,7 @@
             self.Close(True)
         # make sure some defaults are set
         state['workingdir'] = workingdir
-        state['loggedin'] = ''
+        state['loggedin'] = False
         # set state['server'] and state['serverlist'] from
         # existing states and prefs, if any
         server = (state.get('server', None)
@@ -300,7 +303,7 @@
         # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.file_new_partslist)
         # self.Bind(wx.EVT_MENU, self.onNewDocument, self.file_new_document)
         self.Bind(wx.EVT_MENU, self.onLogin, self.file_login)
-        # self.Bind(wx.EVT_MENU, self.onLogout, self.file_logout)
+        self.Bind(wx.EVT_MENU, self.onLogout, self.file_logout)
         # self.Bind(wx.EVT_MENU, self.onExport, self.file_export)
         self.Bind(wx.EVT_MENU, self.onExit, self.file_exit)
         #
@@ -352,6 +355,7 @@
         # self.Bind(wx.EVT_MENU, self.onAdminSearchUser)
         ###################################################
         # end of menu events
+        self.Bind(wx.EVT_CLOSE, self.onExit)
 
     # Event handlers
 
@@ -372,10 +376,54 @@
         Login to a service (repository is it, for now).
         """
         print "PanGalaxian.OnLogin"
-        loginconfirm = prefs.get('ShowLoginConfirmed', None)
-        if loginconfirm is None:
-            loginconfirm = 1
-        # logindlg = LoginClass(self, -1, "PGEF Login" )
+        loginconfirm = prefs.get('ShowLoginConfirmed', True)
+        userid = prefs.get('userid', '') or state.get('userid', '')
+        server = prefs.get('server', '') or state.get('server', '')
+        passwd = getattr(self, 'passwd', '')
+        # if we have a server, a userid, and a saved passwd, try logging in
+        # without further ado ...
+        if self.hold_passwd and server and userid and passwd:
+            if self.dm.login(userid, passwd, secure=self.secure):
+                dlg = wx.Dialog(self, -1, "A Message from PGEF",
+                               wx.DefaultPosition, wx.Size(400, 75),
+                               wx.THICK_FRAME)
+                msg = wx.StaticText(dlg, -1,
+                      "Please wait while PGEF validates your login...",
+                      wx.Point (10, 10), wx.DefaultSize, wx.ALIGN_CENTRE)
+                dlg.CentreOnParent()
+                dlg.Show(True)
+                dlg.Destroy()
+                state['loggedin'] = True
+                state['userid'] = userid
+                self.onStateChange()
+                if prefs.get('ShowLoginConfirmed', 0):
+                    sdlg = wx.MessageDialog(self,
+                               "Login successful.",
+                               "Yay!", wx.OK)
+                    sdlg.CentreOnParent()
+                    sdlg.ShowModal() 
+                    sdlg.Destroy()
+            else:
+                dlg = wx.MessageDialog(self,
+                           "Login failed. Try again?",
+                           "Rats!", wx.YES_NO)
+                dlg.CentreOnParent()
+                if (dlg.ShowModal() == wx.YES):
+                    self.openFullLoginDialog()
+                dlg.Destroy()
+        # otherwise, open the full login dialog ...
+        else:
+            self.openFullLoginDialog()
+
+    def openFullLoginDialog(self):
+        """
+        Open a full login dialog that prompts for a userid, passwd, server,
+        and some options.
+        """
+        loginconfirm = prefs.get('ShowLoginConfirmed', True)
+        userid = prefs.get('userid', '') or state.get('userid', '')
+        server = prefs.get('server', '') or state.get('server', '')
+        passwd = getattr(self, 'passwd', '')
         logindlg = LoginDialog(self, -1)
         logindlg.login_confirm_checkbox.SetValue(bool(int(loginconfirm)))
         logindlg.ssl_checkbox.SetValue(int(self.secure))
@@ -385,36 +433,35 @@
         i = state['serverlist'].index(state['server'])
         logindlg.repo_choice.SetSelection(i)
         logindlg.CentreOnParent()
-        userid = prefs.get('userid', None) or state.get('userid', '')
         logindlg.userid_text_ctrl.SetValue(userid)
         if userid:
             logindlg.passwd_text_ctrl.SetFocus()
         still_trying = True
         while still_trying:
-            logindlg.passwd_text_ctrl.SetValue("")
-            logindlg.passwd_text_ctrl.SetFocus()
+            logindlg.passwd_text_ctrl.SetValue(passwd)
+            if not passwd:
+                logindlg.passwd_text_ctrl.SetFocus()
             result = logindlg.ShowModal()
             if result == wx.ID_CANCEL:
                 logindlg.Destroy()
                 still_trying = False
             elif result == wx.ID_OK:
-                prefs['ShowLoginConfirmed'] = int(
-                                    logindlg.login_confirm_checkbox.GetValue())
+                prefs['ShowLoginConfirmed'] = (
+                                     logindlg.login_confirm_checkbox.GetValue())
                 self.options_loginconfirm.Check(
-                                    logindlg.login_confirm_checkbox.GetValue())
+                                     logindlg.login_confirm_checkbox.GetValue())
+                self.hold_passwd = logindlg.hold_passwd_checkbox.GetValue()
                 self.secure = logindlg.ssl_checkbox.GetValue()
-                hostport    = logindlg.repo_choice.GetStringSelection()
-                loginid     = logindlg.userid_text_ctrl.GetValue()
-                loginpasswd = logindlg.passwd_text_ctrl.GetValue()
+                state['userid'] = logindlg.userid_text_ctrl.GetValue()
+                self.passwd     = logindlg.passwd_text_ctrl.GetValue()
                 state['server'] = state['serverlist'][
                                           logindlg.repo_choice.GetSelection()]
-                print '  - loginid: ', loginid
+                print '  - userid: ', state['userid']
                 print '  - server: ', state['server']
-                if (prefs.get('userid', None)
-                    and loginid == prefs['userid']):
-                    self.dm.user._password = loginpasswd
-                print 'self.secure: ', self.secure
-                if self.dm.login(loginid, loginpasswd, secure=self.secure):
+                print '  - self.secure: ', self.secure
+                if self.dm.login(state['userid'],
+                                 self.passwd,
+                                 secure=self.secure):
                     dlg = wx.Dialog(self, -1, "A Message from PGEF",
                                    wx.DefaultPosition, wx.Size(400, 75),
                                    wx.THICK_FRAME)
@@ -426,8 +473,7 @@
                     dlg.Destroy()
                     logindlg.Destroy()
                     still_trying = False
-                    state['loggedin'] = '1'
-                    state['userid'] = loginid
+                    state['loggedin'] = True
                     self.onStateChange()
                     if prefs.get('ShowLoginConfirmed', 0):
                         sdlg = wx.MessageDialog(self,
@@ -437,14 +483,39 @@
                         sdlg.ShowModal() 
                         sdlg.Destroy()
                 else:
-                    logindlg.SetTitle("Try Again?")
+                    logindlg.SetTitle("Login failed. Try again?")
+
+    def onLogout(self, event):
+        state['loggedin'] = False
+        self.onStateChange()
 
     def onExit(self, event):
         """
         PanGalaxian exit process.
         """
         writeState()
-        self.Close()
+        # Since close is called from inside this method, the guard variable
+        # self.closing skips the event if shut down is already in progress.
+        print 'PanGalaxian.OnClose()'
+        # I don't understand why this is necessary, since os was imported
+        # up above, but this scope doesn't seem to see it!  8^/
+        # import os
+        writeState()
+        if self.closing:
+            event.Skip()
+        else:
+            if self.dm.has_uncommitted_data:
+                text = """Commit work now? (If "No", your work will be saved in the Cache.) """
+                dlg = wx.MessageDialog(self, text,
+                          "PanGalaxian:  Uncommitted Work",
+                          wx.YES_NO | wx.YES_DEFAULT | wx.ICON_EXCLAMATION)
+                dlg.CentreOnParent()
+                if dlg.ShowModal() == wx.ID_YES:
+                    # commit work
+                    print "Committing work (NOT!! -- commit is disabled ;)"
+                dlg.Destroy()
+            self.closing = True
+            self.Close(True)
 
     def onEnableTooltips(self, event):
         print "PanGalaxian.OnEnableTooltips"
@@ -508,7 +579,7 @@
                 self.removeSpecialMenus(state['userid'])
             self.options_repo.Enable(0)
             self.options_proxy.Enable(0)
-            self.options_user.Enable(0)
+            self.options_userid.Enable(0)
             self.options_passwd.Enable(0)
             self.file_login.Enable(0)
             self.file_logout.Enable(1)
@@ -519,7 +590,7 @@
         else:
             self.options_repo.Enable(1)
             self.options_proxy.Enable(1)
-            self.options_user.Enable(1)
+            self.options_userid.Enable(1)
             self.options_passwd.Enable(1)
             self.file_login.Enable(1)
             self.file_logout.Enable(0)

Index: PanGalactic/pangalactic/node/gui/dialogs/login.py
diff -u PanGalactic/pangalactic/node/gui/dialogs/login.py:1.1 PanGalactic/pangalactic/node/gui/dialogs/login.py:1.2
--- PanGalactic/pangalactic/node/gui/dialogs/login.py:1.1	Fri Feb 18 01:06:26 2005
+++ PanGalactic/pangalactic/node/gui/dialogs/login.py	Wed May 18 01:19:47 2005
@@ -2,14 +2,14 @@
 # -*- coding: ISO-8859-1 -*-
 # generated by wxGlade 0.3.5.1 on Fri Jan  7 02:55:19 2005
 
-# $Id: login.py,v 1.1 2005/02/18 06:06:26 waterbug Exp $
+# $Id: login.py,v 1.2 2005/05/18 05:19:47 waterbug Exp $
 
 """
 Dialog for logging into repository server.
 
-@version: $Revision: 1.1 $
+@version: $Revision: 1.2 $
 """
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.2 $"[11:-2]
 
 import wx
 
@@ -28,6 +28,7 @@
         self.ok_button = wx.Button(self, wx.ID_OK, "OK")
         self.cancel_button = wx.Button(self, wx.ID_CANCEL, "Cancel")
         self.login_confirm_checkbox = wx.CheckBox(self, -1, "Show login confirmed message")
+        self.hold_passwd_checkbox = wx.CheckBox(self, -1, "Remember password for this session")
 
         self.__set_properties()
         self.__do_layout()
@@ -41,6 +42,7 @@
         self.ssl_checkbox.SetValue(1)
         self.ok_button.SetDefault()
         self.login_confirm_checkbox.SetValue(1)
+        self.hold_passwd_checkbox.SetValue(1)
         # end wxGlade
 
     def __do_layout(self):
@@ -64,6 +66,7 @@
         ok_cancel_sizer.Add(self.cancel_button, 0, wx.ALL|wx.ALIGN_RIGHT|wx.ALIGN_CENTER_HORIZONTAL|wx.FIXED_MINSIZE, 5)
         button_sizer.Add(ok_cancel_sizer, 1, wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL, 10)
         button_sizer.Add(self.login_confirm_checkbox, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 5)
+        button_sizer.Add(self.hold_passwd_checkbox, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.FIXED_MINSIZE, 5)
         grid_sizer_1.Add(button_sizer, 1, wx.EXPAND|wx.ALIGN_CENTER_HORIZONTAL, 5)
         self.SetAutoLayout(True)
         self.SetSizer(grid_sizer_1)
@@ -73,6 +76,5 @@
         self.Centre()
         # end wxGlade
 
-# end of class LoginDialog
 
 

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.4 PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.5
--- PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.4	Tue May 17 16:05:24 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py	Wed May 18 01:19:48 2005
@@ -1,11 +1,11 @@
-# $Id: pgxnstatusbar.py,v 1.4 2005/05/17 20:05:24 waterbug Exp $
+# $Id: pgxnstatusbar.py,v 1.5 2005/05/18 05:19:48 waterbug Exp $
 
 """
 Custom status bar for PanGalaxian (the PGEF desktop client).
 
-@version: $Revision: 1.4 $
+@version: $Revision: 1.5 $
 """
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 # Python core modules
 from pprint import pprint
@@ -85,9 +85,9 @@
     def onClick(self, evt):
         print "PgxnStatusBar.onClick"
         if state['loggedin']:
-            self.parent.onLogout()
+            self.parent.onLogout(wx.EVT_MENU)
         else:
-            self.parent.onLogin()
+            self.parent.onLogin(wx.EVT_MENU)
 
     def onStateChange(self):
         """

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.10 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.11
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.10	Tue May 17 04:00:04 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Wed May 18 01:19:48 2005
@@ -1,10 +1,10 @@
-# $Id: pgefobjectgrid.py,v 1.10 2005/05/17 08:00:04 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.11 2005/05/18 05:19:48 waterbug Exp $
 """
 The PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.10 $
+@version: $Revision: 1.11 $
 """
-__version__ = "$Revision: 1.10 $"[11:-2]
+__version__ = "$Revision: 1.11 $"[11:-2]
 
 from pprint import pprint
 
@@ -41,8 +41,8 @@
         self.fac = factory or Factory()
         self.objs = objs or []
         # if there are preferred displaymaps, use them initially
-        if prefs.get('displaymaps', None):
-            displaymaps = prefs['displaymaps']
+        displaymaps = prefs.get('displaymaps',
+                                state.get('displaymaps', {}))
         self.setup()
         self._rows = self.GetNumberRows()
         self._cols = self.GetNumberCols()
@@ -57,11 +57,8 @@
             # assumption that all objs have the same schema (see TODO)
             self.schema = self.objs[0]._schema
             # if there is a current displaymap set for the schema, use it
-            if displaymaps[self.schema.id]:
-                self.displaymap = displaymaps[self.schema.id]
-            # if not, use its default displaymap
-            else:
-                self.displaymap = self.schema._default_display_map
+            self.displaymap = (displaymaps.get(self.schema.id, None)
+                               or self.schema._default_display_map)
             # print '  - self.displaymap:'
             # pprint(self.displaymap)
             self.identifiers = [x[0] for x in self.displaymap]

Index: PanGalactic/pangalactic/repo/pgerxmlrpc.py
diff -u PanGalactic/pangalactic/repo/pgerxmlrpc.py:1.21 PanGalactic/pangalactic/repo/pgerxmlrpc.py:1.22
--- PanGalactic/pangalactic/repo/pgerxmlrpc.py:1.21	Tue May 17 04:00:05 2005
+++ PanGalactic/pangalactic/repo/pgerxmlrpc.py	Wed May 18 01:19:48 2005
@@ -1,10 +1,10 @@
 """
 PGER XML-RPC Interfaces module
-@version: $Revision: 1.21 $
+@version: $Revision: 1.22 $
 """
 
-__version__ = "$Revision: 1.21 $"[11:-2]
-# $Id: pgerxmlrpc.py,v 1.21 2005/05/17 08:00:05 waterbug Exp $
+__version__ = "$Revision: 1.22 $"[11:-2]
+# $Id: pgerxmlrpc.py,v 1.22 2005/05/18 05:19:48 waterbug Exp $
 
 from twisted.python import log
 from twisted.web.xmlrpc import XMLRPC
@@ -122,7 +122,7 @@
             elif isinstance(criteria, dict):
                 kw = criteria
             res = self.engine.getObjects(requestor=self.userid,
-                                         schema_id=typename,
+                                         schema_id=schema_id,
                                          refs=refs,
                                          subtypes=subtypes,
                                          **kw)

Index: PanGalactic/pangalactic/utils/datamanager.py
diff -u PanGalactic/pangalactic/utils/datamanager.py:1.177 PanGalactic/pangalactic/utils/datamanager.py:1.178
--- PanGalactic/pangalactic/utils/datamanager.py:1.177	Sat May 14 01:49:07 2005
+++ PanGalactic/pangalactic/utils/datamanager.py	Wed May 18 01:19:49 2005
@@ -1,10 +1,10 @@
-# $Id: datamanager.py,v 1.177 2005/05/14 05:49:07 waterbug Exp $
+# $Id: datamanager.py,v 1.178 2005/05/18 05:19:49 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_datamanager -*-
 
 """
 PanGalaxian's local workspace manager.
 
-@version: $Revision: 1.177 $
+@version: $Revision: 1.178 $
 """
 # TODO:  move the transaction/interface stuff, like XmlrpcInterface, into a
 # separate module -- InterfaceManager, which will handle all client
@@ -15,7 +15,7 @@
 # came from (repository, file import, etc.) and what their state is
 # (committed/uncommitted, etc.)
 
-__version__ = "$Revision: 1.177 $"[11:-2]
+__version__ = "$Revision: 1.178 $"[11:-2]
 
 import time
 import mx.DateTime
@@ -398,17 +398,21 @@
             # print "search cache"
             return local_files
 
-    def uncommittedData(self):
-        """
-        Check for uncommitted work.
-        """
-        print "datamanager.uncommittedData()"
-        if self.getUncommittedObjs():
-            print '  -> yes, uncommitted objects'
-            return True
-        else:
-            print '  -> no uncommitted objects'
-            return False
+    # property:  has_uncommitted_data
+
+    def getUncommittedData(self):
+        return bool(self.getUncommittedObjs())
+
+    def setUncommittedData(self):
+        raise TypeError, 'has_uncommitted_data is read-only'
+
+    def delUncommittedData(self):
+        raise TypeError, 'has_uncommitted_data cannot be deleted'
+
+    has_uncommitted_data = property(getUncommittedData,
+                                    setUncommittedData,
+                                    delUncommittedData,
+                                    'has_uncommitted_data')
 
     def commit(self, unsavedobjs):
         print "datamanager.commit()"

From waterbug at step.nasa.gov  Wed May 18 01:42:52 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May 18 01:42:53 2005
Subject: [pangalactic-commits] More nice tweaks to login (yep,
	I'm obsessed! :)
Message-ID: <200505180542.j4I5gqBn010840@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.12 1.13
PanGalactic/pangalactic/node/gui/dialogs/login.py 1.2 1.3

Log message:
More nice tweaks to login (yep, I'm obsessed! :)

* menu File/Login... *always* gets full dialog
* ... but if 'hold_passwd' is true and it has one, it fills it in
* and the status bar login status button will *always* login without
  a dialog if it finds a userid, passwd, and server

OK, I'm happy now ... g'night!  :)

Index: PanGalactic/pangalactic/node/gui/dialogs/login.py
diff -u PanGalactic/pangalactic/node/gui/dialogs/login.py:1.2 PanGalactic/pangalactic/node/gui/dialogs/login.py:1.3
--- PanGalactic/pangalactic/node/gui/dialogs/login.py:1.2	Wed May 18 01:19:47 2005
+++ PanGalactic/pangalactic/node/gui/dialogs/login.py	Wed May 18 01:42:50 2005
@@ -2,14 +2,14 @@
 # -*- coding: ISO-8859-1 -*-
 # generated by wxGlade 0.3.5.1 on Fri Jan  7 02:55:19 2005
 
-# $Id: login.py,v 1.2 2005/05/18 05:19:47 waterbug Exp $
+# $Id: login.py,v 1.3 2005/05/18 05:42:50 waterbug Exp $
 
 """
 Dialog for logging into repository server.
 
-@version: $Revision: 1.2 $
+@version: $Revision: 1.3 $
 """
-__version__ = "$Revision: 1.2 $"[11:-2]
+__version__ = "$Revision: 1.3 $"[11:-2]
 
 import wx
 
@@ -28,7 +28,7 @@
         self.ok_button = wx.Button(self, wx.ID_OK, "OK")
         self.cancel_button = wx.Button(self, wx.ID_CANCEL, "Cancel")
         self.login_confirm_checkbox = wx.CheckBox(self, -1, "Show login confirmed message")
-        self.hold_passwd_checkbox = wx.CheckBox(self, -1, "Remember password for this session")
+        self.hold_passwd_checkbox = wx.CheckBox(self, -1, "Remember password until exit")
 
         self.__set_properties()
         self.__do_layout()

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.12 PanGalactic/pangalactic/node/pangalaxian_new.py:1.13
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.12	Wed May 18 01:19:46 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Wed May 18 01:42:50 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.12 2005/05/18 05:19:46 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.13 2005/05/18 05:42:50 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.12 $
+@version: $Revision: 1.13 $
 """
-__version__ = "$Revision: 1.12 $"[11:-2]
+__version__ = "$Revision: 1.13 $"[11:-2]
 
 # Python core modules
 import sys
@@ -23,7 +23,6 @@
 import wxversion
 wxversion.select("2.5")
 import wx
-from wx.lib.dialogs import MultipleChoiceDialog
 
 # PyDispatch module
 import dispatch
@@ -94,7 +93,7 @@
         self.file_new_model     = self.file_new_menu.Append(-1, "&Model...", "Create a Model ...", wx.ITEM_NORMAL)
         self.file_new_partslist = self.file_new_menu.Append(-1, "Parts &List...", "Create a new Parts List ...", wx.ITEM_NORMAL)
         self.file_new_doc       = self.file_new_menu.Append(-1, "&Document...", "Create a new Document ...", wx.ITEM_NORMAL)
-        self.file_login         = self.file_menu.Append(-1, "Log&in", "Login to hub ...", wx.ITEM_NORMAL)
+        self.file_login         = self.file_menu.Append(-1, "Log&in...", "Login to hub ...", wx.ITEM_NORMAL)
         self.file_logout        = self.file_menu.Append(-1, "Log&out", "Logout from hub ...", wx.ITEM_NORMAL)
         self.file_export        = self.file_menu.Append(-1, "&Export", "Export file as ...", wx.ITEM_NORMAL)
         self.file_exit          = self.file_menu.Append(-1, "E&xit", "Exit PanGalaxian ...", wx.ITEM_NORMAL)
@@ -302,7 +301,7 @@
         # self.Bind(wx.EVT_MENU, self.onNewModel, self.file_new_model)
         # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.file_new_partslist)
         # self.Bind(wx.EVT_MENU, self.onNewDocument, self.file_new_document)
-        self.Bind(wx.EVT_MENU, self.onLogin, self.file_login)
+        self.Bind(wx.EVT_MENU, self.openFullLoginDialog, self.file_login)
         self.Bind(wx.EVT_MENU, self.onLogout, self.file_logout)
         # self.Bind(wx.EVT_MENU, self.onExport, self.file_export)
         self.Bind(wx.EVT_MENU, self.onExit, self.file_exit)
@@ -409,13 +408,13 @@
                            "Rats!", wx.YES_NO)
                 dlg.CentreOnParent()
                 if (dlg.ShowModal() == wx.YES):
-                    self.openFullLoginDialog()
+                    self.openFullLoginDialog(wx.EVT_MENU)
                 dlg.Destroy()
         # otherwise, open the full login dialog ...
         else:
-            self.openFullLoginDialog()
+            self.openFullLoginDialog(wx.EVT_MENU)
 
-    def openFullLoginDialog(self):
+    def openFullLoginDialog(self, event):
         """
         Open a full login dialog that prompts for a userid, passwd, server,
         and some options.
@@ -493,14 +492,10 @@
         """
         PanGalaxian exit process.
         """
-        writeState()
-        # Since close is called from inside this method, the guard variable
-        # self.closing skips the event if shut down is already in progress.
         print 'PanGalaxian.OnClose()'
-        # I don't understand why this is necessary, since os was imported
-        # up above, but this scope doesn't seem to see it!  8^/
-        # import os
         writeState()
+        # since close is called from inside this method, the guard variable
+        # self.closing skips the event if shut down is already in progress.
         if self.closing:
             event.Skip()
         else:

From waterbug at step.nasa.gov  Wed May 18 16:13:30 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May 18 16:13:32 2005
Subject: [pangalactic-commits] Mostly machinations with userid/passwd ...
Message-ID: <200505182013.j4IKDUKG023002@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian.py 1.56 1.57
PanGalactic/pangalactic/node/pangalaxian_new.py 1.13 1.14
PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py 1.6 1.7
PanGalactic/pangalactic/utils/datamanager.py 1.178 1.179
PanGalactic/pangalactic/utils/localdb.py 1.131 1.132

Log message:
Mostly machinations with userid/passwd ...
probably introduced some bugs!  ;)

Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.56 PanGalactic/pangalactic/node/pangalaxian.py:1.57
--- PanGalactic/pangalactic/node/pangalaxian.py:1.56	Wed May 18 01:19:46 2005
+++ PanGalactic/pangalactic/node/pangalaxian.py	Wed May 18 16:13:25 2005
@@ -1,13 +1,13 @@
 #!/usr/bin/env python 
 
-# $Id: pangalaxian.py,v 1.56 2005/05/18 05:19:46 waterbug Exp $
+# $Id: pangalaxian.py,v 1.57 2005/05/18 20:13:25 waterbug Exp $
 
 """
 Main application module for the PGEF desktop client.
 
-@version: $Revision: 1.56 $
+@version: $Revision: 1.57 $
 """
-__version__ = "$Revision: 1.56 $"[11:-2]
+__version__ = "$Revision: 1.57 $"[11:-2]
 
 import sys
 import os
@@ -731,7 +731,7 @@
                                         "Close this window")
         dbbrowser.mainpanel = CacheBrowser(dbbrowser, -1, self.dm)
         config_access = self.dm.getConfigAccess()
-        dbbrowser.mainpanel.FillChoice(config_access)
+        dbbrowser.mainpanel.FillChoice()
         dbbrowser.CentreOnParent()
         dbbrowser.Show(True)
 

Index: PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py
diff -u PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.6 PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.7
--- PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.6	Sat May 14 01:49:04 2005
+++ PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py	Wed May 18 16:13:26 2005
@@ -1,5 +1,5 @@
 #!/bin/env python
-# $Id: cachebrowser.py,v 1.6 2005/05/14 05:49:04 waterbug Exp $
+# $Id: cachebrowser.py,v 1.7 2005/05/18 20:13:26 waterbug Exp $
 #----------------------------------------------------------------------------
 # Authors:      Ginny, Steve
 #----------------------------------------------------------------------------
@@ -7,9 +7,9 @@
 PanGalaxian cache browser and display customizer
 (Works with PgefObjects in a local ZODB)
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 import wx
 from wx import grid
@@ -31,7 +31,7 @@
 ID_POPUP_CLEAR_SELECTION = wx.NewId()
 OBJECT_VIEWER = wx.NewId()
 # classes excluded from configurability:
-EXCLUDE_CLASSES = ["DisplayConfig", "Passwd", "UncommittedDocumentIDs",
+EXCLUDE = ["DisplayConfig", "Passwd", "UncommittedDocumentIDs",
                    "OidLookup"]
 
 
@@ -118,18 +118,10 @@
         else:
             event.Skip()
 
-    def FillChoice(self, config=99):
-        # TODO:  config=99 is because of localdb cruft -- it just means
-        # "display everything you can" ("god" access); need to make this
-        # configurable by user (prefs) ... probably doesn't need to be an
-        # argument to FillChoice, as it will be determined by prefs.
+    def FillChoice(self):
         choice = self.rootitems
         choice.Clear()
-        items = []
-        if config:
-            for dictname, clearflag, config_access in self.cache.dictlist:
-                if config_access <= config:
-                   items.append(dictname)
+        items = list(self.factory.object_schemas.keys())
         items.sort()
         choice.InsertItems(items, 0)
 
@@ -141,7 +133,7 @@
     def OnClose(self, event):
         if getattr(self.Parent, 'Parent'):
             # print 'cachebrowser parent:', self.Parent.Parent
-            self.Parent.Parent.psmgui.onStateChange()
+            self.Parent.Parent.onStateChange()
         self.Parent.Close()
 
     def OnRefresh(self, event=None):
@@ -275,7 +267,7 @@
             if self.objectgrid.GetNumberRows() > 0:
                 self.objectgrid.DeleteRows(0, self.objectgrid.GetNumberRows())
             selection = self.rootitems.GetStringSelection()
-            if selection in EXCLUDE_CLASSES:
+            if selection in EXCLUDE:
                 print selection, "is not configurable"
                 self.customize_button.Enable(False)
             else:

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.13 PanGalactic/pangalactic/node/pangalaxian_new.py:1.14
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.13	Wed May 18 01:42:50 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Wed May 18 16:13:25 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.13 2005/05/18 05:42:50 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.14 2005/05/18 20:13:25 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.13 $
+@version: $Revision: 1.14 $
 """
-__version__ = "$Revision: 1.13 $"[11:-2]
+__version__ = "$Revision: 1.14 $"[11:-2]
 
 # Python core modules
 import sys
@@ -60,9 +60,9 @@
 class PgxnFrame(wx.Frame):
     """
     Main class for the PGEF desktop client.  PgxnFrame implements
-    PanGalaxian's internal model, plugin API, and the GUI elements of its
-    main window, including a menu bar, a status bar, and sash window with a
-    tree pane on the left and a grid/canvas notebook pane on the right.
+    PanGalaxian's internal model and the GUI elements of its main window,
+    including a menu bar, a status bar, and sash window with a tree pane on
+    the left and a grid/canvas notebook pane on the right.
 
     ivar toolbar:  an instance of
         L{pangalactic.node.gui.widgets.pgxntoolbar.PgxnToolBar}
@@ -193,8 +193,8 @@
         self.user = Person(pgef_oid=useroid,
                            id=prefs.get('userid', useroid),
                            email=prefs.get('email', 'local'))
+        self.userid = prefs['userid']
         print 'PanGalaxian:  userid =', self.user.id
-        state['userid'] = self.user.id
         oid.setOidBase(useroid)
         # Try to start up the local cache (ZODB) -- if it fails, notify
         # user and exit, since nothing can (currently) be done without it.
@@ -328,13 +328,9 @@
         # self.Bind(wx.EVT_MENU, self.onGetMyStuff, self.repo_getmystuff)
         # self.Bind(wx.EVT_MENU, self.onSelectRepo, self.repo_selectrepo)
         #                      was: onServerSettings
-        #
         # Cache menu
-        # self.Bind(wx.EVT_MENU, self.onCacheBrowse, self.cache_browse)
-        #                      was: onDBBrowser
-        # self.Bind(wx.EVT_MENU, self.onCacheClear, self.cache_clear)
-        #                      was: onClearLocalDB
-        #
+        self.Bind(wx.EVT_MENU, self.onCacheBrowse, self.cache_browse)
+        self.Bind(wx.EVT_MENU, self.onCacheClear, self.cache_clear)
         # Options menu
         # self.Bind(wx.EVT_MENU, self.onSetUserId, self.options_userid)
         # self.Bind(wx.EVT_MENU, self.onSetPasswd, self.options_passwd)
@@ -376,13 +372,12 @@
         """
         print "PanGalaxian.OnLogin"
         loginconfirm = prefs.get('ShowLoginConfirmed', True)
-        userid = prefs.get('userid', '') or state.get('userid', '')
         server = prefs.get('server', '') or state.get('server', '')
         passwd = getattr(self, 'passwd', '')
         # if we have a server, a userid, and a saved passwd, try logging in
         # without further ado ...
-        if self.hold_passwd and server and userid and passwd:
-            if self.dm.login(userid, passwd, secure=self.secure):
+        if self.hold_passwd and server and self.userid and passwd:
+            if self.dm.login(self.userid, passwd, secure=self.secure):
                 dlg = wx.Dialog(self, -1, "A Message from PGEF",
                                wx.DefaultPosition, wx.Size(400, 75),
                                wx.THICK_FRAME)
@@ -393,7 +388,6 @@
                 dlg.Show(True)
                 dlg.Destroy()
                 state['loggedin'] = True
-                state['userid'] = userid
                 self.onStateChange()
                 if prefs.get('ShowLoginConfirmed', 0):
                     sdlg = wx.MessageDialog(self,
@@ -420,7 +414,6 @@
         and some options.
         """
         loginconfirm = prefs.get('ShowLoginConfirmed', True)
-        userid = prefs.get('userid', '') or state.get('userid', '')
         server = prefs.get('server', '') or state.get('server', '')
         passwd = getattr(self, 'passwd', '')
         logindlg = LoginDialog(self, -1)
@@ -432,9 +425,8 @@
         i = state['serverlist'].index(state['server'])
         logindlg.repo_choice.SetSelection(i)
         logindlg.CentreOnParent()
-        logindlg.userid_text_ctrl.SetValue(userid)
-        if userid:
-            logindlg.passwd_text_ctrl.SetFocus()
+        logindlg.userid_text_ctrl.SetValue(self.userid)
+        logindlg.passwd_text_ctrl.SetFocus()
         still_trying = True
         while still_trying:
             logindlg.passwd_text_ctrl.SetValue(passwd)
@@ -451,7 +443,7 @@
                                      logindlg.login_confirm_checkbox.GetValue())
                 self.hold_passwd = logindlg.hold_passwd_checkbox.GetValue()
                 self.secure = logindlg.ssl_checkbox.GetValue()
-                state['userid'] = logindlg.userid_text_ctrl.GetValue()
+                prefs['userid'] = logindlg.userid_text_ctrl.GetValue()
                 self.passwd     = logindlg.passwd_text_ctrl.GetValue()
                 state['server'] = state['serverlist'][
                                           logindlg.repo_choice.GetSelection()]
@@ -512,6 +504,32 @@
             self.closing = True
             self.Close(True)
 
+    def onCacheBrowse(self, event):
+        print "PanGalaxian.OnCacheBrowse"
+        tmpsize = wx.Size(750, 500)
+        cachebrowser = toolframe.ToolFrame(self, -1, 'Local Database Browser',
+                                        wx.DefaultPosition, tmpsize)
+        cachebrowser.menuBar.SetLabel(toolframe.ID_FILE_EXIT, '&Close')
+        cachebrowser.menuBar.SetHelpString(toolframe.ID_FILE_EXIT,
+                                        "Close this window")
+        cachebrowser.mainpanel = CacheBrowser(cachebrowser, -1, self.dm)
+        cachebrowser.mainpanel.FillChoice()
+        cachebrowser.CentreOnParent()
+        cachebrowser.Show(True)
+
+    def onCacheClear(self, event):
+        if self.dm.has_uncommitted_data:
+            msg = """
+            You have uncommitted changes.  Really clear the local cache?"""
+        else:
+            msg = "Really clear the local cache?"
+        dlg = wx.MessageDialog(self, msg, "Warning: cleared data will not be recoverable",
+                              wx.YES_NO | wx.YES_DEFAULT | wx.ICON_EXCLAMATION)
+        dlg.CentreOnParent()
+        if dlg.ShowModal() == wx.ID_YES:
+            self.dm.clearCache()
+            # TODO:  displatch message 'clear' to grid and tree
+
     def onEnableTooltips(self, event):
         print "PanGalaxian.OnEnableTooltips"
         if self.options_tooltips.IsChecked():
@@ -559,19 +577,21 @@
         # blab about my state
         print "PanGalaxian.onStateChange"
         print "  - prefs:"
+        for p in prefs:
+            if p != 'displaymaps':
+                print "    * %s" % p
+                pprint(prefs[p])
         pprint(prefs)
         print "  - state:"
         for s in state:
             if s != 'displaymaps':
                 print "    * %s" % s
                 pprint(state[s])
-        # actually do stuff ...
+        # TODO:  use dispatcher for onStateChange message
         self.dm.onStateChange()
         if state['loggedin']:
             print "\n  *** logged in (non-local mode) ***\n"
             # GUI state changes
-            if state['userid'] != 'admin':
-                self.removeSpecialMenus(state['userid'])
             self.options_repo.Enable(0)
             self.options_proxy.Enable(0)
             self.options_userid.Enable(0)

Index: PanGalactic/pangalactic/utils/datamanager.py
diff -u PanGalactic/pangalactic/utils/datamanager.py:1.178 PanGalactic/pangalactic/utils/datamanager.py:1.179
--- PanGalactic/pangalactic/utils/datamanager.py:1.178	Wed May 18 01:19:49 2005
+++ PanGalactic/pangalactic/utils/datamanager.py	Wed May 18 16:13:27 2005
@@ -1,10 +1,10 @@
-# $Id: datamanager.py,v 1.178 2005/05/18 05:19:49 waterbug Exp $
+# $Id: datamanager.py,v 1.179 2005/05/18 20:13:27 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_datamanager -*-
 
 """
 PanGalaxian's local workspace manager.
 
-@version: $Revision: 1.178 $
+@version: $Revision: 1.179 $
 """
 # TODO:  move the transaction/interface stuff, like XmlrpcInterface, into a
 # separate module -- InterfaceManager, which will handle all client
@@ -15,7 +15,7 @@
 # came from (repository, file import, etc.) and what their state is
 # (committed/uncommitted, etc.)
 
-__version__ = "$Revision: 1.178 $"[11:-2]
+__version__ = "$Revision: 1.179 $"[11:-2]
 
 import time
 import mx.DateTime
@@ -65,7 +65,7 @@
             raise LocalStorageError, "LocalStorageError"
         self.uncommittedobjs = self.cache.uncommittedobjs
         self.domains = domains
-        self.user = Person(id = userid or state['userid'])
+        self.tmpuserid = userid
         self.server = None
         self.refresh = False
         self.projects = {}
@@ -83,6 +83,22 @@
             for schema_id, schema in self.factory.object_schemas.items():
                 displaymaps[schema_id] = schema._default_display_map
 
+        # property:  userid
+
+        def getUserid(self):
+            if self.tmpuserid and not state.get('userid', ''):
+                return self.tmpuserid
+            else:
+                return state['userid']
+
+        def setUserid(self, val):
+            raise TypeError, 'dm.userid is not settable -- use state.'
+
+        def delUserid(self, val):
+            raise TypeError, 'dm.userid cannot be deleted.'
+
+        userid = property(getUserid, setUserid, delUserid, 'userid')
+
     def getServerHost(self):
         return state['server'].split(':')[0]
 
@@ -137,22 +153,18 @@
     def getRoot(self):
         return self.cache.dbroot
 
-    def getPasswd(self, pwd_id):
-        return self.cache.getPasswd(pwd_id)
-
-    def changePassword(self, login_pwd, new_pwd, userid="", secure=1):
-        # print "update local passwds"
+    def changePassword(self, login_pwd, new_pwd, secure=1):
+        # print "DM.changePassword"
         if state['loggedin']:
-            self.server.changePassword(new_pwd, userid)
-            if userid == self.user.id:
-                self.login(self.user.id, new_pwd, secure = secure)
+            self.server.changePassword(new_pwd, self.userid)
+            self.login(self.userid, new_pwd, secure=secure)
 
     def getConfigAccess(self):
         print "datamanager.getConfigAccess.GOD"
         return localdb.GOD
         if self.user.god:
             return localdb.GOD
-        elif self.user.id == "admin":
+        elif self.userid == "admin":
             return localdb.ADMIN
         else:
             return localdb.USER
@@ -182,7 +194,7 @@
                                     id="NEW",
                                     id_ns=state['id_ns'],
                                     project=state['project'],
-                                    owner=self.user.id,
+                                    owner=self.userid,
                                     **kw)
         return obj
 
@@ -208,13 +220,7 @@
         except xmlrpclib.ProtocolError, e:
             print "Exception: datamanager.login", e
             return False
-        self.user = Person(id=state['userid'])
-        user2save = Person()
-        user2save = copy.deepcopy(self.user)
-        user2save._authorization = None
-        user2save._password = None
-        self.cache.saveObject(user2save)
-        self.cache.savePasswds(password, password)
+        self.passwd = password
         return True
 
     def getItemsByProject(self, project):
@@ -324,7 +330,7 @@
             print "dm.search.xmlrpc.error"
             return []
 
-    def uploadFile(self, obj):
+    def uploadFile(self, obj, userid, passwd):
         """
         Upload the file corresponding to a FileLink object.
 
@@ -334,9 +340,9 @@
         print " - dm.uploadFile:"
         print "   - FileLink oid is %s" % obj.pgef_oid
         print "   - file is %s" % obj.local_path
-        self._uploadFile(obj.pgef_oid, obj.local_path)
+        self._uploadFile(obj.pgef_oid, obj.local_path, userid, passwd)
 
-    def _uploadFile(self, obj_oid, file_path):
+    def _uploadFile(self, obj_oid, file_path, userid, passwd):
         """
         Upload a file using httpupload.upload.
 
@@ -360,8 +366,8 @@
                    host = self.serverHost,
                    port = self.serverPort,
                    srvpath = "/upload",
-                   userid = self.user.id,
-                   passwd = self.user._password,
+                   userid = userid,
+                   passwd = passwd,
                    secure = 1,
                    useragent = "",
                    oid = obj_oid,
@@ -425,7 +431,7 @@
                 for obj in unsavedobjs:
                     # check for unset attributes and commit-related stuff
                     # print "  - checking", obj.id, obj.name
-                    obj.creator = self.user.id
+                    obj.creator = self.userid
                     if not obj.owner:
                         obj.owner = obj.creator
                     if not obj.modifier:
@@ -457,7 +463,7 @@
                             obj.state = None
                             actionlist.append(obj)
                             if obj.__class__.__name__ == "FileLink":
-                                self.uploadFile(obj)
+                                self.uploadFile(obj, self.userid, self.passwd)
                     else:
                         print "Commit to database failed - addObjects"
 #                if len(dellist) > 0:
@@ -740,7 +746,7 @@
                                 for obj in fileaddlist:
                                     obj.state = None
                                     actionlist.append(obj)
-                                    self.uploadFile(obj)
+                                    self.uploadFile(obj, self.userid, self.passwd)
                     else:
                         print "commit wfs failed"
                 if len(wfdellist) > 0:

Index: PanGalactic/pangalactic/utils/localdb.py
diff -u PanGalactic/pangalactic/utils/localdb.py:1.131 PanGalactic/pangalactic/utils/localdb.py:1.132
--- PanGalactic/pangalactic/utils/localdb.py:1.131	Sat May 14 01:49:07 2005
+++ PanGalactic/pangalactic/utils/localdb.py	Wed May 18 16:13:27 2005
@@ -1,9 +1,9 @@
 """
 Local object cache manager
 
-@version: $Revision: 1.131 $
+@version: $Revision: 1.132 $
 """
-__version__ = "$Revision: 1.131 $"[11:-2]
+__version__ = "$Revision: 1.132 $"[11:-2]
 
 import os
 import glob
@@ -35,8 +35,7 @@
     # first field  - the dict name
     # second field - does this dict persist after clearing localdb?
     # third field  - who sees the dict displayed in the dbbrowser?
-    special_names = ['DisplayConfig', 'OidLookup', 'Passwd', 'Uncommitted',
-                     'User']
+    special_names = ['OidLookup', 'Uncommitted', 'User']
     wf_names = ["WfActivity", "WfProcessInstance", "WfTransition",
                 "WfEventAudit"]
 
@@ -52,7 +51,7 @@
             os.makedirs("data")
         self.core_names = factory.object_schemas.keys()
         self.domain_names = Set(self.core_names + self.wf_names)
-        domainlist = [(n, 1, USER) for n in self.domain_names]
+        domainlist = [(n, 0, USER) for n in self.domain_names]
         specials = [(n, 1, ADMIN) for n in self.special_names]
         # setup() uses dictlist to create and name the cache's dictionaries
         self.dictlist = specials + domainlist
@@ -95,21 +94,6 @@
                 self.dbroot[dict] = PersistentMapping()  
         self.objs = self.dbroot['OidLookup']
 
-    def savePasswds(self, login_pwd, new_pwd):
-        pwd_dict = self.dbroot['Passwd']
-        pwd_dict['login'] = login_pwd
-        pwd_dict['current'] = new_pwd
-        self.dbroot['Passwd'] = pwd_dict
-        self.commit()
-
-    def savePasswd(self, pwd_id, passwd_name):
-        pwd_dict = self.dbroot['Passwd']
-        pwd_dict[passwd_id] = passwd_name
-
-    def getPasswd(self, passwd_id):
-        pwd_dict = self.dbroot['Passwd']
-        return pwd_dict[passwd_id]
-
     def saveObjects(self, objs, only=None, also=None):
         """
         Save some objects in the cache.  Map the object's oid to itself in

From waterbug at step.nasa.gov  Wed May 18 17:05:46 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May 18 17:05:49 2005
Subject: [pangalactic-commits] Use PgefObjectGrid in CacheBrowser -- radical
	simplification!
Message-ID: <200505182105.j4IL5kkX023595@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.14 1.15
PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py 1.7 1.8
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.11 1.12

Log message:
Use PgefObjectGrid in CacheBrowser -- radical simplification!

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.14 PanGalactic/pangalactic/node/pangalaxian_new.py:1.15
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.14	Wed May 18 16:13:25 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Wed May 18 17:05:44 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.14 2005/05/18 20:13:25 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.15 2005/05/18 21:05:44 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.14 $
+@version: $Revision: 1.15 $
 """
-__version__ = "$Revision: 1.14 $"[11:-2]
+__version__ = "$Revision: 1.15 $"[11:-2]
 
 # Python core modules
 import sys
@@ -513,7 +513,6 @@
         cachebrowser.menuBar.SetHelpString(toolframe.ID_FILE_EXIT,
                                         "Close this window")
         cachebrowser.mainpanel = CacheBrowser(cachebrowser, -1, self.dm)
-        cachebrowser.mainpanel.FillChoice()
         cachebrowser.CentreOnParent()
         cachebrowser.Show(True)
 

Index: PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py
diff -u PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.7 PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.8
--- PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.7	Wed May 18 16:13:26 2005
+++ PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py	Wed May 18 17:05:44 2005
@@ -1,5 +1,5 @@
 #!/bin/env python
-# $Id: cachebrowser.py,v 1.7 2005/05/18 20:13:26 waterbug Exp $
+# $Id: cachebrowser.py,v 1.8 2005/05/18 21:05:44 waterbug Exp $
 #----------------------------------------------------------------------------
 # Authors:      Ginny, Steve
 #----------------------------------------------------------------------------
@@ -7,9 +7,9 @@
 PanGalaxian cache browser and display customizer
 (Works with PgefObjects in a local ZODB)
 
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 import wx
 from wx import grid
@@ -23,7 +23,7 @@
 from pangalactic.utils import toolframe
 from pangalactic.utils import objectviewer
 from pangalactic.utils import configuregrid
-from pangalactic.node.gui.state import state, prefs, displaymaps
+from pangalactic.node.gui.widgets.pgefobjectgrid import PgefObjectGrid
 
 from pprint import pprint
 
@@ -53,7 +53,6 @@
         self.factory = dm.factory
         self.cache = dm.cache
         self.dbfile = None
-        # the following section replaces:  ZODBBrowserFunc(self, True)
         vboxsizer0 = wx.BoxSizer(wx.VERTICAL)
         hboxsizer0 = wx.BoxSizer(wx.HORIZONTAL)
         vboxsizer1 = wx.BoxSizer(wx.VERTICAL)
@@ -62,7 +61,6 @@
         text0.SetFont(labelfont)
         text0.SetSize(text0.GetBestSize())
         vboxsizer1.Add(text0, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT|wx.TOP, 5)
-        # rootitems was ID_ROOTITEMS
         self.rootitems = wx.ListBox(self, -1, wx.DefaultPosition, wx.Size(80,100), [], wx.LB_SINGLE)
         vboxsizer1.Add(self.rootitems, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.BOTTOM, 5)
         hboxsizer0.Add(vboxsizer1, 2, wx.ALIGN_CENTER|wx.ALL, 5)
@@ -71,22 +69,9 @@
         text1.SetFont(labelfont)
         text1.SetSize(text0.GetBestSize())
         vboxsizer0.Add(text1, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT|wx.TOP, 5)
-        # objectgrid was ID_GRID
-        gridpanel = ScrolledPanel(self, -1, size=wx.Size(700,220))
-        self.objectgrid = grid.Grid(gridpanel, -1, wx.DefaultPosition, wx.Size(2000,2000), wx.WANTS_CHARS)
-        self.objectgrid.CreateGrid(10, 11, grid.Grid.wxGridSelectCells)
-        gridpanel.SetAutoLayout(1)
-        gridpanel.SetupScrolling()
-        vboxsizer0.Add(gridpanel, 1, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT|wx.BOTTOM, 5)
+        self.objectgrid = PgefObjectGrid(self)
+        vboxsizer0.Add(self.objectgrid, 1, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT|wx.BOTTOM, 5)
         hboxsizer1 = wx.BoxSizer(wx.HORIZONTAL)
-        # customize_button was ID_BUTTON_CONFIG
-        self.customize_button = wx.Button(self, -1, "Customize...", wx.DefaultPosition, wx.DefaultSize, 0)
-        hboxsizer1.Add(self.customize_button, 0, wx.ALIGN_BOTTOM|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5)
-        # refresh_button was ID_REFRESHDB
-        self.refresh_button = wx.Button(self, -1, "&Refresh", wx.DefaultPosition, wx.DefaultSize, 0)
-        self.refresh_button.SetDefault()
-        hboxsizer1.Add(self.refresh_button, 0, wx.ALIGN_CENTER|wx.ALL, 5)
-        # close_button uses ID_CLOSE (a wx constant)
         self.close_button = wx.Button(self, wx.ID_CLOSE, "&Close", wx.DefaultPosition, wx.DefaultSize, 0)
         self.close_button.SetDefault()
         hboxsizer1.Add(self.close_button, 0, wx.ALIGN_CENTER|wx.ALL, 5)
@@ -95,20 +80,14 @@
         self.SetSizer(vboxsizer0)
         vboxsizer0.Fit(self)
         vboxsizer0.SetSizeHints(self)
-        # end of section replacing ZODBBrowserFunc
         self.Bind(wx.EVT_LISTBOX, self.FillGrid, self.rootitems)
-        self.Bind(wx.EVT_BUTTON, self.OnRefresh, self.refresh_button)
-        self.Bind(wx.EVT_BUTTON, self.FileConfig, self.customize_button)
         self.Bind(wx.EVT_BUTTON, self.OnClose, self.close_button)
         self.Bind(wx.EVT_CLOSE, self.OnClose)
-        self.objectgrid.SetColLabelSize(30)
-        self.objectgrid.SetCellHighlightPenWidth(0)
-        self.objectgrid.EnableEditing(False)
         self.objs = None
         grid.EVT_GRID_CELL_RIGHT_CLICK(self.objectgrid, self.OnRightDown)
         grid.EVT_GRID_CELL_LEFT_CLICK(self.objectgrid, self.onLeftClick)
         wx.EVT_MENU(self, OBJECT_VIEWER, self.OnViewObj)
-        wx.EVT_MENU(self, ID_POPUP_CLEAR_SELECTION, self.OnClearSelection)
+        self.FillChoice()
 
     def onLeftClick(self, event):
         # print "cachebrowser.leftclick"
@@ -136,209 +115,13 @@
             self.Parent.Parent.onStateChange()
         self.Parent.Close()
 
-    def OnRefresh(self, event=None):
-        self.ClearGrid()        
-        self.FillGrid()
-
-    def SetDBFile(self, file=None):
-        if file:
-            self.dbfile = file
-
-    def FileConfig(self, event=None):
-        collection_name = self.rootitems.GetStringSelection()
-        if collection_name:
-            tmpsize = wx.Size(750, 500)
-            cfg_frame = toolframe.ToolFrame(self,
-                                            -1,
-                                            'Customize DataBase Browser',
-                                            wx.DefaultPosition,
-                                            tmpsize)
-            cfg_frame.mainpanel = configuregrid.ConfigureGrid(
-                                        cfg_frame, -1,
-                                        dm=self.dm,
-                                        collection_name=collection_name,
-                                        current_config=displaymaps)
-            cfg_frame.CentreOnParent()
-            cfg_frame.Show(True)
-            htext = "The upper section shows lists of what is not (left)\n" + \
-                    "and what is (right) currently shown.\n\n" + \
-                    "The lower section shows the right-hand list and the\n" + \
-                    "corresponding column names.\n\n" + \
-                    "You can add and remove items from the upper lists, and\n" + \
-                    "change the column names in the lower list."
-            cfg_frame.setHelpData(app_title = "Customize DataBase Browser",
-                                  help_text = htext)
-            new_helpmenu = wx.Menu()
-            new_helpmenu.Append(toolframe.ID_HELP_CONTENTS,
-                                "&Contents...",
-                                "General information")
-            old_helpmenu = \
-                cfg_frame.GetMenuBar().Replace(cfg_frame.GetMenuBar().GetMenuCount() - 1,
-                                               new_helpmenu, "&Help")
-            old_helpmenu = None
-        else:
-            errdlg = wx.MessageDialog(self,
-                                     "Select an entry from the list.",
-                                     "No Entry Selected",
-                                     wx.OK|wx.CENTRE|wx.ICON_EXCLAMATION)
-            errdlg.CentreOnParent()
-            errdlg.ShowModal()
-
-    def compareMapping(self, left, right):
-        if left[1] > right[1]:
-            return 1
-        elif left[1] < right[1]:
-            return -1
-        else:
-            return 0
-
-    def newConfigEntry(self, selection, collection_dict):
-        # how many columns should there be?
-        maxcols = 0
-        mapping = []
-        for obj_id, obj in collection_dict.items():
-            if hasattr(obj, "__dict__"):
-                mapping = []
-                fmap = []
-                try:
-                    maxcols = len(obj.__dict__)
-                    self.objectgrid.AppendCols(maxcols)
-                    attr_keys = obj.__dict__.keys()
-                    col = 0
-                    for prop, prop_type in obj._properties.items():
-                        attr_keys.append(prop)
-                    # make the column labels (attribute names) look pretty
-                    for attr_key in attr_keys:
-                        col_label = attr_key.replace("_", " ").title().strip()
-                        fmap.append([attr_key, col_label, "string"])
-                        col += 1
-                except:
-                    print "Sorry.  Ungriddable object.  Better luck next time."
-                    return []
-                # sort the full mapping by column label
-                if len(fmap) > 0:
-                    fmap.sort(self.compareMapping)
-                # look for a default mapping for the specific class
-                if isinstance(obj, PgefObject):
-                    dmap = obj.getDisplayMap()
-                    if len(dmap) > 0:
-                        dnames = obj.getDisplayOrder()
-                        # move any attributes in the class default
-                        # to the front/beginning/left/whatever.
-                        # if selection in cache.NARS_CLASSES:
-                        #     #print "have NARS type"
-                        #     pass
-                        # else:
-                        #     for m_attr, m_label, m_type in fmap:
-                        #         if not (m_attr in dnames):
-                        #             dmap.append([m_attr, m_label, m_type])
-                        for m_attr, m_label, m_type in fmap:
-                            if not (m_attr in dnames):
-                                dmap.append([m_attr, m_label, m_type])
-                    mapping = dmap
-                else:
-                    mapping = fmap
-                for col in range(len(mapping)):
-                    self.objectgrid.SetColLabelValue(col, mapping[col][1])
-                break
-            elif type(obj) is str:
-                maxcols = 2
-                self.objectgrid.AppendCols(maxcols)
-                self.objectgrid.SetColLabelValue(0, "ID")
-                self.objectgrid.SetColLabelValue(1, "Value")
-                break
-            elif type(obj) in [dict, list]:
-                maxcols = 2
-                self.objectgrid.AppendCols(maxcols)
-                self.objectgrid.SetColLabelValue(0, "Name")
-                self.objectgrid.SetColLabelValue(1, "Elements")
-                break
-            else:
-                print "cachebrowser.newconfigentry: only objects or strings", selection
-                return []
-        return mapping
-
     def FillGrid(self, event=None):
-        # print "dbbbrowser.fillgrid"
+        print "CacheBrowser.FillGrid"
         if self.cache:
-            self.ClearGrid()
-            if self.objectgrid.GetNumberCols() > 0:
-                self.objectgrid.DeleteCols(0, self.objectgrid.GetNumberCols())
-            if self.objectgrid.GetNumberRows() > 0:
-                self.objectgrid.DeleteRows(0, self.objectgrid.GetNumberRows())
             selection = self.rootitems.GetStringSelection()
-            if selection in EXCLUDE:
-                print selection, "is not configurable"
-                self.customize_button.Enable(False)
-            else:
-                self.customize_button.Enable(True)
-            # how many rows should there be?
-            objs = self.cache.getDict(selection)
-            self.objs = []
-            numrows = len(objs)
-            if numrows > 0:
-                self.objectgrid.AppendRows(numrows)
-            # look for a configuration entry, and append the columns
-            # pprint(displaymaps)
-            if selection == self.cache.uncommittedobjs:
-                # print "have pgefobject mapping"
-                mapping = list(displaymaps["PgefObject"])
-                mapping.append(['pgef_oid', 'OID', 'str'])
-                mapping.insert(0, ['schema_id', 'Schema', 'str'])
-                self.objectgrid.AppendCols(len(mapping))
-                for col in range(len(mapping)):
-                    self.objectgrid.SetColLabelValue(col, mapping[col][1])
-                # print "mapping", mapping
-            elif displaymaps.has_key(selection) and (len(displaymaps[selection]) > 0):
-                # there is an entry in the configuration dictionary
-                mapping = displaymaps[selection]
-                self.objectgrid.AppendCols(len(mapping))
-                for col in range(len(mapping)):
-                    self.objectgrid.SetColLabelValue(col, mapping[col][1])
-            else:
-                # there is no entry in the configuration dictionary
-                # for the selected name;
-                # generate and save the default configuration
-                mapping = self.newConfigEntry(selection, objs)
-                if len(mapping) > 0:
-                    print "new entry"
-                    displaymaps[selection] = mapping
-                    self.cache.setDisplayConfig(displaymaps)
-                    pprint(displaymaps)
-            # fill in the grid cells
-            curr_row = 0
-            col = 0
-            for obj_id, obj in objs.items():
-                if type(obj) in [str, list, dict]:
-                    self.objectgrid.SetCellValue(curr_row, 0, obj_id)
-                    self.objectgrid.SetCellValue(curr_row, 1, str(obj))
-                # tbd - do this a better way
-                elif isinstance(obj, PgefObject):
-                    # print "obj", obj.id
-                    for col in range(len(mapping)):
-                        attr = mapping[col][0]
-                        attrvalue = getattr(obj, attr)
-                        attr_property = obj._schema.get(attr, None)
-                        if attr_property:
-                            attr_range = attr_property.range
-                            # print "attr", attr, attrvalue
-                            val = str(attrvalue)
-                            if attr_range in self.factory.object_schemas:
-                                if hasattr(attrvalue, 'pgef_oid'):
-                                    val = attr_range + " (oid=" + attrvalue.pgef_oid + ")"
-                                elif type(attrvalue) is str:
-                                    val = attr_range + " (oid=" + attrvalue + ")"
-                                elif type(attrvalue) in [dict, list]:
-                                    if len(attrvalue) > 0:
-                                        val = ' '.join([str(len(attrvalue)),
-                                                        attr_range, "instances"])
-                        self.objectgrid.SetCellValue(curr_row, col, val)
-                        col += 1
-                else:
-                    print "wtf", obj_id
-                self.objs.append(obj)
-                curr_row += 1
-            self.objectgrid.AutoSizeColumns(True)
+            print 'selection:', selection
+            self.objs = self.cache.getDict(selection)
+            self.objectgrid.objs = self.objs.values()
 
     def OnViewObj(self, event):
         # print "dbb.onviewobj"
@@ -354,9 +137,6 @@
         else:
             print "NOTE: only PgefObjects can be shown in the ObjectViewer"
 
-    def OnClearSelection(self, event):
-        self.objectgrid.ClearSelection()
-
     def OnRightDown(self, event):
         """
         Generate and show the menu for a mouse right-click

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.11 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.12
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.11	Wed May 18 01:19:48 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Wed May 18 17:05:44 2005
@@ -1,10 +1,10 @@
-# $Id: pgefobjectgrid.py,v 1.11 2005/05/18 05:19:48 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.12 2005/05/18 21:05:44 waterbug Exp $
 """
 The PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.11 $
+@version: $Revision: 1.12 $
 """
-__version__ = "$Revision: 1.11 $"[11:-2]
+__version__ = "$Revision: 1.12 $"[11:-2]
 
 from pprint import pprint
 
@@ -266,6 +266,7 @@
 
     def set_objs(self, val):
         self._table.objs = val
+        self.reset()
 
     def del_objs(self):
         raise TypeError, 'objs attribute cannot be deleted.'

From waterbug at step.nasa.gov  Thu May 19 02:44:56 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May 19 02:44:57 2005
Subject: [pangalactic-commits] PanGalaxian toolbar just became a little more
	interesting ...
Message-ID: <200505190644.j4J6iu6X028253@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.15 1.16
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.11 1.12
PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py 1.4 1.5

Log message:
PanGalaxian toolbar just became a little more interesting ...

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.11 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.12
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.11	Tue May 17 16:05:24 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Thu May 19 02:44:54 2005
@@ -1,9 +1,9 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.11 $
+@version: $Revision: 1.12 $
 """
-__version__ = "$Revision: 1.11 $"[11:-2]
+__version__ = "$Revision: 1.12 $"[11:-2]
 
 
 import  wx
@@ -71,7 +71,7 @@
             win.SetBackgroundColour('WHITE')
             st = wx.StaticText(win, -1, notreestext,
                           (10, 10), (500, 1000))
-            self.AddPage(win, '[system tree views]')
+            self.AddPage(win, '[No System Tree Views]')
         else:
             for view in self.views:
                 win = wx.Panel(self)

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.15 PanGalactic/pangalactic/node/pangalaxian_new.py:1.16
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.15	Wed May 18 17:05:44 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Thu May 19 02:44:54 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.15 2005/05/18 21:05:44 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.16 2005/05/19 06:44:54 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.15 $
+@version: $Revision: 1.16 $
 """
-__version__ = "$Revision: 1.15 $"[11:-2]
+__version__ = "$Revision: 1.16 $"[11:-2]
 
 # Python core modules
 import sys
@@ -145,7 +145,6 @@
         self.help_about    = self.help_menu.Append(-1, "&About", "Info about PanGalaxian ...", wx.ITEM_NORMAL)
         self.help_contents = self.help_menu.Append(-1, "&Contents", "Contents of help docs ...", wx.ITEM_NORMAL)
         # Menu Bar end
-
         self.__set_properties()
         self.__do_layout()
         # end wxGlade
@@ -154,7 +153,8 @@
         # make sure there's a tmp dir here
         if not os.path.exists('tmp'):
             os.makedirs('tmp')
-        # by default, this client instance will hold a passwd
+        # by default, if this client instance gets a passwd, it will hold
+        # onto it until it exits
         self.hold_passwd = True
         # look for a userid ... if none, run first-time dialog/wizard
         if not prefs.get('userid', None):
@@ -270,9 +270,17 @@
         self.statusbar = PgxnStatusBar(self)
         self.SetStatusBar(self.statusbar)
         self.toolbar = PgxnToolBar(self)
-        self.mainwin = PgxnPanes(self)
+        self.mainwin = PgxnPanes(self) # might not need a ref to mainwin
+        # grab some ivars from my children!
         self.treebook = self.mainwin.treebook
         self.gridbook = self.mainwin.gridbook
+        self.projectwidget = self.toolbar.projectwidget
+        self.systemwidget  = self.toolbar.systemwidget
+        self.viewwidget    = self.toolbar.viewwidget
+        # eine kleine nachttesting!
+        # self.projectwidget.items = ['foo', 'bar']
+        # self.systemwidget.items  = ['spam', 'eggs']
+        # self.viewwidget.items    = ['garg', 'barg']
 
     def __do_layout(self):
         box = wx.BoxSizer(wx.VERTICAL)
@@ -307,6 +315,8 @@
         self.Bind(wx.EVT_MENU, self.onExit, self.file_exit)
         #
         # Tools menu
+        # TODO: jettison all this crap in favor of an object-aware
+        # create/edit/view tool !!
         # self.Bind(wx.EVT_MENU, self.onNewPart, self.tools_new_part)
         # self.Bind(wx.EVT_MENU, self.onEditPart, self.tools_edit_part)
         # self.Bind(wx.EVT_MENU, self.onViewPart, self.tools_view_part)
@@ -492,7 +502,7 @@
             event.Skip()
         else:
             if self.dm.has_uncommitted_data:
-                text = """Commit work now? (If "No", your work will be saved in the Cache.) """
+                text = """Commit work now? (If "No", your work is saved in the Cache.) """
                 dlg = wx.MessageDialog(self, text,
                           "PanGalaxian:  Uncommitted Work",
                           wx.YES_NO | wx.YES_DEFAULT | wx.ICON_EXCLAMATION)
@@ -569,11 +579,14 @@
 
     def onStateChange(self, event=None):
         """
-        Trigger local/remote-mode state changes for PanGalaxian
-        (propagating the call to the onStateChange() methods for
-        DataManager, and PSMTool).
-        """
-        # blab about my state
+        Trigger any state-change-dependent actions for PanGalaxian (also
+        propagate the call to the onStateChange() methods for any
+        state-aware components).  For now, this is mainly about being
+        logged in to a server or not.
+        """
+        # TODO:  see how dispatcher might come into play here ... maybe a
+        # generic 'state-change' message, with relevant state contents ...
+        # here are some prints that blab about my state
         print "PanGalaxian.onStateChange"
         print "  - prefs:"
         for p in prefs:
@@ -587,10 +600,9 @@
                 print "    * %s" % s
                 pprint(state[s])
         # TODO:  use dispatcher for onStateChange message
-        self.dm.onStateChange()
         if state['loggedin']:
             print "\n  *** logged in (non-local mode) ***\n"
-            # GUI state changes
+            # GUI state changes (just menu items for now)
             self.options_repo.Enable(0)
             self.options_proxy.Enable(0)
             self.options_userid.Enable(0)
@@ -615,12 +627,11 @@
             print "\n  *** not logged in (local mode) ***\n"
             # GUI state changes
         self.statusbar.onStateChange()
+        self.dm.onStateChange()
 
 
 # end of class PgxnFrame
 
-#----------------------------------------------------------------------------
-
 class PanGalaxian(wx.App):
 
     def OnInit(self):
@@ -634,7 +645,6 @@
         self.SetTopWindow(self.frame)
         return True
 
-#----------------------------------------------------------------------------
 
 if __name__ == '__main__':
     pgxn = PanGalaxian(0)

Index: PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.4 PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.5
--- PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.4	Fri Feb 18 01:06:27 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py	Thu May 19 02:44:54 2005
@@ -1,16 +1,20 @@
 """
-PanGalaxian's pluggable custom toolbar
+PanGalaxian's custom toolbar
 
-@version: $Revision: 1.4 $
+@version: $Revision: 1.5 $
 """
-__version__ = "$Revision: 1.4 $"[11:-2]
+__version__ = "$Revision: 1.5 $"[11:-2]
 
 import wx
 
 
 class PgxnToolBar(wx.Panel):
     """
-    PanGalaxian's pluggable custom tool bar
+    PanGalaxian's custom tool bar.
+
+    @ivar projectwidget:  the project-selection choice widget
+    @ivar systemwidget:  the system-selection choice widget
+    @ivar viewwidget:  the view-selection choice widget
     """
     def __init__(self, parent):
         wx.Panel.__init__(self, parent, -1, wx.DefaultPosition, wx.Size(400,20), wx.RAISED_BORDER)
@@ -19,22 +23,16 @@
         fgsizer.AddGrowableCol(3)
         projtext = wx.StaticText(self, -1, "Project:", wx.DefaultPosition, wx.DefaultSize, 0)
         fgsizer.Add(projtext, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP|wx.BOTTOM, 5)
-        self.projwgt = wx.Choice(self, -1, wx.DefaultPosition, wx.Size(200,-1), 
-            ["[no projects]","","","",""], 0)
-        self.projwgt.SetForegroundColour('WHITE')
-        self.projwgt.SetBackgroundColour('BLUE')
-        self.projwgt.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL))
-        self.projwgt.Enable(False)
-        fgsizer.Add(self.projwgt, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
+        projwgt = PgefChoiceWidget(self, 'Project', size=(-1, -1))
+        fgsizer.Add(projwgt, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
         systext = wx.StaticText(self, -1, "System:", wx.DefaultPosition, wx.DefaultSize, 0)
-        fgsizer.Add(systext, 0, wx.ALIGN_CENTER|wx.ALL, 5)
-        self.syswgt = wx.Choice(self, -1, wx.DefaultPosition, wx.Size(300,20), 
-            ["[no systems]","","","","",""], 0)
-        self.syswgt.SetForegroundColour('WHITE')
-        self.syswgt.SetBackgroundColour('BLUE')
-        self.syswgt.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL))
-        self.syswgt.Enable(False)
-        fgsizer.Add(self.syswgt, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
+        fgsizer.Add(systext, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
+        syswgt = PgefChoiceWidget(self, 'System', size=(-1, -1))
+        fgsizer.Add(syswgt, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
+        viewtext = wx.StaticText(self, -1, "View:", wx.DefaultPosition, wx.DefaultSize, 0)
+        fgsizer.Add(viewtext, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
+        viewwgt = PgefChoiceWidget(self, 'View', size=(-1, -1))
+        fgsizer.Add(viewwgt, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
         self.SetAutoLayout(True)
         self.SetSizer(fgsizer)
         fgsizer.Fit(self)
@@ -43,39 +41,61 @@
         self.SetSizer(fgsizer)
         self.projectlist = []
         self.systemlist = []
-        self.systemlabel = "Select a System Model"
+        self.projectwidget = projwgt
+        self.systemwidget = syswgt
+        self.viewwidget = viewwgt
+
+
+class PgefChoiceWidget(wx.Choice):
+    """
+    Multi-purpose choice widget for PanGalaxian tool bar.
+
+    @param label:  C{str} to fill in '[No ___]' when empty
+    @param size:  size of the widget (a C{tuple} of 2 C{int}s)
+    @param items:  a C{list} of C{str}s to fill the widget choices
+    """
+    def __init__(self, parent, label, size, items=None):
+        wx.Choice.__init__(self, parent, -1, wx.DefaultPosition,
+                           wx.Size(*size), [], 0)
+        # self.SetForegroundColour('WHITE')
+        # self.SetBackgroundColour('BLUE')
+        self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL))
+        self.label = label
+        if items:
+            self.items = items
+        else:
+            self.items = []
+
+    # properties
 
-    def FillSystemWidget(self, systemlist, systemlabel=None):
+    def get_items(self):
         """
-        Fill the System choice widget from a list of passed in system
-        name/object pairs.
+        Get choice items.
+
+        @param val:  C{list} of C{str}
+        """
+        return self.__items
+
+    def set_items(self, val):
         """
-        wgt = self.syswgt
-        wgt.Clear()
-        if len(systemlist) == 0:
-            wgt.Enable(False)
+        Set choice items.
+
+        @param val:  C{list} of C{str}
+        """
+        self.__items = val
+        self.Clear()
+        if len(val) == 0:
+            self.Append('[No %s]' % self.label)
+            self.Enable(True)
             return
-        if systemlabel:
-            wgt.Append(systemlabel)
-        for systemname, systemobj in systemlist:
-            wgt.Append(systemname)
-        wgt.Enable(True)
-        wgt.SetSelection(0)
-        self.systemlist = systemlist
-        self.systemlabel = systemlabel
-
-    def GetSystemObject(self, ndx):
-        return self.systemlist[ndx][1]
-
-    def AddData(self, systemname, system):
-        # print "toolbarpanel.adddata", self.syswgt.GetCount()
-        if len(self.systemlist) == 0:
-            # print "  append label"
-            # self.systemlist.append(self.systemlabel)
-            self.syswgt.Append(self.systemlabel)
-            self.syswgt.Enable(True)
-            self.syswgt.SetSelection(0)
-        self.systemlist.append([systemname, system])
-        self.syswgt.Append(systemname)
-        #print "  count", self.syswgt.GetCount()
+        self.Append('Any')
+        for v in val:
+            self.Append(v)
+        self.Enable(True)
+        self.SetSelection(0)
+
+    def del_items():
+        raise TypeError, 'Cannot delete items attribute.'
+
+    items = property(get_items, set_items, del_items, 'items')
 

From waterbug at step.nasa.gov  Thu May 19 04:44:31 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May 19 04:44:33 2005
Subject: [pangalactic-commits] Little locked/unlocked icons work now (yay!
	:) ...
Message-ID: <200505190844.j4J8iVi0029506@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.16 1.17
PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py 1.5 1.6
PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py 1.5 1.6

Log message:
Little locked/unlocked icons work now (yay! :) ...
oh, and we got projects, too!  Woikin' ...

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.5 PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.6
--- PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.5	Wed May 18 01:19:48 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py	Thu May 19 04:44:29 2005
@@ -1,11 +1,11 @@
-# $Id: pgxnstatusbar.py,v 1.5 2005/05/18 05:19:48 waterbug Exp $
+# $Id: pgxnstatusbar.py,v 1.6 2005/05/19 08:44:29 waterbug Exp $
 
 """
 Custom status bar for PanGalaxian (the PGEF desktop client).
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 # Python core modules
 from pprint import pprint
@@ -58,8 +58,12 @@
         self.offbutton.Hide()
         self.offbutton.Enable(False)
         # secure/insecure image (field 3):
-        bmplk = toolkitimages.getLockInsecureBitmap()
+        bmpunlk = toolkitimages.getLockInsecureBitmap()
+        self.unlockbitmap = wx.StaticBitmap(self, -1, bmpunlk)
+        bmplk = toolkitimages.getLockSecureBitmap()
         self.lockbitmap = wx.StaticBitmap(self, -1, bmplk)
+        self.unlockbitmap.Show()
+        self.lockbitmap.Hide()
         self.reposition()
 
     def reposition(self):
@@ -69,9 +73,13 @@
         rect = self.GetFieldRect(2)
         self.onbutton.SetPosition((rect.x+1, rect.y+1))
         self.onbutton.SetSize((rect.width-2, rect.height))
+        self.offbutton.SetPosition((rect.x+1, rect.y+1))
+        self.offbutton.SetSize((rect.width-2, rect.height))
         rect = self.GetFieldRect(3)
         self.lockbitmap.SetPosition((rect.x+2, rect.y+2))
         self.lockbitmap.SetSize((rect.width-4, rect.height-4))
+        self.unlockbitmap.SetPosition((rect.x+2, rect.y+2))
+        self.unlockbitmap.SetSize((rect.width-4, rect.height-4))
         self.sizechanged = False
 
     def onSize(self, evt):
@@ -99,10 +107,17 @@
             self.offbutton.Show()
             self.offbutton.Enable(True)
             self.offbutton.SetToolTipString('To log off, click the icon')
+            print 'in PgxnStatusBar, loggedin, state[secure] =', state['secure']
+            if state['secure']:
+                print '  - okay, so showing lockbitmap ... I think!'
+                self.unlockbitmap.Hide()
+                self.lockbitmap.Show()
         else:
             self.onbutton.Show()
             self.onbutton.Enable(True)
             self.onbutton.SetToolTipString('To log on, click the icon')
             self.offbutton.Hide()
             self.offbutton.Enable(False)
+            self.unlockbitmap.Show()
+            self.lockbitmap.Hide()
 

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.16 PanGalactic/pangalactic/node/pangalaxian_new.py:1.17
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.16	Thu May 19 02:44:54 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Thu May 19 04:44:28 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.16 2005/05/19 06:44:54 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.17 2005/05/19 08:44:28 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.16 $
+@version: $Revision: 1.17 $
 """
-__version__ = "$Revision: 1.16 $"[11:-2]
+__version__ = "$Revision: 1.17 $"[11:-2]
 
 # Python core modules
 import sys
@@ -236,7 +236,7 @@
                                    'NoProject')
         print 'PanGalaxian:  project =', state['project']
         # TODO: make 'secure' configurable
-        self.secure = 1
+        state['secure'] = 1
         # TODO: some of these should be in the state dict (or gone)
         self.searchwindow = None
         self.psmplugin = None
@@ -387,7 +387,7 @@
         # if we have a server, a userid, and a saved passwd, try logging in
         # without further ado ...
         if self.hold_passwd and server and self.userid and passwd:
-            if self.dm.login(self.userid, passwd, secure=self.secure):
+            if self.dm.login(self.userid, passwd, secure=state['secure']):
                 dlg = wx.Dialog(self, -1, "A Message from PGEF",
                                wx.DefaultPosition, wx.Size(400, 75),
                                wx.THICK_FRAME)
@@ -397,8 +397,6 @@
                 dlg.CentreOnParent()
                 dlg.Show(True)
                 dlg.Destroy()
-                state['loggedin'] = True
-                self.onStateChange()
                 if prefs.get('ShowLoginConfirmed', 0):
                     sdlg = wx.MessageDialog(self,
                                "Login successful.",
@@ -406,6 +404,8 @@
                     sdlg.CentreOnParent()
                     sdlg.ShowModal() 
                     sdlg.Destroy()
+                state['loggedin'] = True
+                self.onStateChange()
             else:
                 dlg = wx.MessageDialog(self,
                            "Login failed. Try again?",
@@ -428,7 +428,7 @@
         passwd = getattr(self, 'passwd', '')
         logindlg = LoginDialog(self, -1)
         logindlg.login_confirm_checkbox.SetValue(bool(int(loginconfirm)))
-        logindlg.ssl_checkbox.SetValue(int(self.secure))
+        logindlg.ssl_checkbox.SetValue(state['secure'])
         logindlg.repo_choice.Clear()
         for entry in state['serverlist']:
             logindlg.repo_choice.Append(entry)
@@ -452,17 +452,17 @@
                 self.options_loginconfirm.Check(
                                      logindlg.login_confirm_checkbox.GetValue())
                 self.hold_passwd = logindlg.hold_passwd_checkbox.GetValue()
-                self.secure = logindlg.ssl_checkbox.GetValue()
+                state['secure'] = logindlg.ssl_checkbox.GetValue()
                 prefs['userid'] = logindlg.userid_text_ctrl.GetValue()
                 self.passwd     = logindlg.passwd_text_ctrl.GetValue()
                 state['server'] = state['serverlist'][
                                           logindlg.repo_choice.GetSelection()]
-                print '  - userid: ', state['userid']
+                print '  - userid: ', prefs['userid']
                 print '  - server: ', state['server']
-                print '  - self.secure: ', self.secure
-                if self.dm.login(state['userid'],
+                print '  - secure: ', state['secure']
+                if self.dm.login(prefs ['userid'],
                                  self.passwd,
-                                 secure=self.secure):
+                                 secure=state['secure']):
                     dlg = wx.Dialog(self, -1, "A Message from PGEF",
                                    wx.DefaultPosition, wx.Size(400, 75),
                                    wx.THICK_FRAME)
@@ -613,6 +613,9 @@
             self.repo_getmystuff.Enable(1)
             self.repo_selectrepo.Enable(0)
             self.tools_search.Enable(1)
+            # DM checks repository for projects ...
+            # TODO:  pass prefs['context'] or prefs['projects'] to this
+            self.dm.getProjects()
         else:
             self.options_repo.Enable(1)
             self.options_proxy.Enable(1)
@@ -626,10 +629,11 @@
             self.tools_search.Enable(0)
             print "\n  *** not logged in (local mode) ***\n"
             # GUI state changes
+        prefs['projects'] = self.dm.projects.keys()
         self.statusbar.onStateChange()
+        self.toolbar.onStateChange()
         self.dm.onStateChange()
 
-
 # end of class PgxnFrame
 
 class PanGalaxian(wx.App):

Index: PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.5 PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.6
--- PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.5	Thu May 19 02:44:54 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py	Thu May 19 04:44:29 2005
@@ -1,11 +1,12 @@
 """
 PanGalaxian's custom toolbar
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 import wx
+from pangalactic.node.gui.state import state, prefs
 
 
 class PgxnToolBar(wx.Panel):
@@ -17,20 +18,27 @@
     @ivar viewwidget:  the view-selection choice widget
     """
     def __init__(self, parent):
-        wx.Panel.__init__(self, parent, -1, wx.DefaultPosition, wx.Size(400,20), wx.RAISED_BORDER)
+        wx.Panel.__init__(self, parent, -1, wx.DefaultPosition,
+                          wx.Size(400,20), wx.RAISED_BORDER)
         fgsizer = wx.FlexGridSizer(0,4,0,1)
         fgsizer.AddGrowableCol(1)
         fgsizer.AddGrowableCol(3)
-        projtext = wx.StaticText(self, -1, "Project:", wx.DefaultPosition, wx.DefaultSize, 0)
-        fgsizer.Add(projtext, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP|wx.BOTTOM, 5)
+        projtext = wx.StaticText(self, -1, "Project:",
+                                 wx.DefaultPosition, wx.DefaultSize, 0)
+        fgsizer.Add(projtext, 0,
+            wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP|wx.BOTTOM, 5)
         projwgt = PgefChoiceWidget(self, 'Project', size=(-1, -1))
         fgsizer.Add(projwgt, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
-        systext = wx.StaticText(self, -1, "System:", wx.DefaultPosition, wx.DefaultSize, 0)
-        fgsizer.Add(systext, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
+        systext = wx.StaticText(self, -1, "System:",
+                                wx.DefaultPosition, wx.DefaultSize, 0)
+        fgsizer.Add(systext, 0,
+                    wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
         syswgt = PgefChoiceWidget(self, 'System', size=(-1, -1))
         fgsizer.Add(syswgt, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
-        viewtext = wx.StaticText(self, -1, "View:", wx.DefaultPosition, wx.DefaultSize, 0)
-        fgsizer.Add(viewtext, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
+        viewtext = wx.StaticText(self, -1, "View:",
+                                 wx.DefaultPosition, wx.DefaultSize, 0)
+        fgsizer.Add(viewtext, 0,
+                    wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
         viewwgt = PgefChoiceWidget(self, 'View', size=(-1, -1))
         fgsizer.Add(viewwgt, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
         self.SetAutoLayout(True)
@@ -45,6 +53,9 @@
         self.systemwidget = syswgt
         self.viewwidget = viewwgt
 
+    def onStateChange(self):
+        self.projectwidget.items = prefs['projects']
+
 
 class PgefChoiceWidget(wx.Choice):
     """

From waterbug at step.nasa.gov  Thu May 19 04:50:17 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May 19 04:50:19 2005
Subject: [pangalactic-commits] Okay, we heard you, you can shut up now!
Message-ID: <200505190850.j4J8oH42029549@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py 1.6 1.7

Log message:
Okay, we heard you, you can shut up now!

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.6 PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.7
--- PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.6	Thu May 19 04:44:29 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py	Thu May 19 04:50:16 2005
@@ -1,11 +1,11 @@
-# $Id: pgxnstatusbar.py,v 1.6 2005/05/19 08:44:29 waterbug Exp $
+# $Id: pgxnstatusbar.py,v 1.7 2005/05/19 08:50:16 waterbug Exp $
 
 """
 Custom status bar for PanGalaxian (the PGEF desktop client).
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 # Python core modules
 from pprint import pprint
@@ -107,9 +107,7 @@
             self.offbutton.Show()
             self.offbutton.Enable(True)
             self.offbutton.SetToolTipString('To log off, click the icon')
-            print 'in PgxnStatusBar, loggedin, state[secure] =', state['secure']
             if state['secure']:
-                print '  - okay, so showing lockbitmap ... I think!'
                 self.unlockbitmap.Hide()
                 self.lockbitmap.Show()
         else:

From waterbug at step.nasa.gov  Thu May 19 12:51:48 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May 19 12:51:50 2005
Subject: [pangalactic-commits] Forgot to add this guy.
Message-ID: <200505191651.j4JGpmtn005055@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/test/test_chronosynclastic_getObjectsE.py None 1.1

Log message:
Forgot to add this guy.

From waterbug at step.nasa.gov  Thu May 19 12:54:41 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May 19 12:54:42 2005
Subject: [pangalactic-commits] Script to set up pgerd's dirs.
Message-ID: <200505191654.j4JGsfhQ005115@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/admin/installpger None 1.1

Log message:
Script to set up pgerd's dirs.

From waterbug at step.nasa.gov  Thu May 19 12:56:39 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Thu May 19 12:56:41 2005
Subject: [pangalactic-commits] Cruft.
Message-ID: <200505191656.j4JGud9U005199@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/admin/convert.py 1.3 None

Log message:
Cruft.

From waterbug at step.nasa.gov  Fri May 20 12:00:07 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 20 12:00:08 2005
Subject: [pangalactic-commits] Changes to how projects and views are handled
	...
Message-ID: <200505201600.j4KG07l9021894@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.17 1.18
PanGalactic/pangalactic/node/gui/dialogs/searchform_new.py 1.1 1.2
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.12 1.13
PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py 1.6 1.7
PanGalactic/pangalactic/repo/pger.py 1.99 1.100
PanGalactic/pangalactic/utils/datamanager.py 1.179 1.180
PanGalactic/pangalactic/utils/xmlrpcinterface.py 1.80 1.81

Log message:
Changes to how projects and views are handled ...

Index: PanGalactic/pangalactic/utils/xmlrpcinterface.py
diff -u PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.80 PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.81
--- PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.80	Sat May 14 01:49:07 2005
+++ PanGalactic/pangalactic/utils/xmlrpcinterface.py	Fri May 20 12:00:05 2005
@@ -3,10 +3,10 @@
 """
 PanGalactic Client XML-RPC Interfaces
 
-@version: $Revision: 1.80 $
+@version: $Revision: 1.81 $
 """
 
-__version__ = "$Revision: 1.80 $"[11:-2]
+__version__ = "$Revision: 1.81 $"[11:-2]
 
 import base64
 import xmlrpclib
@@ -238,19 +238,19 @@
         #else:
         #    print "no data"
 
-    def getCategories(self, context):
+    def getCategories(self, ns):
         """
-        Get all Category objects for the given context.
+        Get all Category objects for the given namespace.
         """
-        crit = {"id_ns" : context}
+        crit = {"id_ns" : ns}
         data = self._RPC.getObjects("ObjectSchema", 0, 0, crit)
         if data:
             newobjs, objs = self.factory.rememberAll(data, [])
             return newobjs
 
-    def getOrganizations(self, context):
-#        print "xmlrpc.getorganizations", context
-        crit = {"id_ns" : context}
+    def getOrganizations(self, ns):
+#        print "xmlrpc.getorganizations", namespace 
+        crit = {"id_ns" : ns}
         data = self._RPC.getObjects('Organization', 0, 0, crit)
         if data:
             newobjs, objs = self.factory.rememberAll(data, [])

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.17 PanGalactic/pangalactic/node/pangalaxian_new.py:1.18
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.17	Thu May 19 04:44:28 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Fri May 20 12:00:03 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.17 2005/05/19 08:44:28 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.18 2005/05/20 16:00:03 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.17 $
+@version: $Revision: 1.18 $
 """
-__version__ = "$Revision: 1.17 $"[11:-2]
+__version__ = "$Revision: 1.18 $"[11:-2]
 
 # Python core modules
 import sys
@@ -256,7 +256,7 @@
             self.options_tooltips.Check(False)
         self.contexts = state.get('contexts', None) or ['[no context]']
         self.bindEvents()
-        # self.onModeChange()
+        self.onStateChange()
 
     def __set_properties(self):
         # begin wxGlade: PgxnFrame.__set_properties
@@ -271,7 +271,10 @@
         self.SetStatusBar(self.statusbar)
         self.toolbar = PgxnToolBar(self)
         self.mainwin = PgxnPanes(self) # might not need a ref to mainwin
-        # grab some ivars from my children!
+        # TODO:  the following widgets might be made dynamic later (e.g.,
+        # which ones appear might be a user preference) if a more
+        # configurable UI is desired ...
+        # meanwhile, grab these widget references from my children ...
         self.treebook = self.mainwin.treebook
         self.gridbook = self.mainwin.gridbook
         self.projectwidget = self.toolbar.projectwidget
@@ -599,7 +602,6 @@
             if s != 'displaymaps':
                 print "    * %s" % s
                 pprint(state[s])
-        # TODO:  use dispatcher for onStateChange message
         if state['loggedin']:
             print "\n  *** logged in (non-local mode) ***\n"
             # GUI state changes (just menu items for now)
@@ -613,9 +615,14 @@
             self.repo_getmystuff.Enable(1)
             self.repo_selectrepo.Enable(0)
             self.tools_search.Enable(1)
-            # DM checks repository for projects ...
-            # TODO:  pass prefs['context'] or prefs['projects'] to this
-            self.dm.getProjects()
+            # get list of projects from this repo
+            projects = self.dm.getProjects().keys()
+            print '- projects:', projects
+            print '- prefs[projects][state[server]]:', prefs['projects'][state['server']]
+            # prune any projects in prefs that have disappeared
+            for proj in prefs['projects'][state['server']]:
+                if proj not in projects:
+                    prefs['projects'][state['server']].remove(proj)
         else:
             self.options_repo.Enable(1)
             self.options_proxy.Enable(1)
@@ -629,7 +636,10 @@
             self.tools_search.Enable(0)
             print "\n  *** not logged in (local mode) ***\n"
             # GUI state changes
-        prefs['projects'] = self.dm.projects.keys()
+        # TODO:  add 'repository project selection' dialog in which user
+        # selects projects of interest from among those available in the
+        # repository they are logged into.
+        # Here, we check prefs for projects of interest
         self.statusbar.onStateChange()
         self.toolbar.onStateChange()
         self.dm.onStateChange()

Index: PanGalactic/pangalactic/node/gui/dialogs/searchform_new.py
diff -u PanGalactic/pangalactic/node/gui/dialogs/searchform_new.py:1.1 PanGalactic/pangalactic/node/gui/dialogs/searchform_new.py:1.2
--- PanGalactic/pangalactic/node/gui/dialogs/searchform_new.py:1.1	Wed Mar 16 08:24:48 2005
+++ PanGalactic/pangalactic/node/gui/dialogs/searchform_new.py	Fri May 20 12:00:04 2005
@@ -1,9 +1,9 @@
 """
 General PanGalaxian search form
 
-@version: $Revision: 1.1 $
+@version: $Revision: 1.2 $
 """
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.2 $"[11:-2]
 
 
 import wx
@@ -298,6 +298,6 @@
             projectlist.append(project.id + " (" + project.id_ns + ")")
         projectlist.sort()
         self.ProjectWgt.Append("Any")
-        for id_and_context in projectlist:
-            self.ProjectWgt.Append(id_and_context)
+        for id_and_ns in projectlist:
+            self.ProjectWgt.Append(id_and_ns)
 

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.12 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.13
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.12	Thu May 19 02:44:54 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Fri May 20 12:00:04 2005
@@ -1,14 +1,15 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.12 $
+@version: $Revision: 1.13 $
 """
-__version__ = "$Revision: 1.12 $"[11:-2]
+__version__ = "$Revision: 1.13 $"[11:-2]
 
 
 import  wx
 from pangalactic.node.gui.widgets.pgeftree import PgefTree
 from pangalactic.node.gui.widgets.pgefobjectgrid import PgefObjectGrid, testobjs
+from pangalactic.node.gui.state import state, prefs
 
 class PgxnPanes(wx.Panel):
     """
@@ -26,10 +27,10 @@
         minor.SetOrientation(wx.LAYOUT_VERTICAL)
         minor.SetAlignment(wx.LAYOUT_LEFT)
         minor.SetSashVisible(wx.SASH_RIGHT, True)
-        self.treebook = PgxnTreeBook(minor, -1)
+        self.treebook = PgxnTreeBook(minor)
         self.treebook.Fit()
         self.minorpane = minor
-        self.gridbook = PgxnNotebook(self, -1)
+        self.gridbook = PgxnNotebook(self)
         self.Bind(wx.EVT_SASH_DRAGGED, self.onSashDrag, self.minorpane)
         self.Bind(wx.EVT_SIZE, self.onSize)
         self.sizeChanged = True
@@ -49,10 +50,12 @@
 This panel is used for various
 types of decomposition trees.
 
-The types of trees available in
-a given context will be found
-in the tree view selection 
-widget above."""
+The types of Tree Views
+available in a given context
+will be found in the
+Tree View selection widget
+above.
+"""
 
 
 class PgxnTreeBook(wx.Choicebook):
@@ -60,26 +63,26 @@
     The tree/choicebook widget in the left pane of PanGalaxian's sash
     window:  above the tree, a choice widget displays the type of tree.
     """
-    def __init__(self, parent, id, views=None):
-        wx.Choicebook.__init__(self, parent, id=id,
+    def __init__(self, parent, treeviews=None):
+        wx.Choicebook.__init__(self, parent, -1,
                                pos=wx.DefaultPosition,
                                size=wx.Size(250,600))
-        self.views = views
+        self.treeviews = treeviews or []
         self.trees = {}
-        if not views:
+        if not treeviews:
             win = wx.Panel(self)
             win.SetBackgroundColour('WHITE')
             st = wx.StaticText(win, -1, notreestext,
                           (10, 10), (500, 1000))
-            self.AddPage(win, '[No System Tree Views]')
+            self.AddPage(win, '[No Tree Views]')
         else:
-            for view in self.views:
+            for treeview in self.treeviews:
                 win = wx.Panel(self)
                 win.SetBackgroundColour('WHITE')
-                self.trees[view] = PgefTree(win, -1,
+                self.trees[treeview] = PgefTree(win, -1,
                                             datamanager=None,
                                             allowdragndrop=False)
-                self.AddPage(win, view)
+                self.AddPage(win, treeview)
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
 
@@ -97,38 +100,33 @@
 
 
 noviewstext = """
-* No views available *
+* No objects available *
 
-This notebook holds various views of a system.
+This notebook holds object grids and canvases.
 
-The names of the views available for a given system are found
-on the labels of the notebook's tabs.
+If there are objects found in the current context,
+this notebook will have a grid for each type of
+object, and possibly some canvases.
 """
 
 
 class PgxnNotebook(wx.Notebook):
     """
     The notebook widget on the right side of PanGalaxian's sash window:
-    the notebook's tabs show the names of the views.
+    the notebook's tabs show the names of the ObjectSchemas of the objects
+    in the current context.
     """
-    def __init__(self, parent, id, views=None):
-        wx.Notebook.__init__(self, parent, id=id, pos=wx.DefaultPosition,
+    # TODO:  Add object canvas pages for:  (1) ontology diagramming, (2)
+    # COB graphs, (3) Express-X map design [?], (4) interface diagrams, (5)
+    # live simulation diagrams, (6) [ho hum] various UML/SysML diagrams.
+    def __init__(self, parent, objs=None):
+        wx.Notebook.__init__(self, parent, -1, pos=wx.DefaultPosition,
                              size=wx.Size(600,600))
-        # TODO:  views should come from names of object types (schemas)
-        # used by the current project ... or something.
-        self.views = views or ['Models']
-        self.grids = {}
-        if not self.views:
-            win = wx.Panel(self)
-            win.SetBackgroundColour('WHITE')
-            st = wx.StaticText(win, -1, noviewstext,
-                          (10, 10), (1000, 1000))
-            self.AddPage(win, '[system views]')
+        self.pages = {}
+        if not objs:
+            self.objs = []
         else:
-            for view in self.views:
-                self.grids[view] = PgefObjectGrid(self, testobjs,
-                                                  size=(640,480))
-                self.AddPage(self.grids[view], view)
+            self.objs = objs
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
 
@@ -144,5 +142,55 @@
         sel = self.GetSelection()
         event.Skip()
 
+    # property:  objs
+
+    def getObjs(self):
+        return self.__objs
+
+    def setObjs(self, val):
+        """
+        Add a page for each object type in val
+
+        @param val:  a list or set of instances of
+            L{pangalactic.core.pgefobject.PgefObject}
+        """
+        self.__objs = val
+        if self.pages:
+            for page in self.pages.values():
+                self.DeletePage(page)
+        if val:
+            objs_by_type = {}
+            for obj in val:
+                if obj._schema.id in objs_by_type:
+                    objs_by_type[obj._schema.id].append(obj)
+                else:
+                    objs_by_type[obj._schema.id] = [obj]
+            for objs in objs_by_type.values():
+                self._addGridPage(objs)
+        else:
+            self._addDefaultPage()
+
+    def delObjs(self):
+        raise TypeError, 'objs attribute cannot be deleted'
+
+    objs = property(getObjs, setObjs, delObjs, 'objs')
 
+    def _addDefaultPage(self):
+        """
+        Add the default page (if no grid pages).
+        """
+        panel = wx.Panel(self)
+        panel.SetBackgroundColour('WHITE')
+        st = wx.StaticText(panel, -1, noviewstext,
+                           (10, 10), (1000, 1000))
+        self.default_page = self.AddPage(panel, '[No Objects]')
+
+    def _addGridPage(self, objs):
+        """
+        Add a new grid page, with objects, to the notebook.
+        """
+        schema_id = objs[0]._schema.id
+        grid = PgefObjectGrid(self, objs, size=(-1, -1))
+        page = self.AddPage(grid, schema_id)
+        self.pages[schema_id] = page
 

Index: PanGalactic/pangalactic/repo/pger.py
diff -u PanGalactic/pangalactic/repo/pger.py:1.99 PanGalactic/pangalactic/repo/pger.py:1.100
--- PanGalactic/pangalactic/repo/pger.py:1.99	Sat May 14 01:49:05 2005
+++ PanGalactic/pangalactic/repo/pger.py	Fri May 20 12:00:05 2005
@@ -1,10 +1,10 @@
-# $Id: pger.py,v 1.99 2005/05/14 05:49:05 waterbug Exp $
+# $Id: pger.py,v 1.100 2005/05/20 16:00:05 waterbug Exp $
 """
 Pan Galactic Entropy Reverser module
 
-@version: $Revision: 1.99 $
+@version: $Revision: 1.100 $
 """
-__version__ = "$Revision: 1.99 $"[11:-2]
+__version__ = "$Revision: 1.100 $"[11:-2]
 
 import sys
 import os
@@ -17,7 +17,6 @@
 from twisted.application.service import MultiService
 from twisted.internet import defer
 from twisted.python import log
-from twisted.python import context
 from twisted.python import reflect
 
 # PanGalactic imports ...

Index: PanGalactic/pangalactic/utils/datamanager.py
diff -u PanGalactic/pangalactic/utils/datamanager.py:1.179 PanGalactic/pangalactic/utils/datamanager.py:1.180
--- PanGalactic/pangalactic/utils/datamanager.py:1.179	Wed May 18 16:13:27 2005
+++ PanGalactic/pangalactic/utils/datamanager.py	Fri May 20 12:00:05 2005
@@ -1,10 +1,10 @@
-# $Id: datamanager.py,v 1.179 2005/05/18 20:13:27 waterbug Exp $
+# $Id: datamanager.py,v 1.180 2005/05/20 16:00:05 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_datamanager -*-
 
 """
 PanGalaxian's local workspace manager.
 
-@version: $Revision: 1.179 $
+@version: $Revision: 1.180 $
 """
 # TODO:  move the transaction/interface stuff, like XmlrpcInterface, into a
 # separate module -- InterfaceManager, which will handle all client
@@ -15,7 +15,7 @@
 # came from (repository, file import, etc.) and what their state is
 # (committed/uncommitted, etc.)
 
-__version__ = "$Revision: 1.179 $"[11:-2]
+__version__ = "$Revision: 1.180 $"[11:-2]
 
 import time
 import mx.DateTime
@@ -500,32 +500,32 @@
     # FIXME:  domain-specific stuff (everything from here on) should not be
     # in DM -- probably should be in PanGalaxian.
 
-    def getProjects(self, context='http://pangalactic.us/test/'):
+    def getProjects(self, ns='http://pangalactic.us/test/'):
         """
         Get a list of projects.  If logged in, get them from the
         repository, save them locally, and return them as a list.
         If local, check whether there are any in cache; if not, add the
         NoProject project.
         """
-        if context == 'test' and prefs.get('context', None):
-            context = prefs['context']
+        if ns == 'http://pangalactic.us/test/' and prefs.get('ns', None):
+            ns = prefs['ns']
         print 'DM.getProjects'
         if state['loggedin'] and self.server:
             print "  logged in -- going to the server ..."
-            print "  (NOTE: default context is 'test', for now)"
-            fielddict = {"id_ns" : context}
+            print "  (NOTE: default ns is 'test', for now)"
+            fielddict = {"id_ns" : ns}
             projs = self.server.getObjects("Project",
                                            fields=fielddict,
                                            refs=1, subtypes=0,
                                            objs=None)
-            print '  found %s projects in context "%s"' % (
-                                        len(projs), context)
+            print '  found %s projects in ns "%s"' % (
+                                        len(projs), ns)
             if projs:
                 print '  they are:'
                 for p in projs:
                     print '  - %s' % p.id
             else:
-                print '  no projects found in that context ...'
+                print '  no projects found in that ns ...'
                 print '  setting up the NoProject project.'
                 projs = [Project(pgef_oid='NoProject',
                                  id='NoProject',
@@ -539,7 +539,7 @@
                 print '  no local projects ... using NoProject.'
                 self.save([
                     Project(pgef_oid='NoProject',
-                            id='NoProject',
+                            id='No Project',
                             name='Ni',
                             description='No project specified')])
         self.projects = self.cache.getDict('Project')

Index: PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.6 PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.7
--- PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.6	Thu May 19 04:44:29 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py	Fri May 20 12:00:04 2005
@@ -1,9 +1,9 @@
 """
 PanGalaxian's custom toolbar
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 import wx
 from pangalactic.node.gui.state import state, prefs
@@ -54,7 +54,7 @@
         self.viewwidget = viewwgt
 
     def onStateChange(self):
-        self.projectwidget.items = prefs['projects']
+        self.projectwidget.items = prefs['projects'][state['server']]
 
 
 class PgefChoiceWidget(wx.Choice):

From waterbug at step.nasa.gov  Fri May 20 12:02:51 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 20 12:02:53 2005
Subject: [pangalactic-commits] Commit diffs prove their worth.
Message-ID: <200505201602.j4KG2pAc021920@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/utils/xmlrpcinterface.py 1.81 1.82

Log message:
Commit diffs prove their worth.

Index: PanGalactic/pangalactic/utils/xmlrpcinterface.py
diff -u PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.81 PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.82
--- PanGalactic/pangalactic/utils/xmlrpcinterface.py:1.81	Fri May 20 12:00:05 2005
+++ PanGalactic/pangalactic/utils/xmlrpcinterface.py	Fri May 20 12:02:49 2005
@@ -3,10 +3,10 @@
 """
 PanGalactic Client XML-RPC Interfaces
 
-@version: $Revision: 1.81 $
+@version: $Revision: 1.82 $
 """
 
-__version__ = "$Revision: 1.81 $"[11:-2]
+__version__ = "$Revision: 1.82 $"[11:-2]
 
 import base64
 import xmlrpclib
@@ -249,7 +249,7 @@
             return newobjs
 
     def getOrganizations(self, ns):
-#        print "xmlrpc.getorganizations", namespace 
+#        print "xmlrpc.getorganizations", ns
         crit = {"id_ns" : ns}
         data = self._RPC.getObjects('Organization', 0, 0, crit)
         if data:

From waterbug at step.nasa.gov  Fri May 20 16:58:04 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 20 16:58:06 2005
Subject: [pangalactic-commits] More messing w/projects, states,
	prefs ... 8^P ...!
Message-ID: <200505202058.j4KKw4hT026459@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.18 1.19
PanGalactic/pangalactic/node/gui/state.py 1.3 1.4
PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py 1.7 1.8

Log message:
More messing w/projects, states, prefs ... 8^P ...!

Index: PanGalactic/pangalactic/node/gui/state.py
diff -u PanGalactic/pangalactic/node/gui/state.py:1.3 PanGalactic/pangalactic/node/gui/state.py:1.4
--- PanGalactic/pangalactic/node/gui/state.py:1.3	Fri May 13 05:06:32 2005
+++ PanGalactic/pangalactic/node/gui/state.py	Fri May 20 16:58:02 2005
@@ -1,13 +1,13 @@
-# $Id: state.py,v 1.3 2005/05/13 09:06:32 waterbug Exp $
+# $Id: state.py,v 1.4 2005/05/20 20:58:02 waterbug Exp $
 
 """
 Global state for a PGEF application, which is written to a file for
 persistence between sessions, in 'JavaScript Object Notation' (JSON) --
 see: <http://www.crockford.com/JSON/index.html>.
 
-@version: $Revision: 1.3 $
+@version: $Revision: 1.4 $
 """
-__version__ = "$Revision: 1.3 $"[11:-2]
+__version__ = "$Revision: 1.4 $"[11:-2]
 
 from pprint import pprint
 
@@ -31,6 +31,12 @@
 # user's preferred display maps for objects
 if not prefs.get('displaymaps', None):
     prefs['displaymaps'] = {}
+# user's preferred projects, keyed on the repository servers that host them
+# (allowing for possible mirroring among servers)
+if not prefs.get('projects', None):
+    prefs['projects'] = {}
+# TODO:  should make 'projects', and any additional prefs, configurable for
+# applications (by the admin and/or developer)
 
 # current state of display maps for objects
 if not state.get('displaymaps', None):

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.18 PanGalactic/pangalactic/node/pangalaxian_new.py:1.19
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.18	Fri May 20 12:00:03 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Fri May 20 16:58:02 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.18 2005/05/20 16:00:03 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.19 2005/05/20 20:58:02 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.18 $
+@version: $Revision: 1.19 $
 """
-__version__ = "$Revision: 1.18 $"[11:-2]
+__version__ = "$Revision: 1.19 $"[11:-2]
 
 # Python core modules
 import sys
@@ -172,10 +172,10 @@
             email = wx.TextCtrl(dlg, -1, "", size=(180,-1))
             sizer.Add(email, 1, wx.ALIGN_LEFT|wx.BOTTOM|wx.LEFT|wx.RIGHT, 5)
             box = wx.BoxSizer(wx.HORIZONTAL)
-            btn = wx.Button(dlg, wx.ID_OK, " OK ")
+            btn = wx.Button(dlg, wx.ID_OK, "OK")
             btn.SetDefault()
             box.Add(btn, 0, wx.ALIGN_LEFT|wx.ALL, 5)
-            btn = wx.Button(dlg, wx.ID_CANCEL, " Cancel ")
+            btn = wx.Button(dlg, wx.ID_CANCEL, "Cancel")
             box.Add(btn, 0, wx.ALIGN_LEFT|wx.ALL, 5)
             sizer.Add(box, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
             dlg.SetSizer(sizer)
@@ -226,11 +226,11 @@
                 if srv not in serverlist:
                     serverlist.append(srv)
         state['serverlist'] = serverlist
-        state['project'] = state.get('lastproject',
+        state['project'] = state.get('project',
                                      None) or prefs.get(
                                      'defaultproject',
                                      'NoProject')
-        state['id_ns'] = state.get('lastproject',
+        state['id_ns'] = state.get('project',
                                    None) or prefs.get(
                                    'defaultproject',
                                    'NoProject')
@@ -615,14 +615,24 @@
             self.repo_getmystuff.Enable(1)
             self.repo_selectrepo.Enable(0)
             self.tools_search.Enable(1)
-            # get list of projects from this repo
+            # get list of projects from this server
             projects = self.dm.getProjects().keys()
-            print '- projects:', projects
-            print '- prefs[projects][state[server]]:', prefs['projects'][state['server']]
-            # prune any projects in prefs that have disappeared
-            for proj in prefs['projects'][state['server']]:
-                if proj not in projects:
-                    prefs['projects'][state['server']].remove(proj)
+            # get list of user's preferred projects on this server
+            preferred_projects = prefs['projects'].get(state['server'], [])
+            print '- projects on this server:', projects
+            print '- preferred projs on this server:', prefs['projects'].get(state['server'], [])
+            if preferred_projects:
+                # prune any projects in prefs for this server that have
+                # disappeared from this server
+                for proj in prefs['projects'][state['server']]:
+                    if proj not in projects:
+                        prefs['projects'][state['server']].remove(proj)
+                projects = prefs['projects'][state['server']]
+            else:
+                # otherwise, let user select preferred projects from among
+                # those available on the server they are logged into ...
+                # TODO:  selectPreferredProjects()
+                pass
         else:
             self.options_repo.Enable(1)
             self.options_proxy.Enable(1)
@@ -635,10 +645,11 @@
             self.repo_selectrepo.Enable(1)
             self.tools_search.Enable(0)
             print "\n  *** not logged in (local mode) ***\n"
-            # GUI state changes
-        # TODO:  add 'repository project selection' dialog in which user
-        # selects projects of interest from among those available in the
-        # repository they are logged into.
+            # if we are local, get all projects we have in the cache
+            projects = self.dm.getProjects().keys()
+        state['projects'] = projects or ['NoProject']
+        if state['project'] not in projects:
+            state['project'] = projects[0]
         # Here, we check prefs for projects of interest
         self.statusbar.onStateChange()
         self.toolbar.onStateChange()

Index: PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.7 PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.8
--- PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.7	Fri May 20 12:00:04 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py	Fri May 20 16:58:03 2005
@@ -1,9 +1,9 @@
 """
 PanGalaxian's custom toolbar
 
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 import wx
 from pangalactic.node.gui.state import state, prefs
@@ -54,7 +54,8 @@
         self.viewwidget = viewwgt
 
     def onStateChange(self):
-        self.projectwidget.items = prefs['projects'][state['server']]
+        self.projectwidget.items = state['projects']
+        self.projectwidget.SetStringSelection(state['project'])
 
 
 class PgefChoiceWidget(wx.Choice):

From waterbug at step.nasa.gov  Sat May 21 04:17:40 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sat May 21 04:17:42 2005
Subject: [pangalactic-commits] DM.getObjectsByProject and the notebook grids
	now work (yay!).
Message-ID: <200505210817.j4L8HeNc030866@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.19 1.20
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.13 1.14
PanGalactic/pangalactic/utils/datamanager.py 1.180 1.181
PanGalactic/pangalactic/utils/localdb.py 1.132 1.133

Log message:
DM.getObjectsByProject and the notebook grids now work (yay!).

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.13 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.14
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.13	Fri May 20 12:00:04 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Sat May 21 04:17:37 2005
@@ -1,9 +1,9 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.13 $
+@version: $Revision: 1.14 $
 """
-__version__ = "$Revision: 1.13 $"[11:-2]
+__version__ = "$Revision: 1.14 $"[11:-2]
 
 
 import  wx
@@ -156,8 +156,11 @@
         """
         self.__objs = val
         if self.pages:
-            for page in self.pages.values():
-                self.DeletePage(page)
+            for page in self.pages:
+                id = self.GetSelection()
+                print '- PgxnNotebook:  deleting page:', id
+                self.DeletePage(id)
+            self.pages = {}
         if val:
             objs_by_type = {}
             for obj in val:
@@ -183,7 +186,8 @@
         panel.SetBackgroundColour('WHITE')
         st = wx.StaticText(panel, -1, noviewstext,
                            (10, 10), (1000, 1000))
-        self.default_page = self.AddPage(panel, '[No Objects]')
+        page = self.AddPage(panel, '[No Objects]')
+        self.pages['default'] = page
 
     def _addGridPage(self, objs):
         """

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.19 PanGalactic/pangalactic/node/pangalaxian_new.py:1.20
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.19	Fri May 20 16:58:02 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Sat May 21 04:17:37 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.19 2005/05/20 20:58:02 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.20 2005/05/21 08:17:37 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.19 $
+@version: $Revision: 1.20 $
 """
-__version__ = "$Revision: 1.19 $"[11:-2]
+__version__ = "$Revision: 1.20 $"[11:-2]
 
 # Python core modules
 import sys
@@ -64,17 +64,23 @@
     including a menu bar, a status bar, and sash window with a tree pane on
     the left and a grid/canvas notebook pane on the right.
 
-    ivar toolbar:  an instance of
-        L{pangalactic.node.gui.widgets.pgxntoolbar.PgxnToolBar}
+    ivar projectwidget:  choice widget for project selection
+    ivar systemwidget:   choice widget for system selection 
+    ivar viewwidget:     choice widget for view selection
 
-    ivar statusbar:  an instance of
-        L{pangalactic.node.gui.widgets.pgxnstatusbar.PgxnStatusBar}
+        (TODO:  define IViewController [?])
 
-    ivar treebook:  a choicebook containing trees (an instance of
-        L{pangalactic.node.gui.widgets.pgxntreebook.PgxnTreeBook})
+    ivar obj_viewers:  a dictionary of wx-widget-derived objects that are
+        PanGalaxian's view-rendering widgets, each of which knows how to
+        present its views when given a set of domain objects.
 
-    ivar gridbook:  a notebook containing grids (an instance of
-        L{pangalactic.node.gui.widgets.pgxngridbook.PgxnGridBook})
+        (TODO:  define IObjectCollectionViewer)
+
+    ivar tree_viewers:  a dictionary of wx-tree-derived objects that are
+        PanGalaxian's tree-rendering widgets, each of which knows how to
+        present tree views from a directed graph of domain objects.
+
+        (TODO:  define ITreeViewer)
     """
 
     def __init__(self, *args, **kwds):
@@ -273,10 +279,12 @@
         self.mainwin = PgxnPanes(self) # might not need a ref to mainwin
         # TODO:  the following widgets might be made dynamic later (e.g.,
         # which ones appear might be a user preference) if a more
-        # configurable UI is desired ...
+        # configurable UI is desired ... maybe a plugin interface too.
         # meanwhile, grab these widget references from my children ...
-        self.treebook = self.mainwin.treebook
-        self.gridbook = self.mainwin.gridbook
+        self.tree_viewers = {}
+        self.obj_viewers = {}
+        self.tree_viewers['treebook'] = self.mainwin.treebook
+        self.obj_viewers['gridbook'] = self.mainwin.gridbook
         self.projectwidget = self.toolbar.projectwidget
         self.systemwidget  = self.toolbar.systemwidget
         self.viewwidget    = self.toolbar.viewwidget
@@ -364,6 +372,7 @@
         ###################################################
         # end of menu events
         self.Bind(wx.EVT_CLOSE, self.onExit)
+        self.Bind(wx.EVT_CHOICE, self.onSetProject, self.projectwidget)
 
     # Event handlers
 
@@ -584,7 +593,7 @@
         """
         Trigger any state-change-dependent actions for PanGalaxian (also
         propagate the call to the onStateChange() methods for any
-        state-aware components).  For now, this is mainly about being
+        state-aware widgets).  For now, this is mainly about being
         logged in to a server or not.
         """
         # TODO:  see how dispatcher might come into play here ... maybe a
@@ -655,6 +664,23 @@
         self.toolbar.onStateChange()
         self.dm.onStateChange()
 
+    def onModelChange(self, objs):
+        """
+        Perform necessary actions when the 'Model' (as in MVC) -- in the
+        case of PanGalaxian, its cache of objects -- has changed.
+        """
+        for viewer in self.obj_viewers.values():
+            viewer.objs = objs
+
+    def onSetProject(self, event):
+        """
+        Respond to the user's selection of a project.
+        """
+        state['project'] = event.GetString()
+        objs = self.dm.getObjectsByProject(state['project'])
+        self.onModelChange(objs)
+
+
 # end of class PgxnFrame
 
 class PanGalaxian(wx.App):

Index: PanGalactic/pangalactic/utils/datamanager.py
diff -u PanGalactic/pangalactic/utils/datamanager.py:1.180 PanGalactic/pangalactic/utils/datamanager.py:1.181
--- PanGalactic/pangalactic/utils/datamanager.py:1.180	Fri May 20 12:00:05 2005
+++ PanGalactic/pangalactic/utils/datamanager.py	Sat May 21 04:17:38 2005
@@ -1,10 +1,10 @@
-# $Id: datamanager.py,v 1.180 2005/05/20 16:00:05 waterbug Exp $
+# $Id: datamanager.py,v 1.181 2005/05/21 08:17:38 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_datamanager -*-
 
 """
 PanGalaxian's local workspace manager.
 
-@version: $Revision: 1.180 $
+@version: $Revision: 1.181 $
 """
 # TODO:  move the transaction/interface stuff, like XmlrpcInterface, into a
 # separate module -- InterfaceManager, which will handle all client
@@ -15,7 +15,7 @@
 # came from (repository, file import, etc.) and what their state is
 # (committed/uncommitted, etc.)
 
-__version__ = "$Revision: 1.180 $"[11:-2]
+__version__ = "$Revision: 1.181 $"[11:-2]
 
 import time
 import mx.DateTime
@@ -83,45 +83,45 @@
             for schema_id, schema in self.factory.object_schemas.items():
                 displaymaps[schema_id] = schema._default_display_map
 
-        # property:  userid
+    # property:  userid
 
-        def getUserid(self):
-            if self.tmpuserid and not state.get('userid', ''):
-                return self.tmpuserid
-            else:
-                return state['userid']
+    def getUserid(self):
+        if self.tmpuserid and not state.get('userid', ''):
+            return self.tmpuserid
+        else:
+            return state['userid']
 
-        def setUserid(self, val):
-            raise TypeError, 'dm.userid is not settable -- use state.'
+    def setUserid(self, val):
+        raise TypeError, 'dm.userid is not settable -- use state.'
 
-        def delUserid(self, val):
-            raise TypeError, 'dm.userid cannot be deleted.'
+    def delUserid(self, val):
+        raise TypeError, 'dm.userid cannot be deleted.'
 
-        userid = property(getUserid, setUserid, delUserid, 'userid')
+    userid = property(getUserid, setUserid, delUserid, 'userid')
 
     def getServerHost(self):
         return state['server'].split(':')[0]
 
     def setServerHost(self):
-        raise ValueError, 'serverHost is not settable'
+        raise ValueError, 'server_host is not settable'
 
     def delServerHost(self):
-        raise ValueError, 'serverHost is not deletable'
+        raise ValueError, 'server_host is not deletable'
 
-    serverHost = property(getServerHost, setServerHost,
-                          delServerHost, 'serverHost')
+    server_host = property(getServerHost, setServerHost,
+                           delServerHost, 'server_host')
 
     def getServerPort(self):
         return state['server'].split(':')[1]
 
     def setServerPort(self):
-        raise ValueError, 'serverPort is not settable'
+        raise ValueError, 'server_port is not settable'
 
     def delServerPort(self):
-        raise ValueError, 'serverPort is not deletable'
+        raise ValueError, 'server_port is not deletable'
 
-    serverPort = property(getServerPort, setServerPort,
-                          delServerPort, 'serverPort')
+    server_port = property(getServerPort, setServerPort,
+                           delServerPort, 'server_port')
 
     def onStateChange(self, event=None):
         """
@@ -142,8 +142,8 @@
         print 'DM._createServer creating XmlrpcInterface' 
         proxyhost = prefs.get('proxyhost', None)
         proxyport = prefs.get('proxyport', None)
-        return XmlrpcInterface(self.serverHost,
-                               self.serverPort,
+        return XmlrpcInterface(self.server_host,
+                               self.server_port,
                                username,
                                password,
                                secure=secure,
@@ -156,15 +156,15 @@
     def changePassword(self, login_pwd, new_pwd, secure=1):
         # print "DM.changePassword"
         if state['loggedin']:
-            self.server.changePassword(new_pwd, self.userid)
-            self.login(self.userid, new_pwd, secure=secure)
+            self.server.changePassword(new_pwd, state['userid'])
+            self.login(state['userid'], new_pwd, secure=secure)
 
     def getConfigAccess(self):
         print "datamanager.getConfigAccess.GOD"
         return localdb.GOD
         if self.user.god:
             return localdb.GOD
-        elif self.userid == "admin":
+        elif state['userid'] == "admin":
             return localdb.ADMIN
         else:
             return localdb.USER
@@ -194,7 +194,7 @@
                                     id="NEW",
                                     id_ns=state['id_ns'],
                                     project=state['project'],
-                                    owner=self.userid,
+                                    owner=state['userid'],
                                     **kw)
         return obj
 
@@ -223,6 +223,37 @@
         self.passwd = password
         return True
 
+    def getObjectsByProject(self, project):
+        """
+        Retrieves the objects associated with a project (subtypes of
+        VersionedObject, which is the domain of the C{project} Property
+        and is therefore The Mother of All Objects That Are Owned By A
+        Project).
+        """
+        print "- dm.getObjectsByProject"
+        if state['loggedin']:
+            fieldnames = {"project" : project}
+            objs = self.server.getObjects("VersionedObject",
+                                          fields=fieldnames,
+                                          refs=0,
+                                          subtypes=1,
+                                          objs=None)
+        else:
+            objs = self.getLocalObjects(project=project)
+        print "  objs:"
+        pprint(objs)
+        # FIXME:  bug -- should be getting [], not None, if there are no
+        # results
+        if objs:
+            if len(objs) > 0:
+                print "  total objects found: ", len(objs)
+                self.cache.saveObjects(objs)
+        else:
+            print "  dm.getObjectsByProject: no data found."
+            objs = []
+        return objs
+
+    # DEPRECATED! ...
     def getItemsByProject(self, project):
         """
         Retrieves the items associated with a project
@@ -303,7 +334,7 @@
     def getLocalObject(self, oid):
         return self.cache.objs.get(oid, None)
 
-    def getLocalObjects(self, object_schemas, project=None):
+    def getLocalObjects(self, object_schemas=None, project=None):
         return self.cache.getLocalObjects(object_schemas, project)
 
     def approveUser(self, user_info):
@@ -363,8 +394,8 @@
                 # (compressed), so use a generic bag-of-bits type.
                 ctype = 'application/octet-stream'
             upload(localpath = file_path,
-                   host = self.serverHost,
-                   port = self.serverPort,
+                   host = self.server_host,
+                   port = self.server_port,
                    srvpath = "/upload",
                    userid = userid,
                    passwd = passwd,
@@ -431,7 +462,7 @@
                 for obj in unsavedobjs:
                     # check for unset attributes and commit-related stuff
                     # print "  - checking", obj.id, obj.name
-                    obj.creator = self.userid
+                    obj.creator = state['userid']
                     if not obj.owner:
                         obj.owner = obj.creator
                     if not obj.modifier:
@@ -463,7 +494,7 @@
                             obj.state = None
                             actionlist.append(obj)
                             if obj.__class__.__name__ == "FileLink":
-                                self.uploadFile(obj, self.userid, self.passwd)
+                                self.uploadFile(obj, state['userid'], self.passwd)
                     else:
                         print "Commit to database failed - addObjects"
 #                if len(dellist) > 0:
@@ -746,7 +777,7 @@
                                 for obj in fileaddlist:
                                     obj.state = None
                                     actionlist.append(obj)
-                                    self.uploadFile(obj, self.userid, self.passwd)
+                                    self.uploadFile(obj, state['userid'], self.passwd)
                     else:
                         print "commit wfs failed"
                 if len(wfdellist) > 0:

Index: PanGalactic/pangalactic/utils/localdb.py
diff -u PanGalactic/pangalactic/utils/localdb.py:1.132 PanGalactic/pangalactic/utils/localdb.py:1.133
--- PanGalactic/pangalactic/utils/localdb.py:1.132	Wed May 18 16:13:27 2005
+++ PanGalactic/pangalactic/utils/localdb.py	Sat May 21 04:17:38 2005
@@ -1,9 +1,9 @@
 """
 Local object cache manager
 
-@version: $Revision: 1.132 $
+@version: $Revision: 1.133 $
 """
-__version__ = "$Revision: 1.132 $"[11:-2]
+__version__ = "$Revision: 1.133 $"[11:-2]
 
 import os
 import glob
@@ -49,6 +49,7 @@
         # If modifying this stuff, be careful:  order is important
         if not os.path.exists("data"):
             os.makedirs("data")
+        self.factory = factory
         self.core_names = factory.object_schemas.keys()
         self.domain_names = Set(self.core_names + self.wf_names)
         domainlist = [(n, 0, USER) for n in self.domain_names]
@@ -118,6 +119,10 @@
         @type  also:  C{list} or C{str}
         """
         # print "localdb.saveObjects"
+        # TODO:  'merge' -- i.e., in case of oid collision, compare
+        # last-modified dates.  If the repo copy has been modified and the
+        # cache copy has not, replace the cache copy; if both have been
+        # modified, notify user of the conflict.
         if type(objs) is not list:
             objs = [objs]
         if only and also:
@@ -148,13 +153,14 @@
         """
         self.saveObjects(obj, only, also)
 
-    def getLocalObjects(self, object_schema_ids, project=None):
+    def getLocalObjects(self, object_schema_ids=None, project=None):
         """
-        Get all objects with the specified ObjectSchema id from the
-        localdb.  If a project is specified, get only those that have a
-        C{project} attribute with that value.  (Note that that means if a
-        project is specified, only objects with a C{project} attribute will
-        be gotten -- which excludes Acu instances, for example
+        Get objects with the specified C{ObjectSchema.id} (or all objects,
+        if no C{ObjectSchema.id} is specified) from the localdb.  If a
+        project is specified, get only those that have a C{project}
+        attribute with that value.  (Note that that means if a project is
+        specified, only objects with a C{project} attribute will be gotten
+        -- which excludes C{Acu} instances, for example
 
         @param object_schema_ids:  a list of id's of C{ObjectSchema}
             instances (a single id is okay, too)
@@ -166,7 +172,10 @@
         print "localdb.getLocalObjects"
         objs = []
         if type(object_schema_ids) is not list:
-            object_schema_ids = [object_schema_ids]
+            if object_schema_ids:
+                object_schema_ids = [object_schema_ids]
+            else:
+                object_schema_ids = self.factory.schema_base_order
         for schema_id in object_schema_ids:
             if self.dbroot.get(schema_id, None):
                 for obj in self.dbroot[schema_id].values():

From waterbug at step.nasa.gov  Sun May 22 11:52:10 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sun May 22 11:52:13 2005
Subject: [pangalactic-commits] Clean up imports.
Message-ID: <200505221552.j4MFqA3L009828@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/test/utils4test.py 1.4 1.5

Log message:
Clean up imports.

Index: PanGalactic/pangalactic/test/utils4test.py
diff -u PanGalactic/pangalactic/test/utils4test.py:1.4 PanGalactic/pangalactic/test/utils4test.py:1.5
--- PanGalactic/pangalactic/test/utils4test.py:1.4	Sat May 14 01:49:06 2005
+++ PanGalactic/pangalactic/test/utils4test.py	Sun May 22 11:52:08 2005
@@ -1,15 +1,11 @@
-# $Id: utils4test.py,v 1.4 2005/05/14 05:49:06 waterbug Exp $
+# $Id: utils4test.py,v 1.5 2005/05/22 15:52:08 waterbug Exp $
 
 """
 Utilities for testing.
 """
 
-from mx import DateTime
 from datetime import datetime
-from pangalactic.utils import oid
-from pangalactic.utils import sql
 from pangalactic.meta.factory import PanGalacticFactory
-import psycopg
 
 fac = PanGalacticFactory()
 
@@ -92,7 +88,7 @@
     # script will have to set it to something anyway ...
     obj.id = obj.id or "idthis"
     obj.id_ns = obj.id_ns or "TEST"
-    dtstamp = DateTime.now()
+    dtstamp = datetime.now()
     testperson = fac.classes['Person'](
                      pgef_oid='Fester.Bestertester@earth.milkyway.univ',
                      id='Fester Bestertester',

From waterbug at step.nasa.gov  Sun May 22 19:06:12 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sun May 22 19:06:14 2005
Subject: [pangalactic-commits] An addition to the menagerie.
Message-ID: <200505222306.j4MN6CGg011082@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/core/datapackage.py None 1.1

Log message:
An addition to the menagerie.

From waterbug at step.nasa.gov  Mon May 23 01:27:04 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 23 01:27:06 2005
Subject: [pangalactic-commits] Death by a thousand tiny little nibbles ...
Message-ID: <200505230527.j4N5R4om012007@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/__init__.py 1.14 1.15
PanGalactic/pangalactic/core/__init__.py 1.6 1.7
PanGalactic/pangalactic/core/acu.py 1.6 1.7
PanGalactic/pangalactic/core/datapackage.py 1.1 1.2
PanGalactic/pangalactic/core/dataset.py 1.6 1.7
PanGalactic/pangalactic/core/dcu.py 1.5 1.6
PanGalactic/pangalactic/core/document.py 1.6 1.7
PanGalactic/pangalactic/core/filelink.py 1.6 1.7
PanGalactic/pangalactic/core/mime.py 1.5 1.6
PanGalactic/pangalactic/core/model.py 1.7 1.8
PanGalactic/pangalactic/core/organization.py 1.5 1.6
PanGalactic/pangalactic/core/part.py 1.6 1.7
PanGalactic/pangalactic/core/partslist.py 1.7 1.8
PanGalactic/pangalactic/core/partslistitem.py 1.1 1.2
PanGalactic/pangalactic/core/pgefobject.py 1.17 1.18
PanGalactic/pangalactic/core/representation.py 1.5 1.6
PanGalactic/pangalactic/core/versionedobject.py 1.6 1.7
PanGalactic/pangalactic/meta/pgefproperty.py 1.17 1.18
PanGalactic/pangalactic/node/pangalaxian_new.py 1.20 1.21
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.12 1.13
PanGalactic/pangalactic/test/IDTEST 1.116 1.117
PanGalactic/pangalactic/test/test_chronosynclastic_extracts2Records.py 1.7 1.8
PanGalactic/pangalactic/test/test_factory_extract.py 1.4 1.5
PanGalactic/pangalactic/test/test_factory_extractAll.py 1.13 1.14
PanGalactic/pangalactic/test/test_factory_remember.py 1.10 1.11
PanGalactic/pangalactic/test/test_factory_rememberAll.py 1.15 1.16
PanGalactic/pangalactic/test/test_pgef_properties.py 1.3 1.4
PanGalactic/src/sql/insertDocuments.sql 1.23 1.24

Log message:
Death by a thousand tiny little nibbles ...
mostly tweaks, a lot of it to docstrings.

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.12 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.13
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.12	Wed May 18 17:05:44 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Mon May 23 01:27:00 2005
@@ -1,10 +1,10 @@
-# $Id: pgefobjectgrid.py,v 1.12 2005/05/18 21:05:44 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.13 2005/05/23 05:27:00 waterbug Exp $
 """
 The PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.12 $
+@version: $Revision: 1.13 $
 """
-__version__ = "$Revision: 1.12 $"[11:-2]
+__version__ = "$Revision: 1.13 $"[11:-2]
 
 from pprint import pprint
 
@@ -232,11 +232,6 @@
         self.AutoSizeRows(True)
         self.EnableEditing(False)
         self.bindEvents()
-        tooltip = '\n'.join(['This is a PGEF Object Grid',
-                  '- each row in the table represents an object.',
-                  '- right-click in the upper left corner for a menu',
-                  '  that can be used to add or delete columns.'])
-        self.SetToolTip(wx.ToolTip(tooltip))
 
     def bindEvents(self):
         """
@@ -398,15 +393,8 @@
         """
         Display the column popup help when a column label is right clicked.
         """
-        id = self.identifiers[col]
-        prop = self.schema[id]
-        helptext = '\n'.join(['* '+prop.display_name+' *',
-                              prop.description])
-        helpwin = ColHelpPopup(self, helptext)
-        obj = evt.GetEventObject()
-        pos = obj.ClientToScreen((0, 0))
-        helpwin.Position(pos, (50, 50))
-        helpwin.Popup()
+        helptext = self.schema[self.identifiers[col]].help
+        helpwin = wx.TipWindow(self, helptext)
 
     def sortOnColumn(self, evt):
         col = evt.GetCol()
@@ -471,24 +459,6 @@
         displaymaps[self.schema.id] = self.schema._default_display_map
 
 
-class ColHelpPopup(wx.PopupTransientWindow):
-    """
-    Popup help window containing the definition of the property shown in
-    the selected column.
-    """
-    def __init__(self, parent, helptext):
-        wx.PopupTransientWindow.__init__(self, parent, wx.SIMPLE_BORDER)
-        panel = wx.Panel(self, -1)
-        panel.SetBackgroundColour(wx.WHITE)
-        st = wx.StaticText(panel, -1, helptext, pos=(10,10))
-        sz = st.GetBestSize()
-        panel.SetSize((sz.width+20, sz.height+20))
-        self.SetSize(panel.GetSize())
-
-    def ProcessLeftDown(self, evt):
-        return False
-
-
 ###############
 # Testing stuff
 ###############

Index: PanGalactic/pangalactic/test/IDTEST
diff -u PanGalactic/pangalactic/test/IDTEST:1.116 PanGalactic/pangalactic/test/IDTEST:1.117
--- PanGalactic/pangalactic/test/IDTEST:1.116	Mon May 16 17:34:43 2005
+++ PanGalactic/pangalactic/test/IDTEST	Mon May 23 01:27:00 2005
@@ -1 +1 @@
-1674
\ No newline at end of file
+1682
\ No newline at end of file

Index: PanGalactic/pangalactic/core/mime.py
diff -u PanGalactic/pangalactic/core/mime.py:1.5 PanGalactic/pangalactic/core/mime.py:1.6
--- PanGalactic/pangalactic/core/mime.py:1.5	Sun Apr 10 23:31:25 2005
+++ PanGalactic/pangalactic/core/mime.py	Mon May 23 01:26:58 2005
@@ -1,11 +1,11 @@
-# $Id: mime.py,v 1.5 2005/04/11 03:31:25 waterbug Exp $
+# $Id: mime.py,v 1.6 2005/05/23 05:26:58 waterbug Exp $
 
 """
 Multi-purpose Internet Mail Extension (MIME) type.
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 import string
 from pangalactic.core.pgefobject import PgefObject
@@ -37,7 +37,9 @@
             name='Media Type',
             range='str',
             description="""
-            The media type.
+            The MIME Media Type per
+            <http://www.iana.org/assignments/media-types/>
+            (or a custom type).
             """),
         Property(
             id='media_subtype',
@@ -45,9 +47,12 @@
             name='Media Subtype',
             range='str',
             description="""
-            The media subtype.
+            The MIME Media Subtype per
+            <http://www.iana.org/assignments/media-types/>
+            (or a custom subtype).
             """)
-        ]) # end of _schema
+        ])
+        # end of _schema
 
     def __init__(self, **kw):
         """

Index: PanGalactic/pangalactic/core/versionedobject.py
diff -u PanGalactic/pangalactic/core/versionedobject.py:1.6 PanGalactic/pangalactic/core/versionedobject.py:1.7
--- PanGalactic/pangalactic/core/versionedobject.py:1.6	Tue Apr 12 23:59:28 2005
+++ PanGalactic/pangalactic/core/versionedobject.py	Mon May 23 01:26:58 2005
@@ -1,12 +1,11 @@
-# $Id: versionedobject.py,v 1.6 2005/04/13 03:59:28 waterbug Exp $
+# $Id: versionedobject.py,v 1.7 2005/05/23 05:26:58 waterbug Exp $
 
 """
-A thing which evolves in a set of discrete, identified
-incarnations.
+A thing which evolves in a set of discrete, identified incarnations.
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 from pangalactic.core.pgefobject import PgefObject
 from pangalactic import PGEF_URI
@@ -15,8 +14,7 @@
 
 class VersionedObject(PgefObject):
     """
-    A thing which evolves in a set of discrete, identified
-    incarnations.
+    A thing which evolves in a set of discrete, identified incarnations.
     """
     _excluded_fields = ['create_datetime',
                         'record_create_datetime',
@@ -28,10 +26,9 @@
         abbrev='vobj',
         base=PgefObject._schema,
         description="""
-        VersionedObject is the supertype of all PGEF objects that are to be
-        versioned within the context of a PGEF application.
-        VersionedObject supports, but does not require, strict
-        configuration management.
+        Versioned Object is the supertype of all Objects that are to be
+        versioned within the context of an application.  Versioned Object
+        supports, but does not require, strict configuration management.
         """,
         properties=[
         Property(
@@ -42,7 +39,7 @@
             range='str',
             description="""
             Objects that are versions of the same thing have the same
-            base_id.
+            Base ID.
             """),
         Property(
             id='iteration',
@@ -61,8 +58,8 @@
             range='str',
             default_display='True',
             description="""
-            A user-modifiable string used to identify a baseline, release,
-            or version.
+            A user-modifiable alphanumeric string used to identify a
+            baseline, release, or version.
             """),
         Property(
             id='is_head',
@@ -71,9 +68,9 @@
             range='bool',
             default='True',
             description="""
-            This flag is set to True for a VersionedObject committed as a
-            new version (and unset on the previous head VersionedObject
-            that has the same base_id).
+            True for an Object committed as a new version; False for all
+            previous versions.  (These values are maintained by the
+            repository.)
             """),
         Property(
             id='project', # TODO: should probably be 'projects'
@@ -83,8 +80,7 @@
             property_type='object',
             default_display='True',
             description="""
-            The Project under which the Part was created (if applicable --
-            if not applicable, the defaults are used).
+            The Project under which the Object was created (if applicable).
             """)
             ]) # end of _schema
 

Index: PanGalactic/pangalactic/core/datapackage.py
diff -u PanGalactic/pangalactic/core/datapackage.py:1.1 PanGalactic/pangalactic/core/datapackage.py:1.2
--- PanGalactic/pangalactic/core/datapackage.py:1.1	Sun May 22 19:06:11 2005
+++ PanGalactic/pangalactic/core/datapackage.py	Mon May 23 01:26:58 2005
@@ -1,11 +1,11 @@
-# $Id: datapackage.py,v 1.1 2005/05/22 23:06:11 waterbug Exp $
+# $Id: datapackage.py,v 1.2 2005/05/23 05:26:58 waterbug Exp $
 """
 A DataPackage is a collection of one or more
 L{pangalactic.core.dataset.DataSet} instances.
 
-@version: $Revision: 1.1 $
+@version: $Revision: 1.2 $
 """
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.2 $"[11:-2]
 
 from pangalactic.core.document import Document
 from pangalactic import PGEF_URI
@@ -15,14 +15,14 @@
 class DataPackage(Document):
     """
     A collection of one or more L{pangalactic.core.dataset.DataSet}
-    instances.  A DataPackage may include one or more files and may be
+    instances.  A C{DataPackage} may include one or more files and may be
     governed by more than one ontology/schema.
 
-    The primary purpose of the DataPackage Class is to enable the tracking
-    and management of arbitrary collections of exchanged data.
+    The primary purpose of the C{DataPackage} Class is to enable the
+    tracking and management of arbitrary collections of exchanged data.
 
-    Some attributes of the DataPackage class may be modeled from the STEP
-    Part 232 (ISO 10303-232) Application Protocol for Technical Data
+    Some attributes of the C{DataPackage} class may be modeled from the
+    STEP Part 232 (ISO 10303-232) Application Protocol for Technical Data
     Packages.
     """
     _excluded_fields = Document._excluded_fields

Index: PanGalactic/pangalactic/test/test_factory_rememberAll.py
diff -u PanGalactic/pangalactic/test/test_factory_rememberAll.py:1.15 PanGalactic/pangalactic/test/test_factory_rememberAll.py:1.16
--- PanGalactic/pangalactic/test/test_factory_rememberAll.py:1.15	Tue Apr 26 00:53:51 2005
+++ PanGalactic/pangalactic/test/test_factory_rememberAll.py	Mon May 23 01:27:00 2005
@@ -1,10 +1,10 @@
-# $Id: test_factory_rememberAll.py,v 1.15 2005/04/26 04:53:51 waterbug Exp $
+# $Id: test_factory_rememberAll.py,v 1.16 2005/05/23 05:27:00 waterbug Exp $
 """
 Unit test for 'rememberAll' method of PanGalacticFactory
 
-@version: $Revision: 1.15 $
+@version: $Revision: 1.16 $
 """
-__version__ = "$Revision: 1.15 $"[11:-2]
+__version__ = "$Revision: 1.16 $"[11:-2]
 
 from pprint import pprint
 from pangalactic.meta.factory import PanGalacticFactory as Fac
@@ -25,16 +25,14 @@
 zaphod = Person(pgef_oid='zaphod_oid', id='Zaphod Beeblebrox')
 popTestData(zaphod)
 file1 = FileLink(pgef_oid='file1_oid', role='system model',
-                 rep_type='STEP', rep_group='STEP 1',
                  user_file_name='thingy.p21', bytes=42000,
                  mime_type=mime1, owner=zaphod)
 popTestData(file1)
 file2 = FileLink(pgef_oid='file2_oid', role='referenced part',
-                 rep_type='STEP', rep_group='STEP 1',
                  user_file_name='thingy_libpart1.p21', bytes=12345,
                  mime_type=mime1, owner=zaphod)
 popTestData(file2)
-rep1 = Representation(pgef_oid='rep1_oid', rep_type='STEP Part 21',
+rep1 = Representation(pgef_oid='rep1_oid', id='STEP Part 21',
                       files=[file1, file2], rep_purpose='exchange',
                       generable=False, composable=True,
                       is_object_source=True, owner=zaphod)
@@ -70,14 +68,12 @@
 mime1 = Mime(pgef_oid='mime1_oid', media_type='model', media_subtype='p21')
 zaphod = Person(pgef_oid='zaphod_oid', id='Zaphod Beeblebrox')
 file1 = FileLink(pgef_oid='file1_oid', role='system model',
-                 rep_type='STEP', rep_group='STEP 1',
                  user_file_name='thingy.p21', bytes=42000,
                  mime_type=mime1, owner=zaphod)
 file2 = FileLink(pgef_oid='file2_oid', role='referenced part',
-                 rep_type='STEP', rep_group='STEP 1',
                  user_file_name='thingy_libpart1.p21', bytes=12345,
                  mime_type=mime1, owner=zaphod)
-rep1 = Representation(pgef_oid='rep1_oid', rep_type='STEP Part 21',
+rep1 = Representation(pgef_oid='rep1_oid', id='STEP Part 21',
                       files=[file1, file2], rep_purpose='exchange',
                       generable=False, composable=True,
                       is_object_source=True, owner=zaphod)

Index: PanGalactic/pangalactic/test/test_factory_remember.py
diff -u PanGalactic/pangalactic/test/test_factory_remember.py:1.10 PanGalactic/pangalactic/test/test_factory_remember.py:1.11
--- PanGalactic/pangalactic/test/test_factory_remember.py:1.10	Wed Apr 27 10:51:28 2005
+++ PanGalactic/pangalactic/test/test_factory_remember.py	Mon May 23 01:27:00 2005
@@ -1,4 +1,4 @@
-# $Id: test_factory_remember.py,v 1.10 2005/04/27 14:51:28 waterbug Exp $
+# $Id: test_factory_remember.py,v 1.11 2005/05/23 05:27:00 waterbug Exp $
 
 from pprint import pprint
 from pangalactic.meta.factory import PanGalacticFactory as Fac
@@ -18,21 +18,21 @@
 popTestData(mime1)
 file1 = FileLink(pgef_oid='file1_oid',
                  id='file1', id_ns='http://pangalactic.us/test/',
-                 role='assembly', sequence=1, sequence_context='STEP-1',
+                 role='assembly', sequence=1, sequence_context='STEP',
                  user_file_name='thingy.p21', bytes=42000,
                  mime_type=mime1)
 popTestData(file1)
 file2 = FileLink(pgef_oid='file2_oid',
                  id='file2', id_ns='http://pangalactic.us/test/',
-                 role='components', sequence=2, sequence_context='STEP-1',
+                 role='components', sequence=2, sequence_context='STEP',
                  user_file_name='thingy_libpart1.p21', bytes=12345,
                  mime_type=mime1)
 popTestData(file2)
 rep1 = Representation(pgef_oid='rep1_oid',
-                      id='STEP-1', id_ns='http://pangalactic.us/test/',
-                      rep_type='STEP', files=[file1, file2],
-                      rep_purpose='exchange', generable=False,
-                      composable=True, is_object_source=True)
+                      id='STEP', id_ns='http://pangalactic.us/test/',
+                      files=[file1, file2], rep_purpose='exchange',
+                      generable=False, composable=True,
+                      is_object_source=True)
 popTestData(rep1)
 p = Project(pgef_oid='project_oid',
             id='OTHEROTHER', id_ns='http://pangalactic.us/test/',

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.20 PanGalactic/pangalactic/node/pangalaxian_new.py:1.21
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.20	Sat May 21 04:17:37 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Mon May 23 01:26:59 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.20 2005/05/21 08:17:37 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.21 2005/05/23 05:26:59 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.20 $
+@version: $Revision: 1.21 $
 """
-__version__ = "$Revision: 1.20 $"[11:-2]
+__version__ = "$Revision: 1.21 $"[11:-2]
 
 # Python core modules
 import sys
@@ -144,7 +144,7 @@
         self.options_outputdir    = self.options_menu.Append(-1, "Set Output &Directory...", "Select a directory to write files to ...", wx.ITEM_NORMAL)
         self.options_repo         = self.options_menu.Append(-1, "&Repository...", "Select a Repository ...", wx.ITEM_NORMAL)
         self.options_proxy        = self.options_menu.Append(-1, "Pro&xy...", "Use a proxy web server", wx.ITEM_NORMAL)
-        self.options_loginconfirm = self.options_menu.Append(-1, "Show Login &Confirmation", "Confirm when login succeeds ...", wx.ITEM_NORMAL)
+        self.options_loginconfirm = self.options_menu.Append(-1, "Show Login &Confirmation", "Confirm when login succeeds ...", wx.ITEM_CHECK)
         self.options_tooltips     = self.options_menu.Append(-1, "Show &Tooltips", "Allow tooltip pop-up messages", wx.ITEM_CHECK)
         self.help_menu = wx.Menu()
         self.menubar.Append(self.help_menu, "&Help")
@@ -556,9 +556,11 @@
         if self.options_tooltips.IsChecked():
             wx.ToolTip_Enable(True)
             prefs["ShowToolTips"] = True
+            self.options_tooltips.Check(True)
         else:
             wx.ToolTip_Enable(False)
             prefs["ShowToolTips"] = False
+            self.options_tooltips.Check(False)
         event.Skip()
 
     def onShowLoginConfirmed(self, event):
@@ -698,6 +700,6 @@
 
 
 if __name__ == '__main__':
-    pgxn = PanGalaxian(0)
+    pgxn = PanGalaxian(redirect=0)
     pgxn.MainLoop()
 

Index: PanGalactic/pangalactic/test/test_factory_extract.py
diff -u PanGalactic/pangalactic/test/test_factory_extract.py:1.4 PanGalactic/pangalactic/test/test_factory_extract.py:1.5
--- PanGalactic/pangalactic/test/test_factory_extract.py:1.4	Tue Apr 26 00:53:51 2005
+++ PanGalactic/pangalactic/test/test_factory_extract.py	Mon May 23 01:27:00 2005
@@ -16,21 +16,21 @@
 popTestData(mime1)
 file1 = FileLink(pgef_oid='file1_oid',
                  id='file1', id_ns='http://pangalactic.us/test/',
-                 role='assembly', sequence=1, sequence_context='STEP-1',
+                 role='assembly', sequence=1, sequence_context='STEP',
                  user_file_name='thingy.p21', bytes=42000,
                  mime_type=mime1)
 popTestData(file1)
 file2 = FileLink(pgef_oid='file2_oid',
                  id='file2', id_ns='http://pangalactic.us/test/',
-                 role='components', sequence=2, sequence_context='STEP-1',
+                 role='components', sequence=2, sequence_context='STEP',
                  user_file_name='thingy_libpart1.p21', bytes=12345,
                  mime_type=mime1)
 popTestData(file2)
-rep1 = Representation(pgef_oid='rep1_oid',
-                      id='STEP-1', id_ns='TEST.Project.OTHEROTHER.M4',
-                      rep_type='STEP', files=[file1, file2],
-                      rep_purpose='exchange', generable=False,
-                      composable=True, is_object_source=True)
+rep1 = Representation(pgef_oid='rep1_oid', id='STEP',
+                      id_ns='TEST.Project.OTHEROTHER.M4',
+                      files=[file1, file2], rep_purpose='exchange',
+                      generable=False, composable=True,
+                      is_object_source=True)
 popTestData(rep1)
 p = Project(pgef_oid='project_oid',
             id='OTHEROTHER', id_ns='http://pangalactic.us/test/',

Index: PanGalactic/pangalactic/core/acu.py
diff -u PanGalactic/pangalactic/core/acu.py:1.6 PanGalactic/pangalactic/core/acu.py:1.7
--- PanGalactic/pangalactic/core/acu.py:1.6	Sat Apr 30 14:45:23 2005
+++ PanGalactic/pangalactic/core/acu.py	Mon May 23 01:26:58 2005
@@ -1,4 +1,4 @@
-# $Id: acu.py,v 1.6 2005/04/30 18:45:23 waterbug Exp $
+# $Id: acu.py,v 1.7 2005/05/23 05:26:58 waterbug Exp $
 
 """
 Assembly Component Usage (ACU)
@@ -7,9 +7,9 @@
 I{component}) and another Model (the I{assembly}) of which it
 is a constituent part.
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 from pangalactic.core.pgefobject import PgefObject
 from pangalactic import PGEF_URI
@@ -18,9 +18,16 @@
 
 class Acu(PgefObject):
     """
-    An ACU represents the relationship between a Model (the
-    I{component}) and another Model (the I{assembly}) of which it
-    is a constituent part.
+    ACU == "Assembly Component Usage".  This Class maps to STEP
+    assembly_component_usage.  Some STEP subtypes of C{Acu} are:
+
+      - Mfuo ... MakeFromUsageOption
+      - Nauo ... NextAssemblyUsageOccurrence
+      - Shuo ... SpecifiedHigherUsageOccurrence
+      - Puo .... PromissoryUsageOccurrence
+      - Quo .... QuantifiedUsageOccurrence
+
+    These may be implemented as C{ObjectSchema} subtypes of C{Acu}.
     """
     _properties = PgefObject._properties.copy()
     _schema = ObjectSchema(
@@ -30,20 +37,8 @@
         abbrev='acu',
         base=PgefObject._schema,
         description="""
-        Acu stands for "Assembly Component Usage", and this Class
-        maps to STEP assembly_component_usage.
-        *** Note that the objects in this relationship are
-        Models, not Parts. ***
-
-        Some STEP subtypes of Acu are:
-
-            Mfuo ... MakeFromUsageOption
-            Nauo ... NextAssemblyUsageOccurrence
-            Shuo ... SpecifiedHigherUsageOccurrence
-            Puo .... PromissoryUsageOccurrence
-            Quo .... QuantifiedUsageOccurrence
-
-        These may be implemented as ObjectSchema subtypes of Acu.
+        Represents the relationship between a component and the assembly of
+        which it is a constituent part.
         """,
         properties=[
         Property(

Index: PanGalactic/pangalactic/core/partslistitem.py
diff -u PanGalactic/pangalactic/core/partslistitem.py:1.1 PanGalactic/pangalactic/core/partslistitem.py:1.2
--- PanGalactic/pangalactic/core/partslistitem.py:1.1	Tue Apr 12 23:59:28 2005
+++ PanGalactic/pangalactic/core/partslistitem.py	Mon May 23 01:26:58 2005
@@ -1,11 +1,11 @@
-# $Id: partslistitem.py,v 1.1 2005/04/13 03:59:28 waterbug Exp $
+# $Id: partslistitem.py,v 1.2 2005/05/23 05:26:58 waterbug Exp $
 
 """
 A line item on a parts list.
 
-@version: $Revision: 1.1 $
+@version: $Revision: 1.2 $
 """
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.2 $"[11:-2]
 
 from pangalactic.core.pgefobject import PgefObject
 from pangalactic import PGEF_URI
@@ -27,9 +27,9 @@
         abbrev='pli',
         base=PgefObject._schema,
         description="""
-        A PGEF PartsListItem can represent any atomic reference to a part
-        on a parts list, which may actually reference a single part or a
-        collection of parts.
+        A PGEF PartsListItem can represent any reference to a Part on a
+        Parts List, which may actually reference a single Part or a
+        collection of Parts.
         """,
         properties=[
         Property(

Index: PanGalactic/pangalactic/core/dcu.py
diff -u PanGalactic/pangalactic/core/dcu.py:1.5 PanGalactic/pangalactic/core/dcu.py:1.6
--- PanGalactic/pangalactic/core/dcu.py:1.5	Sun Apr 10 23:31:25 2005
+++ PanGalactic/pangalactic/core/dcu.py	Mon May 23 01:26:58 2005
@@ -1,4 +1,4 @@
-# $Id: dcu.py,v 1.5 2005/04/11 03:31:25 waterbug Exp $
+# $Id: dcu.py,v 1.6 2005/05/23 05:26:58 waterbug Exp $
 
 """
 Document Component Usage (DCU)
@@ -7,9 +7,9 @@
 I{component}) and another Document (the I{assembly}) in which it
 occurs as a part.
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 from pangalactic.core.pgefobject import PgefObject
 from pangalactic import PGEF_URI
@@ -18,11 +18,11 @@
 
 class Dcu(PgefObject):
     """
-    Document Component Usage (DCU)
+    Document Component Usage (Dcu)
 
-    A DCU represents the relationship between a Document (the
-    I{component}) and another Document (the I{assembly}) in which
-    it occurs as a part.
+    A C{Dcu} represents the relationship between a C{Document} (the
+    I{component}) and another C{Document} (the I{assembly}) in which it
+    occurs as a part.
     """
     _properties = PgefObject._properties.copy()
     _schema = ObjectSchema(
@@ -32,7 +32,7 @@
         abbrev='dcu',
         base=PgefObject._schema,
         description="""
-        A DocumentComponentUsage (DCU) is an occurrence of a
+        A Document Component Usage (DCU) is an occurrence of a
         Document as a "component" (e.g., a chapter, a table, a
         "node" [as in XML node], an attachment, etc.) within
         another Document.
@@ -47,8 +47,8 @@
             min_cardinality=1,
             default_display='True',
             description="""
-            The Document in which the component appears as a
-            part."""),
+            The Document in which the component appears as a part.
+            """),
         Property(
             id='component',
             id_ns=PGEF_URI,
@@ -58,8 +58,9 @@
             min_cardinality=1,
             default_display='True',
             description="""
-            The Document in the construction of which the
-            component is used."""),
+            The Document in the construction of which the component is
+            used.
+            """),
         Property(
             id='ref_designator',
             id_ns=PGEF_URI,
@@ -67,9 +68,9 @@
             range='str',
             default_display='True',
             description="""
-            A reference designator should be an identifier that
-            is unique within the local Document's name space, and
-            could be used to order attachments, for example.""")
+            An identifier that is unique within the local Document's name
+            space, and could be used to order attachments, for example.
+            """)
             ]) # end of _schema
 
 

Index: PanGalactic/pangalactic/test/test_factory_extractAll.py
diff -u PanGalactic/pangalactic/test/test_factory_extractAll.py:1.13 PanGalactic/pangalactic/test/test_factory_extractAll.py:1.14
--- PanGalactic/pangalactic/test/test_factory_extractAll.py:1.13	Tue Apr 26 00:53:51 2005
+++ PanGalactic/pangalactic/test/test_factory_extractAll.py	Mon May 23 01:27:00 2005
@@ -1,10 +1,10 @@
-# $Id: test_factory_extractAll.py,v 1.13 2005/04/26 04:53:51 waterbug Exp $
+# $Id: test_factory_extractAll.py,v 1.14 2005/05/23 05:27:00 waterbug Exp $
 """
 Unit test for 'extractAll' method of PanGalacticFactory
 
-@version: $Revision: 1.13 $
+@version: $Revision: 1.14 $
 """
-__version__ = "$Revision: 1.13 $"[11:-2]
+__version__ = "$Revision: 1.14 $"[11:-2]
 
 from pprint import pprint
 from pangalactic.meta.factory import PanGalacticFactory as PGF
@@ -24,16 +24,14 @@
 zaphod = Person(pgef_oid='zaphod_oid', id='Zaphod Beeblebrox')
 popTestData(zaphod)
 file1 = FileLink(pgef_oid='file1_oid', role='system model',
-                 rep_type='STEP', rep_group='STEP 1',
                  user_file_name='thingy.p21', bytes=42000,
                  mime_type=mime1, owner=zaphod)
 popTestData(file1)
 file2 = FileLink(pgef_oid='file2_oid', role='referenced part',
-                 rep_type='STEP', rep_group='STEP 1',
                  user_file_name='thingy_libpart1.p21', bytes=12345,
                  mime_type=mime1, owner=zaphod)
 popTestData(file2)
-rep1 = Representation(pgef_oid='rep1_oid', rep_type='STEP Part 21',
+rep1 = Representation(pgef_oid='rep1_oid', id='STEP Part 21',
                       files=[file1, file2], rep_purpose='exchange',
                       generable=False, composable=True,
                       is_object_source=True, owner=zaphod)
@@ -65,14 +63,12 @@
 mime1 = Mime(pgef_oid='mime1_oid', media_type='model', media_subtype='p21')
 zaphod = Person(pgef_oid='zaphod_oid', id='Zaphod Beeblebrox')
 file1 = FileLink(pgef_oid='file1_oid', role='system model',
-                 rep_type='STEP', rep_group='STEP 1',
                  user_file_name='thingy.p21', bytes=42000,
                  mime_type=mime1, owner=zaphod)
 file2 = FileLink(pgef_oid='file2_oid', role='referenced part',
-                 rep_type='STEP', rep_group='STEP 1',
                  user_file_name='thingy_libpart1.p21', bytes=12345,
                  mime_type=mime1, owner=zaphod)
-rep1 = Representation(pgef_oid='rep1_oid', rep_type='STEP Part 21',
+rep1 = Representation(pgef_oid='rep1_oid', id='STEP Part 21',
                       files=[file1, file2], rep_purpose='data exchange',
                       generable=False, composable=True,
                       is_object_source=True, owner=zaphod)

Index: PanGalactic/pangalactic/core/partslist.py
diff -u PanGalactic/pangalactic/core/partslist.py:1.7 PanGalactic/pangalactic/core/partslist.py:1.8
--- PanGalactic/pangalactic/core/partslist.py:1.7	Tue Apr 12 23:59:28 2005
+++ PanGalactic/pangalactic/core/partslist.py	Mon May 23 01:26:58 2005
@@ -1,12 +1,12 @@
-# $Id: partslist.py,v 1.7 2005/04/13 03:59:28 waterbug Exp $
+# $Id: partslist.py,v 1.8 2005/05/23 05:26:58 waterbug Exp $
 
 """
 A Document consisting of a collection of references to Parts and
 associated data.
 
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 from pangalactic.core.document import Document
 from pangalactic import PGEF_URI
@@ -29,13 +29,12 @@
         abbrev='pl',
         base=Document._schema,
         description="""
-        A PGEF PartsList is simply a documented collection of
-        parts and related information.  Parts lists occur in
-        various contexts in the product life cycle, e.g.:  to
-        document component technology research, to document
-        candidate parts for assemblies, to document parts used in
-        model development, to track parts procurement
-        information, to document part stocks and inventory, etc.
+        A documented collection of parts and related information.  Parts
+        Lists occur in various contexts in the product life cycle, e.g.:
+        to document component technology research, to document candidate
+        parts for assemblies, to document Parts used in Model development,
+        to track Parts procurement information, to document Part stocks and
+        inventory, etc.
         """,
         properties=[
         Property(
@@ -45,11 +44,10 @@
             range='str',
             default_display='True',
             description="""
-            The type of the PartsList, selected from a set of
-            standard parts list types, such as 'as-designed'
-            (ADPL), 'as-built' (ABPL), 'preliminary' (PRPL),
-            etc., which should be agreed upon by the Project(s)
-            or Organization(s) using the PartsList.
+            The type of the PartsList, selected from a set of standard
+            parts list types, such as 'as-designed' (ADPL), 'as-built'
+            (ABPL), 'preliminary' (PRPL), etc., which should be agreed upon
+            by the Project(s) or Organization(s) using the PartsList.
             """),
         Property(
             id='status',
@@ -57,11 +55,10 @@
             name='Status',
             range='str',
             description="""
-            The state of the PartsList relative to some possibly
-            extensible set of standard states, e.g. 'in-process',
-            'reviewed', etc.  The set of standard states should
-            be agreed upon by the Project(s) or Organization(s)
-            using the PartsList.
+            The state of the PartsList relative to some possibly extensible
+            set of standard states, e.g. 'in-process', 'reviewed', etc.
+            The set of standard states should be agreed upon by the
+            Project(s) or Organization(s) using the PartsList.
             """)
             ]) # end of _schema
 

Index: PanGalactic/pangalactic/__init__.py
diff -u PanGalactic/pangalactic/__init__.py:1.14 PanGalactic/pangalactic/__init__.py:1.15
--- PanGalactic/pangalactic/__init__.py:1.14	Sat Apr 30 14:45:23 2005
+++ PanGalactic/pangalactic/__init__.py	Mon May 23 01:26:58 2005
@@ -8,6 +8,7 @@
 # TODO:  replace this with core ontology (probably in meta)
 names = ['Acu',
          'DataSet',
+         'DataPackage',
          'Dcu',
          'Document',
          'FileLink',

Index: PanGalactic/pangalactic/meta/pgefproperty.py
diff -u PanGalactic/pangalactic/meta/pgefproperty.py:1.17 PanGalactic/pangalactic/meta/pgefproperty.py:1.18
--- PanGalactic/pangalactic/meta/pgefproperty.py:1.17	Thu May 12 02:49:07 2005
+++ PanGalactic/pangalactic/meta/pgefproperty.py	Mon May 23 01:26:59 2005
@@ -1,4 +1,4 @@
-# $Id: pgefproperty.py,v 1.17 2005/05/12 06:49:07 waterbug Exp $
+# $Id: pgefproperty.py,v 1.18 2005/05/23 05:26:59 waterbug Exp $
 
 """
 The PanGalactic Property class (not to be confused with the Python built-in
@@ -42,9 +42,9 @@
 C{ObjectSchema}, in which the C{ObjectSchema} corresponds to the class that
 is the domain of the binary relationship.
 
-@version: $Revision: 1.17 $
+@version: $Revision: 1.18 $
 """
-__version__ = "$Revision: 1.17 $"[11:-2]
+__version__ = "$Revision: 1.18 $"[11:-2]
 
 
 from pangalactic.meta.utils import getDefault
@@ -363,6 +363,27 @@
         raise ValueError, """Cannot delete 'default' attr."""
 
     default = property(getDefault, setDefault, delDefault,
-                       """Property.default property""")
+                       "default")
+
+    def getHelp(self):
+        """
+        Strip EOL's and 
+        """
+        d = getattr(self, 'description', '')
+        if d:
+            d = d.replace('\n', ' ')
+            while 1:
+                if d.find('  ') == -1:
+                    break
+                d = d.replace('  ', ' ')
+        return d
+
+    def setHelp(self, val):
+        raise TypeError, 'help is read-only (based on description)'
+
+    def delHelp(self):
+        raise ValueError, """Cannot delete 'help' attr."""
+
+    help = property(getHelp, setHelp, delHelp, 'help')
 
 

Index: PanGalactic/pangalactic/core/__init__.py
diff -u PanGalactic/pangalactic/core/__init__.py:1.6 PanGalactic/pangalactic/core/__init__.py:1.7
--- PanGalactic/pangalactic/core/__init__.py:1.6	Sat Apr 30 14:45:23 2005
+++ PanGalactic/pangalactic/core/__init__.py	Mon May 23 01:26:58 2005
@@ -1,5 +1,6 @@
 __all__ = ['acu',
            'dataset',
+           'datapackage',
            'dcu',
            'document',
            'filelink',

Index: PanGalactic/pangalactic/test/test_chronosynclastic_extracts2Records.py
diff -u PanGalactic/pangalactic/test/test_chronosynclastic_extracts2Records.py:1.7 PanGalactic/pangalactic/test/test_chronosynclastic_extracts2Records.py:1.8
--- PanGalactic/pangalactic/test/test_chronosynclastic_extracts2Records.py:1.7	Tue Apr 26 00:53:51 2005
+++ PanGalactic/pangalactic/test/test_chronosynclastic_extracts2Records.py	Mon May 23 01:27:00 2005
@@ -1,4 +1,4 @@
-# $Id: test_chronosynclastic_extracts2Records.py,v 1.7 2005/04/26 04:53:51 waterbug Exp $
+# $Id: test_chronosynclastic_extracts2Records.py,v 1.8 2005/05/23 05:27:00 waterbug Exp $
 
 from pangalactic.repo.chronosynclastic import Infundibulum as I
 from pangalactic.core.filelink import FileLink
@@ -42,21 +42,21 @@
 popTestData(mime1)
 file1 = FileLink(pgef_oid=file1oid,
                  id='file1', id_ns='http://pangalactic.us/test/',
-                 role='assembly', sequence=1, sequence_context='STEP-1',
+                 role='assembly', sequence=1, sequence_context='STEP',
                  user_file_name='thingy.p21', bytes=42000,
                  mime_type=mime1)
 popTestData(file1)
 file2 = FileLink(pgef_oid=file2oid,
                  id='file2', id_ns='http://pangalactic.us/test/',
-                 role='components', sequence=2, sequence_context='STEP-1',
+                 role='components', sequence=2, sequence_context='STEP',
                  user_file_name='thingy_libpart1.p21', bytes=12345,
                  mime_type=mime1)
 popTestData(file2)
-rep1 = Representation(pgef_oid=repoid,
-                      id='STEP-1', id_ns='http://pangalactic.us/test/',
-                      rep_type='STEP', files=[file1, file2],
-                      rep_purpose='exchange', generable=False,
-                      composable=True, is_object_source=True)
+rep1 = Representation(pgef_oid=repoid, id='STEP',
+                      id_ns='http://pangalactic.us/test/',
+                      files=[file1, file2], rep_purpose='exchange',
+                      generable=False, composable=True,
+                      is_object_source=True)
 popTestData(rep1)
 pt = Part(pgef_oid=ptoid, id=ptid, id_ns='http://pangalactic.us/test/',
           name=ptname, project=projoid)

Index: PanGalactic/pangalactic/core/filelink.py
diff -u PanGalactic/pangalactic/core/filelink.py:1.6 PanGalactic/pangalactic/core/filelink.py:1.7
--- PanGalactic/pangalactic/core/filelink.py:1.6	Wed May  4 06:24:11 2005
+++ PanGalactic/pangalactic/core/filelink.py	Mon May 23 01:26:58 2005
@@ -1,18 +1,18 @@
-# $Id: filelink.py,v 1.6 2005/05/04 10:24:11 waterbug Exp $
+# $Id: filelink.py,v 1.7 2005/05/23 05:26:58 waterbug Exp $
 """
-A FileLink object is a semantic link to a system file.  Note that a file
-may have more than one FileLink associated with it (in somewhat the same
-way that a filesystem node may have multiple links to it).  The FileLink
+A C{FileLink} object is a semantic link to a system file.  Note that a file
+may have more than one C{FileLink} associated with it (in somewhat the same
+way that a filesystem node may have multiple links to it).  The C{FileLink}
 class has attributes for information both about the file itself (its
 location, etc.) and about the role of the file in relation to an object
 Representation, if it is related to one.
 
-A FileLink could possibly be used as a semantic link to any file-like
+A C{FileLink} could possibly be used as a semantic link to any file-like
 object, but the implications of this have not yet been explored.
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 from pangalactic import PGEF_URI
 from pangalactic.core.pgefobject import PgefObject
@@ -21,13 +21,13 @@
 
 class FileLink(PgefObject):
     """
-    FileLink is a logical proxy for a system file, including information
+    C{FileLink} is a logical proxy for a system file, including information
     about the file and its location.  Note that a system file may have more
-    than one FileLink associated with it -- in general, the FileLink
+    than one C{FileLink} associated with it -- in general, the C{FileLink}
     carries information about the semantics of the file's relationship to a
-    Representation of another PgefObject such as a Part, Model, or
-    Document, and the file may have relationships to more than one such
-    object.
+    C{Representation} of another C{PgefObject} such as a C{Part}, C{Model},
+    or C{Document}, and the file may have relationships to more than one
+    such object.
     """
     _excluded_fields = []
     _schema=ObjectSchema(
@@ -37,13 +37,7 @@
         abbrev='flink',
         base=PgefObject._schema,
         description="""
-        FileLink is a logical proxy for a system file, including
-        information about the file and its location.  Note that a system
-        file may have more than one FileLink associated with it -- in
-        general, the FileLink carries information about the semantics of
-        the file's relationship to a Representation of another PgefObject
-        such as a Part, Model, or Document, and the file may have
-        relationships to more than one such object.
+        A system file.
         """,
         properties=[
         Property(
@@ -53,9 +47,9 @@
             range='str',
             default_display='True',
             description="""
-            The purpose or meaning of this particular file relative to a
-            Representation to which it is related -- e.g.  "attachment",
-            "content", "stylesheet", "DTD", etc.
+            The purpose of the File relative to a Representation to which
+            it is related.  Possible values are: "attachment", "content",
+            "stylesheet", "DTD", etc.
             """),
         Property(
             id='sequence',
@@ -66,8 +60,8 @@
             description="""
             An integer that can be used to specify the ordering of this
             file within an ordered set of files -- attachments, for
-            example.  NOTE:  'sequence' is intepreted as applying within
-            the 'sequence_context'.
+            example.  NOTE:  Sequence is intepreted as applying within
+            Sequence Context (which see).
             """),
         Property(
             id='sequence_context',
@@ -78,10 +72,10 @@
             default_display='True',
             description="""
             The name of the attribute within the context of which the
-            'sequence' attribute is meaningful.  IOW, if the
-            'sequence_context' value is 'role', and the 'role' value is
-            'attachment', then 'sequence' is the position of this file
-            within the set of files that have a 'role' of 'attachment'.
+            Sequence attribute is meaningful.  If the value of the Sequence
+            Context attribute is 'role', and the value of Role is
+            'attachment', then Sequence is the position of this file within
+            the set of files that have a Role of 'attachment'.
             """),
         Property(
             id='location',
@@ -89,14 +83,8 @@
             name='Location',
             range='str',
             description="""
-            (1) For unsecured files (i.e., those not "vaulted"/controlled
-            by PGER), location == URL.
-            (2) For secured files, location will usually be completely
-            different from a URL (if there even is one) used by an end-user
-            to obtain the file.  It is the computable path used by PGER to
-            read/write the file; in the case of a single PGER instance on a
-            single host, the location is the system path to the file.  The
-            default location is determined by the vault implementation.
+            Location == URL to get the file (from the repository if it is a
+            'secured' file; from elsewhere if not).
             """),
         Property(
             id='user_file_name',
@@ -105,7 +93,7 @@
             range='str',
             default_display='True',
             description="""
-            The user or owner's local name for the system file.
+            The user's name for the file on their machine.
             """),
         Property(
             id='is_secured',
@@ -115,8 +103,8 @@
             default='True',
             min_cardinality=1,
             description="""
-            If True, the file is stored in PGER's vault; if False, the file
-            may be anywhere.
+            If True, the file is stored in the repository's file vault; if
+            False, the file is not stored in the repository.
             """),
         Property(
             id='bytes',
@@ -135,7 +123,7 @@
             property_type='object',
             default_display='True',
             description="""
-            The MIME type of the file's content.
+            The MIME Type of the file's content.
             """)
             ]) # end of _schema
 
@@ -144,6 +132,7 @@
         Initialize a FileLink object.
         """
         PgefObject.__init__(self, **kw)
+        # a non-persistent reference to the file's path on the user's
+        # machine, used by PanGalaxian:
         self.local_path = kw.get("local_path", "")
 
-

Index: PanGalactic/pangalactic/core/dataset.py
diff -u PanGalactic/pangalactic/core/dataset.py:1.6 PanGalactic/pangalactic/core/dataset.py:1.7
--- PanGalactic/pangalactic/core/dataset.py:1.6	Tue Apr 12 23:59:28 2005
+++ PanGalactic/pangalactic/core/dataset.py	Mon May 23 01:26:58 2005
@@ -1,11 +1,11 @@
-# $Id: dataset.py,v 1.6 2005/04/13 03:59:28 waterbug Exp $
+# $Id: dataset.py,v 1.7 2005/05/23 05:26:58 waterbug Exp $
 """
 A DataSet is a collection of object instances governed by a single ontology
 (in this context, 'schema' is the term used for 'ontology').
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 from pangalactic.core.document import Document
 from pangalactic import PGEF_URI
@@ -14,17 +14,39 @@
 
 class DataSet(Document):
     """
-    A DataSet is a collection of object instances governed by a single
+    A C{DataSet} is a collection of object instances governed by a single
     ontology ("schema", in STEP parlance), whose original source is not
     more than one file.  (If a collection of object instances spans more
     than one file or is governed by more than one ontology/schema, it
-    should be represented as a DataPackage.)
+    should be represented as a C{DataPackage}.)
 
-    The primary purpose of the DataSet class is to enable the tracking and
+    The primary purpose of the C{DataSet} class is to enable the tracking and
     management of arbitrary collections of exchanged data.
 
-    The initial attributes of the DataSet class are modeled from the STEP
+    The initial attributes of the C{DataSet} class are modeled from the STEP
     Part 21 (ISO 10303-21-1994) data exchange file header information.
+
+    The initial attributes of the C{DataSet} class are mapped from the STEP
+    Part 21-1994 data exchange file header ("meta") information.  The
+    mappings STEP Part 21 -> C{DataSet} attributes (inherited from) are:
+
+      * file_description.description   -> description        (C{PgefObject})
+      * file_name.time_stamp           -> create_datetime    (C{PgefObject})
+      * file_name.author               -> creator            (C{PgefObject})
+      * file_name.organization         -> owner_org          (C{PgefObject})
+      * file_name.preprocessor_version -> processor_version  (C{DataSet})
+      * file_name.originating_system   -> originating_system (C{DataSet})
+      * file_name.authorization        -> authorization      (C{DataSet})
+      * file_schema.schema_identifiers -> dataset_schema_id  (C{DataSet})
+
+    C{DataSet}s can have a number of different relationships to each other,
+    such as "equivalent" (e.g., the same object population in different
+    encodings), "mapped_from" (C{DataSet} B is mapped from C{DataSet} A), etc.
+    Such relationships will be represented explicitly (reified as objects).
+
+    If an application needs to identify a collection of C{DataSet}s that may
+    have different schemas, a C{DataPackage} object should be used (which
+    see).
     """
     # TODO:  we'll treat the contents of a Part 21-1994 file as a DataSet,
     # but when Part 21-2002 is introduced, there may be multiple schema
@@ -40,35 +62,11 @@
         abbrev='dset',
         base=Document._schema,
         description="""
-        A DataSet is a Document whose function is to serve as a wrapper for
-        a serialized population of objects in a file, governed by a single
-        schema (a.k.a. "ontology").  The file can be a STEP (ISO 10303)
-        file (in a number of possible encoding options), a CAD file, or in
-        general any data exchange or serialization file.
-
-        The initial attributes of the DataSet class are mapped from the
-        STEP Part 21-1994 data exchange file header ("meta") information:
-
-              STEP Part 21                      PGER               inherited from
-              ------------                      ----               --------------
-            * file_description.description   -> description        (PgefObject)
-            * file_name.time_stamp           -> create_datetime    (PgefObject)
-            * file_name.author               -> creator            (PgefObject)
-            * file_name.organization         -> owner_org          (PgefObject)
-            * file_name.preprocessor_version -> processor_version  (DataSet)
-            * file_name.originating_system   -> originating_system (DataSet)
-            * file_name.authorization        -> authorization      (DataSet)
-            * file_schema.schema_identifiers -> dataset_schema_id  (DataSet)
-
-        DataSets can have a number of different relationships to each
-        other, such as "equivalent" (e.g., the same object population in
-        different encodings), "mapped_from" (DataSet B is mapped from
-        DataSet A), etc.  Such relationships will be represented explicitly
-        (reified as objects).
-
-        If an application needs to identify a collection of DataSets that
-        may have different schemas, a DataPackage object is to be used
-        (which see).
+        A Data Set is a Document whose function is to serve as a wrapper
+        for a serialized population of objects in a file, governed by a
+        single schema (a.k.a. "ontology").  The file can be a STEP (ISO
+        10303) file (in a number of possible encoding options), a CAD file,
+        or in general any data exchange or serialization file.
         """,
         properties=[
         Property(
@@ -78,7 +76,7 @@
             range='str',
             description="""
             The version of the software application that was used to
-            produce the DataSet.
+            produce the Data Set.
             """),
         Property(
             id='orginating_system',
@@ -86,7 +84,7 @@
             name='Originating System',
             range='str',
             description="""
-            The system from which the data in this DataSet originated.
+            The system from which the data in the Data Set originated.
             """),
         Property(
             id='authorization',
@@ -95,7 +93,7 @@
             range='Person',
             property_type='object',
             description="""
-            The system from which the data in this DataSet originated.
+            The person who authorized creation of the Data Set.
             """),
         # TODO:  'dataset_oids' is a multi-valued datatype property, which
         # Chronosynclastic will map to an ARRAY datatype, when that is
@@ -107,7 +105,7 @@
             range='str',
             max_cardinality=0,
             description="""
-            The pgef_oids assigned to the objects in the DataSet.
+            The oids assigned to the objects in the Data Set.
             """),
         Property(
             id='dataset_schema_id',
@@ -115,19 +113,15 @@
             name='DataSet Schema',
             range='str',
             description="""
-            The name of the schema that governs the DataSet.  In a
-            collection of data that has sections governed by different
-            schemas, each section will be considered a DataSet, so the
-            collection can be identified as a Document that contains
-            multiple DataSets.  A Technical Data Package is an example of
-            such a Document.
+            The name of the schema that governs the Data Set.
             """)
-            ]) # end of _default_schema
+            ])
+        # end of _schema
 
 
     def __init__(self, **kw):
         """
-        Initialize a DataSet object.
+        Initialize a C{DataSet} object.
         """
         Document.__init__(self, **kw)
 

Index: PanGalactic/pangalactic/core/organization.py
diff -u PanGalactic/pangalactic/core/organization.py:1.5 PanGalactic/pangalactic/core/organization.py:1.6
--- PanGalactic/pangalactic/core/organization.py:1.5	Sun Apr 10 23:31:25 2005
+++ PanGalactic/pangalactic/core/organization.py	Mon May 23 01:26:58 2005
@@ -1,12 +1,12 @@
-# $Id: organization.py,v 1.5 2005/04/11 03:31:25 waterbug Exp $
+# $Id: organization.py,v 1.6 2005/05/23 05:26:58 waterbug Exp $
 
 """
 An Organization is a business entity composed of personnel and
 other resources.
 
-@version: $Revision: 1.5 $
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 from pangalactic.core.pgefobject import PgefObject
 from pangalactic import PGEF_URI
@@ -36,13 +36,12 @@
             name='Organization Name Code',
             range='str',
             description="""
-            An abbreviation for the organization's name.  Maps to
-            mfr_name_code in Part.  Corresponds to the parent
-            organization identifier -- i.e., association_cage --
-            but is a "mnemonic" string.  Therefore, it is not
-            unique within the organization table, since several
-            locations of the same organization will have the same
-            org_name_code.
+            An abbreviation for the Organization's name.  Maps to the Part
+            attribute Manufacturer Name Code.  Corresponds to the parent
+            Organization identifier (Association CAGE) but is a "mnemonic"
+            string.  Therefore, it is not unique among known Organizations,
+            since several locations of the same Organization will have the
+            same Organization Name Code.
             """),
         Property(
             id='name1',
@@ -51,7 +50,7 @@
             range='str',
             description="""
             The first of a possible 5 segments of the
-            organization's name.  (From the CAGE data structure.)
+            Organization's name.  (From the CAGE data structure.)
             """),
         Property(
             id='name2',
@@ -60,7 +59,7 @@
             range='str',
             description="""
             The second of a possible 5 segments of the
-            organization's name.  (From the CAGE data structure.)
+            Organization's name.  (From the CAGE data structure.)
             """),
         Property(
             id='name3',
@@ -69,7 +68,7 @@
             range='str',
             description="""
             The third of a possible 5 segments of the
-            organization's name.  (From the CAGE data structure.)
+            Organization's name.  (From the CAGE data structure.)
             """),
         Property(
             id='name4',
@@ -78,7 +77,7 @@
             range='str',
             description="""
             The fourth of a possible 5 segments of the
-            organization's name.  (From the CAGE data structure.)
+            Organization's name.  (From the CAGE data structure.)
             """),
         Property(
             id='name5',
@@ -87,7 +86,7 @@
             range='str',
             description="""
             The fifth of a possible 5 segments of the
-            organization's name.  (From the CAGE data structure.)
+            Organization's name.  (From the CAGE data structure.)
             """),
         Property(
             id='country_code',
@@ -107,7 +106,7 @@
             range='str',
             description="""
             The first of a possible 2 segments of the
-            organization's street address.  (From the CAGE data
+            Organization's Street Address.  (From the CAGE data
             structure.)
             """),
         Property(
@@ -117,7 +116,7 @@
             range='str',
             description="""
             The second of a possible 2 segments of the
-            organization's street address.  (From the CAGE data
+            Organization's Street Address.  (From the CAGE data
             structure.)
             """),
         Property(
@@ -127,7 +126,7 @@
             range='str',
             default_display='True',
             description="""
-            The organization's city.  (From the CAGE data
+            The Organization's City.  (From the CAGE data
             structure.)
             """),
         Property(
@@ -137,7 +136,7 @@
             range='str',
             default_display='True',
             description="""
-            The organization's state (if in the U.S.) or country.
+            The Organization's state (if in the U.S.) or country.
             (From the CAGE data structure.)
             """),
         Property(
@@ -146,7 +145,7 @@
             name='Zip or Postal Zone',
             range='str',
             description="""
-            The organization's zip code (if in the U.S.) or
+            The Organization's zip code (if in the U.S.) or
             postal zone.  (From the CAGE data structure.)
             """),
         Property(
@@ -155,7 +154,7 @@
             name='Phone',
             range='str',
             description="""
-            The organization's phone number.  (From the CAGE data
+            The Organization's phone number.  (From the CAGE data
             structure.)
             """),
         Property(
@@ -165,7 +164,7 @@
             range='str',
             default_display='True',
             description="""
-            The organization's parent organization's CAGE code.
+            The Organization's parent Organization's CAGE code.
             (From the CAGE data structure.)
             """),
         Property(
@@ -201,7 +200,7 @@
             range='str',
             description="""
             First of a possible 4 Standard Industrial
-            Classification (SIC) codes for this organization.
+            Classification (SIC) codes for this Organization.
             See:  http://www.census.gov/epcd/www/sic.html
             (From the CAGE data structure.)
             """),
@@ -212,7 +211,7 @@
             range='str',
             description="""
             Second of a possible 4 Standard Industrial
-            Classification (SIC) codes for this organization.
+            Classification (SIC) codes for this Organization.
             See:  http://www.census.gov/epcd/www/sic.html
             (From the CAGE data structure.)
             """),
@@ -223,7 +222,7 @@
             range='str',
             description="""
             Third of a possible 4 Standard Industrial
-            Classification (SIC) codes for this organization.
+            Classification (SIC) codes for this Organization.
             See:  http://www.census.gov/epcd/www/sic.html
             (From the CAGE data structure.)
             """),
@@ -234,7 +233,7 @@
             range='str',
             description="""
             Fourth of a possible 4 Standard Industrial
-            Classification (SIC) codes for this organization.
+            Classification (SIC) codes for this Organization.
             See:  http://www.census.gov/epcd/www/sic.html
             (From the CAGE data structure.)
             """)

Index: PanGalactic/pangalactic/core/model.py
diff -u PanGalactic/pangalactic/core/model.py:1.7 PanGalactic/pangalactic/core/model.py:1.8
--- PanGalactic/pangalactic/core/model.py:1.7	Wed Apr 13 12:04:31 2005
+++ PanGalactic/pangalactic/core/model.py	Mon May 23 01:26:58 2005
@@ -1,12 +1,13 @@
-# $Id: model.py,v 1.7 2005/04/13 16:04:31 waterbug Exp $
+# $Id: model.py,v 1.8 2005/05/23 05:26:58 waterbug Exp $
 
 """
-A representation of something, usually for some specific purpose, such as
-analysis, simulation, description, specification, or presentation.
+A digital representation that is used for analysis, simulation,
+description, specification, or presentation of some aspect(s) of a domain
+object.
 
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 from pangalactic.core.versionedobject import VersionedObject
 from pangalactic import PGEF_URI
@@ -15,8 +16,9 @@
 
 class Model(VersionedObject):
     """
-    A representation of something, usually for some specific purpose, such
-    as analysis, simulation, description, specification, or presentation.
+    A digital representation that is used for analysis, simulation,
+    description, specification, or presentation of some aspect(s) of a
+    domain object.
     """
     _excluded_fields = ['create_datetime', 'record_create_datetime', 'pgef_oid']
     _schema = ObjectSchema(
@@ -26,15 +28,18 @@
         abbrev='model',
         base=VersionedObject._schema,
         description="""
-        A representation of something, usually for some specific purpose,
-        such as analysis, simulation, description, specification, or
-        presentation.  A Model itself can be considered a product
-        (therefore the characteristics of any Model are a possible subject
-        of another level of Model, sometimes refer to as a "meta-model"
-        relative to the Model that it models).  A Model can be versioned.
-        PGEF Model generally maps to the STEP (ISO 10303) concept called
-        'product_definition', but there may be other mappings for
-        particular application protocols and types of models.
+        A digital representation that is used for analysis, simulation,
+        description, specification, or presentation of some aspect(s) of a
+        domain object.
+        """,
+        comment="""
+        A Model itself can be considered a "product".  Therefore,  A Model
+        can be versioned.  PGEF Model generally maps to the STEP concept
+        called 'product_definition', but there may be other mappings for
+        particular application protocols and types of models.  (Note that
+        the characteristics of any Model are a possible subject of another
+        level of Model, sometimes refer to as a "meta-model" relative to
+        the original Model.
         """,
         properties=[
         Property(
@@ -43,28 +48,28 @@
             name='Model View',
             range='str',
             description="""
-            Allowed values are:
-            'design' ... STEP AP210 design view
-            'usage' .... STEP AP210 usage view
-            'build' .... supports physical assembly, etc.
-            """), # TODO:  provide the AP210 definitions of these
+            The context in which the model is used.  Allowed values are:
+            "design" (STEP AP210 "design view"), "usage" (STEP AP210 "usage
+            view"), "build" (supports physical assembly, etc.).
+            """),
         Property(
             id='frame_of_reference',
             id_ns=PGEF_URI,
             name='Frame of Reference',
             range='str',
             description="""
-            'frame_of_reference' could be thought of as the
-            activity or context that produced and uses the Model
-            -- which also defines its point of view.  In STEP,
-            this maps to 'pd.frame_of_reference.application'.  In
-            STEP, f_o_r points to an application_context, which
-            refers to the general application domain that defined
-            the data ... the values recommended in the PDM Schema
-            Usage Guide are: 'digital mock up' 'assembly study'
-            'process planning' 'electrical design' 'mechanical
-            design', but a set of values meaningful within the
-            context of a Project or Organization should be
+            The activity or context that produced and uses the Model --
+            which also defines its point of view.
+            """,
+            comment="""
+            PGEF Model Frame of Reference maps directly to STEP
+            "product_definition.frame_of_reference.application".  In STEP,
+            f_o_r points to an application_context, which refers to the
+            general application domain that defined the data ... the values
+            recommended in the STEP PDM Schema Usage Guide are: "digital
+            mock up" "assembly study" "process planning" "electrical
+            design" "mechanical design", but a set of values meaningful
+            within the context of a Project or Organization should be
             defined for this attribute to be useful.
             """),
         Property(
@@ -73,14 +78,16 @@
             name='Definition Context',
             range='str',
             description="""
-            Maps to STEP 'product_definition_context.name'.  From
-            the STEP PDM Schema Usage Guide: "Distinguishes the
-            type of the associated product_definition ...".
-            Examples given in the STEP PDM Schema Usage Guide all
-            use name = 'part definition' ... a set of values
-            meaningful within the context of a Project or
-            Organization should be defined for this attribute to
-            be useful.
+            The context within which the Model is defined.
+            """,
+            comment="""
+            From the STEP PDM Schema Usage Guide: "[Definition context]
+            distinguishes the type of the associated product_definition
+            ...".  Examples given in the STEP PDM Schema Usage Guide all
+            use name = "part definition" ... a set of values meaningful
+            within the context of a Project or Organization should be
+            defined for this attribute to be useful.  Maps to STEP
+            "product_definition_context.name".
             """),
         Property(
             id='life_cycle_stage',
@@ -88,15 +95,18 @@
             name='Life Cycle Stage',
             range='str',
             description="""
-            PGEF 'life_cycle_stage' is equivalent to STEP
-            'product_definition_context.life_cycle_stage'.  The
-            two values recommended in the STEP PDM Schema Usage
-            Guide are: 'design' and 'manufacturing' ... a set of
-            values meaningful within the context of a Project or
-            Organization should be defined for this attribute to
-            be useful.
+            The Life Cycle Stage within which the Model is defined.
+            """,
+            comment="""
+            PGEF Model Life Cycle Stage maps directly to STEP
+            "product_definition_context.life_cycle_stage".  The two values
+            recommended in the STEP PDM Schema Usage Guide are: "design"
+            and "manufacturing" ... a set of values meaningful within the
+            context of a particular Project or Organization should be
+            defined for this attribute to be useful.
             """)
-            ]) # end of _schema
+            ])
+            # end of _schema
 
     def __init__(self, **kw):
         """

Index: PanGalactic/pangalactic/core/representation.py
diff -u PanGalactic/pangalactic/core/representation.py:1.5 PanGalactic/pangalactic/core/representation.py:1.6
--- PanGalactic/pangalactic/core/representation.py:1.5	Mon Apr 25 01:53:51 2005
+++ PanGalactic/pangalactic/core/representation.py	Mon May 23 01:26:58 2005
@@ -1,18 +1,26 @@
-# $Id: representation.py,v 1.5 2005/04/25 05:53:51 waterbug Exp $
+# $Id: representation.py,v 1.6 2005/05/23 05:26:58 waterbug Exp $
 """
-A Representation consists of a file or a set of files that are used in
-publishing, displaying, importing, exporting, or exchanging one or more
-application object(s).  The concept is general and can apply to
-serialization, presentation, or data exchange use-cases, among others.
-Representation can be thought of as a reified relationship between one or
-more PgefObjects (its 'objects' property) and one or more FileLinks (its
-'files' property).  A Representation will often represent a single object
-(such as a Document or Model), but in serialization and data exchange
-use-cases it is common for a Representation to represent many objects.
+A C{Representation} consists of a file or a set of files that are used in
+publishing, displaying, importing, exporting, or exchanging an application
+object.  The concept is general and can apply to serialization,
+presentation, or data exchange use-cases, among others.  C{Representation}
+can be thought of as a reified relationship between a
+L{pangalactic.core.pgefobject.PgefObject} instance (which has the
+C{Representation} as one of the items in its C{reps} property) and one or
+more L{pangalactic.core.filelink.FileLink} instances (its 'files'
+property).  As defined in the PGEF ontology, a C{Representation} represents
+a single domain object (such as a Document or Model).  In serialization and
+data exchange use-cases it is common for a file or collection of files to
+represent many objects -- in PGEF, this is a L{DataSet}.
 
-@version: $Revision: 1.5 $
+C{Representation}(s) can be generated from an object (generable) or can be
+used to create an object (composable).  The C{Representation} in which the
+object was originally imported (if any) will have its 'is_object_source'
+attribute set to True.
+
+@version: $Revision: 1.6 $
 """
-__version__ = "$Revision: 1.5 $"[11:-2]
+__version__ = "$Revision: 1.6 $"[11:-2]
 
 from pangalactic.core.pgefobject import PgefObject
 from pangalactic import PGEF_URI
@@ -21,15 +29,24 @@
 
 class Representation(PgefObject):
     """
-    A Representation is a file or a set of files that represents one or
-    more application object(s).  The concept is general and can apply to
+    A C{Representation} consists of a file or a set of files that are used
+    in publishing, displaying, importing, exporting, or exchanging an
+    application object.  The concept is general and can apply to
     serialization, presentation, or data exchange use-cases, among others.
-    Representation can be thought of as a reified relationship between one
-    or more PgefObjects (its 'objects' property) and one or more FileLinks
-    (its 'files' property).  A Representation will often represent a single
-    object (such as a Document or Model), but in serialization and data
-    exchange use-cases it is common for a Representation to represent many
-    objects.
+    C{Representation} can be thought of as a reified relationship between a
+    L{pangalactic.core.pgefobject.PgefObject} instance (which has the
+    C{Representation} as one of the items in its C{reps} property) and one
+    or more L{pangalactic.core.filelink.FileLink} instances (its 'files'
+    property).  As defined in the PGEF ontology, a C{Representation}
+    represents a single domain object (such as a Document or Model).  In
+    serialization and data exchange use-cases it is common for a file or
+    collection of files to represent many objects -- in PGEF, this is a
+    L{DataSet}.
+
+    C{Representation}(s) can be generated from an object (generable) or can
+    be used to create an object (composable).  The C{Representation} in
+    which the object was originally imported (if any) will have its
+    'is_object_source' attribute set to True.
     """
     _properties = PgefObject._properties.copy()
     _schema = ObjectSchema(
@@ -40,14 +57,22 @@
         base=PgefObject._schema,
         description="""
         A Representation is a file or a set of files that represents one or
-        more application object(s).  The concept is general and can apply
-        to serialization, presentation, or data exchange use-cases, among
+        more application object(s).
+        """,
+        comment="""
+        PGEF Representation is a very general concept and can apply to
+        serialization, presentation, or data exchange use-cases, among
         others.  Representation can be thought of as a reified relationship
         between one or more PgefObjects (its 'objects' property) and one or
         more FileLinks (its 'files' property).  A Representation will often
         represent a single object (such as a Document or Model), but in
         serialization and data exchange use-cases it is common for a
         Representation to represent many objects.
+
+        Representation(s) can be generated from an object (generable) or
+        can be used to create an object (composable).  The Representation
+        in which the object was originally imported (if any) will have its
+        'is_object_source' attribute set to True.
         """,
         properties=[
         Property(
@@ -55,37 +80,20 @@
             id_ns=PGEF_URI,
             name='ID',
             range='str',
-            description="""
-            [step:id] [rdf:ID] (This definition overrides the generic
-            definition inherited from PgefObject.)  A set of representation
-            IDs can be standardized for some specified context, but the
-            main purpose of the ID for a Representation is to
-            distinguish between different representations of the same
-            object or set of objects, so it need only be guaranteed to be
-            unique within that context, which should be set as the
-            id_ns.  (See 'name'.)
-            """),
-        Property(
-            id='rep_type',
-            id_ns=PGEF_URI,
-            name='Representation Type',
-            display_name='Representation Type',
-            range='str',
             default_display='True',
             description="""
-            [pgef:rep_type]  (This definition overrides the generic definition
-            inherited from PgefObject.)  A set of representation names can
-            be standardized for some specified context, but the main
-            purpose is to distinguish between different representations of
-            the same object or set of objects, so it need only be
-            guaranteed to be unique within that context, which should be
-            the same as the id_ns.  Some possible values of name for
-            representations are: "PDF", "HTML", "HTML slides", "text",
-            "STEP Part 21", etc.  While these may in some cases correspond
-            to MIME Media Types, they are more general -- in fact, an
-            object might have multiple distinct representations that have
-            the same Media Type -- e.g.: slides, a paper, and an outline
-            all in PDF, generated from the same object.
+            [step:id] [rdf:ID]  Distinguishes between different types of
+            Representations of the same object or set of objects.  It need
+            only be guaranteed to be unique within that context.  Some
+            possible values of Representation Type are: "PDF", "HTML",
+            "HTML slides", "text", "STEP Part 21", etc.
+            """,
+            comment="""
+            While the value of Representation ID may in some cases
+            correspond to a MIME Media Type, it is more customized.  In
+            fact, an object might have multiple distinct Representations
+            that have the same Media Type -- e.g.: slides, a paper, and an
+            outline all in PDF, generated from the same object.
             """),
         Property(
             id='files',
@@ -97,7 +105,7 @@
             min_cardinality=1,
             description="""
             [pgef:files]  The FileLink(s) that constitute the
-            representation of the object(s).
+            Representation.
             """),
         Property(
             id='rep_purpose',
@@ -108,7 +116,7 @@
             default_display='True',
             description="""
             [pgef:rep_purpose]  The purpose or meaning of this
-            representation -- e.g.  "publication", "presentation",
+            Representation -- e.g.  "publication", "presentation",
             "exchange", etc.  The semantics of this Property are heavily
             context-dependent.
             """),
@@ -119,7 +127,8 @@
             range='bool',
             default_display='True',
             description="""
-            [pgef:generable]  Able to be generated from the objects.
+            [pgef:generable]  Able to be generated (from some other
+            Representation, usually).
             """),
         Property(
             id='composable',
@@ -129,7 +138,8 @@
             default_display='True',
             description="""
             [pgef:composable]  Able to be used (e.g., by an editor or a
-            parser/importer) to construct the objects.
+            parser/importer) to (re)create or edit itself and/or some other
+            Representation.
             """),
         Property(
             id='is_object_source',
@@ -139,7 +149,7 @@
             range='bool',
             default_display='True',
             description="""
-            [pgef:is_object_source]  Indicates whether this representation
+            [pgef:is_object_source]  Indicates whether this Representation
             is the original source from which its parent object was
             instantiated in PGER or in the current PGEF application
             context.

Index: PanGalactic/pangalactic/core/pgefobject.py
diff -u PanGalactic/pangalactic/core/pgefobject.py:1.17 PanGalactic/pangalactic/core/pgefobject.py:1.18
--- PanGalactic/pangalactic/core/pgefobject.py:1.17	Tue May 17 04:00:03 2005
+++ PanGalactic/pangalactic/core/pgefobject.py	Mon May 23 01:26:58 2005
@@ -1,4 +1,4 @@
-# $Id: pgefobject.py,v 1.17 2005/05/17 08:00:03 waterbug Exp $
+# $Id: pgefobject.py,v 1.18 2005/05/23 05:26:58 waterbug Exp $
 
 """
 PgefObject is the Mother of all PanGalactic objects.
@@ -31,9 +31,9 @@
 Note that PgefObject and its subclasses do not (yet) implement all of these
 characteristics, but that is their ultimate goal.
 
-@version: $Revision: 1.17 $
+@version: $Revision: 1.18 $
 """
-__version__ = "$Revision: 1.17 $"[11:-2]
+__version__ = "$Revision: 1.18 $"[11:-2]
 
 import copy
 from mx import DateTime
@@ -160,17 +160,16 @@
             name='OID',
             range='str',
             description="""
-            [pgef:pgef_oid]  In PGEF, an OID is an object identifier that
-            is intended to be unique across all PGEF application instances
-            in all PGEF applications, whether they are in communication or
-            not.  By default, it is constructed as the concatenation of the
-            object creator's id, which is typically their email address
-            (hence a URI for a Person), with the timestamp of the object's
-            creation in Universal Time.  However, in cases in which an
-            object has been assigned a URI, it's preferable to use the URI
-            as the pgef_oid.  In the future, some form of canonical
-            URI-generation might replace the current default pgef_oid
-            construction.
+            [pgef:pgef_oid]  An object identifier that is intended to be
+            unique across all PGEF application instances in all PGEF
+            applications, whether they are in communication or not.  By
+            default, it is constructed as the concatenation of the object
+            creator's id, which is typically their email address (hence a
+            URI for a Person), with the timestamp of the object's creation
+            in Universal Time.  However, in cases in which an object has
+            been assigned a URI, it's preferable to use the URI as the
+            pgef_oid.  In the future, some form of canonical URI-generation
+            might replace the current default pgef_oid construction.
             """),
         Property(
             id='id',
@@ -179,10 +178,10 @@
             range='str',
             default_display='True',
             description="""
-            [step:id] [rdf:ID] An ID is an identifier that is unique within
-            a specified namespace.  In a canonical data definition scheme,
-            id should be a 'local name', its namespace should be specified
-            as a valid URI or locally unique prefix, and the combination of
+            [step:id] [rdf:ID]  An identifier that is unique within a
+            specified namespace.  In a canonical data definition scheme, id
+            should be a 'local name', its namespace should be specified as
+            a valid URI or locally unique prefix, and the combination of
             the two should form a globally unique Qualified Name.
             """),
         Property(
@@ -192,9 +191,8 @@
             range='str',
             default='NOCONTEXT',
             description="""
-            [xml:base]  An ID Namespace is the context within which an
-            identifier (ID) is unique.  (Customarily, a namespace is
-            formulated as a URI.)
+            [xml:base]   The context within which an identifier (ID) is
+            unique.  (Customarily, a namespace is formulated as a URI.)
             """),
         Property(
             id='security_mask',
@@ -203,11 +201,11 @@
             range='int',
             default='0',
             description="""
-            [pgef:security_mask]  In PGEF, a Security Mask is used to
-            implement instance-level customizable access control.
-            Accessibility of each entity instance (row) will be governed by
-            testing its security_mask against the security_mask assigned to
-            the user.  Details TBD.
+            [pgef:security_mask]  Implements instance-level customizable
+            access control.  Accessibility of each entity instance (row)
+            will be governed by testing its security_mask against the
+            security_mask assigned to the user.  [Not yet implemented --
+            details TBD.]
             """),
         Property(
             id='name',
@@ -216,12 +214,12 @@
             range='str',
             default_display='True',
             description="""
-            [rdfs:label]  A Name is a human-readable identifier for an
-            object -- usually the one by which the object is known to the
-            end-user, but it may be used for any type of identification,
-            including aliases and local nomenclatures.  Its meaning is
-            dependent on the application context.  This concept of Name is
-            analogous to a person's given name.
+            [rdfs:label]  A human-readable identifier for an object --
+            usually the one by which the object is known to the end-user,
+            but it may be used for any type of identification, including
+            aliases and local nomenclatures.  Its meaning is dependent on
+            the application context.  This concept of Name is analogous to
+            a person's given name.
             """),
         Property(
             id='description',
@@ -229,8 +227,8 @@
             name='Description',
             range='str',
             description="""
-            [rdf:Description]  A Description is a narrative about the
-            characteristics and identifying features of an object.
+            [rdf:Description]  A narrative about the characteristics and
+            identifying features of an object.
             """),
         Property(
             id='comment',
@@ -238,10 +236,10 @@
             name='Comment',
             range='str',
             description="""
-            [rdfs:comment]  A Comment provides information about an object
-            that may be incidental, temporal, or contextual, and is usually
-            in addition to the information in 'description'.  The meaning
-            of Comment is determined by the application context.
+            [rdfs:comment]  Information about an object that may be
+            incidental, temporal, or contextual, and is usually in addition
+            to the information in 'description'.  The meaning of Comment is
+            determined by the application context.
             """),
         # TODO:  this should be a list of Persons
         Property(
@@ -251,16 +249,15 @@
             range='Person',
             property_type='object',
             description="""
-            [pgef:record_owner] The PGER Owner is the user who owns the
-            object's record in the repository.
-            (1) PGER Owner and PGER Creator are both provided in case the
-            owner and creator of the record of the object in the repository
-            are different.  The default is for them to be the same.
-            (2) The default is PGER Owner == PGER Creator.  (This will
-            be enforced by the repository.)
-            (3) The PGER Owner always has the privilege of modifying the
-            record of the object in the repository (or deleting it, if
-            deletion is allowed for that entity type).
+            [pgef:record_owner]  The user who owns the object's record in
+            the repository.  PGER Owner and PGER Creator are both provided
+            in case the owner and creator of the record of the object in
+            the repository are different.  The default is for them to be
+            the same.  The default is PGER Owner == PGER Creator.  (This
+            will be enforced by the repository.)  The PGER Owner always has
+            the privilege of modifying the record of the object in the
+            repository (or deleting it, if deletion is allowed for that
+            entity type).
             """),
         Property(
             id='record_creator',
@@ -367,18 +364,11 @@
             min_cardinality=0,
             max_cardinality=0,
             description="""
-            [pgef:reps]  A Representation is any artifact used to
-            communicate or display information about a computational object
-            or its real-world counterpart.  Representation(s) can be either
-            generated from a computational object (generable=True) or can
-            used to create an instance of a computational object
-            (composable=True).  The representation from which the
-            computational object was originally imported (if any) will have
-            its 'is_object_source' attribute set to True.  Representations
+            [pgef:reps]  A digital representation of an object (e.g., a CAD
+            model, a spreadsheet, an HTML document).  Representations
             include both "presentations", such as PDF or HTML for a
-            document, and more general representations such as
-            serializations or data sets for exchange (e.g., for an
-            engineering model:  STEP Part 21, UML, OWL, etc.).
+            document, and more general representations such as exchange
+            data sets (e.g., for an engineering model:  STEP, VRML, etc.).
             """)
         ]) # end of _schema
 

Index: PanGalactic/pangalactic/core/part.py
diff -u PanGalactic/pangalactic/core/part.py:1.6 PanGalactic/pangalactic/core/part.py:1.7
--- PanGalactic/pangalactic/core/part.py:1.6	Tue Apr 12 23:59:28 2005
+++ PanGalactic/pangalactic/core/part.py	Mon May 23 01:26:58 2005
@@ -1,14 +1,14 @@
-# $Id: part.py,v 1.6 2005/04/13 03:59:28 waterbug Exp $
+# $Id: part.py,v 1.7 2005/05/23 05:26:58 waterbug Exp $
 
 """
-A Part is a product or some specifiable thing.
+A C{Part} is a product or some specifiable thing.
 
-The Part object encapsulates data pertaining to design,
-specification, or description.  It may be versioned.
+The C{Part} object encapsulates data pertaining to design, specification, or
+description.  It may be versioned.
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 from pangalactic.core.versionedobject import VersionedObject
 from pangalactic import PGEF_URI
@@ -17,10 +17,10 @@
 
 class Part(VersionedObject):
     """
-    A Part is a product or some specifiable thing.
+    A C{Part} is a product or some specifiable thing.
 
-    The Part object encapsulates data pertaining to design,
-    specification, or description.  It may be versioned.
+    The C{Part} object encapsulates data pertaining to design, specification,
+    or description.  It may be versioned.
     """
     # These are the fields that will appear in when an item is placed in a grid.
     # The format for each field is [ Label, attribute, field_type ].
@@ -33,14 +33,14 @@
         abbrev='part',
         base=VersionedObject._schema,
         description="""
-        Part represents an identifiable, specifiable product or
-        thing.  The PGEF Part concept maps to the combination of
-        STEP (ISO 10303) 'product' and
-        'product_definition_formation'
-
-        More mapping notes: STEP 'frame_of_reference' (->
-        product_context.id) is not represented within the PGEF
-        ontology.  STEP 'description' maps to description.
+        Part represents an identifiable, specifiable, versionable product
+        or thing.
+        """,
+        comment="""
+        The PGEF Part concept maps to the combination of STEP (ISO 10303)
+        'product' and 'product_definition_formation'.  STEP
+        'frame_of_reference' (-> product_context.id) is not represented
+        within the PGEF ontology.  STEP 'description' maps to description.
         """,
         properties=[
         Property(
@@ -50,8 +50,7 @@
             range='str',
             default_display='True',
             description="""
-            The identifier for the Part given by its
-            specification.
+            The identifier for the Part given by its specification.
             """),
         Property(
             id='part_number_generic',
@@ -60,9 +59,8 @@
             range='str',
             default_display='True',
             description="""
-            The generic identifier for the Part, which in some
-            cases is specified by a standard (e.g., JEDEC for
-            electronic parts).
+            The generic identifier for the Part, which in some cases is
+            specified by a standard (e.g., JEDEC for electronic parts).
             """),
         Property(
             id='part_number_mfr',
@@ -86,7 +84,7 @@
             name='Cross-Reference Part Number',
             range='str',
             description="""
-            An alias part number for this part.
+            An alias Part Number for this Part.
             """),
         Property(
             id='model_number',
@@ -94,9 +92,8 @@
             name='Model Number',
             range='str',
             description="""
-            The identifier for the Part's 'model', a somewhat
-            arbitrary identifier usually specified by the
-            manufacturer.
+            The identifier for the Part's 'Model', a somewhat arbitrary
+            identifier usually specified by the manufacturer.
             """),
         Property(
             id='drawing_number',
@@ -104,8 +101,8 @@
             name='Drawing Number',
             range='str',
             description="""
-            If the Part has a 'drawing' (a type of
-            specification), this is its identifier.
+            If the Part has a 'drawing' (a type of specification), this is
+            its identifier.
             """),
         Property(
             id='mfr',
@@ -114,8 +111,8 @@
             range='str',
             default_display='True',
             description="""
-            The CAGE Code of the Organization's plant or location
-            where the Part was manufactured.
+            The CAGE Code of the Organization's plant or location where the
+            Part was manufactured.
             """),
         Property(
             id='mfr_name_code',
@@ -124,9 +121,8 @@
             range='str',
             default_display='True',
             description="""
-            A standard abbreviation for the parent Organization
-            of the plant or location where the Part was
-            manufactured.
+            A standard abbreviation for the parent Organization of the
+            plant or location where the Part was manufactured.
             """),
         Property(
             id='vendor',
@@ -134,8 +130,8 @@
             name='Vendor',
             range='str',
             description="""
-            The CAGE Code of the Organization's plant or location
-            from which the Part was procured.
+            The CAGE Code of the Organization's plant or location from
+            which the Part was procured.
             """),
         Property(
             id='vendor_name_code',
@@ -143,9 +139,8 @@
             name='Vendor Name Code',
             range='str',
             description="""
-            A standard abbreviation for the parent Organization
-            of the plant or location from which the Part was
-            procured.
+            A standard abbreviation for the parent Organization of the
+            plant or location from which the Part was procured.
             """),
         Property(
             id='fsc_code',
@@ -154,9 +149,8 @@
             range='str',
             default_display='True',
             description="""
-            The Federal Supply Classification code for the
-            Part (this is also the first four digits of the
-            NSN).
+            The Federal Supply Classification code for the Part (this is
+            also the first four digits of the NSN).
             """),
         Property(
             id='type_designator',
@@ -180,8 +174,8 @@
             name='Specification',
             range='str',
             description="""
-            The name or identifier of the formal specification to
-            which the Part was procured.
+            The name or identifier of the formal specification to which the
+            Part was procured.
             """),
         Property(
             id='military_specification',
@@ -189,8 +183,8 @@
             name='Military Specification',
             range='str',
             description="""
-            The identifier of the military specification to which
-            the Part was procured.
+            The identifier of the military specification to which the Part
+            was procured.
             """),
         Property(
             id='military_standard',
@@ -198,8 +192,8 @@
             name='Military Standard',
             range='str',
             description="""
-            The identifier of a military standard to which the
-            Part conforms.
+            The identifier of a military standard to which the Part
+            conforms.
             """),
         Property(
             id='screening_spec',
@@ -207,8 +201,8 @@
             name='Screening Specification',
             range='str',
             description="""
-            The specification to which any screening of the Part
-            was or is to be performed.
+            The specification to which any screening of the Part was or is
+            to be performed.
             """),
         Property(
             id='lot_date_codes',
@@ -216,9 +210,8 @@
             name='Lot Date Codes',
             range='str',
             description="""
-            Dates of manufacture of the lots that included this
-            Part instance (applicable only to physical Part
-            instances).
+            Dates of manufacture of the lots that included this Part
+            instance (applicable only to physical Part instances).
             """),
         Property(
             id='lot_date_code_start',
@@ -226,9 +219,8 @@
             name='Lot Date Code Start',
             range='str',
             description="""
-            Earliest lot_date_code of the lots that included this
-            Part instance (applicable only to physical Part
-            instances).
+            Earliest lot_date_code of the lots that included this Part
+            instance (applicable only to physical Part instances).
             """),
         Property(
             id='lot_date_code_end',
@@ -236,9 +228,8 @@
             name='Lot Date Code End',
             range='str',
             description="""
-            Latest lot_date_code of the lots that included this
-            Part instance (applicable only to physical Part
-            instances).
+            Latest lot_date_code of the lots that included this Part
+            instance (applicable only to physical Part instances).
             """),
         Property(
             id='quantity',
@@ -247,8 +238,8 @@
             range='int',
             default='1',
             description="""
-            Number of instances of this Part (applicable only to
-            physical Part instances).
+            Number of instances of this Part (applicable only to physical
+            Part instances).
             """),
         Property(
             id='serial_number',
@@ -264,9 +255,8 @@
             name='Reference Designator',
             range='str',
             description="""
-            A unique identifier of a usage of this Part
-            (applicable only to an occurance of a Part in an
-            assembly).
+            A unique identifier of a usage of this Part (applicable only to
+            an occurance of a Part in an assembly).
             """),
         Property(
             id='is_validated',
@@ -274,8 +264,8 @@
             name='Validated',
             range='bool',
             description="""
-            A boolean indicating whether the information in this
-            Part object has been validated.
+            Indicates whether the information in this Part object has been
+            validated (values: 'True', 'False').
             """)
             ]) # end of _schema
 

Index: PanGalactic/pangalactic/core/document.py
diff -u PanGalactic/pangalactic/core/document.py:1.6 PanGalactic/pangalactic/core/document.py:1.7
--- PanGalactic/pangalactic/core/document.py:1.6	Sun Apr 10 23:31:25 2005
+++ PanGalactic/pangalactic/core/document.py	Mon May 23 01:26:58 2005
@@ -1,10 +1,10 @@
-# $Id: document.py,v 1.6 2005/04/11 03:31:25 waterbug Exp $
+# $Id: document.py,v 1.7 2005/05/23 05:26:58 waterbug Exp $
 """
 Document is the Mother of all PanGalactic Document types.  :)
 
-@version: $Revision: 1.6 $
+@version: $Revision: 1.7 $
 """
-__version__ = "$Revision: 1.6 $"[11:-2]
+__version__ = "$Revision: 1.7 $"[11:-2]
 
 from mx import DateTime
 import string
@@ -15,20 +15,43 @@
 
 class Document(VersionedObject):
     """
-    The Document class encapsulates the most generic document attributes
-    and behaviors.
+    The PGEF C{Document} class is intended to support the whole spectrum of
+    "structured product documents", including:
 
-    The purpose of the Document class is primarily to provide an
+      - blob documents, represented as metadata with paths (which may be
+        URL's) to file(s)
+      - versioned and non-versioned documents
+      - master documents, templates, and document components
+      - unstructured text files (including "annotations")
+      - documents containing some validated fields and some unstructured
+        components (free text, attachments, etc.)
+      - fully structured documents with semantically named components and
+        several presentations / representations (see discussion in the
+        explanation of subtype = 'iteration', below)
+
+    A C{Document}'s representations (C{reps} attribute) can include one or
+    more L{pangalactic.core.representation.Representation} instances.
+
+    The purpose of the C{Document} class is primarily to provide an
     application-level interface adaptable to the many contexts in which a
     document concept can be found.  Its methods should probably be defined
-    in an interface (IDocument).
+    in an interface (IDocument).  
 
-    A Document, as a PgefObject, has a 'reps' attribute that can contain
-    one or more L{pangalactic.core.representation.Representation}
-    objects (examples of representations are HTML, PDF, plain text, etc.),
-    each of which can have one or more associated files, referenced by
-    L{pangalactic.core.filelink.FileLink} objects (e.g., a DTD, a
-    stylesheet, an XML file, etc.).
+    NOTE:  a document component is related to an associated document
+    "assembly" in the PGEF ontology by a "Document Component Usage"
+    (C{Dcu}) relationship.  This enables two things: (1) reuse of document
+    components in multiple documents; (2) the use of versioned components
+    (i.e., a document component could also have a subtype of 'master' or
+    'version' and associated rules for effectivity -- which will require
+    modification of this schema to include effectivity ...  but we knew
+    that.  :^)
+
+    [STEP] C{Document} maps to "document as product".  In STEP, a document
+    is represented as a product with which is associated a
+    C{product_related_product_category} with name C{document}.  If its
+    C{product_definition_context.name} is 'physical document definition',
+    it is a non-computerized (paper, etc.) document; if it is 'digital
+    document definition', it is a digitally-encoded representation.
     """
     _excluded_fields = VersionedObject._excluded_fields
     # These are from the Dublin Core, and are computed attributes
@@ -47,35 +70,11 @@
         abbrev='doc',
         base=VersionedObject._schema,
         description="""
-        The PGEF Document class is intended to support the whole
-        spectrum of "structured product documents", including:
-
-        --  blob documents, represented as metadata with paths (which may
-            be URL's) to file(s)
-        --  versioned and non-versioned documents
-        --  master documents, templates, and document components
-        --  unstructured text files (including "annotations")
-        --  documents containing some validated fields and some
-            unstructured components (free text, attachments, etc.)
-        --  fully structured documents with semantically named components
-            and several presentations / representations (see discussion in
-            the explanation of subtype = 'iteration', below)
-       
-        NOTE:  a document component is related to an associated document
-        "assembly" in the PGEF ontology by a "Document Component Usage"
-        (Dcu) relationship.  This enables two things: (1) reuse of document
-        components in multiple documents; (2) the use of versioned
-        components (i.e., a document component could also have a subtype of
-        'master' or 'version' and associated rules for effectivity -- which
-        will require modification of this schema to include effectivity ...
-        but we knew that.  :^)
-       
-        [STEP] Dcu maps to "document as product".  In STEP, a document is
-        represented as a product with which is associated a
-        product_related_product_category with name 'document'.  If its
-        product_definition_context.name 'physical document definition', it
-        is a non-computerized (paper, etc.) document; if it is 'digital
-        document definition', it is a digitally-encoded representation.
+        The Document class encapsulates the most generic document
+        attributes and behaviors.  A Document can have one or more
+        Representations (examples of Representations are HTML, PDF, plain
+        text, etc.), each of which can have one or more associated files
+        (e.g., a DTD, a stylesheet, an XML file, etc.).
         """,
         properties=[
         Property(
@@ -86,14 +85,10 @@
             default_display='True',
             display_name='Title',
             description="""
-            (Overrides definition inherited from PgefObject.)
-            Semantic depends on the value of the structural_role attribute.
-
-            structural_role ==> "name" maps to
-            ---------------     --------------
-            'root' ............ title
-            'component' ....... component name (for XML docs, this may map
-                                to an element tag)
+            Normally, synonymous with 'Title'.  However, if the Document is
+            serving in the role of a component in another document, its
+            Name might map to something like a Chapter title, Section
+            title, etc.
             """),
         Property(
             id='structural_role',
@@ -103,18 +98,9 @@
             default='root',
             min_cardinality=1,
             description="""
-            Determines the semantic of the name attribute (q.v.) and
-            whether the doc_type_code should be populated.  Initial set of
-            allowed values:
-
-            'root' ........ a Document intended to be used as a top-level
-                            parent Document, whether with or without
-                            components; it can be used as an attachment but
-                            not as a component
-
-            'component' ... a Document intended to be used as a 
-                            component of another Document (may have
-                            internal structure itself)
+            Indicates whether the document is intended to be (1)
+            stand-alone, (2) the parent in an assembly of documents, or (3)
+            a component in another document.
             """),
         Property(
             id='abstract',
@@ -130,8 +116,8 @@
             name='Content',
             range='str',
             description="""
-            The content of the Document in a text-based format (preferably
-            plain text, but may be any format with a MIME type of "text",
+            The content of the Document in a text-based format (usually
+            text/plain, but may be any format with a MIME type of "text",
             such as text/html, text/xml, or text/tab-separated-values).
             """),
         Property(
@@ -142,9 +128,9 @@
             property_type='object',
             description="""
             The MIME type of the value of the 'content' attribute.  (This
-            does *not* imply that a Document has an intrinsic MIME type!
+            does *not* imply that a Document has an intrinsic MIME type.
             In general, each representation of the Document will have a
-            distinct MIME type.)
+            MIME type, and they may all be different.)
             """),
         Property(
             id='publish_datetime',
@@ -156,7 +142,8 @@
             description="""
             Date (and time, if relevant) the Document was published.
             """)
-            ]) # end of _default_schema
+            ])
+        # end of _schema
 
 
     def __init__(self, **kw):

Index: PanGalactic/pangalactic/test/test_pgef_properties.py
diff -u PanGalactic/pangalactic/test/test_pgef_properties.py:1.3 PanGalactic/pangalactic/test/test_pgef_properties.py:1.4
--- PanGalactic/pangalactic/test/test_pgef_properties.py:1.3	Tue Apr 26 00:53:51 2005
+++ PanGalactic/pangalactic/test/test_pgef_properties.py	Mon May 23 01:27:00 2005
@@ -1,22 +1,21 @@
 from pprint import pprint
 from pangalactic.core.mime import Mime
-from pangalactic.core.pgeffile import PgefFile
+from pangalactic.core.filelink import FileLink
 from pangalactic.core.project import Project
 from pangalactic.core.part import Part
 from pangalactic.core.model import Model
+from pangalactic.meta.factory import PanGalacticFactory as PGF
 from pangalactic.test.utils4test import popTestData
 
 fac = PGF()
 
 mime1 = Mime(media_type='model', media_subtype='p21')
 popTestData(mime1)
-file1 = PgefFile(role='content', rep_type='STEP', rep_group='STEP 1',
-                 user_file_name='thingy.p21', bytes=42000,
-                 mime_type=mime1)
+file1 = FileLink(role='content', user_file_name='thingy.p21',
+                 bytes=42000, mime_type=mime1)
 popTestData(file1)
-file2 = PgefFile(role='content', rep_type='STEP', rep_group='STEP 1',
-                 user_file_name='thingy_libpart1.p21', bytes=12345,
-                 mime_type=mime1)
+file2 = PgefFile(role='content', user_file_name='thingy_libpart1.p21',
+                 bytes=12345, mime_type=mime1)
 popTestData(file2)
 p = Project(pgef_oid='TEST.Project.OTHEROTHER',
             id='OTHEROTHER', id_ns='http://pangalactic.us/test/',

Index: PanGalactic/src/sql/insertDocuments.sql
diff -u PanGalactic/src/sql/insertDocuments.sql:1.23 PanGalactic/src/sql/insertDocuments.sql:1.24
--- PanGalactic/src/sql/insertDocuments.sql:1.23	Wed Apr 27 15:04:21 2005
+++ PanGalactic/src/sql/insertDocuments.sql	Mon May 23 01:27:01 2005
@@ -1,6 +1,6 @@
 /* PGER Demo Document insertion.  */
 
-/* $Id: insertDocuments.sql,v 1.23 2005/04/27 19:04:21 waterbug Exp $ */
+/* $Id: insertDocuments.sql,v 1.24 2005/05/23 05:27:01 waterbug Exp $ */
 
 BEGIN;
 SET CONSTRAINTS ALL DEFERRED;
@@ -151,7 +151,6 @@
 _modifier,
 _mod_datetime,
 _reps,
-_rep_type,
 _files,
 _rep_purpose,
 _generable,
@@ -162,7 +161,7 @@
 (
 'TEST.Representation.1',
 'Representation',                 -- object_schema_id
-'Representation.1',               -- id
+'HTML Slides',                    -- id
 'http://pangalactic.us/test/',    -- id_ns
 0,                                -- security_mask
 'TEST.Representation.1',          -- name
@@ -178,7 +177,6 @@
 'smallberries@yoyodyne.planet10', -- modifier
 '2002-09-09 01:06:51',            -- mod_datetime
 '',                               -- reps
-'HTML',                           -- rep_type
 'TEST.FileLink.1, TEST.FileLink.2', -- files
 'presentation',                   -- rep_purpose
 'True',                           -- generable
@@ -324,7 +322,6 @@
 _modifier,
 _mod_datetime,
 _reps,
-_rep_type,
 _files,
 _rep_purpose,
 _generable,
@@ -335,7 +332,7 @@
 (
 'TEST.Representation.2',
 'Representation',                 -- object_schema_id
-'Representation.2',               -- id
+'HTML Documentation',             -- id
 'http://pangalactic.us/test/',    -- id_ns
 0,                                -- security_mask
 'TEST.Representation.2',          -- name
@@ -351,7 +348,6 @@
 'smallberries@yoyodyne.planet10', -- modifier
 '2002-09-09 01:06:51',            -- mod_datetime
 '',                               -- reps
-'HTML',                           -- rep_type
 'TEST.FileLink.3, TEST.FileLink.4', -- files
 'presentation',                   -- rep_purpose
 'True',                           -- generable

From waterbug at step.nasa.gov  Mon May 23 02:58:05 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 23 02:58:07 2005
Subject: [pangalactic-commits] wxversion only in PanGalaxian.
Message-ID: <200505230658.j4N6w5i7012767@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py 1.7 1.8

Log message:
wxversion only in PanGalaxian.

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.7 PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.8
--- PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py:1.7	Thu May 19 04:50:16 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnstatusbar.py	Mon May 23 02:58:03 2005
@@ -1,18 +1,16 @@
-# $Id: pgxnstatusbar.py,v 1.7 2005/05/19 08:50:16 waterbug Exp $
+# $Id: pgxnstatusbar.py,v 1.8 2005/05/23 06:58:03 waterbug Exp $
 
 """
 Custom status bar for PanGalaxian (the PGEF desktop client).
 
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 # Python core modules
 from pprint import pprint
 
 # wxPython
-import wxversion
-wxversion.select("2.5")
 import wx
 
 # PanGalactic modules

From waterbug at step.nasa.gov  Mon May 23 03:13:34 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 23 03:13:36 2005
Subject: [pangalactic-commits] See if this solves flicker problem ...
Message-ID: <200505230713.j4N7DY9a012830@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.14 1.15

Log message:
See if this solves flicker problem ...

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.14 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.15
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.14	Sat May 21 04:17:37 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Mon May 23 03:13:33 2005
@@ -1,9 +1,9 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.14 $
+@version: $Revision: 1.15 $
 """
-__version__ = "$Revision: 1.14 $"[11:-2]
+__version__ = "$Revision: 1.15 $"[11:-2]
 
 
 import  wx
@@ -22,7 +22,7 @@
     def __init__(self, parent):
         wx.Panel.__init__(self, parent, -1)
         minor = wx.SashLayoutWindow(self, -1, wx.DefaultPosition,
-                                    (-1,-1), wx.NO_BORDER|wx.SW_3D)
+                                    (-1,-1), wx.NO_BORDER|wx.SW_3D|wx.CLIP_CHILDREN)
         minor.SetDefaultSize((220, 600))
         minor.SetOrientation(wx.LAYOUT_VERTICAL)
         minor.SetAlignment(wx.LAYOUT_LEFT)

From waterbug at step.nasa.gov  Mon May 23 11:10:40 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 23 11:10:43 2005
Subject: [pangalactic-commits] See if this affects the M$Win problem.
Message-ID: <200505231510.j4NFAepf018867@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.15 1.16

Log message:
See if this affects the M$Win problem.

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.15 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.16
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.15	Mon May 23 03:13:33 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Mon May 23 11:10:39 2005
@@ -1,9 +1,9 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.15 $
+@version: $Revision: 1.16 $
 """
-__version__ = "$Revision: 1.15 $"[11:-2]
+__version__ = "$Revision: 1.16 $"[11:-2]
 
 
 import  wx
@@ -22,7 +22,7 @@
     def __init__(self, parent):
         wx.Panel.__init__(self, parent, -1)
         minor = wx.SashLayoutWindow(self, -1, wx.DefaultPosition,
-                                    (-1,-1), wx.NO_BORDER|wx.SW_3D|wx.CLIP_CHILDREN)
+                                    (-1,-1), wx.NO_BORDER|wx.SW_3D)
         minor.SetDefaultSize((220, 600))
         minor.SetOrientation(wx.LAYOUT_VERTICAL)
         minor.SetAlignment(wx.LAYOUT_LEFT)
@@ -33,7 +33,6 @@
         self.gridbook = PgxnNotebook(self)
         self.Bind(wx.EVT_SASH_DRAGGED, self.onSashDrag, self.minorpane)
         self.Bind(wx.EVT_SIZE, self.onSize)
-        self.sizeChanged = True
 
     def onSashDrag(self, event):
         self.minorpane.SetDefaultSize((event.GetDragRect().width, 1000))
@@ -121,7 +120,7 @@
     # live simulation diagrams, (6) [ho hum] various UML/SysML diagrams.
     def __init__(self, parent, objs=None):
         wx.Notebook.__init__(self, parent, -1, pos=wx.DefaultPosition,
-                             size=wx.Size(600,600))
+                             size=wx.Size(600,600), wx.CLIP_CHILDREN)
         self.pages = {}
         if not objs:
             self.objs = []

From waterbug at step.nasa.gov  Mon May 23 13:09:58 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 23 13:10:00 2005
Subject: [pangalactic-commits] try this ...
Message-ID: <200505231709.j4NH9wI6020974@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/psm/psmtool.py 1.32 1.33
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.16 1.17

Log message:
try this ...

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.16 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.17
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.16	Mon May 23 11:10:39 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Mon May 23 13:09:56 2005
@@ -1,9 +1,9 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.16 $
+@version: $Revision: 1.17 $
 """
-__version__ = "$Revision: 1.16 $"[11:-2]
+__version__ = "$Revision: 1.17 $"[11:-2]
 
 
 import  wx
@@ -22,13 +22,14 @@
     def __init__(self, parent):
         wx.Panel.__init__(self, parent, -1)
         minor = wx.SashLayoutWindow(self, -1, wx.DefaultPosition,
-                                    (-1,-1), wx.NO_BORDER|wx.SW_3D)
+                                    (200,30), wx.NO_BORDER|wx.SW_3D)
         minor.SetDefaultSize((220, 600))
         minor.SetOrientation(wx.LAYOUT_VERTICAL)
         minor.SetAlignment(wx.LAYOUT_LEFT)
         minor.SetSashVisible(wx.SASH_RIGHT, True)
         self.treebook = PgxnTreeBook(minor)
-        self.treebook.Fit()
+        # this appears to do *nothing*!
+        # self.treebook.Fit()
         self.minorpane = minor
         self.gridbook = PgxnNotebook(self)
         self.Bind(wx.EVT_SASH_DRAGGED, self.onSashDrag, self.minorpane)
@@ -65,7 +66,8 @@
     def __init__(self, parent, treeviews=None):
         wx.Choicebook.__init__(self, parent, -1,
                                pos=wx.DefaultPosition,
-                               size=wx.Size(250,600))
+                               size=wx.Size(250,600),
+                               style=wx.CLIP_CHILDREN)
         self.treeviews = treeviews or []
         self.trees = {}
         if not treeviews:
@@ -120,7 +122,7 @@
     # live simulation diagrams, (6) [ho hum] various UML/SysML diagrams.
     def __init__(self, parent, objs=None):
         wx.Notebook.__init__(self, parent, -1, pos=wx.DefaultPosition,
-                             size=wx.Size(600,600), wx.CLIP_CHILDREN)
+                             size=wx.Size(600,600), style=wx.CLIP_CHILDREN)
         self.pages = {}
         if not objs:
             self.objs = []

Index: PanGalactic/pangalactic/node/gui/psm/psmtool.py
diff -u PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.32 PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.33
--- PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.32	Mon May 16 17:34:41 2005
+++ PanGalactic/pangalactic/node/gui/psm/psmtool.py	Mon May 23 13:09:56 2005
@@ -1,10 +1,10 @@
-# $Id: psmtool.py,v 1.32 2005/05/16 21:34:41 waterbug Exp $
+# $Id: psmtool.py,v 1.33 2005/05/23 17:09:56 waterbug Exp $
 # Originally Created 04/05/2001
 """
 PSM Tool is the Product Structure Manager.  It handles visualization,
 navigation, and editing of product structures.
 """
-__version__ = "$Revision: 1.32 $"[11:-2]
+__version__ = "$Revision: 1.33 $"[11:-2]
 
 import os
 import sys
@@ -104,7 +104,9 @@
         self.notebook.AddPage(self.modelgrid, "Models")
         # remove funny blank space in the first row of the grid, if it
         # initially has a scrollbar
-        self.modelgrid.Fit()
+# just for grins, comment this out ...
+# hmmm ... wadayaknow?  it doesn't seem to do *anything*!
+#        self.modelgrid.Fit()
         # Create Grid to hold Parts
         self.partgrid = basegrid.BaseGrid(self.notebook, -1,
                                           classname="Part",

From waterbug at step.nasa.gov  Mon May 23 13:58:47 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 23 13:58:49 2005
Subject: [pangalactic-commits] try a couple more things ...
Message-ID: <200505231758.j4NHwlft021397@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian.py 1.57 1.58
PanGalactic/pangalactic/node/pangalaxian_new.py 1.21 1.22

Log message:
try a couple more things ...

Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.57 PanGalactic/pangalactic/node/pangalaxian.py:1.58
--- PanGalactic/pangalactic/node/pangalaxian.py:1.57	Wed May 18 16:13:25 2005
+++ PanGalactic/pangalactic/node/pangalaxian.py	Mon May 23 13:58:45 2005
@@ -1,13 +1,13 @@
 #!/usr/bin/env python 
 
-# $Id: pangalaxian.py,v 1.57 2005/05/18 20:13:25 waterbug Exp $
+# $Id: pangalaxian.py,v 1.58 2005/05/23 17:58:45 waterbug Exp $
 
 """
 Main application module for the PGEF desktop client.
 
-@version: $Revision: 1.57 $
+@version: $Revision: 1.58 $
 """
-__version__ = "$Revision: 1.57 $"[11:-2]
+__version__ = "$Revision: 1.58 $"[11:-2]
 
 import sys
 import os
@@ -993,7 +993,8 @@
         self.frame.Show(True)
 
         self.SetTopWindow(self.frame)
-        self.frame.ConfigureStatusBar(self.frame.sb.GetSizeTuple()[0])
+        # this appears to do *nothing* ...
+        # self.frame.ConfigureStatusBar(self.frame.sb.GetSizeTuple()[0])
         return True
 
 #----------------------------------------------------------------------------

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.21 PanGalactic/pangalactic/node/pangalaxian_new.py:1.22
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.21	Mon May 23 01:26:59 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Mon May 23 13:58:45 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.21 2005/05/23 05:26:59 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.22 2005/05/23 17:58:45 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.21 $
+@version: $Revision: 1.22 $
 """
-__version__ = "$Revision: 1.21 $"[11:-2]
+__version__ = "$Revision: 1.22 $"[11:-2]
 
 # Python core modules
 import sys
@@ -83,11 +83,9 @@
         (TODO:  define ITreeViewer)
     """
 
-    def __init__(self, *args, **kwds):
+    def __init__(self, parent, title, pos, size):
         # begin wxGlade: PgxnFrame.__init__
-        kwds["style"] = wx.DEFAULT_FRAME_STYLE
-        wx.Frame.__init__(self, *args, **kwds)
-        
+        wx.Frame.__init__(self, parent, -1, title, pos, size)
         # Menu Bar
         self.menubar = wx.MenuBar()
         self.SetMenuBar(self.menubar)
@@ -310,7 +308,7 @@
         Bind all PanGalaxian events to handlers here.
         """
         # first, some important generic gui events
-        self.Bind(wx.EVT_SIZE, self.onSize)
+        # self.Bind(wx.EVT_SIZE, self.onSize)
         ###################################################
         # bind menu events
         # (note:  all PanGalaxian menu event names begin with 'menu_')
@@ -376,10 +374,10 @@
 
     # Event handlers
 
-    def onSize(self, event):
-        self.SetSize(self.GetClientSize())
-        #wx.LayoutAlgorithm().LayoutWindow(self, self.notebook) 
-        self.Layout()
+    # def onSize(self, event):
+    #     self.SetSize(self.GetClientSize())
+    #     # wx.LayoutAlgorithm().LayoutWindow(self.mainwin, self.mainwin.gridbook)
+    #     self.Layout()
 
     def onNewPart(self, event):
         """
@@ -682,19 +680,18 @@
         objs = self.dm.getObjectsByProject(state['project'])
         self.onModelChange(objs)
 
-
 # end of class PgxnFrame
 
+
 class PanGalaxian(wx.App):
 
     def OnInit(self):
-        self.frame = PgxnFrame(None, -1,
+        self.frame = PgxnFrame(None,
                                APP_NAME + ' ... to infinity, and beyond!',
                                wx.DefaultPosition,
                                wx.Size(800, 600))
         self.frame.CentreOnParent()
         self.frame.Show(True)
-
         self.SetTopWindow(self.frame)
         return True
 

From waterbug at step.nasa.gov  Mon May 23 22:41:18 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Mon May 23 22:41:20 2005
Subject: [pangalactic-commits] This guy needed splitting off.
Message-ID: <200505240241.j4O2fIPa027817@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgxnchoice.py None 1.1

Log message:
This guy needed splitting off.

From waterbug at step.nasa.gov  Tue May 24 03:15:49 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May 24 03:15:51 2005
Subject: [pangalactic-commits] Repository selection dialog is operational!
Message-ID: <200505240715.j4O7Fn8T029616@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.22 1.23
PanGalactic/pangalactic/node/gui/psm/psmtool.py 1.33 1.34
PanGalactic/pangalactic/node/gui/widgets/pgxnchoice.py 1.1 1.2
PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py 1.8 1.9

Log message:
Repository selection dialog is operational!

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.22 PanGalactic/pangalactic/node/pangalaxian_new.py:1.23
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.22	Mon May 23 13:58:45 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Tue May 24 03:15:47 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.22 2005/05/23 17:58:45 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.23 2005/05/24 07:15:47 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.22 $
+@version: $Revision: 1.23 $
 """
-__version__ = "$Revision: 1.22 $"[11:-2]
+__version__ = "$Revision: 1.23 $"[11:-2]
 
 # Python core modules
 import sys
@@ -30,6 +30,7 @@
 # PanGalactic modules
 from pangalactic.core.person import Person
 from pangalactic.node.gui.dialogs.login import LoginDialog
+from pangalactic.node.gui.dialogs.reposelect import RepoSelectDialog
 from pangalactic.node.gui.state import state, writeState
 from pangalactic.node.gui.state import prefs, displaymaps
 from pangalactic.node.gui.widgets.cachebrowser  import CacheBrowser
@@ -274,7 +275,7 @@
         self.statusbar = PgxnStatusBar(self)
         self.SetStatusBar(self.statusbar)
         self.toolbar = PgxnToolBar(self)
-        self.mainwin = PgxnPanes(self) # might not need a ref to mainwin
+        self.mainwin = PgxnPanes(self)
         # TODO:  the following widgets might be made dynamic later (e.g.,
         # which ones appear might be a user preference) if a more
         # configurable UI is desired ... maybe a plugin interface too.
@@ -307,8 +308,6 @@
         """
         Bind all PanGalaxian events to handlers here.
         """
-        # first, some important generic gui events
-        # self.Bind(wx.EVT_SIZE, self.onSize)
         ###################################################
         # bind menu events
         # (note:  all PanGalaxian menu event names begin with 'menu_')
@@ -345,8 +344,8 @@
         # Repository menu
         # self.Bind(wx.EVT_MENU, self.onCommit, self.repo_commit)
         # self.Bind(wx.EVT_MENU, self.onGetMyStuff, self.repo_getmystuff)
-        # self.Bind(wx.EVT_MENU, self.onSelectRepo, self.repo_selectrepo)
-        #                      was: onServerSettings
+        self.Bind(wx.EVT_MENU, self.onSelectRepo, self.repo_selectrepo)
+        #
         # Cache menu
         self.Bind(wx.EVT_MENU, self.onCacheBrowse, self.cache_browse)
         self.Bind(wx.EVT_MENU, self.onCacheClear, self.cache_clear)
@@ -374,11 +373,6 @@
 
     # Event handlers
 
-    # def onSize(self, event):
-    #     self.SetSize(self.GetClientSize())
-    #     # wx.LayoutAlgorithm().LayoutWindow(self.mainwin, self.mainwin.gridbook)
-    #     self.Layout()
-
     def onNewPart(self, event):
         """
         Create a new instance of Part.
@@ -524,6 +518,14 @@
             self.closing = True
             self.Close(True)
 
+    def onSelectRepo(self, event):
+        """
+        Dialog for user to select or add a repository service.
+        """
+        dlg = RepoSelectDialog(self)
+        dlg.ShowModal()
+        dlg.Destroy()
+
     def onCacheBrowse(self, event):
         print "PanGalaxian.OnCacheBrowse"
         tmpsize = wx.Size(750, 500)

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnchoice.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnchoice.py:1.1 PanGalactic/pangalactic/node/gui/widgets/pgxnchoice.py:1.2
--- PanGalactic/pangalactic/node/gui/widgets/pgxnchoice.py:1.1	Mon May 23 22:41:16 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnchoice.py	Tue May 24 03:15:48 2005
@@ -1,9 +1,9 @@
 """
 PanGalaxian's custom choice widget
 
-@version: $Revision: 1.1 $
+@version: $Revision: 1.2 $
 """
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.2 $"[11:-2]
 
 import wx
 
@@ -13,13 +13,15 @@
     Multi-purpose choice widget for PanGalaxian tool bar.
 
     @param label:  C{str} to fill in '[No ___]' when empty
-    @param size:  size of the widget (a C{tuple} of 2 C{int}s)
+    @param size:   size of the widget (a C{tuple} of 2 C{int}s)
     @param items:  a C{list} of C{str}s to fill the widget choices
+    @param any:    if True, include 'Any' in choices; else not
     """
-    def __init__(self, parent, label, size, items=None):
+    def __init__(self, parent, label, size, items=None, any=True):
         wx.Choice.__init__(self, parent, -1, wx.DefaultPosition,
                            wx.Size(*size), [], 0)
         self.label = label
+        self.any = any
         if items:
             self.items = items
         else:
@@ -47,7 +49,8 @@
             self.Append('[No %s]' % self.label)
             self.Enable(True)
             return
-        self.Append('Any')
+        if self.any:
+            self.Append('Any')
         for v in val:
             self.Append(v)
         self.SetFont(wx.Font(10, family=wx.SWISS,

Index: PanGalactic/pangalactic/node/gui/psm/psmtool.py
diff -u PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.33 PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.34
--- PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.33	Mon May 23 13:09:56 2005
+++ PanGalactic/pangalactic/node/gui/psm/psmtool.py	Tue May 24 03:15:47 2005
@@ -1,10 +1,10 @@
-# $Id: psmtool.py,v 1.33 2005/05/23 17:09:56 waterbug Exp $
+# $Id: psmtool.py,v 1.34 2005/05/24 07:15:47 waterbug Exp $
 # Originally Created 04/05/2001
 """
 PSM Tool is the Product Structure Manager.  It handles visualization,
 navigation, and editing of product structures.
 """
-__version__ = "$Revision: 1.33 $"[11:-2]
+__version__ = "$Revision: 1.34 $"[11:-2]
 
 import os
 import sys
@@ -140,10 +140,10 @@
         self.topWindow = win
         # A window to the left of the client window to hold our tree
         win = wx.SashLayoutWindow(self,
-                                 self.ID_WINDOW_LEFT,
-                                 wx.DefaultPosition,
-                                 wx.Size(200, 30),
-                                 wx.NO_BORDER|wx.SW_3D)
+                                  self.ID_WINDOW_LEFT,
+                                  wx.DefaultPosition,
+                                  wx.Size(200, 30),
+                                  wx.NO_BORDER|wx.SW_3D)
         win.SetDefaultSize(wx.Size(220, 600))
         win.SetOrientation(wx.LAYOUT_VERTICAL)
         win.SetAlignment(wx.LAYOUT_LEFT)
@@ -152,10 +152,10 @@
         hbox = wx.BoxSizer(wx.VERTICAL)
         choice_list = ["Physical Design", "Requirements", "Functions", "Simulations"]
         self.view = wx.Choice(self.leftPanel,
-                             ID_CHOICE_VIEW,
-                             wx.Point(90, 50),
-                             wx.Size(95, -1),
-                             choice_list)
+                              ID_CHOICE_VIEW,
+                              wx.Point(90, 50),
+                              wx.Size(95, -1),
+                              choice_list)
         hbox.Add(self.view, 0, wx.EXPAND)
         self.tree_notebook = wx.Notebook(self.leftPanel,
                                         -1,

Index: PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.8 PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.9
--- PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py:1.8	Fri May 20 16:58:03 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxntoolbar.py	Tue May 24 03:15:48 2005
@@ -1,12 +1,13 @@
 """
 PanGalaxian's custom toolbar
 
-@version: $Revision: 1.8 $
+@version: $Revision: 1.9 $
 """
-__version__ = "$Revision: 1.8 $"[11:-2]
+__version__ = "$Revision: 1.9 $"[11:-2]
 
 import wx
 from pangalactic.node.gui.state import state, prefs
+from pangalactic.node.gui.widgets.pgxnchoice import PgxnChoice
 
 
 class PgxnToolBar(wx.Panel):
@@ -27,20 +28,20 @@
                                  wx.DefaultPosition, wx.DefaultSize, 0)
         fgsizer.Add(projtext, 0,
             wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.TOP|wx.BOTTOM, 5)
-        projwgt = PgefChoiceWidget(self, 'Project', size=(-1, -1))
+        projwgt = PgxnChoice(self, 'Project', size=(-1, -1))
         fgsizer.Add(projwgt, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
-        systext = wx.StaticText(self, -1, "System:",
-                                wx.DefaultPosition, wx.DefaultSize, 0)
-        fgsizer.Add(systext, 0,
-                    wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
-        syswgt = PgefChoiceWidget(self, 'System', size=(-1, -1))
-        fgsizer.Add(syswgt, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
         viewtext = wx.StaticText(self, -1, "View:",
                                  wx.DefaultPosition, wx.DefaultSize, 0)
         fgsizer.Add(viewtext, 0,
                     wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
-        viewwgt = PgefChoiceWidget(self, 'View', size=(-1, -1))
+        viewwgt = PgxnChoice(self, 'View', size=(-1, -1))
         fgsizer.Add(viewwgt, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
+        systext = wx.StaticText(self, -1, "System:",
+                                wx.DefaultPosition, wx.DefaultSize, 0)
+        fgsizer.Add(systext, 0,
+                    wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
+        syswgt = PgxnChoice(self, 'System', size=(-1, -1))
+        fgsizer.Add(syswgt, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
         self.SetAutoLayout(True)
         self.SetSizer(fgsizer)
         fgsizer.Fit(self)
@@ -58,56 +59,3 @@
         self.projectwidget.SetStringSelection(state['project'])
 
 
-class PgefChoiceWidget(wx.Choice):
-    """
-    Multi-purpose choice widget for PanGalaxian tool bar.
-
-    @param label:  C{str} to fill in '[No ___]' when empty
-    @param size:  size of the widget (a C{tuple} of 2 C{int}s)
-    @param items:  a C{list} of C{str}s to fill the widget choices
-    """
-    def __init__(self, parent, label, size, items=None):
-        wx.Choice.__init__(self, parent, -1, wx.DefaultPosition,
-                           wx.Size(*size), [], 0)
-        # self.SetForegroundColour('WHITE')
-        # self.SetBackgroundColour('BLUE')
-        self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL))
-        self.label = label
-        if items:
-            self.items = items
-        else:
-            self.items = []
-
-    # properties
-
-    def get_items(self):
-        """
-        Get choice items.
-
-        @param val:  C{list} of C{str}
-        """
-        return self.__items
-
-    def set_items(self, val):
-        """
-        Set choice items.
-
-        @param val:  C{list} of C{str}
-        """
-        self.__items = val
-        self.Clear()
-        if len(val) == 0:
-            self.Append('[No %s]' % self.label)
-            self.Enable(True)
-            return
-        self.Append('Any')
-        for v in val:
-            self.Append(v)
-        self.Enable(True)
-        self.SetSelection(0)
-
-    def del_items():
-        raise TypeError, 'Cannot delete items attribute.'
-
-    items = property(get_items, set_items, del_items, 'items')
-

From waterbug at step.nasa.gov  Tue May 24 03:21:01 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May 24 03:21:02 2005
Subject: [pangalactic-commits] Tiny doc tweak.
Message-ID: <200505240721.j4O7L1pN029664@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian_new.py 1.23 1.24

Log message:
Tiny doc tweak.

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.23 PanGalactic/pangalactic/node/pangalaxian_new.py:1.24
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.23	Tue May 24 03:15:47 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Tue May 24 03:21:00 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.23 2005/05/24 07:15:47 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.24 2005/05/24 07:21:00 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.23 $
+@version: $Revision: 1.24 $
 """
-__version__ = "$Revision: 1.23 $"[11:-2]
+__version__ = "$Revision: 1.24 $"[11:-2]
 
 # Python core modules
 import sys
@@ -520,7 +520,9 @@
 
     def onSelectRepo(self, event):
         """
-        Dialog for user to select or add a repository service.
+        Dialog for user to add or delete a repository server from the list
+        of known servers or to set one as the preferred server.  (This
+        operates on the state and prefs dictionaries.)
         """
         dlg = RepoSelectDialog(self)
         dlg.ShowModal()

From waterbug at step.nasa.gov  Tue May 24 03:36:04 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Tue May 24 03:36:05 2005
Subject: [pangalactic-commits] Oops, forgot to add this guy.
Message-ID: <200505240736.j4O7a4Pn029944@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/dialogs/reposelect.py None 1.1

Log message:
Oops, forgot to add this guy.

From waterbug at step.nasa.gov  Wed May 25 02:08:25 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May 25 02:08:26 2005
Subject: [pangalactic-commits] PgefObjectGrid now (finally!) works on bloody
	wankin' MS Windows!
Message-ID: <200505250608.j4P68P8B011787@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.13 1.14
PanGalactic/pangalactic/utils/utils.py 1.13 1.14

Log message:
PgefObjectGrid now (finally!) works on bloody wankin' MS Windows!
Praise be to the Python gods for their gift of *curry* (Alex et al.!).

Index: PanGalactic/pangalactic/utils/utils.py
diff -u PanGalactic/pangalactic/utils/utils.py:1.13 PanGalactic/pangalactic/utils/utils.py:1.14
--- PanGalactic/pangalactic/utils/utils.py:1.13	Sun Oct 10 23:38:18 2004
+++ PanGalactic/pangalactic/utils/utils.py	Wed May 25 02:08:23 2005
@@ -1,8 +1,32 @@
+# $Id: utils.py,v 1.14 2005/05/25 06:08:23 waterbug Exp $
 """
 PGEF utility programs
+
+@version: $Revision: 1.14 $
 """
+__version__ = "$Revision: 1.14 $"[11:-2]
+
 
-# $Id: utils.py,v 1.13 2004/10/11 03:38:18 waterbug Exp $
+class curry:
+    """
+    Obtain a new callable from an existing callable by pre-setting the
+    values of some of its arguments.  This is a recipe from the Python
+    Cookbook (1st edition), p. 463, authors:  Scott David Daniels, Ben
+    Wolfson, Nick Perkins, and Alex Martelli.  Thanks, guys!  :)
+    """
+
+    def __init__(self, fun, *args, **kwargs):
+        self.fun = fun
+        self.pending = args[:]
+        self.kwargs = kwargs.copy()
+
+    def __call__(self, *args, **kwargs):
+        if kwargs and self.kwargs:
+            kw = self.kwargs.copy()
+            kw.update(kwargs)
+        else:
+            kw = kwargs or self.kwargs
+        return self.fun(*(self.pending + args), **kw)
 
 
 def compareSequence1(left, right):

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.13 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.14
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.13	Mon May 23 01:27:00 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Wed May 25 02:08:23 2005
@@ -1,10 +1,10 @@
-# $Id: pgefobjectgrid.py,v 1.13 2005/05/23 05:27:00 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.14 2005/05/25 06:08:23 waterbug Exp $
 """
 The PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.13 $
+@version: $Revision: 1.14 $
 """
-__version__ = "$Revision: 1.13 $"[11:-2]
+__version__ = "$Revision: 1.14 $"[11:-2]
 
 from pprint import pprint
 
@@ -14,6 +14,8 @@
 
 from pangalactic.node.gui.state import state, prefs, displaymaps
 from pangalactic.meta.factory import PanGalacticFactory as Factory
+from pangalactic.utils.utils import curry
+
 
 class PgefObjectTable(gridlib.PyGridTableBase):
     """
@@ -51,26 +53,27 @@
         """
         Generate column labels and data based on the current set of objects.
         """
-        # print '- in PgefObjectTable.setup'
+        print '- in PgefObjectTable.setup'
         if self.objs:
             self.row_labels = [str(i) for i in range(1, len(self.objs)+1)]
             # assumption that all objs have the same schema (see TODO)
             self.schema = self.objs[0]._schema
+            print '   self.schema:', self.schema.id
             # if there is a current displaymap set for the schema, use it
             self.displaymap = (displaymaps.get(self.schema.id, None)
                                or self.schema._default_display_map)
-            # print '  - self.displaymap:'
-            # pprint(self.displaymap)
+            print '  - self.displaymap:'
+            pprint(self.displaymap)
             self.identifiers = [x[0] for x in self.displaymap]
-            # print '  - self.identifiers:', self.identifiers
+            print '  - self.identifiers:', self.identifiers
             self.col_labels = dict([(x[0], x[1]) for x in self.displaymap])
             extracts = [self.fac.extract(o) for o in self.objs]
             self.data = [dict([(i, e.get(i, '')) for i in self.identifiers])
                          for e in extracts]
-            # print '  - self.data:'
-            # pprint(self.data)
-            # print '  - self.objs:'
-            # print self.objs
+            print '  - self.data:'
+            pprint(self.data)
+            print '  - self.objs:'
+            print self.objs
         else:
             self.data = []
             self.schema = None
@@ -151,8 +154,8 @@
         (Grid) -> Reset the grid view.   Called to update the grid if rows
         and/or columns have been added or deleted in the underlying model.
         """
-        # print '- in PgefObjectTable.ResetView'
-        # print '  - self.identifiers:', self.identifiers
+        print '- in PgefObjectTable.ResetView'
+        print '  - self.identifiers:', self.identifiers
         grid.BeginBatch()
         for current, new, delmsg, addmsg in [
             (self._rows, self.GetNumberRows(), gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED, gridlib.GRIDTABLE_NOTIFY_ROWS_APPENDED),
@@ -173,7 +176,7 @@
         # update the scrollbars and the displayed part of the grid
         grid.AdjustScrollbars()
         grid.ForceRefresh()
-        # print '  - (at end) self.identifiers:', self.identifiers
+        print '  - (at end) self.identifiers:', self.identifiers
 
     def UpdateValues(self, grid):
         """
@@ -332,38 +335,35 @@
         Display the grid popup menu when the upper left label area is
         right-clicked.
         """
-        # print '- in PgefObjectGrid.gridPopup'
+        print '- in PgefObjectGrid.gridPopup'
         self.grid_menu = wx.Menu()
         self.visible_cols_menu = wx.Menu()
         self.grid_menu.AppendMenu(-1, 'Visible Columns',
                                   self.visible_cols_menu,
                                   'Select columns to be visible in grid')
-        self.visible_cols = {}
         labels = [self.schema[i].display_name for i in self.schema]
         labels.sort()
         label_ids = dict([(self.schema[i].display_name, i) for i in self.schema])
         # first, set checked menu items for visible columns
         for id in self.identifiers:
-            # print '  - adding checked label:', label
             label = self.schema[id].display_name
+            print '  - adding checked label:', label
             labels.remove(label)
-            self.visible_cols[label] = self.visible_cols_menu.Append(
-                                                       -1, label,
-                                                       label_ids[label],
-                                                        wx.ITEM_CHECK)
-            self.visible_cols[label].Check(True)
-            self.Bind(wx.EVT_MENU, self.onSetVisibleCols,
-                      self.visible_cols[label])
+            item = self.visible_cols_menu.Append(-1, label,
+                                                 label_ids[label],
+                                                 wx.ITEM_CHECK)
+            item.Check(True)
+            handler = curry(self.onSetVisibleCols, dn=label)
+            self.Bind(wx.EVT_MENU, handler, item)
         self.visible_cols_menu.AppendSeparator()
         # then, set items for remaining (unchecked) attributes
         for label in labels:
-            # print '  - adding label:', label
-            self.visible_cols[label] = self.visible_cols_menu.Append(
-                                                       -1, label,
-                                                       label_ids[label],
-                                                        wx.ITEM_CHECK)
-            self.Bind(wx.EVT_MENU, self.onSetVisibleCols,
-                      self.visible_cols[label])
+            print '  - adding label:', label
+            item = self.visible_cols_menu.Append(-1, label,
+                                                 label_ids[label],
+                                                 wx.ITEM_CHECK)
+            handler = curry(self.onSetVisibleCols, dn=label)
+            self.Bind(wx.EVT_MENU, handler, item)
         self.save_pref = self.grid_menu.Append(-1, 'Save As Preference',
               'Use the current column config as your preference for %s' % (
                                                           self.schema.id),
@@ -386,8 +386,8 @@
         epos = evt.GetPosition()
         pos = (epos[0] - 80, epos[1] - 30)
         self.PopupMenu(self.grid_menu, pos)
-        self.grid_menu.Destroy()
         self.reset()
+        self.grid_menu.Destroy()
 
     def colPopupHelp(self, col, evt):
         """
@@ -402,32 +402,28 @@
         self.reset()
         self.ClearSelection()
 
-    def onSetVisibleCols(self, evt):
+    def onSetVisibleCols(self, evt, dn=None):
         """
         Add or delete a column to/from the grid in response to a grid menu
         selection.
         """
-        # print ' - onSetVisibleCols'
+        print ' - onSetVisibleCols'
         properties = dict([(self.schema[a].display_name, self.schema[a])
                             for a in self.schema])
-        # find out if a display name was just checked
-        dn_checked = ''
-        for dn in properties:
-            if (self.visible_cols[dn].IsChecked()
-                and not dn in self.col_labels.values()):
-                # add its column to the end (okay, might be better at the
-                # beginning ... we'll see what people say)
-                dn_checked = dn
-                displaymaps[self.schema.id].append(
-                    [properties[dn].id,
-                     properties[dn].display_name,
-                     properties[dn].range])
-        # or if something was unchecked
-        if not dn_checked:
-            displaymaps[self.schema.id] = []
-            for dn in [self.col_labels[i] for i in self.identifiers]:
-                if self.visible_cols[dn].IsChecked():
-                    displaymaps[self.schema.id].append(
+        print '   selection is:', dn
+        if dn not in self.col_labels.values():
+            print '   adding it to visible cols'
+            # add its column to the end (okay, might be better at the
+            # beginning ... we'll see what people say)
+            displaymaps[self.schema.id].append(
+                [properties[dn].id,
+                 properties[dn].display_name,
+                 properties[dn].range])
+        else:
+            print '   deleting it from visible cols'
+            for name in [self.col_labels[i] for i in self.identifiers]:
+                if dn == name:
+                    displaymaps[self.schema.id].remove(
                         [properties[dn].id,
                          properties[dn].display_name,
                          properties[dn].range])

From waterbug at step.nasa.gov  Wed May 25 02:23:30 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May 25 02:23:32 2005
Subject: [pangalactic-commits] Can comment out some of those debug prints
	now ... :)
Message-ID: <200505250623.j4P6NUgj012087@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py 1.14 1.15

Log message:
Can comment out some of those debug prints now ... :)

Index: PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.14 PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.15
--- PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py:1.14	Wed May 25 02:08:23 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgefobjectgrid.py	Wed May 25 02:23:29 2005
@@ -1,10 +1,10 @@
-# $Id: pgefobjectgrid.py,v 1.14 2005/05/25 06:08:23 waterbug Exp $
+# $Id: pgefobjectgrid.py,v 1.15 2005/05/25 06:23:29 waterbug Exp $
 """
 The PGEF table-based, configurable, object-aware grid.
 
-@version: $Revision: 1.14 $
+@version: $Revision: 1.15 $
 """
-__version__ = "$Revision: 1.14 $"[11:-2]
+__version__ = "$Revision: 1.15 $"[11:-2]
 
 from pprint import pprint
 
@@ -53,27 +53,27 @@
         """
         Generate column labels and data based on the current set of objects.
         """
-        print '- in PgefObjectTable.setup'
+        # print '- in PgefObjectTable.setup'
         if self.objs:
             self.row_labels = [str(i) for i in range(1, len(self.objs)+1)]
             # assumption that all objs have the same schema (see TODO)
             self.schema = self.objs[0]._schema
-            print '   self.schema:', self.schema.id
+            # print '   self.schema:', self.schema.id
             # if there is a current displaymap set for the schema, use it
             self.displaymap = (displaymaps.get(self.schema.id, None)
                                or self.schema._default_display_map)
-            print '  - self.displaymap:'
-            pprint(self.displaymap)
+            # print '  - self.displaymap:'
+            # pprint(self.displaymap)
             self.identifiers = [x[0] for x in self.displaymap]
-            print '  - self.identifiers:', self.identifiers
+            # print '  - self.identifiers:', self.identifiers
             self.col_labels = dict([(x[0], x[1]) for x in self.displaymap])
             extracts = [self.fac.extract(o) for o in self.objs]
             self.data = [dict([(i, e.get(i, '')) for i in self.identifiers])
                          for e in extracts]
-            print '  - self.data:'
-            pprint(self.data)
-            print '  - self.objs:'
-            print self.objs
+            # print '  - self.data:'
+            # pprint(self.data)
+            # print '  - self.objs:'
+            # print self.objs
         else:
             self.data = []
             self.schema = None
@@ -154,8 +154,8 @@
         (Grid) -> Reset the grid view.   Called to update the grid if rows
         and/or columns have been added or deleted in the underlying model.
         """
-        print '- in PgefObjectTable.ResetView'
-        print '  - self.identifiers:', self.identifiers
+        # print '- in PgefObjectTable.ResetView'
+        # print '  - self.identifiers:', self.identifiers
         grid.BeginBatch()
         for current, new, delmsg, addmsg in [
             (self._rows, self.GetNumberRows(), gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED, gridlib.GRIDTABLE_NOTIFY_ROWS_APPENDED),
@@ -176,7 +176,7 @@
         # update the scrollbars and the displayed part of the grid
         grid.AdjustScrollbars()
         grid.ForceRefresh()
-        print '  - (at end) self.identifiers:', self.identifiers
+        # print '  - (at end) self.identifiers:', self.identifiers
 
     def UpdateValues(self, grid):
         """
@@ -335,7 +335,7 @@
         Display the grid popup menu when the upper left label area is
         right-clicked.
         """
-        print '- in PgefObjectGrid.gridPopup'
+        # print '- in PgefObjectGrid.gridPopup'
         self.grid_menu = wx.Menu()
         self.visible_cols_menu = wx.Menu()
         self.grid_menu.AppendMenu(-1, 'Visible Columns',
@@ -347,7 +347,7 @@
         # first, set checked menu items for visible columns
         for id in self.identifiers:
             label = self.schema[id].display_name
-            print '  - adding checked label:', label
+            # print '  - adding checked label:', label
             labels.remove(label)
             item = self.visible_cols_menu.Append(-1, label,
                                                  label_ids[label],
@@ -358,7 +358,7 @@
         self.visible_cols_menu.AppendSeparator()
         # then, set items for remaining (unchecked) attributes
         for label in labels:
-            print '  - adding label:', label
+            # print '  - adding label:', label
             item = self.visible_cols_menu.Append(-1, label,
                                                  label_ids[label],
                                                  wx.ITEM_CHECK)
@@ -382,7 +382,7 @@
                      wx.ITEM_NORMAL)
         self.Bind(wx.EVT_MENU, self.onResetPerDefaultDisplaymap,
                       self.reset_default)
-        print 'position:', evt.GetPosition()
+        # print 'position:', evt.GetPosition()
         epos = evt.GetPosition()
         pos = (epos[0] - 80, epos[1] - 30)
         self.PopupMenu(self.grid_menu, pos)
@@ -407,12 +407,12 @@
         Add or delete a column to/from the grid in response to a grid menu
         selection.
         """
-        print ' - onSetVisibleCols'
+        # print ' - onSetVisibleCols'
         properties = dict([(self.schema[a].display_name, self.schema[a])
                             for a in self.schema])
-        print '   selection is:', dn
+        # print '   selection is:', dn
         if dn not in self.col_labels.values():
-            print '   adding it to visible cols'
+            # print '   adding it to visible cols'
             # add its column to the end (okay, might be better at the
             # beginning ... we'll see what people say)
             displaymaps[self.schema.id].append(
@@ -420,7 +420,7 @@
                  properties[dn].display_name,
                  properties[dn].range])
         else:
-            print '   deleting it from visible cols'
+            # print '   deleting it from visible cols'
             for name in [self.col_labels[i] for i in self.identifiers]:
                 if dn == name:
                     displaymaps[self.schema.id].remove(
@@ -440,7 +440,7 @@
         Reset the current displaymap per the user's preferred displaymap
         for the current object schema.
         """
-        print ' - onResetPerPrefDisplaymap'
+        # print ' - onResetPerPrefDisplaymap'
         if prefs['displaymaps'].get(self.schema.id, None):
             displaymaps[self.schema.id] = prefs['displaymaps'][self.schema.id]
         else:
@@ -451,7 +451,7 @@
         Reset the current displaymap per the default displaymap for the
         current object schema.
         """
-        print ' - onResetPerDefaultDisplaymap'
+        # print ' - onResetPerDefaultDisplaymap'
         displaymaps[self.schema.id] = self.schema._default_display_map
 
 

From waterbug at step.nasa.gov  Wed May 25 12:09:36 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Wed May 25 12:09:37 2005
Subject: [pangalactic-commits] Twisted plugins are deprecated.
Message-ID: <200505251609.j4PG9ahX018992@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/plugins.tml 1.9 None

Log message:
Twisted plugins are deprecated.

From waterbug at step.nasa.gov  Fri May 27 00:46:52 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 27 00:46:54 2005
Subject: [pangalactic-commits] No more Twisted plugins or .tap files.
Message-ID: <200505270446.j4R4kqW9009201@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/pgertap.py 1.33 None
PanGalactic/pangalactic/node/pangalaxian_new.py 1.24 1.25
PanGalactic/pangalactic/node/pgerd 1.6 1.7
PanGalactic/pangalactic/node/bin/pger.tac None 1.1
PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py 1.8 1.9
PanGalactic/pangalactic/utils/datamanager.py 1.181 1.182

Log message:
No more Twisted plugins or .tap files.

Index: PanGalactic/pangalactic/node/pangalaxian_new.py
diff -u PanGalactic/pangalactic/node/pangalaxian_new.py:1.24 PanGalactic/pangalactic/node/pangalaxian_new.py:1.25
--- PanGalactic/pangalactic/node/pangalaxian_new.py:1.24	Tue May 24 03:21:00 2005
+++ PanGalactic/pangalactic/node/pangalaxian_new.py	Fri May 27 00:46:49 2005
@@ -2,16 +2,16 @@
 # -*- coding: ANSI_X3.4-1968 -*-
 # generated by wxGlade 0.3.5.1 on Tue Feb  1 00:19:02 2005
 
-# $Id: pangalaxian_new.py,v 1.24 2005/05/24 07:21:00 waterbug Exp $
+# $Id: pangalaxian_new.py,v 1.25 2005/05/27 04:46:49 waterbug Exp $
 
 """
 Main application module for PanGalaxian, the PGEF desktop client.
 
     WE ARE THE PANGALAXIANS!  :)
 
-@version: $Revision: 1.24 $
+@version: $Revision: 1.25 $
 """
-__version__ = "$Revision: 1.24 $"[11:-2]
+__version__ = "$Revision: 1.25 $"[11:-2]
 
 # Python core modules
 import sys
@@ -92,37 +92,12 @@
         self.SetMenuBar(self.menubar)
         self.file_menu = wx.Menu()
         self.menubar.Append(self.file_menu, "&File")
-        self.file_new_menu = wx.Menu()
-        self.file_menu.AppendMenu(-1, "&New", self.file_new_menu, "")
-        self.file_new_part      = self.file_new_menu.Append(-1, "&Part...", "Create a Part ...", wx.ITEM_NORMAL)
-        self.file_new_model     = self.file_new_menu.Append(-1, "&Model...", "Create a Model ...", wx.ITEM_NORMAL)
-        self.file_new_partslist = self.file_new_menu.Append(-1, "Parts &List...", "Create a new Parts List ...", wx.ITEM_NORMAL)
-        self.file_new_doc       = self.file_new_menu.Append(-1, "&Document...", "Create a new Document ...", wx.ITEM_NORMAL)
-        self.file_login         = self.file_menu.Append(-1, "Log&in...", "Login to hub ...", wx.ITEM_NORMAL)
-        self.file_logout        = self.file_menu.Append(-1, "Log&out", "Logout from hub ...", wx.ITEM_NORMAL)
-        self.file_export        = self.file_menu.Append(-1, "&Export", "Export file as ...", wx.ITEM_NORMAL)
-        self.file_exit          = self.file_menu.Append(-1, "E&xit", "Exit PanGalaxian ...", wx.ITEM_NORMAL)
+        self.file_object = self.file_menu.Append(-1, "&New Object...", "Create a New Object ...", wx.ITEM_NORMAL)
+        self.file_login  = self.file_menu.Append(-1, "Log&in...", "Login to hub ...", wx.ITEM_NORMAL)
+        self.file_logout = self.file_menu.Append(-1, "Log&out", "Logout from hub ...", wx.ITEM_NORMAL)
+        self.file_export = self.file_menu.Append(-1, "&Export", "Export file as ...", wx.ITEM_NORMAL)
+        self.file_exit   = self.file_menu.Append(-1, "E&xit", "Exit PanGalaxian ...", wx.ITEM_NORMAL)
         self.tools_menu = wx.Menu()
-        self.tools_part_menu = wx.Menu()
-        self.tools_menu.AppendMenu(-1, "&Parts", self.tools_part_menu, "")
-        self.tools_new_part  = self.tools_part_menu.Append(-1, "&New...", "Create a Part ...", wx.ITEM_NORMAL)
-        self.tools_edit_part = self.tools_part_menu.Append(-1, "&Edit...", "Edit a Part ...", wx.ITEM_NORMAL)
-        self.tools_view_part = self.tools_part_menu.Append(-1, "&View...", "View a Part ...", wx.ITEM_NORMAL)
-        self.tools_model_menu = wx.Menu()
-        self.tools_menu.AppendMenu(-1, "&Models", self.tools_model_menu, "")
-        self.tools_new_model  = self.tools_model_menu.Append(-1, "&New...", "Create a new Model ...", wx.ITEM_NORMAL)
-        self.tools_edit_model = self.tools_model_menu.Append(-1, "&Edit...", "Edit a Model ...", wx.ITEM_NORMAL)
-        self.tools_view_model = self.tools_model_menu.Append(-1, "&View...", "View a Model ...", wx.ITEM_NORMAL)
-        self.tools_partslist_menu = wx.Menu()
-        self.tools_menu.AppendMenu(-1, "Parts &Lists", self.tools_partslist_menu, "")
-        self.tools_new_partslist  = self.tools_partslist_menu.Append(-1, "&New...", "Create a Parts List ...", wx.ITEM_NORMAL)
-        self.tools_edit_partslist = self.tools_partslist_menu.Append(-1, "&Edit...", "Edit a Parts List ...", wx.ITEM_NORMAL)
-        self.tools_view_partslist = self.tools_partslist_menu.Append(-1, "&View...", "View a Parts List ...", wx.ITEM_NORMAL)
-        self.tools_doc_menu = wx.Menu()
-        self.tools_menu.AppendMenu(-1, "&Documents", self.tools_doc_menu, "")
-        self.tools_new_doc  = self.tools_doc_menu.Append(-1, "&New...", "Create a Document ...", wx.ITEM_NORMAL)
-        self.tools_edit_doc = self.tools_doc_menu.Append(-1, "&Edit...", "Edit a Document ...", wx.ITEM_NORMAL)
-        self.tools_view_doc = self.tools_doc_menu.Append(-1, "&View...", "View a Document ...", wx.ITEM_NORMAL)
         self.tools_menu.AppendSeparator()
         self.tools_search = self.tools_menu.Append(-1, "&Search...", "Search repository ...", wx.ITEM_NORMAL)
         self.tools_report = self.tools_menu.Append(-1, "&Report...", "Generate a PDF report from the grid contents ...", wx.ITEM_NORMAL)
@@ -313,30 +288,13 @@
         # (note:  all PanGalaxian menu event names begin with 'menu_')
         #
         # File menu
-        self.Bind(wx.EVT_MENU, self.onNewPart, self.file_new_part)
-        # self.Bind(wx.EVT_MENU, self.onNewModel, self.file_new_model)
-        # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.file_new_partslist)
-        # self.Bind(wx.EVT_MENU, self.onNewDocument, self.file_new_document)
+        self.Bind(wx.EVT_MENU, self.onNewObject, self.file_object)
         self.Bind(wx.EVT_MENU, self.openFullLoginDialog, self.file_login)
         self.Bind(wx.EVT_MENU, self.onLogout, self.file_logout)
         # self.Bind(wx.EVT_MENU, self.onExport, self.file_export)
         self.Bind(wx.EVT_MENU, self.onExit, self.file_exit)
         #
         # Tools menu
-        # TODO: jettison all this crap in favor of an object-aware
-        # create/edit/view tool !!
-        # self.Bind(wx.EVT_MENU, self.onNewPart, self.tools_new_part)
-        # self.Bind(wx.EVT_MENU, self.onEditPart, self.tools_edit_part)
-        # self.Bind(wx.EVT_MENU, self.onViewPart, self.tools_view_part)
-        # self.Bind(wx.EVT_MENU, self.onNewModel, self.tools_new_model)
-        # self.Bind(wx.EVT_MENU, self.onEditModel, self.tools_edit_model)
-        # self.Bind(wx.EVT_MENU, self.onViewModel, self.tools_view_model)
-        # self.Bind(wx.EVT_MENU, self.onNewPartsList, self.tools_new_partslist)
-        # self.Bind(wx.EVT_MENU, self.onEditPartsList, self.tools_edit_partslist)
-        # self.Bind(wx.EVT_MENU, self.onViewPartsList, self.tools_view_partslist)
-        # self.Bind(wx.EVT_MENU, self.onNewDocument, self.tools_new_document)
-        # self.Bind(wx.EVT_MENU, self.onEditDocument, self.tools_edit_document)
-        # self.Bind(wx.EVT_MENU, self.onViewDocument, self.tools_view_document)
         # self.Bind(wx.EVT_MENU, self.onReport, self.tools_report)
         #                      was: onGridToPdf
         # self.Bind(wx.EVT_MENU, self.onSearch, self.tools_search)
@@ -373,12 +331,11 @@
 
     # Event handlers
 
-    def onNewPart(self, event):
+    def onNewObject(self, event):
         """
-        Create a new instance of Part.
+        Create a new PgefObject instance.
         """
-        # TODO:  think about "New Object" instead of hard-coded special cases
-        print "PanGalaxian.onNewPart"
+        print "PanGalaxian.onNewObject"
 
     def onLogin(self, event):
         """

Index: PanGalactic/pangalactic/node/pgerd
diff -u PanGalactic/pangalactic/node/pgerd:1.6 PanGalactic/pangalactic/node/pgerd:1.7
--- PanGalactic/pangalactic/node/pgerd:1.6	Wed Mar  2 03:11:39 2005
+++ PanGalactic/pangalactic/node/pgerd	Fri May 27 00:46:49 2005
@@ -16,26 +16,11 @@
 case $1 in
     start)
         # start pgerd on http://[hostname]:8080
-        mktap --appname=pgerd \
-              pger --domains=PanGalactic,NARS \
-                   --home=$PGERHOME
-        mv pger.tap logs/
-        twistd --no_save \
+        twistd -y bin/pger.tac \
                --file=logs/pger.tap \
                --pidfile=logs/pgerd.pid \
-               --logfile=logs/pgerd.log
-        ;;
-    startsecure)
-        # start pgerd on https://[hostname]:8080
-        mktap --appname=pgerd \
-              pger --domains=PanGalactic,NARS \
-                   --home=$PGERHOME \
-                   --encrypted=1
-        mv pger.tap logs/
-        twistd --no_save \
-               --file=logs/pger.tap \
-               --pidfile=logs/pgerd.pid \
-               --logfile=logs/pgerd.log
+               --logfile=logs/pgerd.log \
+               --no_save
         ;;
     restart)
         # restart pgerd on http://[hostname]:8080
@@ -44,31 +29,11 @@
            logs/archive/log.`date +%Y%m%d.%H.%M`
         sleep 1
         rm logs/*.tap
-        mktap --appname=pgerd \
-              pger --domains=PanGalactic,NARS \
-                   --home=$PGERHOME
-        mv pger.tap logs/
-        twistd --no_save \
-               --file=logs/pger.tap \
-               --pidfile=logs/pgerd.pid \
-               --logfile=logs/pgerd.log
-        ;;
-    restartsecure)
-        # restart pgerd on https://[hostname]:8080
-        kill `cat logs/pgerd.pid`
-        mv logs/pgerd.log \
-           logs/archive/log.`date +%Y%m%d.%H.%M`
-        sleep 1
-        rm logs/*.tap
-        mktap --appname=pgerd \
-              pger --domains=PanGalactic,NARS \
-                   --home=$PGERHOME \
-                   --encrypted=1
-        mv pger.tap logs/
-        twistd --no_save \
+        twistd -y bin/pger.tac \
                --file=logs/pger.tap \
                --pidfile=logs/pgerd.pid \
-               --logfile=logs/pgerd.log
+               --logfile=logs/pgerd.log \
+               --no_save
         ;;
     stop)
         # stop pgerd and archive its log
@@ -76,7 +41,6 @@
         mv logs/pgerd.log \
            logs/archive/log.`date +%Y%m%d.%H.%M`
         sleep 1
-        rm logs/*.tap
         ;;
     *)
         # print help and exit

Index: PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py
diff -u PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.8 PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.9
--- PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py:1.8	Wed May 18 17:05:44 2005
+++ PanGalactic/pangalactic/node/gui/widgets/cachebrowser.py	Fri May 27 00:46:50 2005
@@ -1,5 +1,5 @@
 #!/bin/env python
-# $Id: cachebrowser.py,v 1.8 2005/05/18 21:05:44 waterbug Exp $
+# $Id: cachebrowser.py,v 1.9 2005/05/27 04:46:50 waterbug Exp $
 #----------------------------------------------------------------------------
 # Authors:      Ginny, Steve
 #----------------------------------------------------------------------------
@@ -7,9 +7,9 @@
 PanGalaxian cache browser and display customizer
 (Works with PgefObjects in a local ZODB)
 
-@version: $Revision: 1.8 $
+@version: $Revision: 1.9 $
 """
-__version__ = "$Revision: 1.8 $"[11:-2]
+__version__ = "$Revision: 1.9 $"[11:-2]
 
 import wx
 from wx import grid
@@ -20,9 +20,7 @@
 from ZODB import *
 
 from pangalactic.core.pgefobject import PgefObject
-from pangalactic.utils import toolframe
-from pangalactic.utils import objectviewer
-from pangalactic.utils import configuregrid
+from pangalactic.utils.objectviewer import ObjectViewer
 from pangalactic.node.gui.widgets.pgefobjectgrid import PgefObjectGrid
 
 from pprint import pprint
@@ -133,7 +131,7 @@
         obj = self.objs[selectedrows[0]]
         if isinstance(obj, PgefObject):
             tmpsize = wx.Size(800, 500)
-            foo = objectviewer.ObjectViewer(self, -1, obj, tmpsize)
+            foo = ObjectViewer(self, -1, obj, tmpsize)
         else:
             print "NOTE: only PgefObjects can be shown in the ObjectViewer"
 

Index: PanGalactic/pangalactic/utils/datamanager.py
diff -u PanGalactic/pangalactic/utils/datamanager.py:1.181 PanGalactic/pangalactic/utils/datamanager.py:1.182
--- PanGalactic/pangalactic/utils/datamanager.py:1.181	Sat May 21 04:17:38 2005
+++ PanGalactic/pangalactic/utils/datamanager.py	Fri May 27 00:46:50 2005
@@ -1,10 +1,10 @@
-# $Id: datamanager.py,v 1.181 2005/05/21 08:17:38 waterbug Exp $
+# $Id: datamanager.py,v 1.182 2005/05/27 04:46:50 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_datamanager -*-
 
 """
 PanGalaxian's local workspace manager.
 
-@version: $Revision: 1.181 $
+@version: $Revision: 1.182 $
 """
 # TODO:  move the transaction/interface stuff, like XmlrpcInterface, into a
 # separate module -- InterfaceManager, which will handle all client
@@ -15,7 +15,7 @@
 # came from (repository, file import, etc.) and what their state is
 # (committed/uncommitted, etc.)
 
-__version__ = "$Revision: 1.181 $"[11:-2]
+__version__ = "$Revision: 1.182 $"[11:-2]
 
 import time
 import mx.DateTime
@@ -159,16 +159,6 @@
             self.server.changePassword(new_pwd, state['userid'])
             self.login(state['userid'], new_pwd, secure=secure)
 
-    def getConfigAccess(self):
-        print "datamanager.getConfigAccess.GOD"
-        return localdb.GOD
-        if self.user.god:
-            return localdb.GOD
-        elif state['userid'] == "admin":
-            return localdb.ADMIN
-        else:
-            return localdb.USER
-
     def getDict(self, name):
         """
         Get the {oid : obj} dictionary for the named ObjectSchema from the

From waterbug at step.nasa.gov  Fri May 27 00:50:28 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 27 00:50:30 2005
Subject: [pangalactic-commits] Small doc tweak.
Message-ID: <200505270450.j4R4oS9h009233@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/INSTALL 1.26 1.27

Log message:
Small doc tweak.

Index: PanGalactic/INSTALL
diff -u PanGalactic/INSTALL:1.26 PanGalactic/INSTALL:1.27
--- PanGalactic/INSTALL:1.26	Sun Apr 24 19:56:00 2005
+++ PanGalactic/INSTALL	Fri May 27 00:50:26 2005
@@ -237,7 +237,7 @@
 
 8.  To start up the server, run:
 
-            $PGERHOME/pgerd startsecure
+            $PGERHOME/pgerd start
 
     pgerd will write two files in $PGERHOME/logs:
 
@@ -266,4 +266,4 @@
         (for discussions about development and hacking of PanGalactic)
 
 ---------------------------------------------------------------------------
-$Id: INSTALL,v 1.26 2005/04/24 23:56:00 waterbug Exp $
+$Id: INSTALL,v 1.27 2005/05/27 04:50:26 waterbug Exp $

From waterbug at step.nasa.gov  Fri May 27 09:53:06 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 27 09:53:08 2005
Subject: [pangalactic-commits] Works now!
Message-ID: <200505271353.j4RDr6EA014108@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/bin/pger.tac 1.1 1.2

Log message:
Works now!

Index: PanGalactic/pangalactic/node/bin/pger.tac
diff -u PanGalactic/pangalactic/node/bin/pger.tac:1.1 PanGalactic/pangalactic/node/bin/pger.tac:1.2
--- PanGalactic/pangalactic/node/bin/pger.tac:1.1	Fri May 27 00:46:49 2005
+++ PanGalactic/pangalactic/node/bin/pger.tac	Fri May 27 09:53:05 2005
@@ -1,9 +1,9 @@
 """
 Twisted Tap-builder for the Pan Galactic Repository Service
-@version: $Revision: 1.1 $
+@version: $Revision: 1.2 $
 """
 
-__version__ = "$Revision: 1.1 $"[11:-2]
+__version__ = "$Revision: 1.2 $"[11:-2]
 # $Source: /repo/step_testbed/PanGalactic/pangalactic/node/bin/pger.tac,v $
 
 import os
@@ -104,5 +104,4 @@
 else:
     webserv = internet.TCPServer(webport, site)
 webserv.setServiceParent(pgerhub)
-return webserv
 

From waterbug at step.nasa.gov  Fri May 27 10:04:15 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 27 10:04:16 2005
Subject: [pangalactic-commits] I like this better.
Message-ID: <200505271404.j4RE4F7R014319@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pgerd 1.7 1.8
PanGalactic/pangalactic/node/bin/pger.py None 1.1
PanGalactic/pangalactic/node/bin/pger.tac 1.2 None

Log message:
I like this better.

Index: PanGalactic/pangalactic/node/pgerd
diff -u PanGalactic/pangalactic/node/pgerd:1.7 PanGalactic/pangalactic/node/pgerd:1.8
--- PanGalactic/pangalactic/node/pgerd:1.7	Fri May 27 00:46:49 2005
+++ PanGalactic/pangalactic/node/pgerd	Fri May 27 10:04:13 2005
@@ -15,22 +15,21 @@
 
 case $1 in
     start)
-        # start pgerd on http://[hostname]:8080
-        twistd -y bin/pger.tac \
-               --file=logs/pger.tap \
+        # start pgerd on https://[hostname]:[port]
+        # (default port is 8080)
+        twistd -y bin/pger.py \
                --pidfile=logs/pgerd.pid \
                --logfile=logs/pgerd.log \
                --no_save
         ;;
     restart)
-        # restart pgerd on http://[hostname]:8080
+        # restart pgerd on https://[hostname]:[port]
+        # (default port is 8080)
         kill `cat logs/pgerd.pid`
         mv logs/pgerd.log \
            logs/archive/log.`date +%Y%m%d.%H.%M`
         sleep 1
-        rm logs/*.tap
-        twistd -y bin/pger.tac \
-               --file=logs/pger.tap \
+        twistd -y bin/pger.py \
                --pidfile=logs/pgerd.pid \
                --logfile=logs/pgerd.log \
                --no_save

From waterbug at step.nasa.gov  Fri May 27 16:02:38 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Fri May 27 16:02:41 2005
Subject: [pangalactic-commits] p.n.b.pger -> pgerd
Message-ID: <200505272002.j4RK2cAl018565@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pgerd 1.8 1.9
PanGalactic/pangalactic/node/bin/pgerd.py None 1.1
PanGalactic/pangalactic/node/bin/pger.py 1.1 None

Log message:
p.n.b.pger -> pgerd
.. because I just remembered that there already *is* a pger.py
(p.repo.pger) -- and pgerd is a better name for this module anyway.

Index: PanGalactic/pangalactic/node/pgerd
diff -u PanGalactic/pangalactic/node/pgerd:1.8 PanGalactic/pangalactic/node/pgerd:1.9
--- PanGalactic/pangalactic/node/pgerd:1.8	Fri May 27 10:04:13 2005
+++ PanGalactic/pangalactic/node/pgerd	Fri May 27 16:02:36 2005
@@ -17,7 +17,7 @@
     start)
         # start pgerd on https://[hostname]:[port]
         # (default port is 8080)
-        twistd -y bin/pger.py \
+        twistd -y bin/pgerd.py \
                --pidfile=logs/pgerd.pid \
                --logfile=logs/pgerd.log \
                --no_save
@@ -29,7 +29,7 @@
         mv logs/pgerd.log \
            logs/archive/log.`date +%Y%m%d.%H.%M`
         sleep 1
-        twistd -y bin/pger.py \
+        twistd -y bin/pgerd.py \
                --pidfile=logs/pgerd.pid \
                --logfile=logs/pgerd.log \
                --no_save

From waterbug at step.nasa.gov  Sun May 29 04:11:07 2005
From: waterbug at step.nasa.gov (waterbug CVS)
Date: Sun May 29 04:11:11 2005
Subject: [pangalactic-commits] Mainly making PgefTree more independent.
Message-ID: <200505290811.j4T8B7I0027439@ned.gsfc.nasa.gov>

Modified files:
PanGalactic/pangalactic/node/pangalaxian.py 1.58 1.59
PanGalactic/pangalactic/node/pangalaxian_old.py 1.5 None
PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py 1.9 1.10
PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py 1.8 1.9
PanGalactic/pangalactic/node/gui/psm/itemeditframe.py 1.15 1.16
PanGalactic/pangalactic/node/gui/psm/psmtool.py 1.34 1.35
PanGalactic/pangalactic/node/gui/widgets/pgeftree.py 1.7 1.8
PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py 1.17 1.18
PanGalactic/pangalactic/utils/datamanager.py 1.182 1.183
PanGalactic/pangalactic/utils/localdb.py 1.133 1.134

Log message:
Mainly making PgefTree more independent.
NOTE:  seems to have introduced a funky bug with the way
objects are saved to the cache -- some of them lose
attributes ... very weird.

Index: PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.17 PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.18
--- PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py:1.17	Mon May 23 13:09:56 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgxnpanes.py	Sun May 29 04:11:04 2005
@@ -1,9 +1,9 @@
 """
 The central widgets of the PanGalaxian main window.
 
-@version: $Revision: 1.17 $
+@version: $Revision: 1.18 $
 """
-__version__ = "$Revision: 1.17 $"[11:-2]
+__version__ = "$Revision: 1.18 $"[11:-2]
 
 
 import  wx
@@ -63,27 +63,14 @@
     The tree/choicebook widget in the left pane of PanGalaxian's sash
     window:  above the tree, a choice widget displays the type of tree.
     """
-    def __init__(self, parent, treeviews=None):
+    def __init__(self, parent):
         wx.Choicebook.__init__(self, parent, -1,
                                pos=wx.DefaultPosition,
                                size=wx.Size(250,600),
                                style=wx.CLIP_CHILDREN)
-        self.treeviews = treeviews or []
         self.trees = {}
-        if not treeviews:
-            win = wx.Panel(self)
-            win.SetBackgroundColour('WHITE')
-            st = wx.StaticText(win, -1, notreestext,
-                          (10, 10), (500, 1000))
-            self.AddPage(win, '[No Tree Views]')
-        else:
-            for treeview in self.treeviews:
-                win = wx.Panel(self)
-                win.SetBackgroundColour('WHITE')
-                self.trees[treeview] = PgefTree(win, -1,
-                                            datamanager=None,
-                                            allowdragndrop=False)
-                self.AddPage(win, treeview)
+        self.pages = {}
+        self.onSetTreeViews()
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
         self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)
 
@@ -99,6 +86,38 @@
         sel = self.GetSelection()
         event.Skip()
 
+    def onSetTreeViews(self):
+        """
+        Handler for the event of the state's tree_views being set or
+        changed.
+        """
+        if not state.get('tree_views', None):
+            win = wx.Panel(self)
+            win.SetBackgroundColour('WHITE')
+            st = wx.StaticText(win, -1, notreestext,
+                          (10, 10), (500, 1000))
+            self.AddPage(win, '[No Tree Views]')
+        else:
+            for tree_view in state['tree_views']:
+                win = wx.Panel(self)
+                win.SetBackgroundColour('WHITE')
+                self.trees[tree_view] = PgefTree(win, -1,
+                                            datamanager=None,
+                                            allowdragndrop=False)
+                self.AddPage(win, tree_view)
+                self.pages[tree_view] = win
+
+    def onSelectTreeView(self):
+        """
+        Handler for the event of the state's selected tree_view being set
+        or changed.
+        """
+        if state.get('sync_views', None):
+            pass
+        else:
+            # TODO: construct a page change event to change the page to the
+            # one that has the selected view
+            pass
 
 noviewstext = """
 * No objects available *

Index: PanGalactic/pangalactic/node/gui/psm/itemeditframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.15 PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.16
--- PanGalactic/pangalactic/node/gui/psm/itemeditframe.py:1.15	Wed May 11 03:07:48 2005
+++ PanGalactic/pangalactic/node/gui/psm/itemeditframe.py	Sun May 29 04:11:04 2005
@@ -1,10 +1,10 @@
-# $Id: itemeditframe.py,v 1.15 2005/05/11 07:07:48 waterbug Exp $
+# $Id: itemeditframe.py,v 1.16 2005/05/29 08:11:04 waterbug Exp $
 """
 GUI providing browsing/editing capabilities for Part, Model, Document, and
 PartsList objects.
 """
 
-__version__ = "$Revision: 1.15 $"[11:-2]
+__version__ = "$Revision: 1.16 $"[11:-2]
 
 import wx
 from pangalactic.node.gui.psm import docform
@@ -885,7 +885,7 @@
     def OnClose(self, event = None):
         #print "itemeditframe.onclose"
 
-        if self.dm.uncommittedData():
+        if self.dm.has_uncommitted_data:
             self.dm.refresh = True
 
         if self.ChangesMade():
@@ -942,7 +942,7 @@
             self.currenttree = treetype
 
         self.tree.DeleteAllItems()
-        self.tree.LoadTreeFromObject(rootobj)
+        self.tree.loadTreeForObject(rootobj)
         treedlg.Destroy()
 
     def OnTreeActivate(self, event):

Index: PanGalactic/pangalactic/node/pangalaxian.py
diff -u PanGalactic/pangalactic/node/pangalaxian.py:1.58 PanGalactic/pangalactic/node/pangalaxian.py:1.59
--- PanGalactic/pangalactic/node/pangalaxian.py:1.58	Mon May 23 13:58:45 2005
+++ PanGalactic/pangalactic/node/pangalaxian.py	Sun May 29 04:11:03 2005
@@ -1,13 +1,13 @@
 #!/usr/bin/env python 
 
-# $Id: pangalaxian.py,v 1.58 2005/05/23 17:58:45 waterbug Exp $
+# $Id: pangalaxian.py,v 1.59 2005/05/29 08:11:03 waterbug Exp $
 
 """
 Main application module for the PGEF desktop client.
 
-@version: $Revision: 1.58 $
+@version: $Revision: 1.59 $
 """
-__version__ = "$Revision: 1.58 $"[11:-2]
+__version__ = "$Revision: 1.59 $"[11:-2]
 
 import sys
 import os
@@ -730,7 +730,6 @@
         dbbrowser.menuBar.SetHelpString(toolframe.ID_FILE_EXIT,
                                         "Close this window")
         dbbrowser.mainpanel = CacheBrowser(dbbrowser, -1, self.dm)
-        config_access = self.dm.getConfigAccess()
         dbbrowser.mainpanel.FillChoice()
         dbbrowser.CentreOnParent()
         dbbrowser.Show(True)

Index: PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py
diff -u PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py:1.9 PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py:1.10
--- PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py:1.9	Wed May 11 03:07:48 2005
+++ PanGalactic/pangalactic/node/gui/psm/documenttreeframe.py	Sun May 29 04:11:04 2005
@@ -8,7 +8,7 @@
 from pangalactic.core.document import Document
 from pangalactic.utils.pgefexceptions import RequiredDataError
 
-__version__ = "$Revision: 1.9 $"[11:-2]
+__version__ = "$Revision: 1.10 $"[11:-2]
 
 
 class DocumentTreeFrame(doctreeframe.DocTreeFrame):
@@ -137,7 +137,7 @@
 
 
     def OnClose(self, event = None):
-        if self.dm.uncommittedData():
+        if self.dm.has_uncommitted_data:
             self.dm.refresh = True
 
         if self.ChangesMade():

Index: PanGalactic/pangalactic/utils/localdb.py
diff -u PanGalactic/pangalactic/utils/localdb.py:1.133 PanGalactic/pangalactic/utils/localdb.py:1.134
--- PanGalactic/pangalactic/utils/localdb.py:1.133	Sat May 21 04:17:38 2005
+++ PanGalactic/pangalactic/utils/localdb.py	Sun May 29 04:11:05 2005
@@ -1,9 +1,9 @@
 """
 Local object cache manager
 
-@version: $Revision: 1.133 $
+@version: $Revision: 1.134 $
 """
-__version__ = "$Revision: 1.133 $"[11:-2]
+__version__ = "$Revision: 1.134 $"[11:-2]
 
 import os
 import glob
@@ -97,8 +97,8 @@
 
     def saveObjects(self, objs, only=None, also=None):
         """
-        Save some objects in the cache.  Map the object's oid to itself in
-        the dictionary C{self.objs} (which maps to *all* objects in the
+        Save some objects in the cache.  Map the object's oid to the object
+        in the dictionary C{self.objs} (which includes *all* objects in the
         cache).  By default, also add the object to the dictionary
         C{self.dbroot[schema]}, where C{schema} is the object's _schema.id.
         This default can be changed using the (mutually exclusive) C{only}
@@ -114,7 +114,7 @@
         @type  only:  C{list} or C{str}
 
         @param also:  names of the cache dictionaries to add the object to
-            addition to the dictionary corresponding to this object's
+            in addition to the dictionary corresponding to this object's
             _schema.id.
         @type  also:  C{list} or C{str}
         """
@@ -195,7 +195,10 @@
 
     def getLocalObject(self, pgef_oid):
         #print "localdb.getlocalobject", searchdict, pgef_oid
-        return self.objs[pgef_oid]
+        # TODO:  some kind of handling for objs whose state is 'DELETE'
+        obj = self.objs[pgef_oid]
+        if obj.state != 'DELETE':
+            return obj
 
     def clearUncommittedObjects(self, committedobjs):
         print " - localdb.clearUncommittedObjects", committedobjs
@@ -219,11 +222,6 @@
             print "no uncommitted objects; returning empty list"
             return []
 
-    ### TODO:  the Wf classes need ObjectSchemas
-
-    def getUncommittedPartsListIDs(self):
-        return self.dbroot[self.UNCOMMITTEDPARTSLISTIDS]
-
     def getCommittedObjects(self):
         #print "localdb.getCommittedObjects"
         objdict = {}
@@ -235,16 +233,6 @@
                 objdict.update(objs)
         return objdict
 
-    def AppendUncommittedData(self, uncommitteddict, unsavedlist):
-        tmplist = self.dbroot[uncommitteddict]
-        tmplist.extend(unsavedlist)
-        self.dbroot[uncommitteddict] = tmplist
-        self.commit()
-
-    def SaveUncommittedData(self, uncommitteddict, unsavedlist):
-        self.dbroot[uncommitteddict] = unsavedlist
-        self.commit()
-
     def getDict(self, name):
         # applications may only have some of the dicts that pgef has
         return self.dbroot.get(name, None)
@@ -252,14 +240,17 @@
     def add(self, objs):
         """
         Add new locally created objects to the cache.
+
+        @param objs:  PgefObjects to be added
+        @type  objs:  C{list}
         """
         # print "localdb.add"
         self.saveObjects(objs, also='Uncommitted')
         self.commit()
 
-    def removeObj(self, obj):
+    def delete(self, obj):
         """
-        Remove an object from the local cache, either by direct reference
+        Delete an object from the local cache, either by direct reference
         or by oid.
 
         @param obj:  a PgefObject instance or the pgef_oid of an instance
@@ -275,56 +266,6 @@
     # FIXME:  Domain-specific stuff (everything from here on) shouldn't be
     # in localdb
 
-    def SetProjects(self, objects):
-        self.dbroot['Project'] = objects
-        self.commit()
-
-    def getAcusByComponent(self, component):
-        """
-        Get all Acu's that have this C{Model} instance (or oid of a Model
-        instance) as a component (or its oid).
-
-        @param component:  a component C{Model} or its oid
-        @type  component:  C{Model} or C{str}
-
-        @return:  list of Acu instances
-        @rtype:   C{list}
-        """
-        #print "localdb.getAcusByComponent"
-        acus = []
-        for obj in self.dbroot['Acu'].values():
-            if type(component) is str:
-                if (obj.component.pgef_oid == component):
-                    acus.append(obj)
-            else:
-                if (obj.component == component.pgef_oid
-                    or obj.component == component):
-                    acus.append(obj)
-        return acus
-
-    def getAcusByAssembly(self, assembly):
-        """
-        Get all Acu's that have this C{Model} instance (or oid of a Model
-        instance) as an assembly (or its oid).
-
-        @param assembly:  an assembly C{Model} or its oid
-        @type  assembly:  C{Model} or C{str}
-
-        @return:  list of Acu instances
-        @rtype:   C{list}
-        """
-        #print "localdb.getAcusByAssembly"
-        acus = []
-        for obj in self.dbroot['Acu'].values():
-            if type(assembly) is str:
-                if (obj.assembly.pgef_oid == assembly):
-                    acus.append(obj)
-            else:
-                if (obj.assembly == assembly.pgef_oid
-                    or obj.assembly == assembly):
-                    acus.append(obj)
-        return acus
-
     # strange special cases for Workflow stuff
 
     def getUncommittedWfObjects(self):

Index: PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py
diff -u PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py:1.8 PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py:1.9
--- PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py:1.8	Mon May 16 17:34:41 2005
+++ PanGalactic/pangalactic/node/gui/psm/itemdroptarget.py	Sun May 29 04:11:04 2005
@@ -1,4 +1,4 @@
-# $Id: itemdroptarget.py,v 1.8 2005/05/16 21:34:41 waterbug Exp $
+# $Id: itemdroptarget.py,v 1.9 2005/05/29 08:11:04 waterbug Exp $
 
 import cPickle
 
@@ -10,7 +10,7 @@
 from wxPython.wx import wxPoint, wxTreeItemIcon_Selected
 
 
-__version__ = "$Revision: 1.8 $"[11:-2]
+__version__ = "$Revision: 1.9 $"[11:-2]
 
 
 class ItemDropTarget(wxPyDropTarget):
@@ -34,34 +34,24 @@
 
     def OnData(self, x, y, d):
         """Handles the processing that needs to take place when there is data dropped"""
-
         #print "itemdroptarget.ondata"
         #havetoplevelnode = False
         haverootnode = False
-
         #perform hit test to see if we have a valid node selected as the target
         #if the target node is not OK, just return
         targetnode, flags = self.tree.HitTest(wxPoint(x, y))
         if not targetnode.IsOk():
             return d
-
         if targetnode <> self.tree.GetRootItem():
             if not self.tree.dropOnNode:
                 print "You can only drop onto the root node in this tree.  pththththth..."
                 return d
-            
-
         #If we have data, continue
         if self.GetData():
             #print "getdata returned stuff"
             DragFromGrid = False
             rawdata = self.data.GetData()
             dropdata = cPickle.loads(rawdata)
-            
-            # since the business rule was made that we cannot drag and drop between trees, only within the tree or from
-            # a grid to a tree, the following if-then-else checks for this and exits if an invalid condition exists.
-            moving_within_tree = False
-
             #print "dropdata", dropdata
             if dropdata[2] == "GRID":
                 #print "from grid"
@@ -69,10 +59,6 @@
             elif self.tree.__class__ != dropdata[2]:
                 #print "wrong tree"
                 return d
-            else:
-                #print "moving within tree"
-                moving_within_tree = True
-
             # If there is no acuid, set the dropacuobj to None
             try:
                 dropacuobj = self.dm.getLocalObject(dropdata[0])
@@ -88,7 +74,6 @@
                 #print "have dropitem", dropitem.id
             except:
                 return d
-            
             #check for drop on ancestor
             tempparentnode = targetnode
             while 1:
@@ -100,10 +85,8 @@
                     tempparentnode = self.tree.GetItemParent(tempparentnode)
                 else:
                     break
-
             #print "itemdroptarget: 1: expand"
             self.tree.Expand(targetnode)
-
             # Get the target data
             targetdata = self.tree.GetPyData(targetnode)
             targetacu = None
@@ -125,7 +108,6 @@
                 else:
                     return d
                 targetacu = "ROOT"
-
             elif DragFromGrid:
                 #print "drag from grid"
                 targetitem = self.dm.getLocalObject(targetdata[1])
@@ -135,7 +117,6 @@
                 if targetacu == None:
                     print "no drop target"
                     return
-
             elif targetdata[0]:
                 #print "drop with targetdata[0]"
                 #print "targetdata", targetdata
@@ -145,14 +126,6 @@
             else:
                 print "wtf"
                 return d
-                    
-            if moving_within_tree:
-                #print "moving within tree - delete"
-                try:    
-                    self.dm.removeAcu(dropacuobj.pgef_oid)
-                    self.dm.removeLocalAcu(dropacuobj)
-                except KeyError:
-                    print 'had trouble deleting the acu'
             # create new acu
             #print "create new acu"
             newacu = Acu()
@@ -168,7 +141,7 @@
                 newacu.assembly = targetitem
             #print "newacu", newacu.id, newacu.assembly.id, newacu.component.id
             # add new acu
-            self.dm.addAcu(newacu, targetacu)
+            self.dm.add([newacu])
             try:
                 # if isinstance(targetitem, Model):
                 #     targetitem.has_parts_flag = 1
@@ -188,44 +161,31 @@
             self.tree.SetItemImage(id, self.tree.itemicon)
             self.tree.SetItemImage(id, self.tree.itemicon, wxTreeItemIcon_Selected)
             treeclass = str(self.tree.__class__)
-            if not (treeclass.endswith("PgefEditTree") or treeclass.endswith("PgefDocTree")):
+            if not (treeclass.endswith("PgefEditTree")
+                    or treeclass.endswith("PgefDocTree")):
                 # if dropitem.has_parts_flag:
                 self.tree.SetItemHasChildren(id, True)
             self.tree.SetPyData(id, dropobj)
-
             if haverootnode:
                 #print "itemdroptarget: 3a: expand"
                 self.tree.Expand(self.tree.GetRootItem())
             else:
                 #print "itemdroptarget: 3b: expand"
                 self.tree.Expand(targetnode)
-
-            # delete the old acu from the tree
-            if moving_within_tree:
-                if self.tree.GetSelection() <> self.tree.GetRootItem():
-                    delnode = self.tree.GetSelection()
-                    delitemid = self.tree.GetPyData(delnode)[1]
-                    parentnode = self.tree.GetItemParent(delnode)
-                    self.tree.Delete(delnode)
-                    nkids = self.tree.GetChildrenCount(parentnode)
-                    if nkids == 0:
-                        self.tree.SetItemHasChildren(parentnode, False)
-
-                    for tid in self.dm.topLevelItemIDs:
-                        if tid == delitemid:
-                            self.dm.topLevelItemIDs.remove(delitemid)
-                            
-            event = pgefevents.PgefDragDropClearEvent(pgefevents.DRAG_DROP_CLEAR, self.tree.GetId())
+            event = pgefevents.PgefDragDropClearEvent(
+                                            pgefevents.DRAG_DROP_CLEAR,
+                                            self.tree.GetId())
             self.tree.GetEventHandler().ProcessEvent(event)
             try:
                 # do we have an id for the drag widget? i.e., not the tree
                 # only a grid will have 4 elements; hence the try-except
                 if dropdata[3]:
-                    win = self.tree.GetParent().GetParent().FindWindowById(dropdata[3])
-                    event = pgefevents.PgefDragDropClearEvent(pgefevents.DRAG_DROP_CLEAR, win.GetId())
+                    win = self.tree.GetParent().GetParent().FindWindowById(
+                                    dropdata[3])
+                    event = pgefevents.PgefDragDropClearEvent(
+                                    pgefevents.DRAG_DROP_CLEAR, win.GetId())
                     win.GetEventHandler().ProcessEvent(event)
             except:
                 pass
-        
         return d
 

Index: PanGalactic/pangalactic/node/gui/widgets/pgeftree.py
diff -u PanGalactic/pangalactic/node/gui/widgets/pgeftree.py:1.7 PanGalactic/pangalactic/node/gui/widgets/pgeftree.py:1.8
--- PanGalactic/pangalactic/node/gui/widgets/pgeftree.py:1.7	Mon May 16 17:34:41 2005
+++ PanGalactic/pangalactic/node/gui/widgets/pgeftree.py	Sun May 29 04:11:04 2005
@@ -1,31 +1,28 @@
-# $Id: pgeftree.py,v 1.7 2005/05/16 21:34:41 waterbug Exp $
+# $Id: pgeftree.py,v 1.8 2005/05/29 08:11:04 waterbug Exp $
 """
 Base class for PanGalaxian's trees
 
-@version: $Revision: 1.7 $
+@version: $Revision: 1.8 $
 """
-__version__ = "$Revision: 1.7 $"[11:-2]
+__version__ = "$Revision: 1.8 $"[11:-2]
 
 import wx
 import cPickle, types
 
-from pangalactic.node.images      import toolkitimages
-from pangalactic.utils            import pdfoptions
-from pangalactic.utils            import pgefevents
-from pangalactic.node.gui.state  import state
-from pangalactic.node.gui.psm     import itemdroptarget
-
-__version__ = "$Revision: 1.7 $"[11:-2]
+from pangalactic.node.images    import toolkitimages
+from pangalactic.utils          import pdfoptions
+from pangalactic.utils          import pgefevents
+from pangalactic.node.gui.state import state
+from pangalactic.node.gui.psm   import itemdroptarget
 
 
 class PgefTree(wx.TreeCtrl):
     """
     PGEF custom tree widget.
     """
-    # TODO:  get rid of refs to datamanager!!!
 
-    def __init__(self, parent, ID, datamanager=None, allowdragndrop=True):
-        wx.TreeCtrl.__init__(self, parent, ID,
+    def __init__(self, parent, datamanager=None, allowdragndrop=False):
+        wx.TreeCtrl.__init__(self, parent, -1,
             style=wx.TR_HAS_BUTTONS|wx.TR_DEFAULT_STYLE|wx.SUNKEN_BORDER)
         self.dm = datamanager
         self.Parent = parent       
@@ -45,18 +42,22 @@
         evthandler = pgefevents.PgefDragDropHandler(self)
         self.GetEventHandler().PushEventHandler(evthandler)
         wx.EVT_MOTION(self, self.OnMove)
-        wx.EVT_LEFT_DOWN(self, self.OnLeftDown)
+        # wx.EVT_LEFT_DOWN(self, self.OnLeftDown)
+        # wx.EVT_RIGHT_DOWN(self, self.OnRightDown)
+        self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnNodeExpanding)
+        # TODO:  (later) check to see whether this is needed
+        # self.Bind(wx.EVT_TREE_SEL_CHANGED(self, self.OnTreeActivate)
 
     def SetAllowDrop(self, drop_flag):
         self.AllowDrop = drop_flag
         
     def LoadImageLIst(self):        
         il = wx.ImageList(16, 16)
-        self.itemicon = il.Add (toolkitimages.getItemIcon_16Bitmap())
-        self.alerticon = il.Add (toolkitimages.getRedDocaIcon_16Bitmap())
-        self.documenticon = il.Add (toolkitimages.getBlueDocIcon_16Bitmap())
-        self.partslisticon = il.Add (toolkitimages.getBlueDocpIcon_16Bitmap())
-        self.incompleteicon = il.Add (toolkitimages.getRedBlackDoc_16Bitmap())
+        self.itemicon = il.Add(toolkitimages.getItemIcon_16Bitmap())
+        self.alerticon = il.Add(toolkitimages.getRedDocaIcon_16Bitmap())
+        self.documenticon = il.Add(toolkitimages.getBlueDocIcon_16Bitmap())
+        self.partslisticon = il.Add(toolkitimages.getBlueDocpIcon_16Bitmap())
+        self.incompleteicon = il.Add(toolkitimages.getRedBlackDoc_16Bitmap())
         self.projecticon = il.Add(toolkitimages.getPSMBitmap())
         self.il = il
         self.SetImageList(self.il)
@@ -93,13 +94,13 @@
         # dnd is deactivated for now
         pass
 
-    def LoadTreefromObjects(self, dm, rootobj, parentnode=None):
+    def loadTreeForObject(self, rootobj, parentnode=None):
         """
-        Load the tree from the dicts in the DataManager
+        Load a tree with a root of rootobj and first level of children.
         """
-        print "PgefTree.LoadTreefromObjects"
+        print "PgefTree.loadTreeForObject"
         print "  - rootobj.pgef_oid =", rootobj.pgef_oid
-        AcuIds = []
+        acu_oids = []
         if parentnode:
             rootnode = parentnode
             acu_id = self.GetPyData(parentnode)[0]
@@ -110,52 +111,42 @@
         self.SetItemImage(rootnode, self.itemicon)
         self.SetItemImage(rootnode, self.itemicon, wx.TreeItemIcon_Selected)
         self.SetPyData(rootnode,[acu_id, rootobj.pgef_oid])
-        if state['loggedin']:
-            print "  - getting more acus from server ..."
-            dm.getAcusByAssemblyOid(rootobj.pgef_oid)
-        localacus = dm.getLocalObjects('Acu', state['project'])
-        for acuid, acuobj in localacus.items():
-            if acuobj.assembly == rootobj.pgef_oid and acuobj.state <> 'DELETE':
-                AcuIds.append(acuid)
-        print '  - AcuIds: ', AcuIds
-        for acuid in AcuIds:
-            acuobj = dm.getLocalObject(acuid)
-            itemobj = dm.getLocalObject(acuobj.component)
-            if itemobj and acuobj.state <> 'DELETE':
-                treeid = self.AppendItem(rootnode, itemobj.id)
-                self.SetPyData(treeid, [acuobj.pgef_oid, itemobj.pgef_oid])
+        for acu_obj in self.dm.getAcusByAssemblyOid(rootobj.pgef_oid):
+            acu_oids.append(acu_obj.pgef_oid)
+        print '  - acu_oids: ', acu_oids
+        for acu_oid in acu_oids:
+            acu_obj = self.dm.getObject(acu_oid)
+            component = self.dm.getObject(acu_obj.component)
+            if component:
+                treeid = self.AppendItem(rootnode, component.id)
+                self.SetPyData(treeid, [acu_obj.pgef_oid, component.pgef_oid])
                 self.SetItemImage(treeid, self.itemicon)
-                self.SetItemImage(treeid, self.itemicon, wx.TreeItemIcon_Selected)
+                self.SetItemImage(treeid, self.itemicon,
+                                  wx.TreeItemIcon_Selected)
                 self.SetItemHasChildren(treeid, True)            
         self.SortChildren(rootnode)
 
-    def WalkNodes(self, startnode, currentindent = None, returnlist = None, showall = None):
-        #print '%s - %i' % (self.GetItemText(startnode), currentindent)
-        labels = ['ROOT']
-        if returnlist != None:
-            #print '%s  showall: %s IsVisible: %s' % \
-            #      (self.GetItemText(startnode), repr(showall), repr(self.IsVisible(startnode)))
-            if self.GetPyData(startnode)[1] in labels:
-                #print 'no item - using <%s>' % self.GetItemText(startnode)
-                if showall == 0 and self.IsVisible(startnode) == 0:
-                    pass
-                else:
-                    returnlist.append((self.GetItemText(startnode), currentindent))
-            else:
-                if showall == 0 and self.IsVisible(startnode) == 0:
-                    pass
-                else:
-                    returnlist.append((self.GetPyData(startnode)[1], currentindent))
-                
-        child, junk = self.GetFirstChild(startnode, 0)
-        if child.IsOk():
-            self.WalkNodes(child, currentindent + 1, returnlist, showall)
+    def OnNodeExpanding(self, event):
+        print "- PgefTree.OnNodeExpanding"
+        node = event.GetItem()
+        # This event can happen twice in the self.Expand call
+        if self.IsExpanded(node):
+            return
+        childnode = self.GetFirstChild(node)
+        if childnode[0].IsOk():
+            event.Skip()
+            return
         else:
-            sib, junk = self.GetNextChild(startnode, 0)
-            if sib.IsOk():
-                self.WalkNodes(sib, currentindent, returnlist, showall)
-        child = self.GetNextSibling(startnode)
-        if child.IsOk():
-            self.WalkNodes(child, currentindent, returnlist, showall)
-
+            print "  - looking for children"
+            treetuple = self.GetPyData(node)
+            print '  - treetuple:', treetuple
+            obj = self.dm.getObject(treetuple[1])
+            # print ' - obj:', obj
+            linkedobjs = []
+            linkedobjs = self.dm.getAcusByAssemblyOid(obj.pgef_oid)
+            print '  - child nodes:', linkedobjs
+            if len(linkedobjs) == 0:
+                self.SetItemHasChildren(node, False)
+                return
+            self.loadTreeForObject(obj, node)
 

Index: PanGalactic/pangalactic/node/gui/psm/psmtool.py
diff -u PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.34 PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.35
--- PanGalactic/pangalactic/node/gui/psm/psmtool.py:1.34	Tue May 24 03:15:47 2005
+++ PanGalactic/pangalactic/node/gui/psm/psmtool.py	Sun May 29 04:11:04 2005
@@ -1,10 +1,10 @@
-# $Id: psmtool.py,v 1.34 2005/05/24 07:15:47 waterbug Exp $
+# $Id: psmtool.py,v 1.35 2005/05/29 08:11:04 waterbug Exp $
 # Originally Created 04/05/2001
 """
 PSM Tool is the Product Structure Manager.  It handles visualization,
 navigation, and editing of product structures.
 """
-__version__ = "$Revision: 1.34 $"[11:-2]
+__version__ = "$Revision: 1.35 $"[11:-2]
 
 import os
 import sys
@@ -21,7 +21,8 @@
 from pangalactic.utils import httpdownload
 from pangalactic.node.gui.state import state, prefs, displaymaps
 from pangalactic.node.gui.psm import toolbarpanel
-from pangalactic.node.gui.psm import pgeftree
+# from pangalactic.node.gui.psm import pgeftree
+from pangalactic.node.gui.widgets import pgeftree
 from pangalactic.node.gui.psm import pgefversiontree
 from pangalactic.node.gui.psm import mystuffoptions
 from pangalactic.node.gui.psm import projectframe
@@ -161,11 +162,9 @@
                                         -1,
                                         wx.DefaultPosition,
                                         wx.Size(200, 200)) 
-        self.tID = wx.NewId()
         self.treeMap = {}
-        self.tree = pgeftree.PgefMainTree(self.tree_notebook,
-                                          self.tID,
-                                          self.dm)
+        self.tree = pgeftree.PgefTree(self.tree_notebook,
+                                      self.dm)
         self.tree.SetBackgroundColour(wx.WHITE)
         tree_tooltip = """A hierarchy of the currently selected part.
 Click on a part to highlight its data in the Parts grid.
@@ -231,18 +230,6 @@
         wx.EVT_MENU(self.modelgrid,
                  basegrid.ID_POPUP_EDIT,
                  self.onGridPopupEdit)
-        wx.EVT_RIGHT_DOWN(self.tree,
-                       self.OnRightDown)
-        wx.EVT_TREE_ITEM_EXPANDING(self,
-                                self.tID,
-                                self.OnItemExpanding)
-        wx.EVT_TREE_SEL_CHANGED(self,
-                             self.tID,
-                             self.OnTreeActivate)
-        wx.EVT_LEFT_DCLICK(self.tree,
-                        self.OnEditComponent) 
-        wx.EVT_LEFT_DCLICK(self.version_tree,
-                        self.OnEditComponent) 
         wx.EVT_CHOICE(self,
                    ID_CHOICE_VIEW,
                    self.SelectView)
@@ -282,7 +269,6 @@
         bgrid = event.GetEventObject()
         obj = bgrid.getObject(ndx)
         bgrid.SelectRow(ndx)
-        self.version_tree.LoadTreeFromObject(obj)
         self.synchGridSelections(obj)
 
     def SelectView(self, event):
@@ -297,7 +283,6 @@
             ndxs = bgrid.GetSelectedRows()
             if len(ndxs) > 0:
                 obj = bgrid.getObject(ndxs[0])
-                self.version_tree.LoadTreeFromObject(obj)
 
             # show the treepage that corresponds to the gridpage
             self.tree_notebook.SetSelection(gridpage)
@@ -536,7 +521,7 @@
         print "PSMTool.commit()", len(objectlist)
         print "  -> objectlist: ", objectlist
         retval = []
-        if self.dm.uncommittedData():
+        if self.dm.has_uncommitted_data:
             if not dont_ask:
                 dtext = "Commit ALL uncommitted work?"
                 dlg = pgdialogs.OKCancelDialog(self, -1,
@@ -626,7 +611,7 @@
             print "psmtool.PSMTool:  looking for children"
             treetuple = self.tree.GetPyData(node)
             print ' - treetuple:', treetuple
-            obj = self.dm.getLocalObject(treetuple[1])
+            obj = self.dm.getObject(treetuple[1])
             # print ' - obj:', obj
             linkedobjs = []
             if state['loggedin']:
@@ -641,7 +626,7 @@
             if len(linkedobjs) == 0:
                 self.tree.SetItemHasChildren(node, False)
                 return
-            self.tree.LoadTreeFromObject(obj, node)
+            self.tree.loadTreeForObject(obj, node)
 
     def GetNickName (self):
         return "PSM"
@@ -671,26 +656,21 @@
     def OnSashDrag(self, event):
         if event.GetDragStatus() == wx.SASH_STATUS_OUT_OF_RANGE:
             return
-
         eID = event.GetId()
         if eID == self.ID_WINDOW_TOP:
             self.topWindow.SetDefaultSize(
                 wx.Size(800, event.GetDragRect().height)) #tbd
-
         elif eID == self.ID_WINDOW_LEFT:
             self.leftWindow.SetDefaultSize(
                 wx.Size(event.GetDragRect().width, 600)) #tbd
-
         wx.LayoutAlgorithm().LayoutWindow(self, self.notebook)
         self.notebook.Refresh()
 
-
     def OnSize(self, event):
         self.SetSize(self.parent.GetClientSize())
         wx.LayoutAlgorithm().LayoutWindow(self, self.notebook) 
         self.Layout()
 
-
     def OnTreeActivate(self, event):
         print "PSMTool.OnTreeActivate"
         treeobj = self.tree.GetPyData(event.GetItem())
@@ -698,10 +678,8 @@
         itemid = treeobj[1]
         if nauoid == None and itemid == None:
             raise ValueError, "No data"
-
         self.SelectGridRowByItemId(itemid)
 
-
     def SelectGridRowByItemId(self, itemid):
         currentgrid = self.GetCurrentGrid()
         rowcount = currentgrid.GetNumberRows()
@@ -721,7 +699,7 @@
             return
 
         #bryan
-        if self.dm.uncommittedData():
+        if self.dm.has_uncommitted_data:
            dlg = wx.MessageDialog(self,
                  "You have uncommitted changes.  Shall I commit them?",
                  "Warning: Data Loss Imminent",
@@ -735,14 +713,12 @@
         itemid = itemobj.pgef_oid
 
         self.tree.DeleteAllItems() 
-        self.version_tree.DeleteAllItems() 
 
         if state['loggedin']:
             self.dm.getAcusByAssemblyOid(itemid)
 
-        self.tree.LoadTreeFromObject(itemobj)
+        self.tree.loadTreeForObject(itemobj)
         self.tree.expandRoot()
-        self.version_tree.LoadTreeFromObject(itemobj)
 
 
 
@@ -983,8 +959,8 @@
             self.tree.DeleteAllItems() 
             self.dm.clearNauoIDs() 
             self.dm.getAcusByAssemblyOid(itemid)
-            obj = self.dm.getLocalObject(itemid)
-            self.tree.LoadTreeFromObject(obj)
+            obj = self.dm.getObject(itemid)
+            self.tree.loadTreeForObject(obj)
         except:
             print "PSMTool.BuildTree.error"
 
@@ -1003,7 +979,7 @@
             nodedata = self.tree.GetPyData(node)
             wx.BeginBusyCursor()
             product_id = nodedata[1]
-            temp_obj = self.dm.getLocalObject(product_id)
+            temp_obj = self.dm.getObject(product_id)
             classname = temp_obj.__class__.__name__
             if classname == "Part":
                 pane = 0

Index: PanGalactic/pangalactic/utils/datamanager.py
diff -u PanGalactic/pangalactic/utils/datamanager.py:1.182 PanGalactic/pangalactic/utils/datamanager.py:1.183
--- PanGalactic/pangalactic/utils/datamanager.py:1.182	Fri May 27 00:46:50 2005
+++ PanGalactic/pangalactic/utils/datamanager.py	Sun May 29 04:11:05 2005
@@ -1,10 +1,10 @@
-# $Id: datamanager.py,v 1.182 2005/05/27 04:46:50 waterbug Exp $
+# $Id: datamanager.py,v 1.183 2005/05/29 08:11:05 waterbug Exp $
 # -*- test-case-name:  pangalactic.test.test_datamanager -*-
 
 """
 PanGalaxian's local workspace manager.
 
-@version: $Revision: 1.182 $
+@version: $Revision: 1.183 $
 """
 # TODO:  move the transaction/interface stuff, like XmlrpcInterface, into a
 # separate module -- InterfaceManager, which will handle all client
@@ -15,7 +15,7 @@
 # came from (repository, file import, etc.) and what their state is
 # (committed/uncommitted, etc.)
 
-__version__ = "$Revision: 1.182 $"[11:-2]
+__version__ = "$Revision: 1.183 $"[11:-2]
 
 import time
 import mx.DateTime
@@ -69,7 +69,6 @@
         self.server = None
         self.refresh = False
         self.projects = {}
-        self.nauoIDs = {}
         self.partsListIDs = {}
         self.documentIDs = {}
         self.pdrIDs = {}
@@ -150,9 +149,6 @@
                                domains=self.domains,
                                factory=self.factory)
 
-    def getRoot(self):
-        return self.cache.dbroot
-
     def changePassword(self, login_pwd, new_pwd, secure=1):
         # print "DM.changePassword"
         if state['loggedin']:
@@ -167,7 +163,7 @@
         return self.cache.getDict(name)
 
     def getUser(self, userid):
-        return self.cache.getLocalObject(userid)
+        return self.cache.getObject(userid)
 
     def newObject(self, schema, **kw):
         """
@@ -321,8 +317,24 @@
         self.cache.clear()
         self.cache.pack()
 
-    def getLocalObject(self, oid):
-        return self.cache.objs.get(oid, None)
+    def getObject(self, oid):
+        if type(oid) is str:
+            obj = self.cache.objs.get(oid, None)
+            if (state['loggedin'] and
+                obj.state not in ['ADD', 'MODIFY', 'DELETE']):
+                params = {"pgef_oid" : oid}
+                objs = self.server.getObjects('PgefObject',
+                                              fields=params,
+                                              refs=0,
+                                              subtypes=1,
+                                              objs=None)
+                if objs:
+                    self.cache.saveObjects(objs)
+        elif isinstance(oid, self.factory.classes['PgefObject']):
+            obj = oid
+        else:
+            raise TypeError, 'oid must be oid or PgefObject instance'
+        return obj
 
     def getLocalObjects(self, object_schemas=None, project=None):
         return self.cache.getLocalObjects(object_schemas, project)
@@ -427,18 +439,18 @@
 
     # property:  has_uncommitted_data
 
-    def getUncommittedData(self):
+    def getHasUncommittedData(self):
         return bool(self.getUncommittedObjs())
 
-    def setUncommittedData(self):
+    def setHasUncommittedData(self):
         raise TypeError, 'has_uncommitted_data is read-only'
 
-    def delUncommittedData(self):
+    def delHasUncommittedData(self):
         raise TypeError, 'has_uncommitted_data cannot be deleted'
 
-    has_uncommitted_data = property(getUncommittedData,
-                                    setUncommittedData,
-                                    delUncommittedData,
+    has_uncommitted_data = property(getHasUncommittedData,
+                                    setHasUncommittedData,
+                                    delHasUncommittedData,
                                     'has_uncommitted_data')
 
     def commit(self, unsavedobjs):
@@ -569,105 +581,40 @@
 
     def getAcusByAssemblyOid(self, oid):
         """
-        Retrieves from the server all Acus associated with an assembly oid.
+        Retrieves all Acu objects associated with an assembly oid.
         """
         print "- in dm.getAcusByAssemblyOid"
         print "  - assembly oid:  %s" % oid
-        keydict = {"assembly" : oid}
-        objs = self.server.getLinkedObjs('Acu', keydict,
-                                         self.cache.objs.values())
-        print 'found objs:', objs
-        self.cache.saveObjects(objs)
-        print "  - found acus:  %s" % str([o.pgef_oid for o in objs])
-        print "- end dm.getAcusByAssemblyOid"
-        return objs
-
-    def getLocalAcusByAssemblyOid(self, oid):
-        print " - in dm.getLocalAcusByAssemblyOid"
-        localacus = self.getLocalObjects(['Acu'])
-        print "   local acus:  %s" % str([o.pgef_oid for o in localacus])
         acus = []
-        for obj in localacus:
+        if state['loggedin']:
+            keydict = {"assembly" : oid}
+            objs = self.server.getLinkedObjs('Acu', keydict,
+                                             self.cache.objs.values())
+            print 'found objs:', objs
+            self.cache.saveObjects(objs)
+            print "  - found acus:  %s" % str([o.pgef_oid for o in objs])
+        for obj in self.getLocalObjects(['Acu']):
             if obj.assembly == oid:
                 acus.append(obj)
             elif getattr(obj.assembly, 'pgef_oid', '') == oid:
                 acus.append(obj)
         print "   local acus with assembly oid == %s:  %s" % (oid,
                                         str([o.pgef_oid for o in acus]))
+        print "- end dm.getAcusByAssemblyOid"
         return acus
 
-    def removeLocalAcu(self, acu):
-        self.cache.removeObj[acu]
+    def deleteCacheObj(self, obj):
+        obj.state = 'DELETE'
 
-    def removeAcu(self, acu_oid):
+    def deleteCacheObjByOid(self, oid):
         """
-        Removes the node from the tree and also from the Acu list.
+        Mark a cache object for deletion (analogous to C{cvs remove}).
         """
-        obj = self.getLocalObject(acu_oid)
+        obj = self.getObject(oid)
         obj.state = 'DELETE'
-        # delete the entry for AcuID from the dictionary of its parent
-        self.cache.removeObj[acu_oid]
-        for acus in self.nauoIDs.keys():
-            temp = self.nauoIDs[acus]
-            for key, value in temp.items():
-                if AcuID in value:
-                    ndx = value.index(AcuID)
-                    del value[ndx]
-            self.nauoIDs[acus] = temp
-
-    def clearNauoIDs(self):
-        self.nauoIDs.clear()
-
-    def addAcu(self, acu_to_add, acu_parent):
-        # print "datamanager.addacu"
-        if acu_parent == 'ROOT':
-            if self.nauoIDs.has_key("ROOT"):
-                topdict = self.nauoIDs["ROOT"]
-                tmplist = topdict["TOPLEVEL"]
-                try:
-                    if tmplist.index(acu_to_add.pgef_oid):
-                        pass
-                except:
-                    tmplist.append(acu_to_add.pgef_oid)
-                    self.nauoIDs["ROOT"] = {acu_to_add.assembly : tmplist}
-            else:
-                self.nauoIDs["ROOT"] = {"TOPLEVEL" : [acu_to_add.pgef_oid]}
-        elif acu_parent == "TOPLEVEL":
-            if self.nauoIDs.has_key(acu_to_add.assembly):
-                tmpdict = self.nauoIDs[acu_to_add.assembly]
-                try:
-                    tmplist = tmpdict[acu_parent]
-                except:
-                    tmplist = []
-                    tmplist.append(acu_to_add.pgef_oid)
-                    tmpdict[acu_parent] = tmplist
-                    self.nauoIDs[acu_to_add.assembly] = tmpdict
-                try:
-                    if tmplist.index(acu_to_add.pgef_oid):
-                        pass
-                except:
-                    tmplist.append(acu_to_add.pgef_oid)
-                    tmpdict[acu_parent] = tmplist
-                    self.nauoIDs[acu_to_add.assembly] = tmpdict
-        elif self.nauoIDs.has_key(acu_to_add.assembly):
-            # print "adding to existing dict"
-            tmpdict = self.nauoIDs[acu_to_add.assembly]
-            tmplist = tmpdict[acu_parent.pgef_oid]
-            try:
-                if tmplist.index(acu_to_add.pgef_oid):
-                    pass
-            except:
-                tmplist.append(acu_to_add.pgef_oid)
-                tmpdict[acu_parent.pgef_oid] = tmplist
-                self.nauoIDs[acu_to_add.assembly] = tmpdict
-        else:
-            # print "make leaf a branch; i.e., need a new entry in nauoids"
-            newlist = []
-            newlist.append(acu_to_add.pgef_oid)
-            newdict = {}
-            newdict[acu_parent.pgef_oid] = newlist
-            self.nauoIDs[acu_parent.component] = newdict
-        self.cache.add([acu_to_add])
+
+    # Too much domain-specific stuff here -- DM should be generic
+    # and there should be a Workflow manager with this stuff ...
 
     def getUncommittedWorkflows(self):
         return self.cache.getUncommittedWorkflows()