""" qtgui/mgTreeView.py: CCP4MG Molecular Graphics Program Copyright (C) 2001-2008 University of York, CCLRC Copyright (C) 2009-2011 University of York This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3, modified in accordance with the provisions of the license to address the requirements of UK law. You should have received a copy of the modified GNU Lesser General Public License along with this library. If not, copies may be downloaded from http://www.ccp4.ac.uk/ccp4license.php This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. """ from PyQt4 import QtCore, QtGui import pygl_coord import mmdb2 as mmdb import global_definitions,guiUtils import sys,string import mmut ATOMTYPE = 1001 RESTYPE = 1002 RESTYPE_A = 1003 CHAINTYPE = 1004 SECSTRTYPE = 1005 ALLTYPE = 1001 class AbstractMolData(QtGui.QStandardItemModel): composite = {} composite['ligands'] = dict ( label = 'Ligands', tree = [ 'res','atom'], selection_mask = 'ligands' ) composite['nucleic'] = dict ( label = 'Nucleic acid', selection_mask = 'nucleic' ) composite['nucleotide'] = dict ( label = 'Nucleotide', selection_mask = 'nucleotide' ) composite[ 'nglycosylation'] = dict ( label = 'N-glycosylation', selection_mask = 'nglycosylation' ) composite[ 'oglycosylation'] = dict ( label = 'O-glycosylation', selection_mask = 'oglycosylation' ) composite[ 'saccharide'] = dict ( label = 'Saccharides', selection_mask = 'saccharide' ) composite[ 'peptide'] = dict ( label = 'Peptide', selection_mask = 'peptide' ) composite ['secstr'] = dict ( label = 'Peptide - secondary structure', tree = [ 'chain','secstr','res','atom'], selection_mask = 'amino_acid' ) composite['water'] = dict ( label = 'Water', selection_mask = 'water' ) composite['solute'] = dict ( label = 'Solute', tree = [ 'res','atom'], selection_mask = 'solute' ) composite['metal'] = dict ( label = 'Metal ions', tree = [ 'chain','res','atom'], selection_mask = 'metal' ) composite['all'] = dict ( label = 'Chain/residue/atom', selection_mask = 'all' ) #------------------------------------------------------------------------- def __init__(self,molHnd,MolDataObj): #------------------------------------------------------------------------- ##print "into AbstractMolData" QtGui.QStandardItemModel.__init__(self) import time start = time.clock() # Sort out data to help lookup self.lookup = {} self.groupItems = {} self.molHnd = molHnd self.MolDataObj = MolDataObj self.parentItem = self.invisibleRootItem() #self.allItem = MGStandardItem(QtCore.QString('All'),ALLTYPE) #self.parentItem.appendRow(self.allItem) self.setHeaderData(0,QtCore.Qt.Horizontal,QtCore.QVariant(self.MolDataObj.name_label),QtCore.Qt.DisplayRole) self.udd_chn_chn = self.molHnd.GetUDDHandle( mmdb.UDR_CHAIN,"qt_chn_row") if self.udd_chn_chn <= 0: self.udd_chn_chn = self.molHnd.RegisterUDInteger(mmdb.UDR_CHAIN,"qt_chn_row") self.udd_chn = self.molHnd.GetUDDHandle( mmdb.UDR_RESIDUE,"qt_chn_row") if self.udd_chn <= 0: self.udd_chn = self.molHnd.RegisterUDInteger(mmdb.UDR_RESIDUE,"qt_chn_row") self.udd_res=self.molHnd.GetUDDHandle( mmdb.UDR_RESIDUE,"udr_res_row") if self.udd_res<=0: self.udd_res = self.molHnd.RegisterUDInteger(mmdb.UDR_RESIDUE,"qt_res_row") nChn = self.molHnd.GetNumberOfChains(1) for ic in range(0,nChn): self.molHnd.PutUDData(self.udd_chn_chn,-1) resTable = mmdb.newPPCResidue() nRes = pygl_coord.inta(1) #self.molHnd.GetResidueTable ( 1,ic,resTable,nRes ) resTable = mmut.GetResidueTable(self.molHnd,1,ic,nRes) for ir in range(0,nRes[0]): self.molHnd.PutUDData(self.udd_chn,-1) #print "loading abstact model",time.clock() - start #-------------------------------------------------------------------- def loadGroup(self,groupName='',definition={},**keywords): #-------------------------------------------------------------------- datatype = 0 for key,value in self.lookup.items(): if value['groupName'] == groupName: datatype = key if datatype>0: return datatype definition.update(keywords) #print "loadGroup",groupName,definition # Are there any atoms that match selection criteria? masterHnd = definition.get('masterHnd',0) if not masterHnd: selection_mask = definition.get('selection_mask','all') parent_selection =definition.get('parent_selection','/1/') masterHnd = self.getAtomSelection(selection_mask,parent_selection) #print 'masterHnd',masterHnd if masterHnd<0: return -1 # Create a node for this component groupCode = len(self.lookup)+1 label = definition.get('label',self.MolDataObj.name_label) item = MGStandardItem(QtCore.QString(label),groupCode) self.parentItem.appendRow(item) tree = definition.get('tree',['chain','res','atom']) self.addChildren(groupCode,item,masterHnd,tree) self.molHnd.DeleteSelection(masterHnd) child = item.child(0,0).index() if child: self.groupItems[groupName]=item self.lookup[groupCode] = { 'groupName' : groupName, 'tree' : tree, 'selection_mask' : selection_mask, 'parent_selection' : parent_selection } return groupCode #---------------------------------------------------------------------- def getGroups(self): #---------------------------------------------------------------------- return self.groupItems.keys() def getGroupRow(self,group): row = 0 for key,value in self.lookup.items(): if value['groupName'] == group: row = key return row-1 #------------------------------------------------------------------------ def getAtomSelection(self,selection_mask,parent_selection): #------------------------------------------------------------------------ #print "getAtomSelection selection_mask",selection_mask rv = self.MolDataObj.parse_selection(command=selection_mask) if rv[0] or rv[1] <= 0: print "ERROR selecting ",selection_mask return -1 atmHnd = rv[1] self.molHnd.Select(atmHnd,mmdb.STYPE_ATOM,parent_selection,mmdb.SKEY_AND) nAtoms = self.MolDataObj.nAtoms(atmHnd) #print "nAtoms",nAtoms if nAtoms<=0: self.molHnd.DeleteSelection(rv[1]) return -1 else: return atmHnd #---------------------------------------------------------------------- def addChildren(self,groupCode,parent_item,masterHnd,tree,loadAtoms=0): #---------------------------------------------------------------------- selindexp = pygl_coord.intp() # Be prepared for recursive call to addChildren if len(tree)>1 and (tree[1] != 'atom' or loadAtoms): nxtHnd = self.molHnd.NewSelection() else: nxtHnd = 0 if tree[0] == 'chain': chnHnd = self.molHnd.NewSelection() self.molHnd.Select(chnHnd,mmdb.STYPE_CHAIN,masterHnd,mmdb.SKEY_NEW) chnSel = mmdb.newPPCChain() #nChn = self.molHnd.GetSelIndex(chnHnd,chnSel) chnSel = mmut.GetChainSelIndex(self.molHnd,chnHnd,selindexp) nChn = selindexp.value() #print "nChn",nChn for ic in range(0,nChn): pChn = mmdb.getPCChain(chnSel,ic) name = self.chainName(pChn) try: dum = int(name.rstrip('/')) name = '//'+str(dum)+'/' except: pass item = MGStandardItem(QtCore.QString(name),CHAINTYPE) parent_item.appendRow(item) pChn.PutUDData(self.udd_chn_chn,groupCode + (10*item.row())) # So long as its not atoms load the next layer down if nxtHnd>0: self.molHnd.Select(nxtHnd,mmdb.STYPE_ATOM,masterHnd,mmdb.SKEY_NEW) self.molHnd.Select(nxtHnd,mmdb.STYPE_ATOM,0,pChn.GetChainID(),mmdb.ANY_RES,'*',mmdb.ANY_RES,'*','*','*','*','*',mmdb.SKEY_AND) self.addChildren(groupCode,item,nxtHnd,tree[1:],loadAtoms) self.molHnd.DeleteSelection(chnHnd) if tree[0] == 'res': resHnd = self.molHnd.NewSelection() self.molHnd.Select(resHnd,mmdb.STYPE_RESIDUE,masterHnd,mmdb.SKEY_NEW) resSel = mmdb.newPPCResidue() #nRes = self.molHnd.GetSelIndex(resHnd,resSel) resSel = mmut.GetResidueSelIndex(self.molHnd,resHnd,selindexp) nRes = selindexp.value() #print "nRes",nRes if tree[-1]=='atom': datatype = RESTYPE_A else: datatype = RESTYPE #print "res type",type for ir in range(0,nRes): pRes = mmdb.getPCResidue(resSel,ir) name = self.residueName(pRes) item = MGStandardItem(QtCore.QString(name),datatype) parent_item.appendRow(item) pRes.PutUDData(self.udd_res,item.row()) pRes.PutUDData(self.udd_chn,groupCode + (10*parent_item.row())) # So long as its not atoms load the next layer down if nxtHnd>0: self.molHnd.Select(nxtHnd,mmdb.STYPE_ATOM,masterHnd,mmdb.SKEY_NEW) seqNum = pRes.GetSeqNum() insCode = pRes.GetInsCode() self.molHnd.Select(nxtHnd,mmdb.STYPE_ATOM,pRes.GetModelNum(),pRes.GetChainId(),seqNum,'*',seqNum,'*','*','*','*','*',mmdb.SKEY_AND) self.addChildren(groupCode,item,nxtHnd,tree[1:],loadAtoms) self.molHnd.DeleteSelection(resHnd) elif tree[0] == 'atom': atmHnd = self.molHnd.NewSelection() self.molHnd.Select(atmHnd,mmdb.STYPE_ATOM,masterHnd,mmdb.SKEY_NEW) atmSel = mmdb.newPPCAtom() #nAtm = self.molHnd.GetSelIndex(atmHnd,atmSel) atmSel = mmut.GetAtomSelIndex(self.molHnd,atmHnd,selindexp) nAtm = selindexp.value() #print "nAtm",nAtm for ia in range(0,nAtm): pAtm = mmdb.getPCAtom(atmSel,ia) name = self.atomName(pAtm) item = MGStandardItem(QtCore.QString(name),ATOMTYPE) parent_item.appendRow(item) #print "signal",pAtm,pAtm.name self.emit(QtCore.SIGNAL('addedAtom'),item,pAtm) self.molHnd.DeleteSelection(atmHnd) elif tree[0] == 'secstr': import copy resHnd = self.molHnd.NewSelection() self.molHnd.Select(resHnd,mmdb.STYPE_RESIDUE,masterHnd,mmdb.SKEY_NEW) resSel = mmdb.newPPCResidue() #nRes = self.molHnd.GetSelIndex(resHnd,resSel) selRes = mmut.GetResidueSelIndex(self.molHnd,resHnd,selindexp) nRes = selindexp.value() #print "secstr nres",nRes if nRes>=2: # NOSECSTR, BETA, BULGE, TURN3, TURN4, TURN5, ALPHA mask = [ 0 , 1 , 1 , 0, 0, 0, 2] output = ['L','S','H'] first_i = 0 first_sec = mask[mmdb.getPCResidue(resSel,0).SSE] i = 1 # NB **** one extra time around loop below to flush last secstr while i <= nRes: if i < nRes: sec = mask[mmdb.getPCResidue(resSel,i).SSE] else: sec = 999 if sec != first_sec: if first_sec>=0: name = self.resRangeName(mmdb.getPCResidue(resSel,first_i),mmdb.getPCResidue(resSel,i-1)) #print "secstr name",name item = MGStandardItem(QtCore.QString(output[first_sec]+' '+name),SECSTRTYPE) parent_item.appendRow(item) if nxtHnd>0: self.molHnd.Select(nxtHnd,mmdb.STYPE_ATOM,masterHnd,mmdb.SKEY_NEW) self.molHnd.Select(nxtHnd,mmdb.STYPE_ATOM,name,mmdb.SKEY_AND) self.addChildren(groupCode,item,nxtHnd,tree[1:],loadAtoms) first_i = copy.deepcopy(i) first_sec = copy.deepcopy(sec) i = i + 1 if nxtHnd>0: self.molHnd.DeleteSelection(nxtHnd) #-------------------------------------------------------------------------- def interpretTreeSelection(self,Index_list,returnCommand=0): #-------------------------------------------------------------------------- ''' Convert a list of selected items (QModelIndex) to an mg selelction command or and MMDB selection handle Input: Index_list - list of QModelIndex ''' import re if not Index_list: if returnCommand: return [0,''] else: return [0,'',-1] if returnCommand: pass else: selHnd = self.molHnd.NewSelection() #Index_list.sort(self.QModelIndexSort) selected_list = [] top_selected_list = [] ii = 0 while ii < len(Index_list): name = '' datatype,group,stack,parent_selected = self.interpretIndex(Index_list[ii],Index_list) #print 'interpretTreeSelection',datatype,group,stack,parent_selected index = Index_list[ii] if len(stack) == 0 or parent_selected: # A parent/grand-parent object already selected name = '' elif len(stack)==1 and datatype < ATOMTYPE: # Have clicked top level monomer/peptide etc selected_list.append([1,'',0,self.lookup[datatype].get('selection_mask')]) else: # Residue - test if its first of a range if [RESTYPE,RESTYPE_A].count(datatype): ir,ic = row,column = index.row(),index.column() #if stack[0] == 'Ligands': name = stack[-1] #else: # name = re.sub(r'\(.*\)','',stack[-1]) chn_sort = stack[-2][0:-1] res_sort = string.split(name,'/')[-1] #print "testing next res",ii,ir,str(index.sibling(ir+1,column).data().toString()) sibling_index = index.sibling(ir+1,column) doSiblingCheck = True if len(stack)>0 and stack[0] == "Ligands": doSiblingCheck = False while doSiblingCheck and sibling_index.isValid() and Index_list.count(sibling_index): ir = ir +1 last_res_name = str(index.sibling(ir,column).data().toString()) jj = Index_list.index(index.sibling(ir,column)) Index_list[jj] = QtCore.QModelIndex() sibling_index = index.sibling(ir+1,column) #print "testing next res",ii,ir,str(index.sibling(ir,column).data().toString()) if ir != row: name = re.sub(r'\(.*\)','',name) + '-' + re.sub(r'\(.*\)','',string.split(last_res_name,'/')[-1]) selected_list.append([2,chn_sort,res_sort,name]) elif datatype == ATOMTYPE: # its an atom - test if there are other selected atoms in residue # Complication .. mmdb does not altlocs in atom list of form ..'A/23/CA:A,CB:A' # but does understand 'A/23/CA,CB:A' altloc_lists = {} #name =re.sub(r'\(.*\)','', stack[-1]) name = stack[-1] if name.count(':'): altloc_lists[name.split(':')[1]] = name.split(':')[0] else: altloc_lists[''] = name #print 'interpretTreeSelection ATOMTYPE',name,altloc_lists chn_sort = stack[-3][0:-1] res_sort = string.split(name,'/')[-2] tt = string.split(name,'/')[-2] ir = 0 sib_index = index.parent().child(ir,0) while sib_index.isValid(): if Index_list.count(sib_index): jj = Index_list.index(sib_index) if jj != ii: atm_name = str(Index_list[jj].data().toString()) #print 'interpretTreeSelection testing same residue',atm_name if atm_name.count(':'): alt = atm_name.split(':')[1] if altloc_lists.has_key(alt): altloc_lists[alt]=altloc_lists[alt] + ',' + string.split(string.split(atm_name,'/')[-1],':')[0] else: altloc_lists[alt]=atm_name.split(':')[0] else: alt = '' if altloc_lists.has_key(alt): altloc_lists[alt]=altloc_lists[alt] + ',' + string.split(atm_name,'/')[-1] else: altloc_lists[alt]=atm_name #print "zeroing jj",jj Index_list[jj ] = QtCore.QModelIndex() ir = ir + 1 sib_index = index.parent().child(ir,0) for key,value in altloc_lists.items(): if key: selected_list.append([2,chn_sort,res_sort,value+':'+key]) else: selected_list.append([2,chn_sort,res_sort,value]) elif datatype == SECSTRTYPE: name = stack[-1][2:] chn_sort = stack[-2][0:-1] res_sort = string.split(string.split(name,'/')[-1],'-')[0] selected_list.append([2,chn_sort,res_sort,name]) # Asume chain level else: name = stack[-1] if hasattr(self.molHnd,"duplicateChainIDS") and self.molHnd.duplicateChainIDS: for key,val in self.composite.items(): if val.has_key('label') and val['label'] == stack[0]: selected_list.append([2,name[0:-1],'','{'+key+ ' and '+name+'}']) break else: selected_list.append([2,name[0:-1],'',name]) else: #selected_list.append([2,name[0:-1],'',name]) compname = [ cnkey for cnkey,cnval in self.composite.items() if (cnval.has_key('label') and cnval['label'] == stack[0])] if len(compname)>0: selected_list.append([2,name[0:-1],'','{'+compname[0]+' and '+name+'}']) #print "interpretTreeSelection name",name if not returnCommand and name: self.molHnd.Select(int(selHnd),int(mmdb.STYPE_ATOM),str(name),int(mmdb.SKEY_OR)) ii = ii + 1 #print "selected_list",selected_list if selected_list: selected_list.sort() comstring = selected_list[0][3] for item in selected_list[1:]: comstring = comstring + ' or ' + item[3] else: comstring = '' if returnCommand: return [0,comstring] else: return [0,self.molHnd,selHnd] #------------------------------------------------------------------------ def interpretIndex (self,index,Index_list=[]): #------------------------------------------------------------------------ ''' Return details about a selected item from tree Input: index : QModelIndex Index_list=[] : List of indices other selected items Output datatype,group,stack,parent_selected datatype : int MGStandardItem.datatype() of the item group: int MGStandardItem.datatype() of the top level item stack: list of QStandardItem.data() for item, parent, grand-parent - in reverse order parent_selected: true if Index_list contains an ancestor of index ''' if not index.isValid(): return 0,0,[],0 stack = [] datatype = int(self.itemFromIndex(index).datatype()) parent_selected = 0 while index.isValid(): stack.append(str(index.data().toString())) if index.parent().isValid(): if Index_list.count(index.parent()): parent_selected = 1 else: group = int(self.itemFromIndex(index).datatype()) index = index.parent() stack.reverse() #print "stack",stack,'parent_selected',parent_selected,'type',datatype,'group',group return datatype,group,stack,parent_selected def QModelIndexSort(self,i1,i2): if i1 == i2: return 0 elif i1 < i2: return -1 else: return 1 def MolData(self): return self.MolDataObj #------------------------------------------------------------------------ def canFetchMore(self,index): #------------------------------------------------------------------------ ''' Reimplement QStandardItemModel.canFetchMore() to return true when extra atoms can be loaded ''' if (not index.isValid()) or index.child(0,0).isValid(): return 0 #print "canFetchMore",self.itemFromIndex(index).datatype(),index.child(0,0).isValid() if self.itemFromIndex(index).datatype() == RESTYPE_A: return 1 else: return 0 #----------------------------------------------------------------------- def fetchMore(self,index): #----------------------------------------------------------------------- ''' Reimplement QStandardItemModel.fetchMore() to load atom data ''' #print "fetchMore",index # Check index is valid and that it does not already have children if (not index.isValid()) or index.child(0,0).isValid(): return item = self.itemFromIndex(index) if item.datatype() == RESTYPE_A: datatype,groupCode,stack,parent_selected = self.interpretIndex(index) parent_selection = str(item.data(QtCore.Qt.DisplayRole).toString()) # As ever beware the unnamed chain if parent_selection[0:4] != '// /': parent_selection = '/1/' + parent_selection #print 'fetchMore fetchMoreparent_selection',parent_selection atmHnd = self.getAtomSelection(self.lookup[groupCode]['selection_mask'],parent_selection) if atmHnd>0: self.addChildren(groupCode,item,atmHnd,['atom'],1) self.molHnd.DeleteSelection(atmHnd) self.emit(QtCore.SIGNAL('moreFetched'),index) #---------------------------------------------------------------------- def hasChildren(self,index): #---------------------------------------------------------------------- ''' Reimplement QStandardItemModel.hasChildren() to return true for residues which could have atom children ''' if not index.isValid(): return 1 datatype = int(self.itemFromIndex(index).datatype()) if datatype == RESTYPE_A: return 1 else: return QtGui.QStandardItemModel.hasChildren(self,index) #--------------------------------------------------------------------------- def atomName(self,pAtom,inclRes=1,inclResName=1): #--------------------------------------------------------------------------- name = string.strip(pAtom.GetAtomName()) alt = pAtom.GetAltLoc() if alt: name = name + ':' + alt if inclRes: return self.residueName(pAtom,inclResName) +'/'+name else: return name #--------------------------------------------------------------------------- def residueName(self,pAtom=None,inclResName=1,inclChainName=1): #--------------------------------------------------------------------------- if inclChainName: resname = self.chainName(pAtom) + str(pAtom.GetSeqNum()) else: resname = str(pAtom.GetSeqNum()) inscode = str(pAtom.GetInsCode()) if inscode: resname = resname + '.' + inscode if not inclResName: return resname resname = resname + "(" + pAtom.GetResName() + ')' return resname #--------------------------------------------------------------------------- def chainName(self,pAtom): #--------------------------------------------------------------------------- chnid = str(pAtom.GetChainID()) if not chnid or chnid == ' ': chnid = '// ' return chnid + '/' #--------------------------------------------------------------------------- def resRangeName(self,pRes1,pRes2): #--------------------------------------------------------------------------- name = self.residueName(pRes1,inclResName=0) + '-' + \ self.residueName(pRes2,inclResName=0,inclChainName=0) return name #------------------------------------------------------------------------ def getModelIndex(self,selRes,ir): #------------------------------------------------------------------------ # get table groupCode, chain row and residue row from # the mmdb information chn_row = pygl_coord.inta(1) res_row = pygl_coord.inta(1) pcres = mmdb.getPCResidue(selRes,ir) rv = pcres.GetUDData(self.udd_res,res_row) rv = pcres.GetUDData(self.udd_chn,chn_row) resRow = res_row[0] groupCode = chn_row[0]%10 chnRow = chn_row[0]/10 #print "getModelIndex",resRow,groupCode,chnRow if groupCode<=0: return None if not groupCode in self.lookup or not 'groupName' in self.lookup[groupCode] or not self.lookup[groupCode]['groupName'] in self.groupItems: return None groupItem = self.groupItems[self.lookup[groupCode]['groupName']] if self.lookup[groupCode]['tree'][0]=='res': return groupItem.child(resRow,0).index() elif self.lookup[groupCode]['tree'][0:2]==['chain','res']: return groupItem.child(chnRow,0).child(resRow,0).index() else: return None #------------------------------------------------------------------------ def getChainIndex(self,selChn,ic): #------------------------------------------------------------------------ # get table groupCode, chain row and residue row from # the mmdb information chn_row = pygl_coord.inta(1) pcchn = mmdb.getPCChain(selChn,ic) rv = pcchn.GetUDData(self.udd_chn_chn,chn_row) groupCode = chn_row[0]%10 chnRow = chn_row[0]/10 if groupCode<=0: return None groupItem = self.groupItems[self.lookup[groupCode]['groupName']] if self.lookup[groupCode]['tree'][0:2]==['chain','res']: return groupItem.child(chnRow,0).index() else: return None #------------------------------------------------------------------------ class mgTreeView ( QtGui.QTreeView): #------------------------------------------------------------------------ def __init__(self,parent=None,abstractModel=None): super(mgTreeView,self).__init__(parent) # Don't display the header self.header().setVisible(0) self.setSelectionMode(QtGui.QAbstractItemView.MultiSelection) self.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.setModel(abstractModel) self.setExpanded(QtCore.QModelIndex(),1) for group,item in abstractModel.groupItems.items(): #print "expanded",group,item self.setExpanded(item.index(),1) self.loadedAtomSelHnd = -1 self.lastSelection = '' self.connect(self.model(),QtCore.SIGNAL('addedAtom'),self.handleAddedAtom) self.connect(self.selectionModel(),QtCore.SIGNAL('selectionChanged(QItemSelection,QItemSelection)'),self.changed) def __del__(self): if self.loadedAtomSelHnd>0: self.model().molHnd.DeleteSelection(self.loadedAtomSelHnd) #--------------------------------------------------------------------------- def changed(self): #--------------------------------------------------------------------------- #print "mgTreeView.changed emitting" self.emit(QtCore.SIGNAL('changed')) #--------------------------------------------------------------------------- def loadGroups(self,groups=[]): #--------------------------------------------------------------------------- self.selectionModel().blockSignals(True) for group in groups: self.model().loadGroup(group,definition=AbstractMolData.composite[group]) for group in self.model().getGroups(): if not groups.count(group): self.collapse(self.model().groupItems[group].index()) row = self.model().getGroupRow(group) #print "getGroupRow",row if row>0: self.setRowHidden(row,self.model().groupItems[group].index().parent(),1) self.selectionModel().blockSignals(False) #self.changed() #-------------------------------------------------------------------------- def setGroupSelection(self,command='all'): #-------------------------------------------------------------------------- import string rv = 1 groupList = self.model().getGroups() #print "mgTreeView.setGroupSelection groupList",command,groupList self.selectionModel().blockSignals(True) if command == 'all': for group in groupList: self.selectionModel().select(self.model().groupItems[group].index(), QtGui.QItemSelectionModel.Select) rv = 0 elif groupList.count(command): self.selectionModel().select(self.model().groupItems[command].index(), QtGui.QItemSelectionModel.Select) rv = 0 elif string.find(command,' or '): ok = 1 for item in string.split(command,' or '): if not groupList.count(string.strip(item)): ok = 0 if ok: for item in string.split(command,' or '): self.selectionModel().select(self.model(). groupItems[string.strip(item)].index(),QtGui.QItemSelectionModel.Select) rv = 0 self.selectionModel().blockSignals(False) return rv #--------------------------------------------------------------------- def loadMMDBSelection(self,selHnd): #--------------------------------------------------------------------- self.selectionModel().blockSignals(True) molHnd = self.model().molHnd selAtoms = mmdb.newPPCAtom() selRes = mmdb.newPPCResidue() selChains = mmdb.newPPCChain() selindexp = pygl_coord.intp() if self.loadedAtomSelHnd<0: self.loadedAtomSelHnd = molHnd.NewSelection() molHnd.Select(self.loadedAtomSelHnd,mmdb.STYPE_ATOM,selHnd,mmdb.SKEY_NEW) # make sure these are just in the first model molHnd.SelectAtoms(self.loadedAtomSelHnd, self.model().MolDataObj.first_nmr_model, "*",mmdb.ANY_RES,"*",mmdb.ANY_RES,"*","*","*","*","*",mmdb.SKEY_AND ) #nselAtom =molHnd.GetSelIndex(self.loadedAtomSelHnd,selAtoms) selAtoms = mmut.GetAtomSelIndex(molHnd,self.loadedAtomSelHnd,selindexp) nselAtom = selindexp.value() #print "loadMMDBSelection initially nselAtom",nselAtom if nselAtom == 0: self.selectionModel().blockSignals(False) return 0 # Set up mask for all atoms/residues/chains allAtomHnd = molHnd.NewSelection() molHnd.SelectAtoms(allAtomHnd, 1, "*",mmdb.ANY_RES,"*",mmdb.ANY_RES,"*","*","*","*","*",mmdb.SKEY_NEW ) allResHnd= molHnd.NewSelection() molHnd.Select(allResHnd,mmdb.STYPE_RESIDUE,allAtomHnd,mmdb.SKEY_NEW) allChnHnd= molHnd.NewSelection() molHnd.Select(allChnHnd,mmdb.STYPE_CHAIN,allResHnd,mmdb.SKEY_NEW) wrkAtomHnd = molHnd.NewSelection() wrkResHnd = molHnd.NewSelection() wrkChnHnd = molHnd.NewSelection() #### CHAINS # Get Residues for which *all* atoms are selected molHnd.Select(wrkAtomHnd,mmdb.STYPE_ATOM,allAtomHnd,mmdb.SKEY_NEW) # Get all the non-selected atoms (in first model) molHnd.Select(wrkAtomHnd,mmdb.STYPE_ATOM,self.loadedAtomSelHnd,mmdb.SKEY_XOR) # Get all chains containing non-selected atoms molHnd.Select(wrkChnHnd,mmdb.STYPE_CHAIN,wrkAtomHnd,mmdb.SKEY_NEW) # Get chains not containing non-selected atoms - i.e. all atoms # in the chain are selected molHnd.Select(wrkChnHnd,mmdb.STYPE_CHAIN,allChnHnd,mmdb.SKEY_XOR) # Retreive these chains and select in the tree selChn = mmdb.newPPCChain() #nSelChn=molHnd.GetSelIndex(wrkChnHnd,selChn) selChn = mmut.GetAtomSelIndex(molHnd,wrkChnHnd,selindexp) nSelChn = selindexp.value() #print "wrkChnHnd nSelChn",nSelChn for ic in range(0,nSelChn): index = self.model().getChainIndex(selChn,ic) if index: self.selectionModel().select(index,QtGui.QItemSelectionModel.Select) #### RESIDUES # Get Residues for which *all* atoms are selected molHnd.Select(wrkAtomHnd,mmdb.STYPE_ATOM,allAtomHnd,mmdb.SKEY_NEW) # Get all the non-selected atoms (in first model) molHnd.Select(wrkAtomHnd,mmdb.STYPE_ATOM,self.loadedAtomSelHnd,mmdb.SKEY_XOR) # Get all residues containing non-selected atoms molHnd.Select(wrkResHnd,mmdb.STYPE_RESIDUE,wrkAtomHnd,mmdb.SKEY_NEW) # Get residues not containing non-selected atoms - i.e. all atoms # in the residue are selected molHnd.Select(wrkResHnd,mmdb.STYPE_RESIDUE,allResHnd,mmdb.SKEY_XOR) # And exclude any residues in completely selected chains molHnd.Select(wrkResHnd,mmdb.STYPE_RESIDUE,wrkChnHnd,mmdb.SKEY_CLR) # Retreive these residues and select in the tree #nSelRes=molHnd.GetSelIndex(wrkResHnd,selRes) selRes = mmut.GetResidueSelIndex(molHnd,wrkResHnd,selindexp) nSelRes = selindexp.value() #print "wrkResHnd nSelRes",nSelRes for ir in range(0,nSelRes): index = self.model().getModelIndex(selRes,ir) if index: self.selectionModel().select(index,QtGui.QItemSelectionModel.Select) # Find residues with some (but not all) atoms selected someResHnd= molHnd.NewSelection() molHnd.Select(someResHnd,mmdb.STYPE_RESIDUE,self.loadedAtomSelHnd,mmdb.SKEY_NEW) molHnd.Select(someResHnd,mmdb.STYPE_RESIDUE,wrkResHnd,mmdb.SKEY_CLR) #nSelRes=molHnd.GetSelIndex(someResHnd,selRes) selRes = mmut.GetResidueSelIndex(molHnd,someResHnd,selindexp) nSelRes = selindexp.value() #print "semi-selected residues",nSelRes ###### ATOMS # Get table of atoms in the residue and loop over these testing # if they are in the self.loadedAtomSelHnd selection # BIG ASSUMPTION -- order of atoms in treeView is same as that returned # by GetAtomTable - expect this to be true but possibly could be broken by # atom editting if nSelRes>0: atomTable = mmdb.newPPCAtom() nAtom = mmdb.intp() for ir in range(0,nSelRes): index = self.model().getModelIndex(selRes,ir) #print "ir,index",ir,str(index.data().toString()),self.isExpanded(index) if index and self.isExpanded(index): atomTable = mmut.GetAtomTable(mmdb.getPCResidue(selRes,ir),nAtom) #pRes = mmdb.getPCResidue(selRes,ir).GetAtomTable(atomTable,nAtom) for ia in range(0,nAtom.value()): if mmdb.getPCAtom(atomTable,ia).isInSelection(self.loadedAtomSelHnd): self.selectionModel().select(index.child(ia,0),QtGui.QItemSelectionModel.Select) else: # We do not need to keep the selection molHnd.DeleteSelection(self.loadedAtomSelHnd) self.loadedAtomSelHnd = -1 molHnd.DeleteSelection(allAtomHnd) molHnd.DeleteSelection(allResHnd) molHnd.DeleteSelection(wrkAtomHnd) molHnd.DeleteSelection(wrkResHnd) molHnd.DeleteSelection(someResHnd) molHnd.DeleteSelection(wrkChnHnd) molHnd.DeleteSelection(allChnHnd) #molHnd.DeleteSelection(someChnHnd) self.selectionModel().blockSignals(False) #self.changed() #-------------------------------------------------------------------------- def getMMDBSelection(self): #-------------------------------------------------------------------------- selected = self.selectedIndexes() #print "treeView.getMMDBSelection selected",selected ret = self.model().interpretTreeSelection(selected) #print "getMMDBSelection ret",ret if ret[0]: return -1 else: return ret[2] #--------------------------------------------------------------------------- def getSelectionCommand(self): #--------------------------------------------------------------------------- selected = self.selectedIndexes() #print "selected",selected ret = self.model().interpretTreeSelection(selected,returnCommand=1) return ret #--------------------------------------------------------------------------- def handleExpanded(self,index): #--------------------------------------------------------------------------- item = self.model().itemFromIndex(index) if item.datatype() != RESTYPE_A or not item.hasChildren(): return #print "handleExpanded",index.data().toString() ii = 0 child = index.child(ii,0) #--------------------------------------------------------------------------- def handleAddedAtom(self,item,pAtom): #--------------------------------------------------------------------------- #print "handleAddedAtom",item.text(),pAtom,pAtom.name if self.loadedAtomSelHnd > 0 and \ pAtom.isInSelection(self.loadedAtomSelHnd): self.selectionModel().select(self.model().indexFromItem(item),QtGui.QItemSelectionModel.Select) ''' #--------------------------------------------------------------------------- def focusOutEvent(self,event): #--------------------------------------------------------------------------- #print 'mgTreeView.focusOutEvent' self.emit(QtCore.SIGNAL('focusOut')) QtGui.QTreeView.focusOutEvent(self,event) event.ignore() ''' #-------------------------------------------------------------------------- class MGStandardItem(QtGui.QStandardItem): #-------------------------------------------------------------------------- def __init__(self,text,mgtype=1001): super(MGStandardItem,self).__init__(text) self.mgtype=mgtype #self.setCheckable(1) def datatype(self): #print "MGStandardItem type",self.mgtype return self.mgtype