コード例 #1
0
ファイル: kkit.py プロジェクト: dilawar/moose-gui
class KineticsWidget(EditorWidgetBase):

    def __init__(self, plugin, *args):
        EditorWidgetBase.__init__(self, *args)
        self.plugin = plugin
        self.border = 5
        self.comptPen = 5
        self.iconScale = 1
        self.arrowsize = 2
        self.defaultComptsize = 5
        self.noPositionInfo = True
        self.xyCord = {}
        self.reset()
        self.qGraCompt = {}
        self.mooseId_GObj = {}
        self.srcdesConnection = {}
        self.editor = None
        self.xmin = 0.0
        self.xmax = 1.0
        self.ymin = 0.0
        self.ymax = 1.0
        self.xratio = 1.0
        self.yratio = 1.0

    def reset(self):
        self.createdItem = {}
        # This are created at drawLine
        self.lineItem_dict = {}
        self.object2line = defaultdict(list)
        self.itemignoreZooming = False

        if hasattr(self, 'sceneContainer'):
            self.sceneContainer.clear()
        self.sceneContainer = QtGui.QGraphicsScene(self)
        self.sceneContainer.setItemIndexMethod(QtGui.QGraphicsScene.NoIndex)
        sceneDim = self.sceneContainer.itemsBoundingRect()
        # if (sceneDim.width() == 0 and sceneDim.height() == 0):
        #     self.sceneContainer.setSceneRect(0,0,30,30)
        # else:
        # elf.sceneContainer.setSceneRect(self.sceneContainer.itemsBoundingRect())
        self.sceneContainer.setBackgroundBrush(QColor(230, 220, 219, 120))

    def updateModelView(self):
        self.getMooseObj()
        minmaxratiodict = {
            'xmin': self.xmin,
            'xmax': self.xmax,
            'ymin': self.ymin,
            'ymax': self.ymax,
            'xratio': self.xratio,
            'yratio': self.yratio}
        if not self.m:
            # At the time of model building
            # when we want an empty GraphicView while creating new model,
            # then remove all the view and add an empty view
            if hasattr(self, 'view') and isinstance(self.view, QtGui.QWidget):
                self.layout().removeWidget(self.view)
           # self.sceneContainer.setSceneRect(-self.width()/2,-self.height()/2,self.width(),self.height())
            self.view = GraphicalView(
                self.modelRoot,
                self.sceneContainer,
                self.border,
                self,
                self.createdItem,
                minmaxratiodict)

            if isinstance(self, KineticEditorWidget):
                self.view.setRefWidget("editorView")
                self.view.setAcceptDrops(True)
            elif isinstance(self, kineticRunWidget):
                self.view.setRefWidget("runView")
            # self.connect(self.view, QtCore.SIGNAL("dropped"), self.objectEditSlot)
            hLayout = QtGui.QGridLayout(self)
            self.setLayout(hLayout)
            hLayout.addWidget(self.view, 0, 0)
        else:
            # Already created Model
            # maxmium and minimum coordinates of the objects specified in kkit file.
            # self.mooseObjOntoscene()
            # self.drawLine_arrow()
            if hasattr(self, 'view') and isinstance(self.view, QtGui.QWidget):
                self.layout().removeWidget(self.view)
            self.view = GraphicalView(
                self.modelRoot,
                self.sceneContainer,
                self.border,
                self,
                self.createdItem,
                minmaxratiodict)
            if isinstance(self, KineticEditorWidget):
                # self.getMooseObj()
                self.mooseObjOntoscene()
                self.drawLine_arrow()
                self.view.setRefWidget("editorView")
                self.view.setAcceptDrops(True)
                # self.connect(self.view, QtCore.SIGNAL("dropped"), self.objectEditSlot)
                hLayout = QtGui.QGridLayout(self)
                self.setLayout(hLayout)
                hLayout.addWidget(self.view)
            elif isinstance(self, kineticRunWidget):
                self.view.setRefWidget("runView")
                hLayout = QtGui.QGridLayout(self)
                self.setLayout(hLayout)
                hLayout.addWidget(self.view)
                self.view.fitInView(
                    self.sceneContainer.itemsBoundingRect().x() - 10,
                    self.sceneContainer.itemsBoundingRect().y() - 10,
                    self.sceneContainer.itemsBoundingRect().width() + 20,
                    self.sceneContainer.itemsBoundingRect().height() + 20,
                    Qt.Qt.IgnoreAspectRatio)

    def getMooseObj(self):
        # This fun call 2 more function
        # -- setupMeshObj(self.modelRoot),
        #    ----self.meshEntry has [meshEnt] = function: {}, Pool: {} etc
        # setupItem
        self.m = wildcardFind(self.modelRoot + '/##[ISA=ChemCompt]')
        if self.m:
            # self.xmin = 0.0
            # self.xmax = 1.0
            # self.ymin = 0.0
            # self.ymax = 1.0
            self.autoCordinatepos = {}
            self.srcdesConnection = {}

            #self.meshEntry.clear= {}
            # Compartment and its members are setup
            self.meshEntry, self.xmin, self.xmax, self.ymin, self.ymax, self.noPositionInfo = setupMeshObj(
                self.modelRoot)
            self.autocoordinates = False
            if self.srcdesConnection:
                self.srcdesConnection.clear()
            else:
                self.srcdesConnection = {}
            setupItem(self.modelRoot, self.srcdesConnection)
            if not self.noPositionInfo:
                self.autocoordinates = True

                self.xmin, self.xmax, self.ymin, self.ymax, self.autoCordinatepos = autoCoordinates(
                    self.meshEntry, self.srcdesConnection)
            # TODO: size will be dummy at this point, but size I need the
            # availiable size from the Gui
            self.size = QtCore.QSize(1000, 550)

            if self.xmax - self.xmin != 0:
                self.xratio = (self.size.width() - 10) / \
                    (self.xmax - self.xmin)
            else:
                self.xratio = self.size.width() - 10

            if self.ymax - self.ymin:
                self.yratio = (self.size.height() - 10) / \
                    (self.ymax - self.ymin)
            else:
                self.yratio = (self.size.height() - 10)

            self.xratio = int(self.xratio)
            self.yratio = int(self.yratio)
            if self.xratio == 0:
                self.xratio = 1
            if self.yratio == 0:
                self.yratio = 1

    def sizeHint(self):
        return QtCore.QSize(800, 400)

    def updateItemSlot(self, mooseObject):
        # This is overridden by derived classes to connect appropriate
        # slot for updating the display item.
        # In this case if the name is updated from the keyboard both in
        # mooseobj and gui gets updation
        changedItem = ''

        for item in list(self.sceneContainer.items()):
            if isinstance(item, PoolItem):
                if mooseObject.getId() == element(item.mobj).getId():
                    item.updateSlot()
                    # once the text is edited in editor, laydisplay gets
                    # updated in turn resize the length, positionChanged signal
                    # shd be emitted
                    self.positionChange(mooseObject)
                    self.view.removeConnector()
                    self.view.showConnector(item)

    def updateColorSlot(self, mooseObject, color):
        # Color slot for changing background color for PoolItem from
        # objecteditor
        anninfo = moose.Annotator(mooseObject.path + '/info')
        textcolor, bgcolor = getColor(anninfo)
        anninfo.color = str(color.name())
        item = self.mooseId_GObj[mooseObject]
        if (isinstance(item, PoolItem) or isinstance(
                item, EnzItem) or isinstance(item, MMEnzItem)):
            item.updateColor(color)

    def mooseObjOntoscene(self):
        #  All the compartments are put first on to the scene \
        #  Need to do: Check With upi if empty compartments exist
        self.qGraCompt = {}
        self.mooseId_GObj = {}
        if self.qGraCompt:
            self.qGraCompt.clear()
        else:
            self.qGraCompt = {}
        if self.mooseId_GObj:
            self.mooseId_GObj.clear()
        else:
            self.mooseId_GObj = {}

        for cmpt in sorted(self.meshEntry.keys()):
            self.createCompt(cmpt)
            self.qGraCompt[cmpt]
            #comptRef = self.qGraCompt[cmpt]

        # Enzymes of all the compartments are placed first, \
        #     so that when cplx (which is pool object) queries for its parent, it gets its \
        #     parent enz co-ordinates with respect to QGraphicsscene """

        for cmpt, memb in list(self.meshEntry.items()):
            for enzObj in find_index(memb, 'enzyme'):
                enzinfo = enzObj.path + '/info'
                if enzObj.className == 'Enz':
                    enzItem = EnzItem(enzObj, self.qGraCompt[cmpt])
                else:
                    enzItem = MMEnzItem(enzObj, self.qGraCompt[cmpt])
                self.mooseId_GObj[element(enzObj.getId())] = enzItem
                self.setupDisplay(enzinfo, enzItem, "enzyme")

                # self.setupSlot(enzObj,enzItem)
        for cmpt, memb in list(self.meshEntry.items()):
            for poolObj in find_index(memb, 'pool'):
                poolinfo = poolObj.path + '/info'
                # depending on Editor Widget or Run widget pool will be created
                # a PoolItem or PoolItemCircle
                poolItem = self.makePoolItem(poolObj, self.qGraCompt[cmpt])
                self.mooseId_GObj[element(poolObj.getId())] = poolItem
                self.setupDisplay(poolinfo, poolItem, "pool")

            for reaObj in find_index(memb, 'reaction'):
                reainfo = reaObj.path + '/info'
                reaItem = ReacItem(reaObj, self.qGraCompt[cmpt])
                self.setupDisplay(reainfo, reaItem, "reaction")
                self.mooseId_GObj[element(reaObj.getId())] = reaItem

            for tabObj in find_index(memb, 'table'):
                tabinfo = tabObj.path + '/info'
                tabItem = TableItem(tabObj, self.qGraCompt[cmpt])
                self.setupDisplay(tabinfo, tabItem, "tab")
                self.mooseId_GObj[element(tabObj.getId())] = tabItem

            for funcObj in find_index(memb, 'function'):
                funcinfo = moose.element(funcObj).path + '/info'
                if funcObj.parent.className in [ "ZombieBufPool", "BufPool" ]:
                    funcinfo = moose.element(funcObj).path + '/info'
                    Af = Annotator(funcinfo)
                    funcParent = self.mooseId_GObj[element(funcObj.parent)]
                elif funcObj.parent.className in [ "CubeMesh", "CylMesh"] :
                    funcParent = self.qGraCompt[cmpt]
                funcItem = FuncItem(funcObj, funcParent)
                self.mooseId_GObj[element(funcObj.getId())] = funcItem
                self.setupDisplay(funcinfo, funcItem, "Function")

            for cplxObj in find_index(memb, 'cplx'):
                cplxinfo = (cplxObj.parent).path + '/info'
                p = element(cplxObj).parent
                cplxItem = CplxItem(
                    cplxObj, self.mooseId_GObj[
                        element(cplxObj).parent])
                self.mooseId_GObj[element(cplxObj.getId())] = cplxItem
                self.setupDisplay(cplxinfo, cplxItem, "cplx")

        # compartment's rectangle size is calculated depending on children
        self.comptChilrenBoundingRect()

    def comptChilrenBoundingRect(self):
        for k, v in list(self.qGraCompt.items()):
            # compartment's rectangle size is calculated depending on children
            rectcompt = calculateChildBoundingRect(v)
            v.setRect(
                rectcompt.x() - 10,
                rectcompt.y() - 10,
                (rectcompt.width() + 20),
                (rectcompt.height() + 20))
            v.setPen(
                QtGui.QPen(
                    Qt.QColor( 66, 66, 66, 100),
                    self.comptPen,
                    Qt.Qt.SolidLine,
                    Qt.Qt.RoundCap,
                    Qt.Qt.RoundJoin)
                )

    def createCompt(self, key):
        self.new_Compt = ComptItem(self, 0, 0, 0, 0, key)
        self.qGraCompt[key] = self.new_Compt
        self.new_Compt.setRect(10, 10, 10, 10)
        self.sceneContainer.addItem(self.new_Compt)

    def setupDisplay(self, info, graphicalObj, objClass):
        Annoinfo = Annotator(info)
        if objClass in [ "reaction", "cplx", "Function", "StimulusTable" ]:
            textcolor, bgcolor = QColor("white"), QColor("white")
        else:
            textcolor, bgcolor = getColor(info)
            if bgcolor.name() == "#ffffff" or bgcolor == "white":
                bgcolor = getRandColor()
                Annoinfo.color = str(bgcolor.name())

        if isinstance(self, KineticEditorWidget):
            funct = ["Function", "ZombieFunction"]
            comptt = ["CubeMesh", "CylMesh"]

            if objClass in funct:
                poolt = ["ZombieBufPool", "BufPool"]
                if graphicalObj.mobj.parent.className in poolt:
                    xpos = 0
                    ypos = 30
                if graphicalObj.mobj.parent.className in comptt:
                    xpos, ypos = self.positioninfo(info)
            else:
                xpos, ypos = self.positioninfo(info)

            self.xylist = [xpos, ypos]
            self.xyCord[moose.element(info).parent] = [xpos, ypos]

        elif isinstance(self, kineticRunWidget):
            self.editormooseId_GObj = self.editor.getCentralWidget().mooseId_GObj
            editorItem = self.editormooseId_GObj[moose.element(info).parent]
            xpos = editorItem.scenePos().x()
            ypos = editorItem.scenePos().y()
            #Annoinfo.x = xpos
            #Annoinfo.y = -ypos
        graphicalObj.setDisplayProperties(xpos, ypos, textcolor, bgcolor)
        #Annoinfo.x = xpos
        #Annoinfo.y = ypos

    def positioninfo(self, iteminfo):
        Anno = moose.Annotator(self.modelRoot + '/info')
        if not self.noPositionInfo:
            try:
                # kkit does exist item's/info which up querying for parent.path
                # gives the information of item's parent
                x, y = self.autoCordinatepos[(element(iteminfo).parent).path]
            except:
                # But in Cspace reader doesn't create item's/info, up on querying gives me the error which need to change\
                # in ReadCspace.cpp, at present i am taking care b'cos i don't want to pass just the item where I need to check\
                # type of the object (rea,pool,enz,cplx,tab) which I have
                # already done.
                parent, child = posixpath.split(iteminfo)
                x, y = self.autoCordinatepos[parent]
            ypos = (y - self.ymin) * self.yratio
        else:
            x = float(element(iteminfo).getField('x'))
            y = float(element(iteminfo).getField('y'))
            # Qt origin is at the top-left corner. The x values increase to the right and the y values increase downwards \
            # as compared to Genesis codinates where origin is center and y value is upwards, that is why ypos is negated
            # if Anno.modeltype == "kkit":
            #     ypos = 1.0-(y-self.ymin)*self.yratio
            # else:
            #     ypos = (y-self.ymin)*self.yratio
            ypos = 1.0 - (y - self.ymin) * self.yratio
        xpos = (x - self.xmin) * self.xratio
        return(xpos, ypos)

    def drawLine_arrow(self, itemignoreZooming=False):
        for inn, out in list(self.srcdesConnection.items()):
            # print "inn ",inn, " out ",out
            # self.srcdesConnection is dictionary which contains key,value \
            #    key is Enzyme or Reaction  and value [[list of substrate],[list of product]] (tuple)
            #    key is Function and value is [list of pool] (list)

            #src = self.mooseId_GObj[inn]
            if isinstance(out, tuple):
                src = self.mooseId_GObj[inn]
                if len(out[0]) == 0:
                    print(
                        inn.className +
                        ' : ' +
                        inn.name +
                        " doesn't output message")
                else:
                    for items in (items for items in out[0]):
                        des = self.mooseId_GObj[element(items[0])]
                        self.lineCord(src, des, items, itemignoreZooming)
                if len(out[1]) == 0:
                    print(
                        inn.className +
                        ' : ' +
                        inn.name +
                        " doesn't output message")
                else:
                    for items in (items for items in out[1]):
                        des = self.mooseId_GObj[element(items[0])]
                        self.lineCord(src, des, items, itemignoreZooming)
            elif isinstance(out, list):
                if len(out) == 0:
                    if inn.className == "StimulusTable":
                        print(inn.name + " doesn't have output")
                    elif inn.className == "ZombieFunction" or inn.className == "Function":
                        print(inn.name + " doesn't have sumtotal ")
                else:
                    src = self.mooseId_GObj[inn]
                    for items in (items for items in out):
                        des = self.mooseId_GObj[element(items[0])]
                        self.lineCord(src, des, items, itemignoreZooming)

    def lineCord(self, src, des, type_no, itemignoreZooming):
        srcdes_list = []
        endtype = type_no[1]
        line = 0
        if (src == "") and (des == ""):
            print("Source or destination is missing or incorrect")
            return
        srcdes_list = [src, des, endtype, line]
        arrow = calcArrow(srcdes_list, itemignoreZooming, self.iconScale)
        self.drawLine(srcdes_list, arrow)

        while(type_no[2] > 1 and line <= (type_no[2] - 1)):
            srcdes_list = [src, des, endtype, line]
            arrow = calcArrow(srcdes_list, itemignoreZooming, self.iconScale)
            self.drawLine(srcdes_list, arrow)
            line = line + 1

        if type_no[2] > 5:
            print("Higher order reaction will not be displayed")

    def drawLine(self, srcdes_list, arrow):
        src = srcdes_list[0]
        des = srcdes_list[1]
        endtype = srcdes_list[2]
        line = srcdes_list[3]
        source = element(
            next(
                (k for k,
                 v in list(
                     self.mooseId_GObj.items()) if v == src),
                None))
        for l, v, et, o in self.object2line[src]:
            if v == des and o == line:
                l.setPolygon(arrow)
                arrowPen = l.pen()
                arrowPenWidth = self.arrowsize * self.iconScale
                arrowPen.setColor(l.pen().color())
                arrowPen.setWidth(arrowPenWidth)
                l.setPen(arrowPen)
                return
        qgLineitem = self.sceneContainer.addPolygon(arrow)
        qgLineitem.setParentItem(src.parentItem())
        pen = QtGui.QPen(
            QtCore.Qt.green,
            0,
            Qt.Qt.SolidLine,
            Qt.Qt.RoundCap,
            Qt.Qt.RoundJoin)
        pen.setWidth(self.arrowsize)
        # Green is default color moose.ReacBase and derivatives - already set
        # above
        if isinstance(source, EnzBase):
            if ((endtype == 's') or (endtype == 'p')):
                pen.setColor(QtCore.Qt.red)
            elif(endtype != 'cplx'):
                p1 = (
                    next(
                        (k for k,
                         v in list(
                             self.mooseId_GObj.items()) if v == src),
                        None))
                pinfo = p1.parent.path + '/info'
                color, bgcolor = getColor(pinfo)
                #color = QColor(color[0],color[1],color[2])
                pen.setColor(bgcolor)

        elif isinstance(source, moose.PoolBase) or isinstance(source, moose.Function):
            pen.setColor(QtCore.Qt.blue)
        elif isinstance(source, moose.StimulusTable):
            pen.setColor(QtCore.Qt.yellow)
        self.lineItem_dict[qgLineitem] = srcdes_list
        self.object2line[src].append((qgLineitem, des, endtype, line))
        self.object2line[des].append((qgLineitem, src, endtype, line))
        qgLineitem.setPen(pen)

    def positionChange(self, mooseObject):
        # If the item position changes, the corresponding arrow's are
        # calculated
        if isinstance(element(mooseObject), ChemCompt):
            for k, v in list(self.qGraCompt.items()):
                mesh = mooseObject
                if k.path == mesh:
                    for rectChilditem in v.childItems():
                        if isinstance(rectChilditem, KineticsDisplayItem):
                            if isinstance(
                                    moose.element(
                                        rectChilditem.mobj.path),
                                    PoolBase):
                                t = moose.element(rectChilditem.mobj.path)
                                moose.element(t).children
                                for items in moose.element(t).children:
                                    if isinstance(
                                            moose.element(items), Function):
                                        test = moose.element(items.path + '/x')
                                        for i in moose.element(
                                                test).neighbors['input']:
                                            j = self.mooseId_GObj[
                                                moose.element(i)]
                                            self.updateArrow(j)
                            self.updateArrow(rectChilditem)
        else:
            mobj = self.mooseId_GObj[element(mooseObject)]
            self.updateArrow(mobj)
            elePath = moose.element(mooseObject).path
            pos = elePath.find('/', 1)
            l = elePath[0:pos]
            linfo = moose.Annotator(l + '/info')
            for k, v in list(self.qGraCompt.items()):
                #rectcompt = v.childrenBoundingRect()
                rectcompt = calculateChildBoundingRect(v)
                comptBoundingRect = v.boundingRect()
                if not comptBoundingRect.contains(rectcompt):
                    self.updateCompartmentSize(v)
                '''
                if linfo.modeltype == "new_kkit":
                    #if newly built model then compartment is size is fixed for some size.
                    comptBoundingRect = v.boundingRect()
                    if not comptBoundingRect.contains(rectcompt):
                        self.updateCompartmentSize(v)
                else:
                    #if already built model then compartment size depends on max and min objects
                    rectcompt = calculateChildBoundingRect(v)
                    v.setRect(rectcompt.x()-10,rectcompt.y()-10,(rectcompt.width()+20),(rectcompt.height()+20))
                '''

    def updateCompartmentSize(self, compartment):
        compartmentBoundary = compartment.rect()
        # print " compartmentBoundary ",compartmentBoundary, "  ",compartment.childrenBoundingRect()
        #compartmentBoundary =compartment.childrenBoundingRect()
        #childrenBoundary    = compartment.childrenBoundingRect()
        # print " 758 ",compartment.childrenBoundaryRect()
        childrenBoundary = calculateChildBoundingRect(compartment)
        # print " ch ",childrenBoundary
        x = min(compartmentBoundary.x(), childrenBoundary.x())
        y = min(compartmentBoundary.y(), childrenBoundary.y())
        width = max(compartmentBoundary.width(), childrenBoundary.width())
        height = max(compartmentBoundary.height(), childrenBoundary.height())
        compartment.setRect(x - 10, y - 10, width + 20, height + 20
                            )

    def updateArrow(self, qGTextitem):
        # if there is no arrow to update then return
        if qGTextitem not in self.object2line:
            return
        listItem = self.object2line[qGTextitem]
        for ql, va, endtype, order in self.object2line[qGTextitem]:
            srcdes = []
            srcdes = self.lineItem_dict[ql]
            # Checking if src (srcdes[0]) or des (srcdes[1]) is ZombieEnz,
            # if yes then need to check if cplx is connected to any mooseObject,
            # so that when Enzyme is moved, cplx connected arrow to other
            # mooseObject(poolItem) should also be updated
            if(isinstance(srcdes[0], EnzItem) or type(srcdes[0] == MMEnzItem)):
                self.cplxUpdatearrow(srcdes[0])
            elif(isinstance(srcdes[1], EnzItem) or type(srcdes[1] == MMEnzItem)):
                self.cplxUpdatearrow(srcdes[1])
            # For calcArrow(src,des,endtype,itemignoreZooming) is to be
            # provided
            arrow = calcArrow(srcdes, self.itemignoreZooming, self.iconScale)
            ql.setPolygon(arrow)

    def cplxUpdatearrow(self, srcdes):
        # srcdes which is 'EnzItem' from this,get ChildItems are retrived (b'cos cplx is child of zombieEnz)
        # And cplxItem is passed for updatearrow
        for item in srcdes.childItems():
            if isinstance(item, CplxItem):
                self.updateArrow(item)

    # def deleteSolver(self):
    #     print " delete Solver"
    #     print "### ",moose.wildcardFind(self.modelRoot+'/data/graph#/#')
    #     if moose.wildcardFind(self.modelRoot+'/##[ISA=ChemCompt]'):
    #         compt = moose.wildcardFind(self.modelRoot+'/##[ISA=ChemCompt]')
    #         print " deletSolver ",
    #         # print moose.exists(compt[0].path+'/stoich'), " ksolve ", moose.exists(compt[0].path+'/ksolve')
    #         # print "gsolve ", moose.delete( compt[0].path+'/gsolve' )
    #         if ( moose.exists( compt[0].path+'/stoich' ) ):
    #             #print "delete"
    #             moose.delete( compt[0].path+'/stoich' )
    #         if ( moose.exists( compt[0].path+'/ksolve' ) ):
    #             moose.delete( compt[0].path+'/ksolve' )
    #         if ( moose.exists( compt[0].path+'/gsolve' ) ):
    #             moose.delete( compt[0].path+'/gsolve' )
    #         for x in moose.wildcardFind( self.modelRoot+'/data/graph#/#' ):
    #                 x.tick = -1
    def positionChange1(self, mooseObject):
        # If the item position changes, the corresponding arrow's are
        # calculated
        if ((isinstance(element(mooseObject), CubeMesh))
                or (isinstance(element(mooseObject), CylMesh))):
            v = self.qGraCompt[mooseObject]
            for rectChilditem in v.childItems():
                self.updateArrow(rectChilditem)
        else:
            mobj = self.mooseId_GObj[mooseObject.getId()]
            self.updateArrow(mobj)
            mooseObjcompt = self.findparent(mooseObject)
            v = self.qGraCompt[mooseObjcompt]
            #childBoundingRect = v.childrenBoundingRect()
            childBoundingRect = calculateChildBoundingRect(v)
            comptBoundingRect = v.boundingRect()
            rectcompt = comptBoundingRect.united(childBoundingRect)
            comptPen = v.pen()
            comptWidth = 5
            comptPen.setWidth(comptWidth)
            v.setPen(comptPen)
            if not comptBoundingRect.contains(childBoundingRect):
                v.setRect(rectcompt.x() - comptWidth,
                          rectcompt.y() - comptWidth,
                          rectcompt.width() + (comptWidth * 2),
                          rectcompt.height() + (comptWidth * 2))
コード例 #2
0
ファイル: kkit.py プロジェクト: dilawar/moose-gui
 def createCompt(self, key):
     self.new_Compt = ComptItem(self, 0, 0, 0, 0, key)
     self.qGraCompt[key] = self.new_Compt
     self.new_Compt.setRect(10, 10, 10, 10)
     self.sceneContainer.addItem(self.new_Compt)
コード例 #3
0
ファイル: buildkkit.py プロジェクト: dilawar/moose-gui
class  KineticsWidget(EditorWidgetBase):
    def __init__(self, *args): 
        EditorWidgetBase.__init__(self, *args)
        self.setAcceptDrops(True)
        self.border = 10        
        self.sceneContainer = QtGui.QGraphicsScene(self)
        self.sceneContainer.setSceneRect(self.sceneContainer.itemsBoundingRect())
        self.sceneContainer.setBackgroundBrush(QtGui.QColor(230,220,219,120))

        self.insertMenu = QtGui.QMenu('&Insert')
        self._menus.append(self.insertMenu)
        self.insertMapper = QtCore.QSignalMapper(self)

        classlist = ['CubeMesh','CylMesh','Pool','FuncPool','SumFunc','Reac','Enz','MMenz','StimulusTable','Table']
        insertMapper, actions = self.getInsertActions(classlist)

        for action in actions:
            self.insertMenu.addAction(action)        
    
    def getToolBars(self):
        if not hasattr(self, '_insertToolBar'):
            self._insertToolBar = QtGui.QToolBar('Insert')
            self._toolBars.append(self._insertToolBar)
            for action in self.insertMenu.actions():
                button = MToolButton()
                button.setDefaultAction(action)
                self._insertToolBar.addWidget(button)
        return self._toolBars

    def sizeHint(self):
        return QtCore.QSize(800,400)

    def updateModelView(self):
        #print "update model view",self.modelRoot
        if self.modelRoot == '/':
            m = wildcardFind('/##[ISA=ChemCompt]')
        else:
            m = wildcardFind(self.modelRoot+'/##[ISA=ChemCompt]')
        #print "111",self.modelRoot,m
        if not m:
            # when we want an empty GraphicView while creating new model,
            # then remove all the view and add an empty view
            if hasattr(self, 'view') and isinstance(self.view, QtGui.QWidget):
                self.layout().removeWidget(self.view)
            self.view = GraphicalView(self.sceneContainer,self.border,self)
            self.layout().addWidget(self.view)
        else:
            # maxmium and minimum coordinates of the objects specified in kkit file. 
            self.xmin = 0.0
            self.xmax = 1.0
            self.ymin = 0.0
            self.ymax = 1.0
            self.autoCordinatepos = {}
            self.sceneContainer.clear()
            # TODO: size will be dummy at this point, but I need the availiable size from the Gui
            self.size = QtCore.QSize(1024 ,768)
            #self.size = QtCore.QSize(300,400)
            self.autocoordinates = False
            
            # pickled the color map file """
            colormap_file = open(os.path.join(config.settings[config.KEY_COLORMAP_DIR], 'rainbow2.pkl'),'rb')
            self.colorMap = pickle.load(colormap_file)
            colormap_file.close()
            
            # Compartment and its members are setup """
            self.meshEntry,self.xmin,self.xmax,self.ymin,self.ymax,self.noPositionInfo = setupMeshObj(self.modelRoot)
            # srcdesConnection dictonary will have connection information between src and des """

            self.srcdesConnection = {}
            setupItem(self.modelRoot,self.srcdesConnection)
            if self.noPositionInfo:
                self.autocoordinates = True
                QtGui.QMessageBox.warning(self, 
                                          'No coordinates found for the model', 
                                          '\n Automatic layouting will be done')
            #raise Exception('Unsupported kkit version')
                
                
                self.xmin,self.xmax,self.ymin,self.ymax,self.autoCordinatepos = autoCoordinates(self.meshEntry,self.srcdesConnection)

            # Scale factor to translate the x -y position to fit the Qt graphicalScene, scene width. """
            if self.xmax-self.xmin != 0:
                self.xratio = (self.size.width()-10)/(self.xmax-self.xmin)
            else: self.xratio = self.size.width()-10
            
            if self.ymax-self.ymin:
                self.yratio = (self.size.height()-10)/(self.ymax-self.ymin)
            else: self.yratio = (self.size.height()-10)

        #A map b/w moose compartment key with QGraphicsObject
            self.qGraCompt = {}
        
        #A map between mooseId of all the mooseObject (except compartment) with QGraphicsObject
            self.mooseId_GObj = {}
        
            self.border = 5
            self.arrowsize = 2
            self.iconScale = 1
            self.defaultComptsize = 5
            self.itemignoreZooming = False
            self.lineItem_dict = {}
            self.object2line = defaultdict(list)
            
            # Compartment and its members are put on the qgraphicsscene
            self.mooseObjOntoscene()
            
            # All the moose Object are connected for visualization 
            self.drawLine_arrow(itemignoreZooming=False)
            if hasattr(self, 'view') and isinstance(self.view, QtGui.QWidget):
                self.layout().removeWidget(self.view)
            self.view = GraphicalView(self.sceneContainer,self.border,self)
            hLayout = QtGui.QGridLayout(self)
            self.setLayout(hLayout)
            hLayout.addWidget(self.view)
            #self.layout().addWidget(self.view)
    
    def mooseObjOntoscene(self):
        #  All the compartments are put first on to the scene \
        #  Need to do: Check With upi if empty compartments exist 
        for cmpt in sorted(self.meshEntry.keys()):
            self.createCompt(cmpt)
            self.qGraCompt[cmpt]
            #comptRef = self.qGraCompt[cmpt]
        
        #Enzymes of all the compartments are placed first, \
        #     so that when cplx (which is pool object) queries for its parent, it gets its \
        #     parent enz co-ordinates with respect to QGraphicsscene """
        
        for cmpt,memb in list(self.meshEntry.items()):
            for enzObj in find_index(memb,'enzyme'):
                enzinfo = enzObj.path+'/info'
                if enzObj.className == 'ZEnz':
                    enzItem = EnzItem(enzObj,self.qGraCompt[cmpt])
                else:
                    enzItem = MMEnzItem(enzObj,self.qGraCompt[cmpt])
                self.setupDisplay(enzinfo,enzItem,"enzyme")
                self.setupSlot(enzObj,enzItem)

        for cmpt,memb in list(self.meshEntry.items()):
            for poolObj in find_index(memb,'pool'):
                poolinfo = poolObj.path+'/info'
                poolItem = PoolItem(poolObj,self.qGraCompt[cmpt])
                self.setupDisplay(poolinfo,poolItem,"pool")
                self.setupSlot(poolObj,poolItem)
            
            for cplxObj in find_index(memb,'cplx'):
                cplxinfo = (cplxObj[0].parent).path+'/info'
                cplxItem = CplxItem(cplxObj,self.mooseId_GObj[element(cplxObj[0]).parent.getId()])
                self.setupDisplay(cplxinfo,cplxItem,"cplx")
                self.setupSlot(cplxObj,cplxItem)

            for reaObj in find_index(memb,'reaction'):
                reainfo = reaObj.path+'/info'
                reaItem = ReacItem(reaObj,self.qGraCompt[cmpt])
                self.setupDisplay(reainfo,reaItem,"reaction")
                self.setupSlot(reaObj,reaItem)

            for tabObj in find_index(memb,'table'):
                tabinfo = tabObj.path+'/info'
                tabItem = PoolItem(tabObj,self.qGraCompt[cmpt])
                self.setupDisplay(tabinfo,tabItem,"tab")
                self.setupSlot(tabObj,tabItem)
        # compartment's rectangle size is calculated depending on children 
        for k, v in list(self.qGraCompt.items()):
            rectcompt = v.childrenBoundingRect()
            v.setRect(rectcompt.x()-10,rectcompt.y()-10,(rectcompt.width()+20),(rectcompt.height()+20))
            v.setPen(QtGui.QPen(Qt.QColor(66,66,66,100), 5, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin))
            v.cmptEmitter.connect(v.cmptEmitter,QtCore.SIGNAL("qgtextPositionChange(PyQt_PyObject)"),self.positionChange)
            v.cmptEmitter.connect(v.cmptEmitter,QtCore.SIGNAL("qgtextItemSelectedChange(PyQt_PyObject)"),self.objectEditSlot)
    
    def createCompt(self,key):
        self.new_Compt = ComptItem(self,0,0,0,0,key)
        self.qGraCompt[key] = self.new_Compt
        self.new_Compt.setRect(10,10,10,10)
        self.sceneContainer.addItem(self.new_Compt)

    def setupDisplay(self,info,graphicalObj,objClass):
        xpos,ypos = self.positioninfo(info)
        
        # For Reaction and Complex object I have skipped the process to get the facecolor and background color as \
        #    we are not using these colors for displaying the object so just passing dummy color white 

        if( (objClass == "reaction" ) or (objClass == "cplx")):
            textcolor,bgcolor = "white","white"
        elif objClass == "tab":
            textcolor,bgcolor = getColor(info,self.colorMap)
        else:
            textcolor,bgcolor = getColor(info,self.colorMap)

        graphicalObj.setDisplayProperties(xpos,ypos,textcolor,bgcolor)
    
    def positioninfo(self,iteminfo):
        if self.noPositionInfo:
            
            try:
                # kkit does exist item's/info which up querying for parent.path gives the information of item's parent 
                x,y = self.autoCordinatepos[(element(iteminfo).parent).path]
            except:
                # But in Cspace reader doesn't create item's/info, up on querying gives me the error which need to change\
                # in ReadCspace.cpp, at present i am taking care b'cos i don't want to pass just the item where I need to check\
                # type of the object (rea,pool,enz,cplx,tab) which I have already done. 
                parent, child = posixpath.split(iteminfo)
                x,y = self.autoCordinatepos[parent]
            ypos = (y-self.ymin)*self.yratio
        else:
            x = float(element(iteminfo).getField('x'))
            y = float(element(iteminfo).getField('y'))
            #Qt origin is at the top-left corner. The x values increase to the right and the y values increase downwards \
            #as compared to Genesis codinates where origin is center and y value is upwards, that is why ypos is negated 
            ypos = -(y-self.ymin)*self.yratio
        xpos = (x-self.xmin)*self.xratio
        
        return(xpos,ypos)

    def setupSlot(self,mooseObj,qgraphicItem):
        self.mooseId_GObj[element(mooseObj).getId()] = qgraphicItem
        qgraphicItem.connect(qgraphicItem,QtCore.SIGNAL("qgtextPositionChange(PyQt_PyObject)"),self.positionChange)
        qgraphicItem.connect(qgraphicItem,QtCore.SIGNAL("qgtextItemSelectedChange(PyQt_PyObject)"),self.objectEditSlot)

    def updateItemSlot(self, mooseObject):
        #This is overridden by derived classes to connect appropriate
        #slot for updating the display item.
        #In this case if the name is updated from the keyboard both in mooseobj and gui gets updation
        changedItem = ''
        for item in list(self.sceneContainer.items()):
            if isinstance(item,PoolItem):
                if mooseObject.getId() == element(item.mobj).getId():
                    item.updateSlot()
                    #once the text is edited in editor, laydisplay gets updated in turn resize the length, positionChanged signal shd be emitted
                    self.positionChange(mooseObject)

    def positionChange(self,mooseObject):
        #If the item position changes, the corresponding arrow's are calculated
        if isinstance(element(mooseObject),CubeMesh):
            for k, v in list(self.qGraCompt.items()):
                mesh = mooseObject.path+'/mesh[0]'
                if k.path == mesh:
                    for rectChilditem in v.childItems():
                        self.updateArrow(rectChilditem)
        else:
            mobj = self.mooseId_GObj[mooseObject.getId()]
            self.updateArrow(mobj)
            for k, v in list(self.qGraCompt.items()):
                rectcompt = v.childrenBoundingRect()
                v.setRect(rectcompt.x()-10,rectcompt.y()-10,(rectcompt.width()+20),(rectcompt.height()+20))

    def emitItemtoEditor(self,mooseObject):
        #self.emit(QtCore.SIGNAL("itemPressed(PyQt_PyObject)"),mooseObject)
        self.editObject.emit(mooseObject.path)

    def drawLine_arrow(self, itemignoreZooming=False):
        for inn,out in list(self.srcdesConnection.items()):
            # self.srcdesConnection is dictionary which contains key,value \
            #    key is Enzyme or Reaction  and value [[list of substrate],[list of product]] (tuple)
            #    key is FuncBase and value is [list of pool] (list)

            #src = self.mooseId_GObj[inn]
            if isinstance(out,tuple):
                if len(out[0])== 0:
                    print(inn.className + ':' +inn[0].name+ " doesn't output message")
                else:
                    src = self.mooseId_GObj[inn]
                    for items in (items for items in out[0] ):
                        des = self.mooseId_GObj[element(items[0]).getId()]
                        
                        self.lineCord(src,des,items,itemignoreZooming)
                if len(out[1]) == 0:
                    print(inn.className + ':' +inn[0].name+ " doesn't output message")
                else:
                    for items in (items for items in out[1] ):
                        des = self.mooseId_GObj[element(items[0]).getId()]
                        self.lineCord(src,des,items,itemignoreZooming)

            elif isinstance(out,list):
                if len(out) == 0:
                    print("Func pool doesn't have sumtotal")
                else:
                    src = self.mooseId_GObj[element(inn).getId()]
                    for items in (items for items in out ):
                        des = self.mooseId_GObj[element(items[0]).getId()]
                        self.lineCord(src,des,items,itemignoreZooming)
    
    def lineCord(self,src,des,type_no,itemignoreZooming):
        endtype = type_no[1]
        line = 0
        if (src == "") and (des == ""):
            print("Source or destination is missing or incorrect")
            return 
        srcdes_list = [src,des,endtype,line]
        arrow = calcArrow(srcdes_list,itemignoreZooming,self.iconScale)
        self.drawLine(srcdes_list,arrow)

        while(type_no[2] > 1 and line <= (type_no[2]-1)):
            srcdes_list =[src,des,endtype,line]
            arrow = calcArrow(srcdes_list,itemignoreZooming,self.iconScale)
            self.drawLine(srcdes_list,arrow)
            line = line +1

        if type_no[2] > 5:
            print("Higher order reaction will not be displayed")

    def drawLine(self,srcdes_list,arrow):
        src = srcdes_list[0]
        des = srcdes_list[1]
        endtype = srcdes_list[2]
        line = srcdes_list[3]
        source = element(next((k for k,v in list(self.mooseId_GObj.items()) if v == src), None))
        for l,v,o in self.object2line[src]:
            if v == des and o ==line:
                l.setPolygon(arrow)
                arrowPen = l.pen()
                arrowPenWidth = self.arrowsize*self.iconScale
                arrowPen.setColor(l.pen().color())
                arrowPen.setWidth(arrowPenWidth)
                l.setPen(arrowPen)
                return
        
        qgLineitem = self.sceneContainer.addPolygon(arrow)
        pen = QtGui.QPen(QtCore.Qt.green, 0, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin)
        pen.setWidth(self.arrowsize)
        #pen.setCosmetic(True)
        # Green is default color moose.ReacBase and derivatives - already set above
        if  isinstance(source, EnzBase):
            if ( (endtype == 's') or (endtype == 'p')):
                pen.setColor(QtCore.Qt.red)
            elif(endtype != 'cplx'):
                p1 = (next((k for k,v in list(self.mooseId_GObj.items()) if v == src), None))
                pinfo = p1.path+'/info'
                color,bgcolor = getColor(pinfo,self.colorMap)
                pen.setColor(color)
        elif isinstance(source, moose.PoolBase):
            pen.setColor(QtCore.Qt.blue)
        elif isinstance(source,moose.StimulusTable):
            pen.setColor(QtCore.Qt.yellow)
        self.lineItem_dict[qgLineitem] = srcdes_list
        self.object2line[ src ].append( ( qgLineitem, des,line) )
        self.object2line[ des ].append( ( qgLineitem, src,line ) )
        qgLineitem.setPen(pen)

    def updateArrow(self,qGTextitem):
        #if there is no arrow to update then return
        if qGTextitem not in self.object2line:
            return
        listItem = self.object2line[qGTextitem]
        for ql, va,order in self.object2line[qGTextitem]:
            srcdes = []
            srcdes = self.lineItem_dict[ql]
            # Checking if src (srcdes[0]) or des (srcdes[1]) is ZombieEnz,
            # if yes then need to check if cplx is connected to any mooseObject, 
            # so that when Enzyme is moved, cplx connected arrow to other mooseObject(poolItem) should also be updated
            if( type(srcdes[0]) == EnzItem):
                self.cplxUpdatearrow(srcdes[0])
            elif( type(srcdes[1]) == EnzItem):
                self.cplxUpdatearrow(srcdes[1])
            
            # For calcArrow(src,des,endtype,itemignoreZooming) is to be provided
            arrow = calcArrow(srcdes,self.itemignoreZooming,self.iconScale)
            ql.setPolygon(arrow)
    
    def cplxUpdatearrow(self,srcdes):
        # srcdes which is 'EnzItem' from this,get ChildItems are retrived (b'cos cplx is child of zombieEnz)
        #And cplxItem is passed for updatearrow

        #Note: Here at this point enzItem has just one child which is cplxItem and childItems returns, PyQt4.QtGui.QGraphicsEllipseItem,CplxItem
        #Assuming CplxItem is always[1], but still check if not[0], if something changes in structure one need to keep an eye.
        if (srcdes.childItems()[1],CplxItem):
            self.updateArrow(srcdes.childItems()[1])
        else:
            self.updateArrow(srcdes.childItems()[0])
    
    def keyPressEvent(self,event):
        # key1 = event.key() # key event does not distinguish between capital and non-capital letters
        key = event.text().toAscii().toHex()
        if key ==  '41': # 'A' fits the view to iconScale factor
            itemignoreZooming = False
            self.updateItemTransformationMode(itemignoreZooming)
            self.view.fitInView(self.sceneContainer.itemsBoundingRect().x()-10,self.sceneContainer.itemsBoundingRect().y()-10,self.sceneContainer.itemsBoundingRect().width()+20,self.sceneContainer.itemsBoundingRect().height()+20,Qt.Qt.IgnoreAspectRatio)
            self.drawLine_arrow(itemignoreZooming=False)
            
        elif (key == '2e'): # '.' key, lower case for '>' zooms in 
            self.view.scale(1.1,1.1)

        elif (key == '2c'): # ',' key, lower case for '<' zooms in
            self.view.scale(1/1.1,1/1.1)

        elif (key == '3c'): # '<' key. zooms-in to iconScale factor
            self.iconScale *= 0.8
            self.updateScale( self.iconScale )

        elif (key == '3e'): # '>' key. zooms-out to iconScale factor
            self.iconScale *= 1.25
            self.updateScale( self.iconScale )
            
        elif (key == '61'):  # 'a' fits the view to initial value where iconscale=1
            self.iconScale = 1
            self.updateScale( self.iconScale )
            self.view.fitInView(self.sceneContainer.itemsBoundingRect().x()-10,self.sceneContainer.itemsBoundingRect().y()-10,self.sceneContainer.itemsBoundingRect().width()+20,self.sceneContainer.itemsBoundingRect().height()+20,Qt.Qt.IgnoreAspectRatio)
                   
    def updateItemTransformationMode(self, on):
        for v in list(self.sceneContainer.items()):
            if( not isinstance(v,ComptItem)):
                #if ( isinstance(v, PoolItem) or isinstance(v, ReacItem) or isinstance(v, EnzItem) or isinstance(v, CplxItem) ):
                if isinstance(v,KineticsDisplayItem):
                    v.setFlag(QtGui.QGraphicsItem.ItemIgnoresTransformations, on)

    def updateScale( self, scale ):
        for item in list(self.sceneContainer.items()):
            if isinstance(item,KineticsDisplayItem):
                item.refresh(scale)
                #iteminfo = item.mobj.path+'/info'
                #xpos,ypos = self.positioninfo(iteminfo)
                xpos = item.scenePos().x()
                ypos = item.scenePos().y()

                if isinstance(item,ReacItem) or isinstance(item,EnzItem) or isinstance(item,MMEnzItem):
                     item.setGeometry(xpos,ypos, 
                                     item.gobj.boundingRect().width(), 
                                     item.gobj.boundingRect().height())
                elif isinstance(item,CplxItem):
                    item.setGeometry(item.gobj.boundingRect().width()/2,item.gobj.boundingRect().height(), 
                                     item.gobj.boundingRect().width(), 
                                     item.gobj.boundingRect().height())
                elif isinstance(item,PoolItem):
                     item.setGeometry(xpos, ypos,item.gobj.boundingRect().width()
                                     +PoolItem.fontMetrics.width('  '), 
                                     item.gobj.boundingRect().height())
                     item.bg.setRect(0, 0, item.gobj.boundingRect().width()+PoolItem.fontMetrics.width('  '), item.gobj.boundingRect().height())

        self.drawLine_arrow(itemignoreZooming=False)
        for k, v in list(self.qGraCompt.items()):
            rectcompt = v.childrenBoundingRect()
            comptPen = v.pen()
            comptWidth =  self.defaultComptsize*self.iconScale
            comptPen.setWidth(comptWidth)
            v.setPen(comptPen)
            v.setRect(rectcompt.x()-comptWidth,rectcompt.y()-comptWidth,(rectcompt.width()+2*comptWidth),(rectcompt.height()+2*comptWidth))