""" CCP4ProjectWidget.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. """ """ Liz Potterton Feb 2010 - Copied from earlier review.py used for Developers meeting demo """ ##@package CCP4ProjectWidget (QtGui) The demo project view widget from PyQt4 import QtGui,QtCore from core.CCP4Modules import WEBBROWSER FONT_SIZE = 14 STATUS_TEXT = { -1: 'unknown', 0 :'queued',1:'running',2:'cancelled',3:'finished',4:'forwarded' ,5:'terminated'} STATUS_FINISHED = [3,4,5] STAGES_TITLES = { 'DP' : 'Data processing','DR' : 'Data reduction','PP' : 'Phasing preparation','PH' : 'Phasing','PR' : 'Phase refinement', 'BB' : 'Building','RF' : 'Refinement'} STAGES_CODE_LIST = ['DP' , 'DR' , 'PP', 'PH', 'PR', 'BB', 'RF' ] COLUMN_ORDER = ['parent_id','label','priority','estimated_time','confidence','status','action'] COLUMN_TITLES = { 'id' : 'ID', 'parent_id': 'Parent', 'label' : 'Description', 'estimated_time' : 'Time', 'estimated_confidence' : 'Confidence', 'priority' : 'Priority', 'confidence' : 'Quality', 'status' : 'Status', 'action' : 'Action' } #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ class CProjectWidgetDemo(QtGui.QFrame): #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ MARGIN = 1 def __init__(self,parent=None): QtGui.QFrame.__init__(self) layout = QtGui.QVBoxLayout() layout.setMargin(CProjectWidgetDemo.MARGIN) layout.setContentsMargins(CProjectWidgetDemo.MARGIN,CProjectWidgetDemo.MARGIN, CProjectWidgetDemo.MARGIN,CProjectWidgetDemo.MARGIN) layout.setSizeConstraint(QtGui.QLayout.SetMinAndMaxSize) top_line_layout = QtGui.QHBoxLayout() l = QtGui.QLabel('Show jobs for',self) l.font().setPointSize(FONT_SIZE) top_line_layout.addWidget(l) self.stage_selector = QtGui.QComboBox(self) for item in STAGES_CODE_LIST: self.stage_selector.addItem(STAGES_TITLES[item]) top_line_layout.addWidget(self.stage_selector) ''' l = QtGui.QLabel('following from job') l.font().setPointSize(FONT_SIZE) top_line_layout.addWidget(l) self.parent_selector = QtGui.QLineEdit(self) self.parent_selector.setMaximumWidth(40) top_line_layout.addWidget(self.parent_selector) self.show_low_scoring = QtGui.QCheckBox('Show low scoring',self) top_line_layout.addWidget(self.show_low_scoring) self.show_low_scoring.setChecked(1) ''' top_line_layout.addStretch(5) layout.addLayout(top_line_layout) self.tableFrame = QtGui.QFrame(self) tlayout = QtGui.QVBoxLayout() tlayout.setMargin(CProjectWidgetDemo.MARGIN) tlayout.setContentsMargins(CProjectWidgetDemo.MARGIN,CProjectWidgetDemo.MARGIN, CProjectWidgetDemo.MARGIN,CProjectWidgetDemo.MARGIN) self.tableFrame.setLayout(tlayout) layout.addWidget(self.tableFrame) self.setLayout(layout) self.jobsModel = JobTableModel() self.table = None #------------------------------------------------------------------------------------------------------ def setProjectData(self,filename): #------------------------------------------------------------------------------------------------------ global_data = {} local_data = {} execfile(filename,global_data,local_data) self.DUMMYDATA = {} for key,value in local_data.get('DUMMYDATA',{}).items(): self.DUMMYDATA[key] = value # 'CProjectWidgetDemo.setProjectData',self.DUMMYDATA self.loadDummy(0) self.setTable() self.connect(self.stage_selector,QtCore.SIGNAL('currentIndexChanged(int)'),self.handleStageSelector) #self.parent_selector.setText(str(13)) #self.connect(self.show_low_scoring,QtCore.SIGNAL('stateChanged(int)'),self.handleLowScoring) self.connect(self.jobsModel,QtCore.SIGNAL('priorityChanged'),self.handlePriorityChange) #------------------------------------------------------------------------------------------------------ def setTable(self): #------------------------------------------------------------------------------------------------------ if self.table: self.tableFrame.layout().removeWidget(self.table) #self.layout().removeWidget(self.table) self.table.close() self.table = None self.table = QtGui.QTableView(self) #self.table.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.table.setModel(self.jobsModel) delegate = JobDelegate(self) self.table.setItemDelegate(delegate) self.connect(delegate,QtCore.SIGNAL('buttonClicked'),self.handleShow) self.setPersistentEditors() self.table.resizeColumnsToContents() self.tableFrame.layout().addWidget(self.table) #self.layout().addWidget(self.table) self.table.show() #print 'CProjectReview.setTable',self.table.size().width(),self.table.size().height() #self.table.setEditTriggers(self.table.AllEditTriggers) #self.tableFrame.show() #self.show() #------------------------------------------------------------------------------------------------------ def tableSize(self): #------------------------------------------------------------------------------------------------------ width = self.table.verticalHeader().width() height = self.table.horizontalHeader().height() for ic in range(0,self.jobsModel.columnCount()): width = width + self.table.columnWidth(ic) for ir in range(0,self.jobsModel.rowCount()): height = height + self.table.rowHeight(ir) print 'CProjectWidgetDemo.tableSize',width,height return width,height #------------------------------------------------------------------------------------------------------ def Size(self): #------------------------------------------------------------------------------------------------------ width,height = self.tableSize() width = width + 4*CProjectWidgetDemo.MARGIN height = height + 8*CProjectWidgetDemo.MARGIN + self.stage_selector.height() return width,height #------------------------------------------------------------------------------------------------------ def setPersistentEditors(self): #------------------------------------------------------------------------------------------------------ for mode in ['priority','action']: column = COLUMN_ORDER.index(mode) for row in range(self.jobsModel.rowCount()): self.table.openPersistentEditor(self.jobsModel.index(row,column)) #------------------------------------------------------------------------------------------------------ def runDemo(self,id): #------------------------------------------------------------------------------------------------------ if id != 104: return self.loadDummy(1) import functools QtCore.QTimer.singleShot(1000, functools.partial(self.loadDummy,2)) QtCore.QTimer.singleShot(3000, functools.partial(self.loadDummy,3)) QtCore.QTimer.singleShot(8000, functools.partial(self.loadDummy,4)) #------------------------------------------------------------------------------------------------------ def loadDummy(self,step=0): #------------------------------------------------------------------------------------------------------ #print 'loadDummy',step self.jobsModel.loadJobs(self.DUMMYDATA.get(step)) self.jobsModel.setVisibleJobs() if self.table: self.table.reset() #------------------------------------------------------------------------------------------------------ def handleStageSelector(self,istage): #------------------------------------------------------------------------------------------------------ self.jobsModel.setVisibleJobs(stage=STAGES_CODE_LIST[istage]) self.setTable() #------------------------------------------------------------------------------------------------------ def handleLowScoring(self,low): #------------------------------------------------------------------------------------------------------ #print 'handleLowScoring',low self.jobsModel.setVisibleJobs(filter_low_scoring=1-int(self.show_low_scoring.isChecked())) self.setTable() #------------------------------------------------------------------------------------------------------ def handlePriorityChange(self,args): #------------------------------------------------------------------------------------------------------ #print 'handlePriorityChange',args id,priority = args if priority>=0.99: self.runDemo(id) #------------------------------------------------------------------------------------------------------ def handleShow(self,index): #------------------------------------------------------------------------------------------------------ idx = self.jobsModel.getIdFromIndex(index) #print 'CProjectReview.handleShow',idx if idx == 104: #self.openCCP4i('XVNTGE') from core.CCP4Utils import getCCP4I2Dir import os filename=os.path.join(getCCP4I2Dir(),'test','data','test_job_104.data.xml') from core.CCP4TaskManager import TASKMANAGER TASKMANAGER().openDataFile(fileName=filename,editableData=False) elif idx == 401: self.openMG('/Users/lizp/I2/demo/dUTPase.pdb') #------------------------------------------------------------------------------------------------------ def openCCP4i(self,task): #------------------------------------------------------------------------------------------------------ process = QtCore.QProcess(self) rv = process.start('ccp4i -t '+task) #rv = process.start('ccp4i -t fft') #------------------------------------------------------------------------------------------------------ def openMG(self,pdbfile): #------------------------------------------------------------------------------------------------------ process = QtCore.QProcess(self) process.start('/Users/lizp/Desktop/dev/ccp4mg/bin/ccp4mg -nore '+pdbfile) #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ class Job: #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ def __init__(self,defn): #print 'Job defn',defn self.id = defn[0] self.parent_id = defn[3] self.stage = defn[1] self.template = defn[2] self.label = defn[4] self.estimated_time = defn[5] self.estimated_confidence = defn[6] self.priority = defn[7] self.confidence = defn[8] self.status = defn[9] #------------------------------------------------------------------------------------------------------ def setValue(self,name,value): #------------------------------------------------------------------------------------------------------ setattr(self,name,value) #------------------------------------------------------------------------------------------------------ def __cmp__(self,other): #------------------------------------------------------------------------------------------------------ if self.id > other.id: return 1 elif self.id > other.id: return -1 else: return 0 #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ class JobTableModel(QtCore.QAbstractTableModel): #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ def __init__(self): QtCore.QAbstractTableModel.__init__(self) self.jobs = {} self.stage = 'PH' self.parent_id = 0 self.filter_low_scoring =0 self.visibleJobs = [] #------------------------------------------------------------------------------------------------------ def setVisibleJobs(self,stage='',parent_id=-1, filter_low_scoring=-1): #------------------------------------------------------------------------------------------------------ if stage: self.stage = stage if parent_id>=0: self.parent_id = parent_id if filter_low_scoring>=0: self.filter_low_scoring = filter_low_scoring self.visibleJobs = [] for id,job in self.jobs.items(): if job.stage == self.stage: if (not self.filter_low_scoring) or (STATUS_FINISHED.count(job.status) and job.confidence>0.3) or (STATUS_FINISHED.count(job.status)<=0 and job.estimated_confidence>0.3): self.visibleJobs.append(id) #print 'setVisibleJobs',self.visibleJobs #------------------------------------------------------------------------------------------------------ def rowCount(self,index=QtCore.QModelIndex()): #------------------------------------------------------------------------------------------------------ #print 'rowCount',len(self.visibleJobs) return len(self.visibleJobs) #------------------------------------------------------------------------------------------------------ def columnCount(self,index=QtCore.QModelIndex()): #------------------------------------------------------------------------------------------------------ return len(COLUMN_ORDER) #------------------------------------------------------------------------------------------------------ def data(self, index, role = QtCore.Qt.DisplayRole): #------------------------------------------------------------------------------------------------------ if not index.isValid() or not ( 0 <= index.row() < self.rowCount() ): return QtCore.QVariant() job = self.jobs [ self.visibleJobs[index.row()]] name = COLUMN_ORDER[index.column()] if role == QtCore.Qt.DisplayRole: if ['id','parent_id','estimated_time'].count(name): if name == 'estimated_time' and STATUS_FINISHED.count(job.status): return QtCore.QVariant() else: return QtCore.QVariant(str(getattr(job,name,0))) elif ['estimated_confidence','priority','confidence'].count(name): if name == 'confidence' and not STATUS_FINISHED.count(job.status): value = getattr(job,'estimated_confidence',-1.0) else: value = getattr(job,name,-1.0) if value<0.0: return QtCore.QVariant(' ') elif ['estimated_confidence','priority'].count(name) and STATUS_FINISHED.count(job.status): return QtCore.QVariant() else: return QtCore.QVariant("%4.1f"%value) elif name == 'status': return QtCore.QVariant(STATUS_TEXT[getattr(job,name,-1)]) else: return QtCore.QVariant(getattr(job,name,' ')) elif role == QtCore.Qt.BackgroundColorRole: if job.status == 1: return QtCore.QVariant(QtGui.QColor('navajowhite')) elif STATUS_FINISHED.count(job.status): return QtCore.QVariant(QtGui.QColor('paleturquoise')) elif ['confidence','estimated_time'].count(name) and not STATUS_FINISHED.count(job.status): return QtCore.QVariant(QtGui.QColor('lightgrey')) else: return QtCore.QVariant(QtGui.QColor('white')) return QtCore.QVariant() #------------------------------------------------------------------------------------------------------ def setData(self, index, value, role=QtCore.Qt.EditRole): #------------------------------------------------------------------------------------------------------ id = self.getIdFromIndex(index) if id<0: return job = self.jobs [ id ] #print 'JobTableModel.setData',job.id,value, value.toDouble() if COLUMN_ORDER[index.column()] == 'priority': job.priority = value.toDouble()[0] self.emit(QtCore.SIGNAL('priorityChanged'),(job.id,job.priority)) #------------------------------------------------------------------------------------------------------ def getData(self,index,name): #------------------------------------------------------------------------------------------------------ job = self.jobs [ self.visibleJobs[index.row()]] return getattr(job,name,0.0) #------------------------------------------------------------------------------------------------------ def getIdFromIndex(self,index): #------------------------------------------------------------------------------------------------------ if index.isValid() and 0 <= index.row() < len(self.visibleJobs): id = self.visibleJobs[index.row()] return id else: return -1 #------------------------------------------------------------------------------------------------------ def getIdData(self,id,name): #------------------------------------------------------------------------------------------------------ if self.jobs.has_key(id): return getattr(self.jobs[id],name,0.0) else: return 0.0 #------------------------------------------------------------------------------------------------------ def headerData(self,section, orientation, role = QtCore.Qt.DisplayRole): #------------------------------------------------------------------------------------------------------ if role == QtCore.Qt.DisplayRole: if orientation == QtCore.Qt.Horizontal: return QtCore.QVariant(COLUMN_TITLES[COLUMN_ORDER[section]]) else: if 0 <= section < len(self.visibleJobs): job = self.jobs [ self.visibleJobs[section]] return QtCore.QVariant(str(getattr(job,'id',0))) else: pass #print 'headerData section',section return QtCore.QVariant() #------------------------------------------------------------------------------------------------------ def loadJobs(self,datalist=[]): #------------------------------------------------------------------------------------------------------ for item in datalist: self.jobs[item[0]] = Job(item) print 'Loaded',len(self.jobs),'jobs' #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ class JobDelegate(QtGui.QItemDelegate): #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ #------------------------------------------------------------------------------------------------------ def __init__(self,parent=None): super(JobDelegate, self).__init__(parent) #------------------------------------------------------------------------------------------------------ def createEditor(self,parent, option, index): #------------------------------------------------------------------------------------------------------ #print 'JobDelegate.createEditor',parent, option, index,index.column() import functools if index.column() == COLUMN_ORDER.index('priority'): spinbox = QtGui.QDoubleSpinBox(parent) spinbox.setRange(0.0,1.0) spinbox.setSingleStep(0.1) spinbox.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignVCenter) return spinbox if index.column() == COLUMN_ORDER.index('action'): button = QtGui.QPushButton('Show',parent) self.connect(button,QtCore.SIGNAL('clicked()'),functools.partial(self.handleButtonClick,index)) id = index.row() return button else: return QtGui.QItemDelegate.createEditor(self,parent, option, index) #------------------------------------------------------------------------------------------------------ def setEditorData ( self, editor, index) : #------------------------------------------------------------------------------------------------------ if index.column() == COLUMN_ORDER.index('priority'): editor.setValue(index.model().getData(index,'priority')) else: QtGui.QItemDelegate.setEditorData( self, editor, index) #------------------------------------------------------------------------------------------------------ def setModelData(self,editor,model,index): #------------------------------------------------------------------------------------------------------ #print 'setModelData',editor,model,index if index.column() == COLUMN_ORDER.index('priority'): model.setData(index,QtCore.QVariant(editor.value())) #------------------------------------------------------------------------------------------------------ def handleButtonClick(self,index): #------------------------------------------------------------------------------------------------------ #print 'JobDelegate.handleButtonClick',index self.emit(QtCore.SIGNAL('buttonClicked'),index) #=========================================================================== if __name__ == "__main__": from core.CCP4Modules import QTAPPLICATION app = QTAPPLICATION() window = QtGui.QDialog() window.setWindowTitle('CCP4 Project: Coseners') #print 'font' , window.font().setPointSize(FONT_SIZE) layout = QtGui.QVBoxLayout() widget = CProjectReview() layout.addWidget(widget) window.setLayout(layout) window.show() widget.stage_selector.setCurrentIndex(3) sys.exit(app.exec_())