""" qtgui/CCP4ModelWidgets.py: CCP4 Gui Project Copyright (C) 2010 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. """ ##@package CCP4ModelWidgets (QtGui) Collection of widgets for model data types from PyQt4 import QtGui,QtCore import CCP4ModelData from CCP4ErrorHandling import * import CCP4Widgets class CResidueRangeView(CCP4Widgets.CComplexLineWidget): MODEL_CLASS = CCP4ModelData.CResidueRange ERROR_CODES = { } def __init__(self,parent=None,model=None,qualifiers={}): qualis = qualifiers CCP4Widgets.CComplexLineWidget.__init__(self,parent,qualis) #if self.editable: self.connect(self.iconButton,QtCore.SIGNAL('acceptDropData'),self.handleDrop) if model is not None: self.setModel(model) self.layout().addWidget(QtGui.QLabel('Chain')) if self.editable: self.widgets['chainId'] = CCP4Widgets.CComboBox(self,charWidth=2,dragType=self.dragType()) else: self.widgets['chainId'] = CCP4Widgets.CLabel(self,charWidth=4,uneditable=True,dragType=self.dragType()) self.layout().addWidget(self.widgets['chainId']) for item,label in [['firstRes','residue'],['lastRes','to']]: self.layout().addWidget(QtGui.QLabel(label)) if self.editable: self.widgets[item] = CCP4Widgets.CLineEdit(self,charWidth=10,dragType=self.dragType()) else: self.widgets[item] = CCP4Widgets.CLabel(self,charWidth=10,uneditable=True,dragType=self.dragType()) self.layout().addWidget(self.widgets[item]) if self.editable: for item in self.widgets.keys(): self.connect(self.widgets[item],QtCore.SIGNAL('editingFinished()'),self.updateModelFromView) self.connect(self.widgets[item],QtCore.SIGNAL('acceptDropData'),self.acceptDropData) pdbFileObj = self.model.parent().getDataByKey('pdbFileKey') if pdbFileObj is not None: self.loadChains() self.connect(pdbFileObj,QtCore.SIGNAL('dataChanged'),self.loadChains) self.layout().addStretch(5) def loadChains(self): self.widgets['chainId'].clear() for chn in self.model.parent().getChains(): self.widgets['chainId'].addItem(chn) def getMenuDef(self): return ['clear','copy','paste','help'] class CSequenceEdit: def __init__(self,parent=None,model=None): pass class CSequenceView(CCP4Widgets.CComplexLineWidget): ERROR_CODES = { } MODEL_CLASS = CCP4ModelData.CSequence def __init__(self,parent=None,model=None,qualifiers={}): qualis = {'gridLayout':True} qualis.update(qualifiers) CCP4Widgets.CComplexLineWidget.__init__(self,parent,qualis) if model is not None: self.setModel(model) #if qualis.get('stackButton',None) is not None: # self.layout().addWidget(qualis['stackButton'],0,1) self.layout().addWidget(QtGui.QLabel('Description:',self),1,0) if self.editable: self.widgets['identifier'] = CCP4Widgets.CLineEdit(self,qualifiers=qualis) self.widgets['reference'] = CCP4Widgets.CLineEdit(self,qualifiers=qualis) self.widgets['referenceDb'] = CCP4Widgets.CComboBox(self,qualifiers= CCP4ModelData.CSequence.CONTENTS['referenceDb']['qualifiers'] ) else: self.widgets['identifier'] = CCP4Widgets.CLabel(self,qualifiers=qualis) self.widgets['reference'] = CCP4Widgets.CLabel(self,qualifiers=qualis) self.widgets['referenceDb'] = CCP4Widgets.CLabel(self,qualifiers=qualis) self.widgets['identifier'].setToolTip('Name of the sequence') self.widgets['reference'].setToolTip('Database identifier') self.widgets['referenceDb'].setToolTip('Sequence database') self.layout().addWidget(self.widgets['identifier'],1,1,1,2) self.layout().addWidget(QtGui.QLabel('Database reference:',self),0,0) self.layout().addWidget(self.widgets['referenceDb'],0,1) self.layout().addWidget(self.widgets['reference'],0,2) #if self.editable: # self.widgets['moleculeType']=CCP4Widgets.CComboBox(self,qualifiers= CCP4ModelData.CSequence.CONTENTS['moleculeType']['qualifiers']) #else: # self.widgets['moleculeType']=CCP4Widgets.CLabel(self,qualifiers=qualis) #self.layout().addWidget(self.widgets['moleculeType'],0,5) self.widgets['sequence'] = CCP4Widgets.CTextEdit(self,qualifiers=qualis) self.layout().addWidget(self.widgets['sequence'],2,0,1,3) for item in CCP4ModelData.CSequence.CONTENTS_ORDER: widget = self.widgets.get(item,None) if widget is not None: #print 'CSequenceView.__init__',item,repr(self.model.getDataObjects(item)),type(self.model.getDataObjects(item)) if model is not None: tT = self.model.getDataObjects(item).qualifiers('toolTip') if tT is NotImplemented: tT = '' widget.setToolTip(tT) if self.editable: self.connect(widget,QtCore.SIGNAL(widget.editSignal()),self.updateModelFromView) self.connect(widget,QtCore.SIGNAL('acceptDropData'),self.acceptDropData) def getMenuDef(self): menu = CCP4Widgets.CComplexLineWidget.getMenuDef(self) menu.insert(0,'content') return menu def updateViewFromModel(self): #print 'CSequenceView.updateViewFromModel widgets',self.widgets if len(self.widgets) == 0: return if self.model is None: for item in ['identifier','reference','referenceDb','sequence']: self.widgets[item].setValue('') else: for item in ['identifier','reference','referenceDb','sequence']: #print 'CSequenceView.updateViewFromModel',item,self.model.__dict__['_value'][item].__str__() self.widgets[item].setValue(self.model.__dict__['_value'][item].__str__()) self.validate() class CSeqDataFileView(CCP4Widgets.CDataFileView): MODEL_CLASS = CCP4ModelData.CSeqDataFile def __init__(self,parent=None,model=None,qualifiers={}): qualis = {'vboxLayout':True} qualis.update(qualifiers) self.enableEdit = qualifiers.get('enableEdit',True) CCP4Widgets.CDataFileView.__init__(self,parent=parent,model=model,qualifiers=qualis) qualis['iconButton'] = False if model is not None: self.widgets['sequence'] = CSequenceView(parent=parent,model=model.getFileContent(),qualifiers=qualis) else: self.widgets['sequence'] = CSequenceView(parent=parent,qualifiers=qualis) self.layout().addWidget(self.widgets['sequence']) self.widgets['sequence'].hide() self.setModel(model) parentTask = self.parentTaskWidget() if parentTask is not None: self.connect(parentTask,QtCore.SIGNAL('doFix'),self.saveSequence) def getMenuDef(self): if self.editable: menu = ['clear',['View','view_text'],'sep','copy','paste','help'] if self.enableEdit: menu.insert(2,'edit') else: menu = [['View','view_text'],'sep','copy','editLabel','export','help'] return menu def getActionDef(self,name): if name == 'edit': return dict ( text = self.tr("View/edit sequence"), tip = self.tr('You can cut-n-paste sequence into the widget'), slot = self.showEditor ) else: return CCP4Widgets.CDataFileView.getActionDef(self,name) def showEditor(self,visible=None): if visible is None: visible = not self.widgets['sequence'].isVisible() #print 'CSeqDataFile.showEditor',visible,self.model.exists(),self.widgets['sequence'].model if visible and self.model.exists(): self.model.loadFile() #print 'CSeqDataFile.showEditor after loadFile',repr(self.widgets['sequence'].model),self.widgets['sequence'].model if self.widgets['sequence'].model is None: self.widgets['sequence'].setModel(model.fileContent) self.widgets['sequence'].updateViewFromModel() self.widgets['sequence'].setVisible(visible) def setModel(self,model): CCP4Widgets.CDataFileView.setModel(self,model) if self.widgets.get('sequence',None) is None: return if model is not None: if hasattr(model,'fileContent'): self.widgets['sequence'].setModel(model.fileContent) self.connect(model,QtCore.SIGNAL('dataChanged'),self.loadSequence) self.loadSequence() else: self.widgets['sequence'].setModel(None) def loadSequence(self): if not self.editable: return if self.model.isSet(): try: self.model.loadFile() except: self.model.fileContent.unSet() else: self.model.fileContent.unSet() self.updateViewFromModel() def saveSequence(self): widgetValue = self.widgets['sequence'].widgets['sequence'].getValue() #print 'CSeqDataFileView.saveSequence',widgetValue if widgetValue is None or len(widgetValue.strip())==0: return jobId = self.parentTaskWidget().jobId() self.widgets['sequence'].updateModelFromView() if not self.model.baseName.isSet(): self.model.saveSequence(jobId=jobId) self.validate() else: if self.model.fileContent.sequence.isSet(): # User has a filename set and a sequence set - test if they match fileContent = CCP4ModelData.CSequence() #try: if 1: fileContent.loadFile(str(self.model),format=self.model.__dict__['format']) err = self.model.fileContent.assertSame(fileContent) #print 'CSeqDataFileView.saveSequence',self.model.fileContent,fileContent,err.report() if err.maxSeverity()>SEVERITY_WARNING: mess = QtGui.QMessageBox(self) mess.setWindowTitle('Sequence file') mess.setText('Save sequence or reference data to a new file') mess.addButton('Save to file', QtGui.QMessageBox.AcceptRole) mess.addButton('Keep existing file',QtGui.QMessageBox.ActionRole) mess.addButton('Cancel', QtGui.QMessageBox.RejectRole) mess.show() ret = mess.exec_() if ret == QtGui.QMessageBox.RejectRole: return elif ret == QtGui.QMessageBox.ActionRole: self.model.loadFile() else: self.model.saveSequence(jobId=jobId) self.validate() def validate(self,isValid=None,reportMessage=True): dataFileIsValid = CCP4Widgets.CDataFileView.validate(self,isValid=isValid,reportMessage=reportMessage) if self.editable: try: sequenceIsValid = self.widgets['sequence'].validate(isValid=isValid,reportMessage=reportMessage) if self.model.qualifiers('allowUndefined') and sequenceIsValid.maxSeverity()0 and self.model.fileContent.__dict__['loadWarning'][0]['code'] == 108: import CCP4Utils win = self.makeImportReport('Importing '+str(filename),self.acceptFixedPir) label = QtGui.QLabel(self) label.setText( 'The input file is not correct PIR format but has been fixed and is shown below.\nIf this is still incorrect please correct the file and select it again.\n' + CCP4ModelData.PIR_DESCRIPTION + '\nYour corrected file:') #label.setReadOnly(True) win.layout().insertWidget(0,label) label = QtGui.QTextEdit(self) label.setText(CCP4Utils.readFile(self.model.fileContent.__dict__['loadWarning'][0]['details'])) label.setReadOnly(True) win.layout().insertWidget(1,label) win.show() return elif self.model.fileContent.__dict__['loadWarning'].maxSeverity()>SEVERITY_WARNING: self.model.fileContent.__dict__['loadWarning'].warningMessage(windowTitle='Importing sequence file',parent=self,message='Failed importing sequence file') self.model.unSet() self.updateViewFromModel() return elif len(self.model.__dict__.get('identifiers',[]))>1: #print 'handleBrowserOpenFile drawing idChooser',getattr(self,'idChooser',None) if getattr(self,'idChooser',None) is None: self.idChooser = QtGui.QListWidget(self) self.idChooser.setSelectionMode(QtGui.QListWidget.SingleSelection) win = self.makeImportReport('Importing '+str(filename),self.handleIdChooser) win.layout().insertWidget(0,QtGui.QLabel('Select one of the sequences in the file',self)) win.layout().insertWidget(1,self.idChooser) self.idChooser.clear() for item in self.model.__dict__['identifiers']: self.idChooser.addItem(item) self.idChooser.window().show() self.idChooser.window().raise_() return if self.model.__dict__['format'] is None or self.model.__dict__['format'] != 'internal': #self.model.importFile(jobId=self.parentTaskWidget().jobId(),jobNumber=self.parentTaskWidget().jobNumber()) self.doImportFile() else: self.model.emitDataChanged() # No problems just display it! self.updateViewFromModel() self.validate() def makeImportReport(self,title,callBack=None): win = QtGui.QDialog(self) win.setWindowTitle(title) win.setLayout(QtGui.QVBoxLayout()) line = QtGui.QHBoxLayout() box = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok|QtGui.QDialogButtonBox.Cancel) win.layout().addLayout(line) line.addStretch(1) line.addWidget(box) line.addStretch(1) if callBack is not None: self.connect(box,QtCore.SIGNAL('clicked ( QAbstractButton * )'),callBack) #self.connect(box,QtCore.SIGNAL('clicked ( QAbstractButton * )'),win.close) return win def doImportFile(self,label=None): if self.model.fileContent.identifier.isSet() and len(self.model.fileContent.identifier)>0: anno = self.model.fileContent.identifier elif label is not None: anno = label+' imported from '+ str(self.model.baseName) else: anno = self.model.qualifiers('guiLabel')+' imported from '+ str(self.model.baseName) #print 'doImportFile anno',anno,'label',label #self.model.blockSignals(True) validatedFile=self.model.fileContent.__dict__.get('validatedFile',None) self.model.importFile(jobId=self.parentTaskWidget().jobId(),annotation=anno,validatedFile=validatedFile,jobNumber=self.parentTaskWidget().jobNumber()) self.model.annotation = anno #self.model.blockSignals(False) self.updateViewFromModel() import CCP4Modules if CCP4Modules.PREFERENCES().AUTO_INFO_ON_FILE_IMPORT and not self.model.dbFileId.isSet(): self.openInfo(label=self.model.qualifiers('guiLabel').lower(),sourceFileAnnotation=self.model.__dict__.get('sourceFileAnnotation','')) def acceptFixedPir(self,but): #print 'CSeqDataFileView.acceptFixedPir',but.text().__str__() if but.text().__str__() == 'Cancel': self.model.unSet() self.updateViewFromModel() else: self.doImportFile() win = but.window() win.close() self.updateViewFromModel() def handleIdChooser(self,but): #print 'CSeqDataFileView.handleIdChooser', but.text().__str__() record = self.idChooser.currentRow() win = but.window() win.setModal(False) win.close() if but.text().__str__() == 'Cancel': self.model.unSet() self.updateViewFromModel() return else: #print 'CSeqDataFileView.handleIdChooser',record; import sys; sys.stdout.flush() self.model.fileContent.loadExternalFile(self.model.__str__(),self.model.__dict__['format'],record=record) self.doImportFile() self.updateViewFromModel() def filterText(self): # make the filters text for QFileDialog to include the alignment extensions textList = [] for desc,extList in [ [CCP4ModelData.CSeqDataFile.QUALIFIERS['mimeTypeDescription'] , CCP4ModelData.EXTLIST ], ]: text = desc + ' (' for ext in extList.keys(): text = text + '*.'+ext+' ' textList.append( text[0:-1]+')' ) return textList ''' class CDictDataFileView(CCP4Widgets.CDataFileView): MODEL_CLASS = CCP4ModelData.CDictDataFile PROJECT_FILE_LABEL = 'Ideal ligand geometry file for project' def __init__(self,parent=None,model=None,qualifiers={},**kw): qualis = {} qualis.update(qualifiers) qualis.update(kw) CCP4Widgets.CDataFileView.__init__(self,parent=parent,model=model,qualifiers=qualis) def getActionDef(self,name): if name == 'manage_dict': return dict ( text = self.tr("View/edit dictionary"), tip = self.tr('View/edit the currently selected dictionary'), slot = self.manageProjectDictionary ) else: return CCP4Widgets.CDataFileView.getActionDef(self,name) def manageProjectDictionary(self): if not hasattr(self,'dictManager'): #self.dictManager = CDictDataDialog(model=self.model.fileContent) self.dictManager = CDictDataDialog(parent=self.parentTaskWidget(),projectId=self.parentTaskWidget().projectId()) self.dictManager.show() self.dictManager.raise_() def handleMerge(self): import CCP4FileBrowser,CCP4Modules self.mergeFileBrowser = CCP4FileBrowser.CFileDialog(parent=self,title='Select dictionary file to merge into project dictionary', defaultSuffix=CCP4Modules.MIMETYPESHANDLER().getMimeTypeInfo(name='application/refmac-dictionary',info='fileExtensions'), fileMode=QtGui.QFileDialog.ExistingFiles,saveButtonText='Merge these files') self.mergeFileBrowser.show() self.connect(self.mergeFileBrowser,QtCore.SIGNAL('selectFiles'),self.mergeFiles) def mergeFiles(self,selectedFiles=[]): # 'CDictDataFileView.mergeFiles',selectedFiles if hasattr(self,'mergeFileBrowser'): self.mergeFileBrowser.close() self.mergeFileBrowser.deleteLater() import CCP4Modules workDirectory = CCP4Modules.PROJECTSMANAGER().jobDirectory( jobId=self.parentTaskWidget().jobId(),projectId=self.parentTaskWidget().projectId()) newFile,err = self.model.mergeInDictFiles(dictFileList=selectedFiles,parentWorkDirectory=workDirectory) for fileName in selectedFiles: err = self.model.fileContent.mergeFile(fileName=fileName,overwrite=True) #print 'CDictDataFileView.mergeFiles',err.report(),err.maxSeverity() if err.maxSeverity()>SEVERITY_WARNING: err.warningMessage(windowTitle='Error merging Refmac dictionaries',parent=self,message='Error attempting to merge Refmac dictionaries') return """ def loadJobCombo(self): CCP4Widgets.CDataFileView.loadJobCombo(self) if self.jobCombo.findText(CDictDataFileView.PROJECT_FILE_LABEL)<0: # Call the defaultProjectDict even though result is not used it will ensure that # a file exists (by creting emptly file if necessary) if self.model is None: return dictFile = self.model.defaultProjectDict(projectId=self.parentTaskWidget().projectId()) self.jobCombo.insertItem(1,CDictDataFileView.PROJECT_FILE_LABEL) self.jobCombo.setCurrentIndex(1) """ def handleFollowFrom(self,contextJobId,projectId): self.jobCombo.setCurrentIndex(1) def handleJobComboChange(self,indx=None): self.connectUpdateViewFromModel(False) if indx is None: indx = 0 if str(self.jobCombo.itemText(indx)) == CDictDataFileView.PROJECT_FILE_LABEL: self.model.set(self.model.defaultProjectDict(projectId=self.parentTaskWidget().projectId())) self.model.annotation = CDictDataFileView.PROJECT_FILE_LABEL else: CCP4Widgets.CDataFileView.handleJobComboChange(self,indx0=indx) ''' class CMonomerView(CCP4Widgets.CComplexLineWidget): MODEL_CLASS = CCP4ModelData.CMonomer def __init__(self,parent=None,model=None,qualifiers={}): qualis = {'gridLayout':True} qualis.update(qualifiers) CCP4Widgets.CComplexLineWidget.__init__(self,parent,qualis) if model is not None: self.setModel(model) self.layout().addWidget(QtGui.QLabel('Identifier:',self),0,1) if self.editable: self.widgets['identifier'] = CCP4Widgets.CStringView(self,qualifiers=qualis) else: self.widgets['identifier'] = CCP4Widgets.CLabel(self,qualifiers=qualis) self.layout().addWidget(self.widgets['identifier'],0,2) self.layout().addWidget(QtGui.QLabel('Formula:',self),0,3) if self.editable: self.widgets['formula'] = CCP4Widgets.CStringView(self,qualifiers=qualis) else: self.widgets['formula'] = CCP4Widgets.CLabel(self,qualifiers=qualis) self.layout().addWidget(self.widgets['formula'],0,4) self.layout().addWidget(QtGui.QLabel('Dictionary name:',self),1,1) if self.editable: self.widgets['dictionaryName'] = CCP4Widgets.CStringView(self,qualifiers=qualis) else: self.widgets['dictionaryName'] = CCP4Widgets.CLabel(self,qualifiers=qualis) self.layout().addWidget(self.widgets['dictionaryName'],1,2) self.layout().addWidget(QtGui.QLabel('Smiles string:',self),1,3) if self.editable: self.widgets['smiles'] = CCP4Widgets.CStringView(self,qualifiers=qualis) else: self.widgets['smiles'] = CCP4Widgets.CLabel(self,qualifiers=qualis) self.layout().addWidget(self.widgets['smiles'],1,4) ''' toolTip = self.model.qualifiers('toolTip') if toolTip is NotImplemented: toolTip = '' else: toolTip = toolTip for item in self.model.CONTENTS_ORDER: widget = self.widgets[item] tT = self.model.getDataObjects(item).qualifiers('toolTip') if tT is NotImplemented: tT = '' widget.setToolTip(toolTip+tT) if self.editable: self.connect(widget,QtCore.SIGNAL(widget.editSignal()),self.updateModelFromView) self.connect(widget,QtCore.SIGNAL('acceptDropData'),self.acceptDropData) ''' class CPdbEnsembleItemView(CCP4Widgets.CComplexLineWidget): MODEL_CLASS = CCP4ModelData.CPdbEnsembleItem def __init__(self,parent=None,model=None,qualifiers={}): qualis = {'vboxLayout':True,'iconButton':False} qualis.update(qualifiers) CCP4Widgets.CComplexLineWidget.__init__(self,parent,qualis) if model is not None: self.setModel(model) self.widgets = {} self.widgets['structure'] = CPdbDataFileView(self,qualifiers={'iconButton':True,'iconName':'PdbDataFile','ifAtomSelection' : True}) self.layout().addWidget(self.widgets['structure']) self.widgets['identity_to_target'] = CCP4Widgets.CFloatView(self) self.widgets['rms_to_target'] = CCP4Widgets.CFloatView(self) self.widgets['number'] = CCP4Widgets.CIntView(self, qualifiers = { 'editable' : self.editable, 'guiMode' : 'combo', 'enumerators' : [i for i in range(21)], 'menuText' : [str(i) for i in range(21)]}) self.widgets['number'].setMaximumWidth(60) line = QtGui.QHBoxLayout() line.addWidget(QtGui.QLabel('Copies:',self)) line.addWidget(self.widgets['number']) line.addWidget(QtGui.QLabel('Sequence identity:',self)) line.addWidget(self.widgets['identity_to_target']) line.addWidget(QtGui.QLabel('OR RMS difference:',self)) line.addWidget(self.widgets['rms_to_target']) self.layout().addLayout(line) def setModel(self, model): ensemble = None if model is not None and hasattr(model,'parent') and model.parent() is not None: ensemble = model.parent().parent() cEnsembleLabelView = self.parent().findChildren(CEnsembleLabelView)[0] if self.model is not None: for item in ['structure','identity_to_target','rms_to_target']: self.disconnect(self.model.get(item),QtCore.SIGNAL('dataChanged'),self.validate) if ensemble is not None: for item in ['number']: self.disconnect(ensemble.get(item),QtCore.SIGNAL('dataChanged'),self.numberChanged) if model is None or isinstance(model,self.MODEL_CLASS): from CCP4Widgets import CViewWidget CViewWidget.setModel(self,model) if model is not None: self.connect(model,QtCore.SIGNAL('dataChanged'),self.validate) toolTip = model.qualifiers('toolTip') if toolTip is not NotImplemented and toolTip is not None and self.iconButton is not None: self.iconButton.setToolTip(toolTip+'\n'+self.iconButton.toolTip()) for key,w in self.widgets.items(): if key in ['structure','identity_to_target','rms_to_target']: if isinstance(w,CViewWidget): w.setModel(model.get(key)) elif key in ['number']: if ensemble is not None: if isinstance(w,CViewWidget): w.setModel(ensemble.get(key)) else: for key,w in self.widgets.items(): if isinstance(w,CViewWidget): w.setModel(None) # Set allowUndefined True for the first CPdbEnsembleItem in the first CEnsemble where the CEnsembleList # is allowed zero length if model is not None and ensemble is not None: if isinstance(ensemble,CCP4ModelData.CEnsemble) and ensemble.qualifiers('allowUndefined'): if model.parent().index(model) == 0: model.setQualifier('allowUndefined',True) model.structure.setQualifier('allowUndefined',True) if model is not None and self.editable: for item in ['structure','identity_to_target','rms_to_target']: self.connect(model.get(item),QtCore.SIGNAL('dataChanged'),self.validate) for item in ['number']: if ensemble is not None: self.connect(ensemble.get(item),QtCore.SIGNAL('dataChanged'),self.numberChanged) if self.widgets['structure'].widgets.get('selection',None) is None: self.widgets['structure'].showAtomSelection() def updateViewFromModel(self): for key,widget in self.widgets.items(): widget.updateViewFromModel() #self.parent().findChildren(CEnsembleLabelView)[0].updateViewFromModel() def numberChanged(self, **kw): cEnsembleLabelView = self.parent().findChildren(CEnsembleLabelView)[0] self.parent().parent().updateViewFromModel(**kw) cEnsembleLabelView.validate() ''' def getMenuDef(self): return self.widgets['structure'].getMenuDef() def getActionDef(self,name): return self.widgets['structure'].getActionDef(name) def showAtomSelection(self): self.widgets['structure'].showAtomSelection() def viewContents(self): self.widgets['structure'].viewContents() ''' class CEnsembleView(CCP4Widgets.CComplexLineWidget): def __init__(self,parent=None,model=None,qualifiers={}): qualis = {'vboxLayout':True} qualis.update(qualifiers) CCP4Widgets.CComplexLineWidget.__init__(self,parent,qualis) if model is not None: self.setModel(model) self.widgets = {} line = QtGui.QHBoxLayout() iconWidgetItem = self.layout().takeAt(0) line.addWidget(iconWidgetItem.widget()) line.addWidget(QtGui.QLabel('Label for ensemble:',self)) self.widgets['label'] = CCP4Widgets.CStringView(self) line.addWidget(self.widgets['label']) self.layout().addLayout(line) self.widgets['pdbItemList'] = CCP4Widgets.CListView(self,model=self.model.pdbItemList,qualifiers={ 'editable' : self.editable, 'mode' : 'table', 'tableItems': ['structure','identity_to_target','rms_to_target'], 'columnHeaders':['Filename','Identity','RMS'] }) self.layout().addWidget(self.widgets['pdbItemList']) class CEnsembleLabelView(CCP4Widgets.CComplexLineWidget): MODEL_CLASS = CCP4ModelData.CEnsemble def __init__(self,parent=None,model=None,qualifiers={}): CCP4Widgets.CComplexLineWidget.__init__(self,parent,qualifiers=qualifiers) self.widgets['use'] = CCP4Widgets.CBooleanView(self, qualifiers = { 'editable' : self.editable } ) self.widgets['number'] = CCP4Widgets.CIntView(self, qualifiers = { 'editable' : self.editable, 'guiMode' : 'combo', 'enumerators' : [i for i in range(21)], 'menuText' : [str(i) for i in range(21)]}) self.widgets['number'].setMaximumWidth(60) self.widgets['label'] = CCP4Widgets.CStringView(self, qualifiers = { 'editable' : self.editable } ) self.layout().addWidget( self.widgets['use'] ) self.layout().addWidget(QtGui.QLabel('Find',self)) self.layout().addWidget( self.widgets['number'] ) self.layout().addWidget(QtGui.QLabel('of search ensemble called',self)) self.layout().addWidget( self.widgets['label'] ) self.setModel(model) def validate(self,isValid=None,reportMessage=True): # Just validate the number and label if isValid is None: if self.model is None: isValid = False else: v = self.model.number.validity(self.model.number.get()) v.extend(self.model.label.validity(self.model.label.get())) isValid = (v.maxSeverity()<=SEVERITY_WARNING) CCP4Widgets.CComplexLineWidget.validate(self,isValid=isValid,reportMessage=reportMessage) class CEnsembleListView(CCP4Widgets.CTreeView): MODEL_CLASS = CCP4ModelData.CEnsembleList def __init__(self,parent=None,model=None,qualifiers={}): displayRole = QtCore.Qt.DisplayRole qualis = { 'editors' : [ { 'modelClass' : CCP4ModelData.CEnsemble, 'name' : 'ensemble', 'label':'ensemble' } , { 'modelClass' : CCP4ModelData.CPdbEnsembleItem , 'name' : 'pdbEnsembleItem','label':'structure in ensemble' } ], 'columnHeaders':[ {displayRole:'Ensemble/Filename','width':240}, {displayRole:'Selection','width':240}, {displayRole:'Identity','width':50}, {displayRole:'RMS','width':50} ] } """ 'hierarchy' : [ {'name':'self','label':'ensemble','editorClass':CEnsembleLabelView, 'grey':True, 'list': [{'name':'pdbItemList','label':'structure in ensemble','editorClass':CPdbEnsembleItemView }] } ], """ print 'INTO CEnsembleListView',model qualis.update(qualifiers) super(CEnsembleListView,self).__init__(parent,model=model,qualifiers=qualis) class CPdbDataFileView(CCP4Widgets.CDataFileView): MODEL_CLASS = CCP4ModelData.CPdbDataFile def __init__(self,parent=None,model=None,qualifiers={}): self.ifAtomSelection = qualifiers.get('ifAtomSelection',False) qualis = { 'vboxLayout' : True } qualis.update(qualifiers) #print 'CPdbDataFileView parent',parent #CCP4Widgets.CDataFileView.__init__(self,parent=parent,model=model,qualifiers=qualis) super(CPdbDataFileView,self).__init__(parent=parent,model=model,qualifiers=qualis) #if self.ifAtomSelection: self.showAtomSelection() def getMenuDef(self): if self.editable: #menu = ['clear','view','annotate','sep','copy','paste','help'] menu = ['clear',['View','quick_view','view_text','view_CCP4mg','view_Coot'],'sep','copy','paste','help'] if self.ifAtomSelection: menu.insert(menu.index('sep'),'select') else: if self.role is not None and self.role == 'output': menu = [['View','quick_view','view_text','view_CCP4mg','view_Coot'],'sep','copy','editLabel','export','help'] else: menu = [['View','quick_view','view_text','view_CCP4mg','view_Coot'],'sep','copy','export','help'] if self._stacked: menu.insert(0,'handleStack') if self.ifInfo: menu.insert(menu.index('sep'),'annotate') return menu def getActionDef(self,name): if name == 'select': def iC(): try: return self.widgets['selection'].isVisible() except: return False return dict ( text = self.tr("Select atoms"), tip = self.tr('Select limited set of atoms'), slot = self.showAtomSelection, checkable = True, isChecked = iC ) elif name == 'quick_view': def e(): return (self.model is not None and self.model.exists()) return dict ( text = self.tr("Quick view"), tip = self.tr('Quick view of model data'), slot = self.viewContents, enabled = e ) else: return CCP4Widgets.CDataFileView.getActionDef(self,name) def openViewer(self,mode): import CCP4Modules if mode == 'view_text': CCP4Modules.WEBBROWSER().openFile(fileName=self.model.__str__(),toFront=True) else: CCP4Widgets.CDataFileView.openViewer(self,mode) def setModel(self,model=None): #print 'CPdbDataFileView.setModel',repr(model),self.widgets.has_key('selection') #if model is not None: print model.objectName() if self.model is not None and self.widgets.has_key('selection'): self.disconnect(self.model,QtCore.SIGNAL('dataChanged'),self.widgets['selection'].applySelection) super(CPdbDataFileView,self).setModel(model=model) if self.ifAtomSelection and model is not None: if 'selection' in self.widgets: self.widgets['selection'].setModel(model.selection) self.widgets['selection'].updateViewFromModel() elif model is not None and model.selection.isSet(): if 'selection' not in self.widgets: self.showAtomSelection() self.widgets['selection'].setModel(model.selection) self.widgets['selection'].updateViewFromModel() def getValue(self): val = CCP4Widgets.CDataFileView.getValue(self) if getattr(self,'selectionLine',None) is not None: val['selection'] = self.widgets['selection'].getValue() #print 'CPdbDataFileView.getValue',val return val def setValue(self,value): #print 'CPdbDataFileView.setValue',self.model.objectName(),value CCP4Widgets.CDataFileView.setValue(self,value) if value.get('selection',None) is not None: self.showAtomSelection() self.widgets['selection'].setValue(value.get('selection',{})) elif getattr(self,'selectionLine',None) is not None: self.widgets['selection'].clear() else: return self.widgets['selection'].applySelection() def showAtomSelection(self): #print 'CPdbDataFileView.showAtomSelection' if self.widgets.get('selection',None) is None: self.selectionLine = QtGui.QFrame(self) self.selectionLine.setLayout(QtGui.QHBoxLayout()) self.selectionLine.layout().setSpacing(0) self.selectionLine.layout().setContentsMargins(0,0,0,0) self.selectionLine.layout().addWidget(QtGui.QLabel('Atom selection')) selection = None if hasattr(self,'model') and self.model is not None: selection = self.model.selection self.widgets['selection'] = CAtomSelectionView(parent=self,model=selection, qualifiers= { 'editable' :self.editable} ) if hasattr(self,'model') and self.model is not None: self.connect(self.model,QtCore.SIGNAL('dataChanged'),self.widgets['selection'].applySelection) self.selectionLine.layout().addWidget(self.widgets['selection']) self.layout().addWidget(self.selectionLine) elif not self.widgets['selection'].isVisible(): self.selectionLine.show() else: self.selectionLine.hide() def viewContents(self): if not hasattr(self,'contentsViewer'): self.contentsViewer = CPdbContentsViewer(self) try: fileContent = self.model.fileContent except: pass self.connect(self.model.fileContent,QtCore.SIGNAL('dataChanged'),self.contentsViewer.load) self.contentsViewer.load() self.contentsViewer.show() def setFocus1(self,reason,index=None): #print 'CPdbDataFileView.setFocus1',index if index is None: CCP4Widgets.CDataFileView.setFocus(self,reason) elif index==1 and self.ifAtomSelection: self.showAtomSelection() self.selectionLine.setFocus(reason) else: self.jobCombo.setFocus(reason) def handleBrowserOpenFile(self,filename,downloadInfo,**kw): kw['validate'] = False kw['updateView'] = False CCP4Widgets.CDataFileView.handleBrowserOpenFile(self,filename,downloadInfo,**kw) err = self.model.importFile(jobId=self.parentTaskWidget().jobId(),jobNumber=self.parentTaskWidget().jobNumber()) if err is not None and len(err)>0: if err.maxSeverity()>SEVERITY_WARNING: message = 'File failed validation test' err.warningMessage(windowTitle='Importing coordinate file',parent=self,message=message) self.model.unSet() self.updateViewFromModel() self.validate() class CPdbContentsViewer(QtGui.QDialog): def __init__(self,parent): QtGui.QDialog.__init__(self,parent) self.setLayout(QtGui.QVBoxLayout()) self.textEdit = QtGui.QTextEdit(self) self.textEdit.setReadOnly(True) self.layout().addWidget(self.textEdit) butBox = QtGui.QDialogButtonBox(self) self.layout().addWidget(butBox) but = butBox.addButton(QtGui.QDialogButtonBox.Close) self.connect(but,QtCore.SIGNAL('released()'),self.close) def load(self): #print 'CPdbContentsViewer.load', self.parent().model.fileContent.composition.chains self.textEdit.setReadOnly(False) self.textEdit.clear() if self.parent().model.annotation.isSet(): self.setWindowTitle(self.parent().model.annotation.__str__()) else: self.setWindowTitle(self.parent().model.__str__()) text = '\nSpace group: ' + str(self.parent().model.fileContent.mmdbManager.GetSpaceGroup()) try: cell = self.parent().model.fileContent.mmdbManager.GetCell() text = text + '\nCell:' for ii in range(1,7): text = text + ' ' + str(cell[ii]) except: pass if len( self.parent().model.fileContent.composition.chains)>0: text = text + '\n\nChains in model:\n' comp = self.parent().model.fileContent.composition for i in range(len(comp.chains)): text = text + str(comp.chains[i])+ ' ' + comp.chainInfo[i][1].split('/')[3] + ' - ' + comp.chainInfo[i][2].split('/')[3] + \ ' ('+str(comp.chainInfo[i][0]) +' residues)\n' if len( self.parent().model.fileContent.composition.monomers)>0: text = text + '\n\nMonomers in model:\n'+self.parent().model.fileContent.composition.monomers[0] for mon in self.parent().model.fileContent.composition.monomers[1:]: text = text + ', ' + str(mon) self.textEdit.document().setPlainText(text) self.textEdit.setReadOnly(True) class CPdbDataFileListView(CCP4Widgets.CListView): MODEL_CLASS = CCP4ModelData.CPdbDataFileList def __init__(self,parent=None,model=None,qualifiers={}): #print 'CPdbDataFileListView' qualis = { 'mode' : 'table', 'tableItems' : ['fullPath','selection'] , 'columnHeaders':['Coordinate file','Selection'], } qualis.update(qualifiers) CCP4Widgets.CListView.__init__(self,parent,model=model,qualifiers=qualis) # Tis broke! self.editor.showAtomSelection() class CAtomSelectionView(CCP4Widgets.CComplexLineWidget): MODEL_CLASS = CCP4ModelData.CAtomSelection ERROR_CODES = { 101 : { 'description' : 'No CPdbDataFile when applying atom selection' }, 102 : { 'description' : 'Error applying atom selection' } } def __init__(self,parent=None,model=None,qualifiers={}): super(CAtomSelectionView,self).__init__(parent=parent,qualifiers=qualifiers) if self.editable: self.widgets['text'] = CCP4Widgets.CLineEdit(self) self.widgets['text'].setToolTip("Enter selection command e.g. 'A/ or B/11-21'") self.setFocusProxy(self.widgets['text']) else: self.widgets['text'] = CCP4Widgets.CLabel(self) self.layout().addWidget(self.widgets['text']) self.label = QtGui.QLabel(' ( 0 atoms)',self) self.layout().addWidget(self.label) self.help = QtGui.QPushButton('Help',self) self.help.setToolTip('Details of atom selection syntax') self.layout().addWidget(self.help) self.connect(self.widgets['text'],QtCore.SIGNAL('textEdited(const QString &)'),self.applySelection0) self.connect(self.help,QtCore.SIGNAL('released()'),self.showHelp) if self.parent().model is not None: self.connect(self.parent().model,QtCore.SIGNAL('dataLoaded'),self.applySelection) if model is not None: self.setModel(model) self.updateViewFromModel() def validate(self,isValid=None,reportMessage=True): pass def showHelp(self): import CCP4Modules CCP4Modules.WEBBROWSER().loadWebPage(helpFileName='general/atom_selection.html') def setValue(self,value={}): CCP4Widgets.CComplexLineWidget.setValue(self,value=value) try: self.applySelection() except: self.label.setText('No atoms') def updateViewFromModel(self): #print 'CAtomSelectionView.updateViewFromModel' #import traceback #traceback.print_stack(limit=10) self.widgets['text'].blockSignals(True) self.widgets['text'].setText(self.model.__str__()) self.widgets['text'].blockSignals(False) try: self.applySelection() except: self.label.setText('No atoms') def clear(self): CCP4Widgets.CComplexLineWidget.clear(self) self.widgets['text'].clear() self.label.setText('No atoms') def applySelection0(self,text=None): try: self.applySelection(text=text) except: pass else: self.connectUpdateViewFromModel(False) self.model.text.set(text) self.connectUpdateViewFromModel(True) def applySelection(self,text=None): #print 'CSelectionLine.applySelection',text if text is None: text = self.widgets['text'].text() if isinstance(self.model.parent(),CCP4ModelData.CPdbDataFile): pdbDataObj = self.model.parent() else: pdbDataObj = self.model.getDataByKey('pdbFileKey') #print 'CSelectionLine.applySelection',text,pdbDataObj if pdbDataObj is None: try: pdbDataObj = self.model.parent() except: self.label.setText('No atoms') raise CException(self.__class__,101,name=self.modelObjectPath()) try: # Call to loadFile removed from here - CPdbDataFile.updateData() unsets fileContent # so this accessing fileContent should cause a loadFile() if necessasy nSelAtoms,selHnd = pdbDataObj.fileContent.interpretSelection(str(text)) if selHnd is not None: pdbDataObj.fileContent.molHnd.DeleteSelection(selHnd) except Exception as e: #print 'CSelectionLine.applySelection loadFile fail\n',e self.label.setText('No atoms') raise CException(self.__class__,102,name=self.modelObjectPath()) self.label.setText(' ( '+str(nSelAtoms)+' atoms)') class CHomologListView(CCP4Widgets.CListView): MODEL_CLASS =CCP4ModelData.CHomologList def __init__(self,parent=None,model=None,qualifiers={}): qualis = { 'mode' : 'table', 'tableItems' : ['baseName','selection'], 'columnHeaders':['File','Selection'] } qualis.update(qualifiers) CCP4Widgets.CListView.__init__(self,parent,model=model,qualifiers=qualis) def connectDataChanged(self,mode=True): CCP4Widgets.CListView.connectDataChanged(self,mode) #print 'CHomologListView.connectDataChanged',self.editor.model,mode if self.editor.model is None: return if mode: self.connect(self.editor.model.selection,QtCore.SIGNAL('dataChanged'),self.updateListItem) else: self.disconnect(self.editor.model.selection,QtCore.SIGNAL('dataChanged'),self.updateListItem) class CDictDataDialog(QtGui.QDialog): def __init__(self,parent=None,model=None,projectId=None): import CCP4Modules if parent is None: parent = CCP4Modules.QTAPPLICATION() QtGui.QDialog. __init__(self,parent) self.setLayout(QtGui.QHBoxLayout()) self.setModal(False) if projectId is not None: pName = ' for '+CCP4Modules.PROJECTSMANAGER().db().getProjectInfo(projectId=projectId,mode='projectname') else: pName='' self.setWindowTitle('Manage project dictionary'+pName) self.frame = CDictDataView(self,model=model,projectId=projectId) self.layout().addWidget(self.frame) def closeEvent(self,event): import CCP4Utils,CCP4Modules #print 'CDictDataDialog.closeEvent',self.frame.showWidget if self.frame.showWidget is not None and CCP4Utils.isAlive(self.frame.showWidget): CCP4Modules.WEBBROWSER().tab().deleteTabWidget(widget=self.frame.showWidget) event.accept() class CDictDataView(CCP4Widgets.CViewWidget): def __init__(self,parent=None,model=None,projectId=None): CCP4Widgets.CViewWidget.__init__(self,parent=parent) self.showWidget = None if model is None: self.dictDataFile = CCP4ModelData.CDictDataFile() #self.dictDataFile.set(self.dictDataFile.defaultProjectDict(projectId=projectId)) self.dictDataFile.loadFile() self.model = self.dictDataFile.fileContent import CCP4ProjectViewer import os CCP4ProjectViewer.FILEWATCHER().addJobPath(os.path.split( os.path.split(str(self.dictDataFile))[0])[1],self.dictDataFile.__str__()) self.connect(CCP4ProjectViewer.FILEWATCHER(),QtCore.SIGNAL('fileChanged(const QString &)'),self.handleFileChanged) else: self.model = model self.dictDataFile = model.parent() #print 'CDictDataView',self.dictDataFile,self.model,self.model.monomerList QtGui.QFrame.__init__(self,parent) self.setLayout(QtGui.QHBoxLayout()) self.layout().setContentsMargins(1,1,1,1) self.layout().setSpacing(1) self.monomerListWidget = CDictDataList(self) self.layout().addWidget(self.monomerListWidget ) butLayout = QtGui.QVBoxLayout() for label,connect in [['Show',self.handleShow],['Import geometry file',self.handleMerge],['Delete',self.handleDelete]]: but = QtGui.QPushButton(label,self) self.connect(but,QtCore.SIGNAL('released()'),connect) butLayout.addWidget(but) self.layout().addLayout(butLayout) self.updateViewFromModel() self.connect(self.model,QtCore.SIGNAL('dataChanged'),self.updateViewFromModel) self.connect(self.monomerListWidget,QtCore.SIGNAL('itemDoubleClicked(QTreeWidgetItem *,int)'),self.handlDoubleClick) def handleFileChanged(self,path): #print 'CDictDataView.handleFileChanged',path if str(path) == str(self.dictDataFile): #print 'CDictDataView.handleFileChanged updating' self.dictDataFile.fileContent.loadFile(str(self.dictDataFile)) self.updateViewFromModel() def handlDoubleClick(self,item,col): #print 'CDictDataView.handlDoubleClick',item,col idd = item.data(0).toStrint().__str__() self.handleShow(idd) def updateViewFromModel(self): import CCP4Utils self.monomerListWidget.load(self.model.monomerList) if self.showWidget is not None and CCP4Utils.isAlive(self.showWidget): self.showWidget.reload() def updateModelFromView(self): # All updates should be handled by the edit methods pass def handleShow(self,idd=None): if idd is None: idd = self.monomerListWidget.currentSelection() import CCP4Modules,CCP4Utils #print 'CDictDataView.handleShow',idd,self.model,self.model.parent() if self.showWidget is not None: print 'alive?',CCP4Utils.isAlive(self.showWidget) if self.showWidget is None or (not CCP4Utils.isAlive(self.showWidget)): self.showWidget = CCP4Modules.WEBBROWSER().openFile(self.model.parent().__str__()) else: self.showWidget.browserWindow().show() self.showWidget.browserWindow().raise_() if idd is not None: self.showWidget.findText(subString='data_comp_'+idd) def handleMerge(self): import CCP4FileBrowser,CCP4Modules self.mergeFileBrowser = CCP4FileBrowser.CFileDialog(parent=self,title='Select geometry file to merge into project geometry file', defaultSuffix=CCP4Modules.MIMETYPESHANDLER().getMimeTypeInfo(name='application/refmac-dictionary',info='fileExtensions'), filters = ['Geometry file for refinement(*.cif)'], fileMode=QtGui.QFileDialog.ExistingFiles,saveButtonText='Merge these files') self.mergeFileBrowser.show() self.connect(self.mergeFileBrowser,QtCore.SIGNAL('selectFiles'),self.mergeFiles) def mergeFiles(self,selectedFiles): if hasattr(self,'mergeFileBrowser'): self.mergeFileBrowser.close() self.mergeFileBrowser.deleteLater() #print 'CDictDataFileView.mergeFiles',selectedFiles for fileName in selectedFiles: err = self.model.mergeFile(fileName=fileName,overwrite=True) #print 'CDictDataFileView.mergeFiles',err.report(),err.maxSeverity() if err.maxSeverity()>SEVERITY_WARNING: err.warningMessage(windowTitle='Error merging geometry files',parent=self,message='Error attempting to merge geometry files') return def handleDelete(self): idd = self.monomerListWidget.currentSelection() #print 'CDictDataView.handleDelete',idd if idd is None: return err = self.model.delete(idd) if err.maxSeverity()>SEVERITY_WARNING: err.warningMessage(windowTitle='Error deleting item in geometry file',parent=self,message='Error attempting to edit geometry file') return class CDictDataList(QtGui.QTreeWidget): def __init__(self,parent): QtGui.QTreeWidget.__init__(self,parent) self.setMinimumWidth(400) self.setColumnCount(3) self.setHeaderLabels(['Id','Code','Name']) self.setColumnWidth(0,80) self.setColumnWidth(1,80) self.setColumnWidth(2,200) self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) def load(self,monomerList): # monomerList is a Clist of CChemComp #print 'CDictDataList.load',monomerList self.clear() for monomer in monomerList: #print 'CDictDataList.load',monomer.get('id') qList = QtCore.QStringList() for item in ['id','three_letter_code','name']: qList.append(str(monomer.get(item))) item = QtGui.QTreeWidgetItem(qList) treeId=self.addTopLevelItem(item) def handleMonomerDeleted(self,id): #print 'CDictDataList.handleMonomerDeleted',id if self.model().rowCount()==0: return modInxList = self.model().match(id) if len(modInxList)==0: #print 'CDictDataList.handleMonomerDeleted no match to id',id pass else: self.model().removeRow(modInxList[0].row()) def handleMonomerAdded(self,id): pass def currentSelection(self): indices = self.selectionModel().selectedRows() if len(indices) == 0: return None idd = str(indices[0].data().toString()) return idd