From f18d2016bc8ae5a4b13d7c51f919acb2f7321847 Mon Sep 17 00:00:00 2001 From: Dilawar Singh <dilawars@ncbs.res.in> Date: Thu, 6 Sep 2018 12:14:21 +0530 Subject: [PATCH] Squashed 'moose-gui/' changes from 3fd3739e86..d226931e0b d226931e0b while deleting the group a warning box is set,deleteSolve is now mooseDeleteChemSolver, while saving to sbml model scenepos is picked up, hopefully this works for others. Tested for single compartment multiple group c1a3949a3e adding/deleting the solvers are picked from the python/chemUtil folder instead of local setsolver file and addsolver is now mooseAddChemSolver 2f8fcab25f in disableModel function added dsolve also b4d5376ae8 From command line if filename is passed it load into moose-gui a82842f683 group border color can be editable 395d5f0a9c if moose object is moved from compartment to group or from group to another group/compartment, then mooseobject path and qt object parentItem are updated git-subtree-dir: moose-gui git-subtree-split: d226931e0b932407ecea7863588b1f3d9e8721a7 --- mgui.py | 98 ++++++++++++++++++++++++++++++++++++-- objectedit.py | 6 ++- plugins/kkit.py | 64 +++++++++++++++++-------- plugins/kkitViewcontrol.py | 70 +++++++++++++++++++++------ 4 files changed, 196 insertions(+), 42 deletions(-) diff --git a/mgui.py b/mgui.py index 24d2bf83..372fde8f 100644 --- a/mgui.py +++ b/mgui.py @@ -6,7 +6,7 @@ # Maintainer: HarshaRani # Created: Mon Nov 12 09:38:09 2012 (+0530) # Version: -# Last-Updated: Thu Oct 5 14:54:33 2017 (+0530) +# Last-Updated: Fri Aug 31 14:54:33 2017 (+0530) # By: Harsha # Update #: # URL: @@ -44,6 +44,10 @@ # '''' +Aug 31: Pass file from the command to load into gui + : added dsolver in disableModel function is used to unset the solver for the model + into moose-gui which are not to be run. + Oct 5: clean up with round trip of dialog_exe ''' @@ -75,7 +79,8 @@ from PyQt4 import Qt, QtCore, QtGui from PyQt4.QtGui import * from MdiArea import MdiArea import os -from setsolver import * +from moose.chemUtil.add_Delete_ChemicalSolver import * +#from setsolver import * from defines import * from collections import OrderedDict @@ -181,7 +186,88 @@ class MWindow(QtGui.QMainWindow): self.setPlugin('default', '/') self.plugin.getEditorView().getCentralWidget().parent().close() self.popup = None - self.createPopup() + cmdfilepath = "" + try: + sys.argv[1] + except: + pass + else: + cmdfilepath = os.path.abspath(sys.argv[1]) + try: + sys.argv[2] + except: + solver = 'gsl' + else: + solver = os.path.abspath(sys.argv[2]) + + if cmdfilepath: + filepath,fileName = os.path.split(cmdfilepath) + modelRoot,extension = os.path.splitext(fileName) + if extension == '.py': + self.show() + self.createPopup() + freeCursor() + reply = QtGui.QMessageBox.information(self,"Model file can not open","At present python file cann\'t be laoded into GUI",QtGui.QMessageBox.Ok) + if reply == QtGui.QMessageBox.Ok: + QtGui.QApplication.restoreOverrideCursor() + return + if not os.path.exists(cmdfilepath): + self.show() + self.createPopup() + reply = QtGui.QMessageBox.information(self,"Model file can not open","Check filename or filepath ",QtGui.QMessageBox.Ok) + if reply == QtGui.QMessageBox.Ok: + QtGui.QApplication.restoreOverrideCursor() + return + else: + filePath = filepath+'/'+fileName + ret = loadFile(str(filePath), '%s' % (modelRoot), solver, merge=False) + self.objectEditSlot('/',False) + pluginLookup = '%s/%s' % (ret['modeltype'], ret['subtype']) + try: + pluginName = subtype_plugin_map['%s/%s' % (ret['modeltype'], ret['subtype'])] + except KeyError: + pluginName = 'default' + self.loadedModelsAction(ret['model'].path,pluginName) + if len(self._loadedModels)>5: + self._loadedModels.pop(0) + + if not moose.exists(ret['model'].path+'/info'): + moose.Annotator(ret['model'].path+'/info') + + modelAnno = moose.Annotator(ret['model'].path+'/info') + if ret['subtype']: + modelAnno.modeltype = ret['subtype'] + else: + modelAnno.modeltype = ret['modeltype'] + #modelAnno.dirpath = str(dialog.directory().absolutePath()) + if moose.exists(ret['model'].path + "/data"): + self.data = moose.element(ret['model'].path + "/data") + self.data = moose.Neutral(ret['model'].path + "/data") + + modelAnno.dirpath = str(filepath) + self.setPlugin(pluginName, ret['model'].path) + self.show() + # if pluginName == 'kkit': + # QtCore.QCoreApplication.sendEvent(self.plugin.getEditorView().getCentralWidget().view, QtGui.QKeyEvent(QtCore.QEvent.KeyPress, Qt.Qt.Key_A, Qt.Qt.NoModifier)) + + # noOfCompt = len(moose.wildcardFind(ret['model'].path+'/##[ISA=ChemCompt]')) + # grp = 0 + # for c in moose.wildcardFind(ret['model'].path+'/##[ISA=ChemCompt]'): + # noOfGrp = moose.wildcardFind(moose.element(c).path+'/#[TYPE=Neutral]') + # grp = grp+len(noOfGrp) + + # noOfPool = len(moose.wildcardFind(ret['model'].path+'/##[ISA=PoolBase]')) + # noOfFunc = len(moose.wildcardFind(ret['model'].path+'/##[ISA=Function]')) + # noOfReac = len(moose.wildcardFind(ret['model'].path+'/##[ISA=ReacBase]')) + # noOfEnz = len(moose.wildcardFind(ret['model'].path+'/##[ISA=EnzBase]')) + # noOfStimtab = len(moose.wildcardFind(ret['model'].path+'/##[ISA=StimulusTable]')) + + # reply = QtGui.QMessageBox.information(self,"Model Info","Model has : \n %s Compartment \t \n %s Group \t \n %s Pool \t \n %s Function \t \n %s reaction \t \n %s Enzyme \t \n %s StimulusTable" %(noOfCompt, grp, noOfPool, noOfFunc, noOfReac, noOfEnz, noOfStimtab)) + # if reply == QtGui.QMessageBox.Ok: + # QtGui.QApplication.restoreOverrideCursor() + # return + else: + self.createPopup() def createPopup(self): self.popup = dialog = QDialog(self) @@ -450,7 +536,8 @@ class MWindow(QtGui.QMainWindow): if compts: #setCompartmentSolver(self._loadedModels[i][0],"gsl") - addSolver(self._loadedModels[i][0],"gsl") + mooseAddChemSolver(self._loadedModels[i][0],"gsl") + #addSolver(self._loadedModels[i][0],"gsl") else: c.tickDt[7] = self._loadedModels[i][3] c.tickDt[8] = self._loadedModels[i][4] @@ -1117,6 +1204,9 @@ class MWindow(QtGui.QMainWindow): if moose.exists(compt[0].path+'/gsolve'): gsolve = moose.Gsolve( compt[0].path+'/gsolve' ) gsolve.tick = -1 + if moose.exists(compt[0].path+'/dsolve'): + dsolve = moose.Dsolve(compt[0].path+'/dsolve') + dsolve.tick = -1 if moose.exists(compt[0].path+'/stoich'): stoich = moose.Stoich( compt[0].path+'/stoich' ) stoich.tick = -1 diff --git a/objectedit.py b/objectedit.py index dcb019a4..08c38bbb 100644 --- a/objectedit.py +++ b/objectedit.py @@ -6,7 +6,7 @@ # Maintainer: # Created: Wed Jun 30 11:18:34 2010 (+0530) # Version: -# Last-Updated: Thu Jul 27 11:05:59 2017 (+0530) +# Last-Updated: Tue Jun 19 11:05:59 2017 (+0530) # By: Harsha # Update #: # URL: @@ -42,6 +42,7 @@ # by setting/unsetting isbuffered field # Fri May 17 23:45:59 2017 (+0530) - Harsha added, notes header, # Kd is calculated for the second order reaction and value is displayed +# Tue Jun 18 12:10:54 IST 2018 - Harsha now group boundary color can be editable from the object editor # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License as @@ -174,7 +175,8 @@ class ObjectEditModel(QtCore.QAbstractTableModel): #harsha: For signalling models will be pulling out notes field from Annotator # can updates if exist for other types also if ( isinstance(self.mooseObject, moose.PoolBase) - or isinstance(self.mooseObject,moose.EnzBase) ) : + or isinstance(self.mooseObject,moose.EnzBase) + or isinstance(self.mooseObject,moose.Neutral)) : self.fields.append("Color") flag = QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEditable self.fieldFlags[fieldName] = flag diff --git a/plugins/kkit.py b/plugins/kkit.py index 3b997400..692de4b2 100644 --- a/plugins/kkit.py +++ b/plugins/kkit.py @@ -6,10 +6,13 @@ __version__ = "1.0.0" __maintainer__ = "HarshaRani" __email__ = "hrani@ncbs.res.in" __status__ = "Development" -__updated__ = "Oct 18 2017" -''' +__updated__ = "Jun 19 2018" + +#Change log: +# 2018 Jun 18: update the color of the group from objecteditor + +#code -''' import math import sys from PyQt4 import QtGui, QtCore, Qt @@ -30,8 +33,8 @@ from PyQt4.QtGui import QGridLayout from PyQt4.QtGui import QColor import RunWidget from os.path import expanduser -from setsolver import * - +#from setsolver import * +from moose.chemUtil.add_Delete_ChemicalSolver import * class KkitPlugin(MoosePlugin): """Default plugin for MOOSE GUI""" @@ -81,6 +84,8 @@ class KkitPlugin(MoosePlugin): self.plugin = KkitEditorView(self).getCentralWidget().plugin self.defaultScenewidth = KkitEditorView(self).getCentralWidget().defaultScenewidth self.defaultSceneheight = KkitEditorView(self).getCentralWidget().defaultSceneheight + self.coOrdinates = KkitEditorView(self).getCentralWidget().getsceneCord() + ''' for k,v in self.sceneObj.items(): if moose.exists(moose.element(k).path+'/info'): annoInfo = Annotator(k.path+'/info') @@ -88,6 +93,7 @@ class KkitPlugin(MoosePlugin): self.coOrdinates[k] = {'x':annoInfo.x*self.defaultScenewidth, 'y':annoInfo.y*self.defaultSceneheight} else: self.coOrdinates[k] = {'x':annoInfo.x, 'y':annoInfo.y} + ''' #writeerror = moose.writeSBML(self.modelRoot,str(filename),self.coOrdinates) writeerror = -2 conisitencyMessages = "" @@ -231,11 +237,11 @@ class AnotherKkitRunView(RunView): def setSolver(self, modelRoot,solver = None): if solver == None: - reinit = addSolver(modelRoot,self.getSchedulingDockWidget().widget().solver) + reinit = mooseAddChemSolver(modelRoot,self.getSchedulingDockWidget().widget().solver) if reinit: self.getSchedulingDockWidget().widget().resetSimulation() else: - reinit = addSolver(modelRoot,solver) + reinit = mooseAddChemSolver(modelRoot,solver) if reinit: self.getSchedulingDockWidget().widget().resetSimulation() @@ -364,6 +370,17 @@ class KineticsWidget(EditorWidgetBase): # else: #elf.sceneContainer.setSceneRect(self.sceneContainer.itemsBoundingRect()) self.sceneContainer.setBackgroundBrush(QColor(230,220,219,120)) + + def getsceneCord(self): + self.cord = {} + for item in self.sceneContainer.items(): + if isinstance(item,KineticsDisplayItem): + #item.refresh(scale) + #self.update() + xpos = item.scenePos().x() + ypos = item.scenePos().y() + self.cord[item.mobj] = {'x':xpos,'y':ypos} + return self.cord def updateModelView(self): self.getMooseObj() @@ -483,14 +500,20 @@ class KineticsWidget(EditorWidgetBase): 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 + def updateColorSlot(self,mooseObject, colour): + #Color slot for changing background color for Pool,Enz and group 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) + anninfo.color = str(colour.name()) + + if mooseObject.className == "Neutral": + item = self.qGraGrp[mooseObject] + item.setPen(QtGui.QPen(QtGui.QColor(colour),item.pen().width(),item.pen().style(),item.pen().capStyle(),item.pen().joinStyle()))# self.comptPen, Qt.Qt.SolidLine, Qt.Qt.RoundCap, Qt.Qt.RoundJoin)) + + elif (isinstance(mooseObject,PoolBase) or isinstance(mooseObject,EnzBase) ): + item = self.mooseId_GObj[mooseObject] + item.updateColor(colour) + ''' def mooseObjOntoscene(self): # All the compartments are put first on to the scene \ @@ -738,6 +761,8 @@ class KineticsWidget(EditorWidgetBase): else: x = float(element(iteminfo).getField('x')) y = float(element(iteminfo).getField('y')) + self.defaultScenewidth = 1 + self.defaultSceneheight = 1 return(x,y) def drawLine_arrow(self, itemignoreZooming=False): @@ -862,13 +887,11 @@ class KineticsWidget(EditorWidgetBase): x = grpChilditem.scenePos().x()/self.defaultScenewidth y = grpChilditem.scenePos().y()/self.defaultSceneheight else: - #print "Check for other models at grp level ",grpChilditem.scenePos() x = grpChilditem.scenePos().x() y = grpChilditem.scenePos().y() - #print " x and y at 863 ",grpChilditem.scenePos() anno.x = x anno.y = y - #print " anno ",anno, anno.x, anno.y + if isinstance(moose.element(grpChilditem.mobj.path),PoolBase): t = moose.element(grpChilditem.mobj.path) moose.element(t).children @@ -897,7 +920,6 @@ class KineticsWidget(EditorWidgetBase): x = mobj.scenePos().x()/self.defaultScenewidth y = mobj.scenePos().y()/self.defaultSceneheight else: - #print "Check for other models ",mobj.scenePos() x = mobj.scenePos().x() y = mobj.scenePos().y() #print " x and y at 863 ",mobj.scenePos() @@ -919,15 +941,15 @@ class KineticsWidget(EditorWidgetBase): v.setRect(rectcompt.x()-10,rectcompt.y()-10,(rectcompt.width()+20),(rectcompt.height()+20)) pass - def updateGrpSize(self,compartment): - compartmentBoundary = compartment.rect() + def updateGrpSize(self,grp): + compartmentBoundary = grp.rect() - childrenBoundary = calculateChildBoundingRect(compartment) + childrenBoundary = calculateChildBoundingRect(grp) x = childrenBoundary.x() y = childrenBoundary.y() height = childrenBoundary.height() width = childrenBoundary.width() - compartment.setRect( x-10 + grp.setRect( x-10 , y-10 , width + 20 , height + 20 diff --git a/plugins/kkitViewcontrol.py b/plugins/kkitViewcontrol.py index 255de612..91113596 100644 --- a/plugins/kkitViewcontrol.py +++ b/plugins/kkitViewcontrol.py @@ -5,20 +5,23 @@ __version__ = "1.0.0" __maintainer__ = "HarshaRani" __email__ = "hrani@ncbs.res.in" __status__ = "Development" -__updated__ = "Feb 3 2018" +__updated__ = "Jun 8 2018" ''' -Oct 17: If object is moved from one group or compartment to another group or with in same Compartment, + +Jun8 : If object is moved from one group or compartment to another group or with in same Compartment, then both at moose level (group or compartment path is updated ) and qt level the setParentItem is set -If object is moved to Empty place or not allowed place in the GUI its moved back to origin position -also some clean up when object is just clicked in QsvgItem and v/s clicked and some action done -with Rubber selection if object are moved then group size is updated +2018 Oct 3 : At mousePressEvent, a clean way of checking on what object mouse press Event happened is checked. This is after group is added where Group Interior and Boundary is checked, with in groupInterior if click in on COMPARTMENT BOUNDARY is clicked then COMPARTMENT_BOUNDARY is return, else top most group object is returned. Sep 20: Group related function added -resolveGroupInteriorAndBoundary, findGraphic_groupcompt, graphicsIsInstance -@resolveItem,editorMousePressEvent,editorMouseMoveEvent,editorMouseReleaseEvent checks made for group +2017 ''' import sys from modelBuild import * @@ -189,12 +192,13 @@ class GraphicalView(QtGui.QGraphicsView): if itemType == GROUP_BOUNDARY: popupmenu = QtGui.QMenu('PopupMenu', self) popupmenu.addAction("DeleteGroup", lambda : self.deleteGroup(item,self.layoutPt)) - popupmenu.addAction("CloneGroup" ,lambda : handleCollisions(comptList, moveMin, self.layoutPt )) + #popupmenu.addAction("CloneGroup" ,lambda : handleCollisions(comptList, moveMin, self.layoutPt )) popupmenu.exec_(self.mapToGlobal(event.pos())) elif itemType == COMPARTMENT_BOUNDARY: if len(list(self.layoutPt.qGraCompt.values())) > 1: popupmenu = QtGui.QMenu('PopupMenu', self) + #popupmenu.addAction("DeleteCmpt", lambda : self.deleteCmpt(item,self.layoutPt)) popupmenu.addAction("LinearLayout", lambda : handleCollisions(list(self.layoutPt.qGraCompt.values()), moveX, self.layoutPt)) popupmenu.addAction("VerticalLayout" ,lambda : handleCollisions(list(self.layoutPt.qGraCompt.values()), moveMin, self.layoutPt )) popupmenu.exec_(self.mapToGlobal(event.pos())) @@ -341,6 +345,38 @@ class GraphicalView(QtGui.QGraphicsView): pressItem = self.state["press"]["item"] if actionType == "move": + tobemoved = True + movedGraphObj = self.state["press"]["item"].parent() + if itemType != EMPTY: + item = self.findGraphic_groupcompt(item) + if movedGraphObj.parentItem() != item: + if moose.exists(item.mobj.path+'/'+movedGraphObj.mobj.name): + desObj = item.mobj.className + if desObj == "CubeMesh" or desObj == "CyclMesh": + desObj = "compartment" + elif desObj == "Neutral": + desObj = "group" + tobemoved = False + self.layoutPt.setupDisplay(movedGraphObj.mobj.path+'/info',movedGraphObj,"pool") + self.layoutPt.updateArrow(movedGraphObj) + QtGui.QMessageBox.warning(None,'Could not move the object', "The object name \'%s\' exist in \'%s\' %s" %(movedGraphObj.mobj.name,item.mobj.name,desObj)) + else: + movedGraphObj.setParentItem(item) + moose.move(movedGraphObj.mobj, item.mobj) + if tobemoved: + if isinstance(movedGraphObj,KineticsDisplayItem): + itemPath = movedGraphObj.mobj.path + if moose.exists(itemPath): + iInfo = itemPath+'/info' + anno = moose.Annotator(iInfo) + x = movedGraphObj.scenePos().x()/self.layoutPt.defaultScenewidth + y = movedGraphObj.scenePos().y()/self.layoutPt.defaultSceneheight + anno.x = x + anno.y = y + QtGui.QApplication.setOverrideCursor(QtGui.QCursor(Qt.Qt.ArrowCursor)) + self.layoutPt.positionChange(item.mobj) + self.updateScale(self.iconScale) + ''' QtGui.QApplication.setOverrideCursor(QtGui.QCursor(Qt.Qt.ArrowCursor)) #If any case, move is not valide need to move back the object to original position is store and calculation initscenepos = self.state["press"]["scenepos"] @@ -398,7 +434,7 @@ class GraphicalView(QtGui.QGraphicsView): self.layoutPt.positionChange(item.mobj) self.updateScale(self.iconScale) - + ''' if actionType == "delete": self.removeConnector() pixmap = QtGui.QPixmap(24, 24) @@ -417,7 +453,7 @@ class GraphicalView(QtGui.QGraphicsView): QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: #delete solver first as topology is changing - deleteSolver(self.modelRoot) + mooseDeleteChemSolver(self.layoutPt.modelRoot) self.deleteObj([item.parent()]) QtGui.QApplication.restoreOverrideCursor() else: @@ -461,7 +497,7 @@ class GraphicalView(QtGui.QGraphicsView): #Solver should be deleted ## if there is change in 'Topology' of the model ## or if copy has to made then oject should be in unZombify mode - deleteSolver(self.modelRoot) + mooseDeleteChemSolver(self.layoutPt.modelRoot) #As name is suggesting, if item is Compartment, then search in qGraCompt and if group then qGraGrp if isinstance(itemAtView,ComptItem): lKey = [key for key, value in self.layoutPt.qGraCompt.iteritems() if value == itemAtView][0] @@ -560,13 +596,17 @@ class GraphicalView(QtGui.QGraphicsView): self.resetState() def deleteGroup(self,item,layoutPt): - key = [k for k,v in self.layoutPt.qGraGrp.items() if v == item] - if key[0] in self.layoutPt.qGraGrp: - self.layoutPt.qGraGrp.pop(key[0]) - self.groupItemlist1 = item.childItems() - self.groupItemlist = [ i for i in self.groupItemlist1 if not isinstance(i,QtGui.QGraphicsPolygonItem)] - self.deleteObj(self.groupItemlist) - self.deleteItem(item) + reply = QtGui.QMessageBox.question(self, "Deleting Object",'Do want to delete group \'{groupname}\' and its children and connections'.format(groupname=item.mobj.name), + QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) + if reply == QtGui.QMessageBox.Yes: + mooseDeleteChemSolver(self.layoutPt.modelRoot) + key = [k for k,v in self.layoutPt.qGraGrp.items() if v == item] + if key[0] in self.layoutPt.qGraGrp: + self.layoutPt.qGraGrp.pop(key[0]) + self.groupItemlist1 = item.childItems() + self.groupItemlist = [ i for i in self.groupItemlist1 if not isinstance(i,QtGui.QGraphicsPolygonItem)] + self.deleteObj(self.groupItemlist) + self.deleteItem(item) def drawExpectedConnection(self, event): self.connectionSource = self.state["press"]["item"] @@ -847,7 +887,7 @@ class GraphicalView(QtGui.QGraphicsView): def deleteObj(self,item): self.rubberbandlist = item - deleteSolver(self.layoutPt.modelRoot) + mooseDeleteChemSolver(self.layoutPt.modelRoot) self.Enz_cplxlist = [ i for i in self.rubberbandlist if (isinstance(i,MMEnzItem) or isinstance(i,EnzItem) or isinstance(i,CplxItem) )] self.PFRSlist = [ i for i in self.rubberbandlist if (isinstance(i,PoolItem) or isinstance(i,TableItem) or isinstance(i,ReacItem) or isinstance(i,FuncItem) )] self.grp = [ i for i in self.rubberbandlist if isinstance(i,GRPItem)] @@ -892,7 +932,7 @@ class GraphicalView(QtGui.QGraphicsView): reply = QtGui.QMessageBox.question(self, "Deleting Object","Do want to delete object and its connections", QtGui.QMessageBox.Yes | QtGui.QMessageBox.No) if reply == QtGui.QMessageBox.Yes: - deleteSolver(self.layoutPt.modelRoot) + mooseDeleteChemSolver(self.layoutPt.modelRoot) msgIdforDeleting = " " if isinstance(item,QtGui.QGraphicsPolygonItem): src = self.layoutPt.lineItem_dict[item] -- GitLab