[Bio] / ModelEditor / Catalogpanel.py Repository:
ViewVC logotype

View of /ModelEditor/Catalogpanel.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.11 - (download) (as text) (annotate)
Sun Dec 4 17:20:34 2005 UTC (12 years, 11 months ago) by efrank
Branch: MAIN
CVS Tags: before-dynamics-persistence, lwc, HEAD
Changes since 1.10: +14 -8 lines
1. migrate from deprecated xmlrpcconverter to PrimitiveConverter.  This
makes shared editing by AG work again.  Also, now trivial to add arbitrary
object networks to Model and still ship  between kah instances.  maybe.

2. fix up dynamics stuff.  dunno how charl's stuff ever worked, but it did.
then it didn't.  now it does again.  migrate to classFromPath and rationalize
a bunch of stuff.

import copy
import xmlrpclib
from wxPython.wx                       import *

from KahOM.RecoElem                    import RecoElem
from KahOM.Model                       import Model
from ModelEditor.RecoElempanel         import RecoElempanel
from CatalogServices.Catalog           import Catalog
from MeSharedEditServer                import meSharedEditServerStart
from MeSharedEditServer                import getRecoElemById
from MeSharedEditServer                import getRecoElemByIdLocal
from KahDataServices.KahPrimitiveConverter import KahPrimitiveConverter
#from KahOMGen.KahOMDataPrimitiveHandler              import registerAll as registerKahOM
#from FoundryInfoGen.FoundryInfoDataPrimitiveHandler  import registerAll as registerFoundryInfo


class CatalogTreeItemData:
    """
    Manages data associated with a treeItem in the wx catalog tree
    """
    def __init__(self, theLoader, theLoaderArg, theTreeItemId, isCb ):
        """
        @rtype theLoader:  method to load associated data
        @rtype theLoaderArg: arg to theLoader.  will be wrapped in []
        @rtype theTreeItemId: wx id of tree item that we're associated with
        @rtype isCb:  1/0  1 if this is a clipboard entry.
        """
        
        self.loader     = theLoader
        self.loaderArg  = theLoaderArg
        self.treeItemId = theTreeItemId
        self.isCb       = isCb

        return
    


#------------------------------------------------------------------------
class Catalogpanel:
#------------------------------------------------------------------------

    #------------------------------------------------------------------------
    def __init__(self, parent):
    #------------------------------------------------------------------------
        self.parent            = parent

        self.selected = None       #remember last selected catalog entry
                                   #..is used when LOAD button is hit.

        self.meAGMgr =  None
        """ MeAGMgr that manages AG shared app ops.  Set in startAGClipboard """

        self.cbRootItemId = None
        """ itemId of the wxTree item that has the clipboards under it."""

        self.cbStarted = 0
        """ flags whether shared editing has started """

        self.__myCbHost = None
        """ (host, portid) of our own connection so we can recognize self """

        #self.__convMgr  = ConversionManager(XmlRpcConverter())
        self.__convMgr  = KahPrimitiveConverter( debugPrint = 1)
        """ ConversionManager for serialize/deserialze of complex obj nets """

        #registerKahOM(self.__convMgr  )
        #registerFoundryInfo( self.__convMgr )

        # seedItemId is the wxPython id for the "Seed" node
        # in the catalog tree under which all specific Seed servers
        # are listed

        self.seedItemId        = None

        self.initCatEvents()
        self.initCatData()


        # setup catalog editing menu (right click)

        self.catEditMenu         = wxMenu()
        self.catEditMkItemId     = wxNewId()
        self.catEditMkDirId      = wxNewId()
        self.setupCatEditMenu()

        return

    
    #------------------------------------------------------------------------
    def initCatEvents(self):
    #------------------------------------------------------------------------

        EVT_TREE_SEL_CHANGED(self.parent.catalog_tree,
                             self.parent.catalog_treeId,
                             self.onLeftClick)

        # Right click on List item for Seed will let you connect to
        # another Seed server

        EVT_RIGHT_DOWN(self.parent.catalog_tree, self.onRightClickCatalogTree)

                
        EVT_LEFT_DCLICK (self.parent.catalog_tree, self.onLeftDClick)

        EVT_COMBOBOX(self.parent.catVersionValueComboBox,
                     self.parent.catVersionValueComboBox.GetId(),
                     self.onCatVersionValueComboBox)

        return
        
    #------------------------------------------------------------------------
    def initCatData( self ):
    #------------------------------------------------------------------------

        catalogRootId             = self.parent.catalog_tree.AddRoot("/")
        self.parent.catalogRootId = catalogRootId
        parentTree                = self.parent.catalog_tree

        newItemId = parentTree.AppendItem(catalogRootId, "AG Shared Clipboards" )
        d         = CatalogTreeItemData(self.clipboardItemLoader, (), newItemId, 1)
        self.cbRootItemId = newItemId

        parentTree.SetPyData( newItemId, d)

        self.loadCatalog()

        self.parent.catalog_tree.Expand( self.parent.catalogRootId)
        return

    #------------------------------------------------------------------
    def setupCatEditMenu(self):
    #------------------------------------------------------------------

        self.catEditMenu.Append( self.catEditMkDirId,
                                 "New Directory", "NewDirectory" )
        EVT_MENU(self.parent, self.catEditMkDirId, self.doCatEditMkDir)

        self.catEditMenu.Append( self.catEditMkItemId,
                                 "New Item", "NewDirectory" )
        EVT_MENU(self.parent, self.catEditMkItemId, self.doCatEditMkItem)

        return

    #------------------------------------------------------------------------
    def loadCatalog(self):
    #------------------------------------------------------------------------
        wxBeginBusyCursor()

        #localSeedServer        = "http://localhost/FIG"
        #seedFactory   = SeedDataFactory( localSeedServer )

        ##
        # DO NOT CREATE BssFactory() HERE ANY LONGER
        # See main progam, ModelEditor
        ##

        ##
        # Handle top/root of catalog/tree specially to avoid "two root"
        # on display problem
        ##

        top = Catalog.instance().getCatalogTop()
        parentTree = self.parent.catalog_tree
        d=CatalogTreeItemData(self.recoElemLoader, top, self.parent.catalogRootId,0)
        parentTree.SetPyData( self.parent.catalogRootId, d)

        for e in top.entries():
            self.recurseCatalog( e, parentTree, self.parent.catalogRootId)

        parentTree.SortChildren( self.parent.catalogRootId)

        wxEndBusyCursor()

        return

    #------------------------------------------------------------------------
    def recurseCatalog( self, catEntry, parentTree, parentItemId):
    #------------------------------------------------------------------------
        """
        Create a new item under parentItemId in wxTree, parentTree.  Associate
        catEntry with it.  If catEntry has entries, recurse on them.
        """

        if ( catEntry.isTerminal() ): 
            displayedName = catEntry.name()
        else:
            displayedName = catEntry.name() + "/"

        newItemId=parentTree.AppendItem(parentItemId, displayedName )

        # associate data needed to manipulate the catEntry

        d=CatalogTreeItemData(self.recoElemLoader, catEntry, newItemId, 0 )
        parentTree.SetPyData( newItemId, d)

        if ( not catEntry.isTerminal() ):
            for e in catEntry.entries():
                self.recurseCatalog( e, parentTree, newItemId)

        parentTree.SortChildren( newItemId )

        return

    #------------------------------------------------------------------------
    def DOOMloadSeedCatalog(self, seedServer ):
    #------------------------------------------------------------------------
        """
        This adds a Seed instance to the catalog.  It is called from the
        MainMenuBar when Data->Add Seed Instance is called, for example.
        """

        wxBeginBusyCursor()

	# The SeedDataFactory ctor is slow and actually reads a bunch of
	# data from the server

        seedFactory   = SeedDataFactory( seedServer )

        # add it to the list in the catalog
        try:
            Catalog.instance().addDataFactory( seedFactory )
        except:
            self.parent.error("loadSeedCatalog: %s already in foundry list." % seedServer)
            wxEndBusyCursor()
            return

        top = seedFactory.getCatalogTop()
        self.recurseCatalog( top, self.parent.catalog_tree, self.parent.catalogRootId)

        wxEndBusyCursor()

        return

    #------------------------------------------------------------------------
    def onLeftClick(self,treeEvent):
    #------------------------------------------------------------------------
        item = treeEvent.GetItem()
        
        catTreeItemData = self.parent.tree_ctr.GetPyData(item)
        if (catTreeItemData == None ):
            return
        self.selected = catTreeItemData

        if (catTreeItemData.isCb): return

        catEntry   = catTreeItemData.loaderArg

        ##
        # update the history information display
        ##

        theBox = self.parent.catVersionValueComboBox
        theBox.Clear()

        if ( not catEntry.isTerminal() ):
            
            self.parent.catPathValue.SetValue( catEntry.path() + "/" )
            self.parent.catVersionValueComboBox.SetLabel( "")
            self.parent.catHistoryDateValue.SetLabel( "" )
            self.parent.catHistoryUserValue.SetLabel( "" )
            self.parent.catHistoryCreatedFromValue.SetLabel( "")
            theBox.SetValue( "" )
        else:
            versions   = catEntry.versions()
            if ( [] == versions ):
                self.parent.catPathValue.SetValue( catEntry.path()+";[None]" )
                theBox.SetValue( "None" )
            else:
                maxVersion = max( versions )
                for v in versions:
                    theBox.Append( "%s" % (v ) )
                    theBox.SetValue( "%s" % (maxVersion) )
                self.parent.catPathValue.SetValue(catEntry.path()+";[%s]" % (maxVersion))
            #
            self.parent.catHistoryDateValue.SetLabel( "no date info yet" )
            self.parent.catHistoryUserValue.SetLabel( "no user info yet" )
            self.parent.catHistoryCreatedFromValue.SetLabel( "no history info yet" )
            
        return


    #------------------------------------------------------------------------
    def onCatVersionValueComboBox(self, event):
    #------------------------------------------------------------------------
        """
        Handles activity in combo box where user sets Verion to use
        """
                
        if self.selected.isCb: return
        
        # get the value selected in the combo box.
        choice = event.GetString()
        self.parent.catVersionValueComboBox.SetValue( "%s" % (choice) )

        # the operation is interpreted relative to the currently selected
        # catalogEntry.  find what that is.
        
        catEntry   = self.selected.loaderArg

        # update stuff
        #version = self.parent.catVersionValueComboBox.GetValue()
        self.parent.catPathValue.SetValue( catEntry.path()+";[%s]" % (choice) )

        return
    
        
    #------------------------------------------------------------------------
    def onRightClickCatalogTree(self, event):
    #------------------------------------------------------------------------
        """ Fires off the pop-up menu to handle right click events. """

        event.GetEventObject().PopupMenu(self.catEditMenu, event.GetPosition())
        return

    #------------------------------------------------------------------------
    def doCatEditMkDir( self, event ):
    #------------------------------------------------------------------------

        if (None == self.selected):
            self.parent.error( "A selection is required first.")
            return
        
        if (self.selected.isCb):
            self.parent.error( "No catalog editing for clipboard items" )
            return

        catTreeItemData = self.selected
        catEntry      = catTreeItemData.loaderArg
        treeItemId    = catTreeItemData.treeItemId
        
        if (catEntry.isTerminal()):
            self.parent.error("Directories can not be added to items.")
            return

        prompt = "New catalog directory name:"
        dlg = wxTextEntryDialog(self.parent, message=prompt, style=wxOK|wxCANCEL)
        if ( dlg.ShowModal() == wxID_OK):
            theName = dlg.GetValue()
            if ( theName=="" ): return
            dlg.Destroy()
        else:
            #didn't get a kid name
            dlg.Destroy()
            return

        try:
            newCatEntry=catEntry.mkDir( theName )
            parentTree=self.parent.catalog_tree
            newItemId=parentTree.AppendItem(treeItemId, newCatEntry.name() )
            d=CatalogTreeItemData(self.recoElemLoader, newCatEntry, newItemId, 0)
            parentTree.SetPyData( newItemId, d)

            parentTree.SortChildren( treeItemId )
        except:
            self.parent.error( "Operation refused.by owning Factory" )
            

        return 

    #------------------------------------------------------------------------
    def doCatEditMkItem( self, event ):
    #------------------------------------------------------------------------
        if (None == self.selected):
            self.parent.error( "A selection is required first.")
            return

        if (self.selected.isCb):
            self.parent.error( "No catalog editing for clipboard items" )
            return

        catTreeItemData = self.selected
        catEntry      = catTreeItemData.loaderArg
        treeItemId    = catTreeItemData.treeItemId

        if (catEntry.isTerminal()):
            self.parent.error("Items can not be added to items. Add to a directory.")
            return

        prompt = "New catalog entry name:"
        dlg = wxTextEntryDialog(self.parent, message=prompt, style=wxOK|wxCANCEL)

        if ( dlg.ShowModal() == wxID_OK):
            theName = dlg.GetValue()
            if ( theName=="" ): return
            dlg.Destroy()
        else:
            #didn't get a kid name
            dlg.Destroy()
            return

        try:
            newCatEntry = catEntry.mkItem( theName )
            parentTree=self.parent.catalog_tree
            newItemId=parentTree.AppendItem(treeItemId, newCatEntry.name() )
            d=CatalogTreeItemData(self.recoElemLoader, newCatEntry, newItemId, 0)
            parentTree.SetPyData( newItemId, d)

            parentTree.SortChildren( treeItemId )
        except:
            self.parent.error( "Operation refused.by owning Factory" )
            

        return 


    #------------------------------------------------------------------------
    def onLeftDClick(self, event):
    #------------------------------------------------------------------------
        """ Double left-click means, "Load the currently selected item." """

        if ( self.selected == None ):
            self.parent.error( "You must select a catalog entry before requesting load.")
            return 

        # We store a loader to actually load the selected item.  This dates
        # back to a time before a single loader could handle all the various
        # data factory kinds.

        catTreeItemData = self.selected
        apply( catTreeItemData.loader, [catTreeItemData.loaderArg] )

        return
    
    #------------------------------------------------------------------------
    def recoElemLoader(self,  argList ):
    #------------------------------------------------------------------------
        wxBeginBusyCursor()

        (catalogEntry) = argList

        if (catalogEntry.isTerminal() ):
            if ( self.parent.catVersionValueComboBox.IsEmpty()):
                model = Model(  catalogEntry.name() )
                top = RecoElem( catalogEntry.name() )
                model.setTop( top )
            else:
                ver = self.parent.catVersionValueComboBox.GetValue()
                model =  catalogEntry.read( int( ver ) )
                top = model.getTop()
                
            self.parent.re.addRecoElemTree(self.parent.rootId, model, top, catalogEntry)
        else:
            # current selection is directory. can't load that!
            wxEndBusyCursor()
            return


        wxEndBusyCursor()
        return

    #------------------------------------------------------------------------
    def startAGClipboard(self, cbName, meAGMgr):
    #------------------------------------------------------------------------
        """
        @type cbName: string    Name that everyone will see in the catalog tree
        @rtype: None

        It is a mistake to call this twice.  Called from MainMenuBar.
        """

        print "starting new cb"

        # stash a ptr to the AG manager
        self.meAGMgr = meAGMgr

        # Make sure name isn't already used
        if self.meAGMgr.nameUsed( cbName ):
            raise KeyError

        # register AG event handlers
        print "registering cb handlers"
        self.meAGMgr.registerHandlers(self.newCbHandler,
                                      self.changedCbHandler,
                                      self.delCbHandler)

        # start up xmlrpc server.
        # remember our own identifier so we can recognize self later

        (host,port) = meSharedEditServerStart()
        self.__myCbHost = (host, port)
        

        # Set state in shared app and send event announcing our cb.
        # This will come back to us as a newCb event which will
        # cause us to update our own catalog display
        
        self.meAGMgr.newCb(cbName, host, port)

        self.cbStarted = 1
        self.parent.SetTitle("MONERA Model Editor (clipboard=%s)" % (cbName) )

        return
    
    #------------------------------------------------------------------------
    def stopAGClipboard(self):
    #------------------------------------------------------------------------
        """
        @rtype: None

        Stop shared clipboard.  Remove ourselves from the shared app (but
        stay connected).  Drop the clipboards shared from others.
        """

        print "stopAGClipboard"
        self.cbStarted = 0
        self.meAGMgr.delCb()
        self.parent.catalog_tree.DeleteChildren( self.cbRootItemId )
        
        self.parent.SetTitle("MONERA Model Editor")
        return

    #------------------------------------------------------------------------
    def newCbHandler(self, event ):
    #------------------------------------------------------------------------
        """ Handles  AG event corresponding to someone adding a new clipboard """
        print "newCbHandler"
        self.rebuildCbView()

        return

    #------------------------------------------------------------------------
    def changedCbHandler( self, event ):
    #------------------------------------------------------------------------
        """ Handles AG event when someones clipboard has changed """
        print "changedCbHandler"
        self.rebuildCbView()
        return

    #------------------------------------------------------------------------
    def delCbHandler(self, event ):
    #------------------------------------------------------------------------
        """ Handles AG event when someone has removed their clipboard """
        print "delCbHandler"
        self.rebuildCbView()
        return

    #------------------------------------------------------------------------
    def rebuildCbView(self):
    #------------------------------------------------------------------------
        """ updates the wxTree holding the clipboard info """
        
        print "rebuildCbView"
        

        try:
            parentTree                = self.parent.catalog_tree

            parentTree.DeleteChildren( self.cbRootItemId )
        
            state = self.meAGMgr.getAllCbState()

            for (cbInfo, cbObjList) in state:
                (cbName, host, port) = cbInfo
                print "cbInfo: ", cbInfo
                displayName = "%s@%s:%d" % (cbName, host, int(port) )
                cbItemId = parentTree.AppendItem(self.cbRootItemId, displayName)
                d  = CatalogTreeItemData(self.clipboardItemLoader, (), cbItemId, 1)
                parentTree.SetPyData( cbItemId, d)

                for (objName, objId) in cbObjList:
                    objItemId = parentTree.AppendItem(cbItemId, objName )
                    d =CatalogTreeItemData(self.clipboardItemLoader,
                                           (cbName, host, port, objId), objItemId, 1)
                    parentTree.SetPyData( objItemId, d)
        except Exception, e:
            print e
                
            
        parentTree.Refresh()

        print "done rebuildCbView"
        return
    
    #------------------------------------------------------------------------
    def clipboardItemLoader(self,  argList ):
    #------------------------------------------------------------------------
        """ Loads an item on the clipboard from the remote peer """
        
        wxBeginBusyCursor()

        print "clipboardItemLoader", argList
        if ( () == argList ):
            print "Not an item"
            return

        print "trying for ", argList

        (cbName, host, port, objItemId) = argList
        print "(cbName, host, port, objItemId) ", cbName, host, port, objItemId, objItemId
        
        if (self.__myCbHost == (host,port)):
            # no sense going remote to talk to myself
            print "going for self"
            top = getRecoElemByIdLocal( objItemId )
        else:
            # get from remote clipboard server
            url       = "http://%s:%d" % (host, port)
            xmlServer = xmlrpclib.Server(url)
            try:
                pRe       = xmlServer.getRecoElemById( objItemId )
            except:
                self.parent.error( "Could not connect to peer")
                wxEndBusyCursor()
                return

            try:
                print "loader got pRe of", pRe
                lRe       = xmlrpclib.loads(pRe)
                print "loader makes lRe of", lRe
                top       = self.__convMgr.read(lRe[0][0])
                print "loader made top:"
                top.dump()
            except:
                self.parent.error( "Data format error" )
                wxEndBusyCursor()
                return

        # add to the navigator
        
        cbDescription = "%s@%s:%d::" % (cbName, host, int(port) )
        self.parent.re.addCbItem(top, cbDescription)

        wxEndBusyCursor()
        return


MCS Webmaster
ViewVC Help
Powered by ViewVC 1.0.3