""" CCP4DbApi.py: CCP4 GUI Project Copyright (C) 2012 STFC 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. """ # May 2012 Tools to handle import/export of files from PyQt4 import QtCore,QtGui import CCP4Widgets,CCP4File,CCP4Annotation,CCP4Data from CCP4ErrorHandling import * from CCP4Modules import PROJECTSMANAGER,TASKMANAGER,PREFERENCES from CCP4DataManager import DATAMANAGER import os class CExportedFileCombo(CCP4Widgets.CComplexLineWidget): MODEL_CLASS = CCP4File.CExportedFile def __init__(self,parent=None,model=None,qualifiers={}): CCP4Widgets.CComplexLineWidget.__init__(self,parent,qualifiers=qualifiers) self.widget = CCP4Widgets.CComboBox(self) self.widget.setEditable(False) self.layout().addWidget(self.widget) self.fileTypeClass = qualifiers.get('fileTypeClass',None) self.before = qualifiers.get('before',None) self.projectId = None self.setProjectId(qualifiers.get('projectId',None)) #print 'CExportedFileCombo',qualifiers self.setModel(model) self.updateViewFromModel() self.connect(self.widget,QtCore.SIGNAL('currentIndexChanged(int)'),self.updateModelFromView0) def setProjectId(self,projectId=None): self.projectId = projectId self.widget.clear() if self.projectId is not None: self.load() def setValue(self,value): #print 'CExportedFileCombo.setValue',value expId = value.get('exportId',None) if expId is None or expId < 0: self.widget.setCurrentIndex(0) else: indx = self.widget.findData(QtCore.QVariant(expId)) if indx>=0: self.widget.setCurrentIndex(indx) def load(self): exportedFiles = PROJECTSMANAGER().db().getExportFilesByFileType(fileTypeClass=self.fileTypeClass,before=self.before,projectId=self.projectId) self.widget.addItem('',QtCore.QVariant(-1)) for exFile in exportedFiles: title = TASKMANAGER().getTitle(exFile['taskname']) if len(exFile['exportfilename'])>22: self.widget.addItem('..'+exFile['exportfilename'][-20:]+' '+exFile['jobnumber']+' '+title,QtCore.QVariant(exFile['exportid'])) else: self.widget.addItem(exFile['exportfilename']+' '+exFile['jobnumber']+' '+title,QtCore.QVariant(exFile['exportid'])) def getValue(self): #print 'CExportedFileCombo.getValue',self.widget.currentIndex(),item,type(item) indx = CCP4Data.varToUUID( self.widget.itemData(self.widget.currentIndex()) ) return { 'exportId' : indx } def updateModelFromView0(self,indx): self.updateModelFromView() class CExportedFileListView(CCP4Widgets.CListView): MODEL_CLASS = CCP4File.CExportedFileList def __init__(self,parent,model=None,qualifiers={},**kw): qualis = { 'editorClassName' : 'CExportedFileCombo', 'dragType' : 'file_info' } qualis.update(qualifiers) qualis.update(kw) CCP4Widgets.CListView.__init__(self,parent,model=model,qualifiers=qualis,editorQualifiers={'before':qualis.get('before',None)}) class CImportInfo(QtGui.QFrame): def __init__(self,parent,model=None,importId=None,importFileName=None,label=None,sourceFileAnnotation=''): QtGui.QFrame.__init__(self,parent) self.setMinimumWidth(500) self.model = model self.importId = importId if importId is not None: importFileInfo = PROJECTSMANAGER().db().getImportFileInfo(importId=importId) before = importFileInfo.get('creationtime') if importFileInfo.get('annotation',None) is not None: sourceFileAnnotation = sourceFileAnnotation + importFileInfo['annotation'] sourceFileName = importFileInfo['sourcefilename'] else: before = None if importFileName is not None: sourceFileName = importFileName else: try: sourceFileName = model.getSourceFileName() except: sourceFileName = model.__str__() #print 'CImportInfo',importId,before,sourceFileName try: self.parent().setWindowTitle('Provenance of file: '+os.path.split(sourceFileName)[1]) except: pass self.setLayout(QtGui.QVBoxLayout()) if label is None: label = 'Provide info on the origin of the file: ' else: label = 'Provide info on the origin of '+label+' from the file:' self.layout().addWidget(QtGui.QLabel(label)) self.layout().addWidget(QtGui.QLabel(sourceFileName)) self.annotation = CCP4Annotation.CAnnotation(parent=self) self.annotation.text.set(sourceFileAnnotation) self.annotationView = DATAMANAGER().widget(model=self.annotation,parentWidget=self, qualifiers = { 'multiLine' : True, 'title' : 'Describe source of this file' } ) #print 'CImportInfo.__init__',self.annotationView,self.annotationView.model,repr(self.annotation),self.annotation self.annotationView.updateViewFromModel() self.annotationView.setMaximumHeight(150) self.layout().addWidget(self.annotationView) self.exportedFiles = CCP4File.CExportedFileList(parent=self) self.exportedFilesView = DATAMANAGER().widget(model=self.exportedFiles,parentWidget=self , qualifiers = { 'title' :'Select any previously exported files used to derive this file', 'before' : before } ) self.exportedFilesView.setMaximumHeight(150) self.layout().addWidget(self.exportedFilesView) def save(self): self.annotationView.updateModelFromView() #print 'CImportInfo.save',self.annotation.get('text').__str__() if self.importId is not None: if self.annotation.isSet(): anno = self.annotation.get('text').__str__() else: anno = '' PROJECTSMANAGER().db().updateImportFile(importId=self.importId,key='annotation',value=anno) else: anno = self.annotation.get('text').__str__() if len(anno)>0: self.model.__dict__['sourceFileAnnotation'] = anno class CImportInfoDialog(QtGui.QDialog): def __init__(self,parent,model=None,importId=None,importFileName=None,label=None,sourceFileAnnotation=''): # Expect input model to be set to a CDataFile if this is called for a freshly imported file # for a job that has not yet been run (so no files and importFiles yet saved to db) # Expect database importId and importFileName if eiting the import annotation after the # job has been run #print 'CImportInfoDialog',model,importFileName QtGui.QDialog.__init__(self,parent) self.setModal(True) self.setLayout(QtGui.QVBoxLayout()) self.showAutoWidget = QtGui.QCheckBox('Show this window automatically when importing a file (can be changed via Preferences)',self) self.connect(self.showAutoWidget,QtCore.SIGNAL('toggled(bool)'),self.handleShowAuto) self.layout().addWidget(self.showAutoWidget) #self.layout().addWidget(QtGui.QLabel('This window accessible from the file icon menu',self)) if PREFERENCES().AUTO_INFO_ON_FILE_IMPORT: self.showAutoWidget.setCheckState(QtCore.Qt.Checked) else: self.showAutoWidget.setCheckState(QtCore.Qt.Unchecked) self.infoWidget = CImportInfo(self,model=model,importId=importId,importFileName=importFileName,label=label, sourceFileAnnotation=sourceFileAnnotation) self.layout().addWidget(self.infoWidget) butBox = QtGui.QDialogButtonBox(self) self.layout().addWidget(butBox) but = butBox.addButton(QtGui.QDialogButtonBox.Ok) but.setAutoDefault(0) self.connect(but,QtCore.SIGNAL('released()'),self.saveInfo) but = butBox.addButton(QtGui.QDialogButtonBox.Cancel) but.setAutoDefault(0) self.connect(but,QtCore.SIGNAL('released()'),self.close) def setProjectId(self,projectId): self.infoWidget.exportedFilesView.editor.setProjectId(projectId) def saveInfo(self): self.infoWidget.save() self.close() def handleShowAuto(self,auto): #print 'CImportInfoDialog.handleShowAuto',auto PREFERENCES().AUTO_INFO_ON_FILE_IMPORT = auto PREFERENCES().save() class CManageImportFiles(QtGui.QDialog): def __init__(self,parent,projectId): QtGui.QDialog.__init__(self,parent) self.setModal(False) self.projectId = projectId self.setLayout(QtGui.QHBoxLayout()) self.fileList = CImportFileList(self) self.layout().addWidget(self.fileList ) self.fileList.load(self.projectId) butLayout = QtGui.QVBoxLayout() for label,connect in [['Edit info',self.editInfo],['Delete',self.deleteFile]]: but = QtGui.QPushButton(label,self) self.connect(but,QtCore.SIGNAL('released()'),connect) butLayout.addWidget(but) self.layout().addLayout(butLayout) self.importInfoGui = None self.deleteFilesGui = None self.connect(PROJECTSMANAGER().db(),QtCore.SIGNAL('jobDeleted'),self.fileList.handleJobDeleted) def editInfo(self): rv = self.fileList.currentSelection() if rv is None: return importId,fileId,jobId,fileName = rv if self.importInfoGui is not None: self.importInfoGui.hide() self.importInfoGui.deleteLater() self.importInfoGui = CImportInfoDialog(self,importFileName=fileName,importId=importId) self.importInfoGui.show() def deleteFile(self): rv = self.fileList.currentSelection() if rv is None: return importId,fileId,jobId,fileName = rv #followOnJobs = PROJECTSMANAGER().db().getFollowOnJobs(jobId=jobId) jobTree = PROJECTSMANAGER().db().getFollowOnJobs(jobId=jobId) delJobId,importFiles,followOnJobs = jobTree import CCP4ProjectViewer self.deleteJobGui = CCP4ProjectViewer.CDeleteJobGui(self,projectId=self.projectId,jobIdList=[jobId],jobTreeList=[jobTree], label='Delete jobs that use imported file:'+fileName,deleteImportFiles=True) self.deleteJobGui.show() class CImportFileList(QtGui.QTreeWidget): def __init__(self,parent): QtGui.QTreeWidget.__init__(self,parent) self.setColumnCount(5) self.setHeaderLabels(['Source file','Saved as','Date','Job number','Task name']) self.setColumnWidth(0,200) self.setColumnWidth(1,200) self.setColumnWidth(2,60) self.setColumnWidth(3,60) self.setColumnWidth(4,200) self.setMinimumWidth(460) self.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows) self.setSelectionMode(QtGui.QAbstractItemView.SingleSelection) self.projectId = None self.connect(PROJECTSMANAGER().db(),QtCore.SIGNAL('importFileDeleted'),self.handleImportFileDeleted) def load(self,projectId): # This returns list of: ImportId,JobId,FileID,FileTypeId,Filename,Annotation, JobNumber TaskName SourceFileName CreateTime # 0 1 2 3 4 5 6 7 8 9 self.projectId = projectId self.clear() fileInfoList = PROJECTSMANAGER().db().getProjectImportFiles(projectId=projectId,ifJobInfo=True) for fileInfo in fileInfoList: taskTitle = TASKMANAGER().getTitle(fileInfo[7]) qList = QtCore.QStringList() for item in [fileInfo[8],fileInfo[4],fileInfo[9],fileInfo[6],taskTitle]: qList.append(str(item)) item = QtGui.QTreeWidgetItem(qList) item.setData(0,QtCore.Qt.UserRole,QtCore.QVariant(fileInfo[0])) item.setData(1,QtCore.Qt.UserRole,QtCore.QVariant(fileInfo[1])) item.setData(2,QtCore.Qt.UserRole,QtCore.QVariant(fileInfo[2])) treeId=self.addTopLevelItem(item) def handleImportFileDeleted(self,args): #print 'CImportFileList.handleImportFileDeleted',args if self.model().rowCount()==0: return modInxList = self.model().match(self.model().index(0,0),QtCore.Qt.UserRole,QtCore.QVariant(args['importId']),1) if len(modInxList)==0: print 'CImportFileList.handleImportFileDeleted no match to importId',args else: self.model().removeRow(modInxList[0].row()) def handleJobDeleted(self,args): #print 'CImportFileList.handleJobDeleted',args if args['projectId'] == self.projectId: self.load(self.projectId) def currentSelection(self): indices = self.selectionModel().selectedRows() #print 'CImportFileList.currentSelection',indices,len(indices) if len(indices) == 0: return None #print 'CImportFileList.currentSelection row',indices[0].row() importId = CCP4Data.varToUUID(indices[0].data(QtCore.Qt.UserRole)) jobId = CCP4Data.varToUUID(indices[0].sibling(indices[0].row(),1).data(QtCore.Qt.UserRole)) fileId = CCP4Data.varToUUID(indices[0].sibling(indices[0].row(),2).data(QtCore.Qt.UserRole)) fileName = indices[0].data().toString().__str__() #print 'CImportFileList.currentSelection', fileId,ok return importId,fileId,jobId,fileName