""" CCP4TaskWidget.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 Jan 2010 - Create CCP4TaskWidget prototype """ ##@package CCP4TaskWidget (QtGui) Widget to view CCP4 tasks from PyQt4 import QtGui,QtCore import CCP4Widgets from CCP4Modules import * from CCP4ErrorHandling import * from CCP4DataManager import DATAMANAGER from CCP4Config import DEVELOPER import functools,time MARGIN = 1 WIDTH = 600 PADDING_ALLOWANCE = 0 LINEHEIGHT = 20 USER_NOVICE = 0 USER_REGULAR = 1 USER_EXPERT = 2 def whatNext(self,jobId=None,childJobs=[],childTaskName=None): return [] class CFolderAttributes: def __init__(self): self.atts = { 'all' : { 'editable' : True } } #print 'CFolderAttributes.__init__' def setAttribute(self,attribute='editable',folderFunction='all',value=None): if not attribute in ['editable'] or folderFunction is None or value is None: print 'Invalid input to CFolderAttributes.setAttribute',attribute,folderFunction,value return if not self.atts.has_key(folderFunction): self.atts[folderFunction] = {} self.atts[folderFunction][attribute] = value #print 'CFolderAttributes.setAttribute',self.atts def attribute(self,attribute='editable',folderFunction='all'): if not self.atts.has_key(folderFunction): folderFunction = 'all' if self.atts[folderFunction].has_key(attribute): #print 'CFolderAttributes.attribute',attribute,folderFunction,self.atts[folderFunction][attribute] return self.atts[folderFunction][attribute] else: return NotImplemented def allAttributes(self,folderFunction='all'): if not self.atts.has_key(folderFunction): return self.atts['all'] else: atts = {} atts.update(self.atts['all']) atts.update(self.atts[folderFunction]) return atts class CTaskWidgetDrawMethods: ERROR_CODES = { 100 : { 'description' : 'No definition found for data name' }, 101 : { 'description' : 'Parameter name not recognised in setMenuText' }, 102 : { 'description' : 'Wrong number of menu text items in setMenuText' }, 103 : { 'description' : 'Reference to unknown enumerator value(s) in setMenuText' }, 104 : { 'description' : 'Parameter name not recognised in setTooltip' }, 105 : { 'description' : 'Parameter name not recognised in setLabel' } } STACK_LAYOUT = True def __init__(self): self.toggleList = [] self.subFrame = None self.stack = None self.tabWidget = None self.currentFolder = None self.currentFolderLayout = None self.jobTitleWidget = None self.ignoreInput = False def openTabFrame(self,title=None,toolTip=None): if self.tabWidget is None: self.tabWidget = QtGui.QTabWidget(self) self.currentFolderLayout.addWidget( self.tabWidget) else: self.tabWidget.widget(self.tabWidget.count()-1).layout().addStretch(2) frame = QtGui.QFrame() frame.setLayout(QtGui.QVBoxLayout()) frame.layout().setSpacing(MARGIN) frame.layout().setContentsMargins(MARGIN,MARGIN,MARGIN,MARGIN) self.tabWidget.addTab(frame,title) if toolTip is not None: self.tabWidget.setTabToolTip(self.tabWidget.count()-1,toolTip) else: #Worth setting title astool tip so it is readable if title display is trucated self.tabWidget.setTabToolTip(self.tabWidget.count()-1,title) def closeTabFrame(self): self.tabWidget.widget(self.tabWidget.count()-1).layout().addStretch(2) self.tabWidget = None def openSubFrame(self,toggle=[],toggleFunction=[],frame=False,title=None): if self.ignoreInput: return self.closeSubFrame() if self.currentFolder is None: print 'ERROR in openSubFrame: there is not current open folder' return [1,'ERROR in openSubFrame: there is not current open folder'] self.subFrame = CSubFrame(self) self.subFrame.setObjectName ( 'tasksubframe' ) self.currentFolderLayout.addWidget( self.subFrame) layout = QtGui.QVBoxLayout() layout.setSpacing(MARGIN) layout.setContentsMargins(MARGIN,MARGIN,MARGIN,MARGIN) self.subFrame.setLayout(layout) self.noChildFrame = False #print 'openSubFrame args',self.subFrame,arg if len(toggle)==2: self.setToggle(target=self.subFrame,parameter=toggle[0],state=toggle[1]) #print 'setToggle',target elif len(toggle)==3: self.setToggle(target=self.subFrame,parameter=toggle[0],state=toggle[1],values=toggle[2]) elif len(toggleFunction)==2: self.setToggleFunction(target=self.subFrame,toggleFunction=toggleFunction[0],parameterList=toggleFunction[1]) if frame: self.subFrame.setFrameShape(QtGui.QFrame.StyledPanel) self.noChildFrame = True if title is not None: self.createLine(['advice',title]) return self.subFrame def closeSubFrame(self): if self.ignoreInput: return if self.subFrame is not None and self.noChildFrame: children = self.subFrame.findChildren(CCP4Widgets.CComplexLineWidget) for child in children: child.setFrameShape(QtGui.QFrame.NoFrame) self.subFrame.layout().update() self.subFrame = None def openStack(self,controlVar=None): if self.ignoreInput: return if self.stack is not None: self.closeStack() if self.STACK_LAYOUT: self.stack = CStackedLayout(self,controlVar) else: self.stack = CStackedWidget(self,controlVar) return self.stack def closeStack(self): if self.ignoreInput: return if self.stack is not None: #print 'closeStack',self.stack,self.currentFolderLayout if self.STACK_LAYOUT: if self.subFrame is not None: self.subFrame.layout().addLayout(self.stack) else: self.currentFolderLayout.addLayout(self.stack) else: if self.subFrame is not None: self.subFrame.layout().addWidget(self.stack) else: self.currentFolderLayout.addWidget(self.stack) #self.stack.update() self.stack = None def createTitleLine(self,name='TITLE'): if self.ignoreInput: return self.createLine( [ 'label', 'Comment', 'widget', name ]) def createLine(self,definition=[],appendLine=None,toggle=[],toggleFunction=[]): if self.ignoreInput: return container = self.parentTaskWidget()._container line = CTaskLine(self) if len(definition)>0: #if self.parentTaskWidget().layoutMode == 'TAB': # rv = line.draw(definition=definition,dataContainer=container,setupFolder=self.currentFolder.setupUpdateFolder,attributes=self.currentFolder._attributes) #else: rv = line.draw(definition=definition,dataContainer=container,attributes=self.currentFolder._attributes) self.myException.extend(rv,stack=False) else: rv = [] if len(rv)>0: line.deleteLater() else: if appendLine is not None: appendLine.addWidget(line) elif self.stack is not None: self.stack.addWidget(line) elif self.subFrame is not None: self.subFrame.layout().addWidget(line) elif self.tabWidget is not None: self.tabWidget.widget(self.tabWidget.count()-1).layout().addWidget(line) else: self.currentFolderLayout.addWidget(line) #print 'CTaskWidgetDrawMethods.createLine toggle',self.subFrame, definition if len(toggle)>0: if len(toggle)==2: self.setToggle(line,toggle[0],toggle[1],[True]) else: self.setToggle(line,toggle[0],toggle[1],toggle[2]) if len(toggleFunction)>0: self.setToggleFunction(line,toggleFunction[0],toggleFunction[1]) return line def applyToggles(self): if self.ignoreInput: return for toggle in self.toggleList: if not toggle.connected: toggle.handleSignal() toggle.makeConnection() childStacks = self.findChildren(CStackedLayout) for stack in childStacks: stack.update() def setToggle(self,target=None,parameter=None,state='open',values =[]): if self.ignoreInput: return #print 'setToggle',target if target is None or parameter is None or len(values)==0: return self.toggleList.append(CToggle(self,target,parameter,state,values)) def setToggleFunction(self,target=None,toggleFunction=None,parameterList=[]): if self.ignoreInput: return if target is None or toggleFunction is None or len(parameterList)==0: return self.toggleList.append(CToggle(self,target,parameterList=parameterList,toggleFunction=toggleFunction)) def createRadioGroup(self,label=None,itemList=[],objectName=None): if self.ignoreInput: return if objectName is not None: varObj = self.parentTaskWidget()._container.getObject(objectName) itemList = varObj.qualifiers('enumerators') else: varObj = None line = QtGui.QFrame(self) line.setLayout(QtGui.QHBoxLayout()) if label is not None: line.layout().addWidget(QtGui.QLabel(label,self)) group = QtGui.QButtonGroup(self) idx = -1 for item in itemList: idx = idx + 1 button = QtGui.QRadioButton(item,self) group.addButton(button,idx) line.layout().addWidget(button) self.currentFolderLayout.addWidget(line) return group def createJobTitle(self,followFrom=True): import CCP4TaskManager self.jobHeaderFrame = self.parentTaskWidget().openSubFrame ( frame=[False] ) self.jobHeaderFrame.setObjectName('jobHeaderFrame') # so that it can be styled if self.ignoreInput: return #print 'createJobTitle followFrom',followFrom line = self.parentTaskWidget().createLine(['label','Job title','widget','jobTitle']) try: self.jobTitleWidget = line.layout().itemAt(1).widget().widget except: return t = self.getWidget('jobTitle').model if not t.isSet() or len(t)==0: t.set(CCP4TaskManager.TASKMANAGER().getShortTitle(self.parentTaskWidget().taskName())) self.connect ( self.jobTitleWidget, QtCore.SIGNAL('editingFinished()'), self.saveTitle ) self.jobTitleWidget.setToolTip('Short description of job to appear in Job list') if followFrom and self.parentTaskWidget().folderAttributes.attribute('editable'): self.parentTaskWidget().createLine(['widget','followFrom']) self.parentTaskWidget().closeSubFrame() def createPatchFrame(self): if self.ignoreInput: return taskWidget = self.parentTaskWidget() # Force 'fix' of the patchSelection object before drawing try: patchSelectionObj = taskWidget._container.guiAdmin.patchSelection except: return patchSelectionObj.set(patchSelectionObj.fix({'taskName' : taskWidget.taskName(), 'patch' : patchSelectionObj.get('patch') })) if len(patchSelectionObj.getPatchList())>0: taskWidget.createLine(['widget','patchSelection']) self.connect(patchSelectionObj,QtCore.SIGNAL('dataChanged'),self.handlePatchChange) self.handlePatchChange() def handlePatchChange(self): taskWidget = self.parentTaskWidget() #print 'CTaskWidget.handlePatchChange patch',taskWidget._container.guiAdmin.patchSelection.patch try: if not taskWidget._container.guiAdmin.patchSelection.patch.isSet(): return except: return controlParameters = COMFILEPATCHMANAGER().getComFileControlParameters(name=taskWidget._container.guiAdmin.patchSelection.patch.__str__()) #print 'CTaskWidget.handlePatchChange',controlParameters taskWidget._container.controlParameters.update(controlParameters) #print 'CTaskWidget after update',taskWidget._container.controlParameters for key in controlParameters.dataOrder(): widget = self.findChild(CCP4Widgets.CViewWidget,key) if widget is not None: widget.updateViewFromModel() def saveTitle(self): jobId = self.parentTaskWidget().jobId() if jobId is None: return text = str(self.jobTitleWidget.text()) print 'CTaskWidgetDrawMethods.saveTitle',jobId,text try: PROJECTSMANAGER().db().updateJob(jobId=jobId,key='jobTitle',value=text) except: pass class CTaskWidget(QtGui.QFrame): EDITOR = False AUTOPOPULATEINPUT = True USEPLUGIN = None ERROR_CODES = { 101 : { 'description' : 'Error updating view from model' }, 102 : { 'description' : 'Error updating model from view' }, 103 : { 'description' : 'Error in cootFix' } } def __init__(self,parent=None,title=None,projectId=None,jobId=None,layoutMode=None): QtGui.QFrame.__init__(self,parent) import CCP4GuiUtils import CCP4Container self.setTitle(title) self.helpFile = '' self.programHelpFile = '' # Dict of sub-job widgets (eg workflows) self.subJobTaskWidgets = {} self.paramsFileName = None # For special cases (eg workflows) do not draw input data frame self.excludeInputData = False self.paramsList = [] self.widgetLookup = {} self.layoutMode = layoutMode if layoutMode is not None and layoutMode in ['TAB','FOLDER']: self.layoutMode = layoutMode else: self.layoutMode = str(PREFERENCES().TASK_WINDOW_LAYOUT) # Project is projectName as this is used by the CDataFileView most frequently self._projectId = projectId self._jobId=jobId self._jobNumber = None self._container = CCP4Container.CContainer() self.folderAttributes = CFolderAttributes() self.contextMenuWidget = QtGui.QMenu(self) self.widgetWithContextMenu = [] self.setLayout(QtGui.QVBoxLayout()) self.layout().setContentsMargins(0,0,0,0) self.layout().setSpacing(0) if self.layoutMode == 'TAB': self.widget = CTabTaskWidget(parent=self) self.layout().addWidget(self.widget) else: self.scrollArea= QtGui.QScrollArea(self) self.layout().addWidget(self.scrollArea) self.widget = CFolderTaskWidget(parent=self) self.scrollArea.setWidget(self.widget) self.scrollArea.setWidgetResizable(1) self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) #print 'CTaskWidget self',self,'scrollArea',self.scrollArea,'widget',self.widget,'widget.parent',self.widget.parent(),self.widget.parent().parent() self.messageScrollArea= QtGui.QScrollArea(self) self.messageScrollArea.setMinimumHeight(40) self.messageScrollArea.setMaximumHeight(40) self.messageScrollArea.setMinimumWidth(WIDTH) self.messageScrollArea.setMaximumWidth(WIDTH) self.message = QtGui.QLabel(self) self.message.setObjectName('errorMessage') self.message.setWordWrap(True) self.messageScrollArea.setWidget(self.message) self.messageScrollArea.setWidgetResizable(1) self.layout().addWidget(self.messageScrollArea) self.messageStack = [] def setMessage(self,text='',parameter=None): if text is None: text = '' self.message.setText(text) self.messageStack.append([parameter,text]) #print 'setMessage',text,parameter,self.messageStack def unsetMessage(self,parameter=None): if len(self.messageStack)==0: return if self.messageStack[-1][0] == parameter: del self.messageStack[-1] else: delFrom = None for ii in range(len(self.messageStack)-2,-1,-1): if self.messageStack[ii][0] == parameter: delFrom = ii if delFrom is not None: #print 'unsetMessage deleting multi levels of stack',self.messageStack,delFrom del self.messageStack[delFrom:-1] #print 'unsetMessage',parameter,self.messageStack if len(self.messageStack)>0: self.message.setText(self.messageStack[-1][1]) def updateMessage(self,text='',parameter=None): for ii in range(len(self.messageStack)): if self.messageStack[ii][0] == parameter: if text is None: text = '' self.messageStack[ii][1] = text if len(self.messageStack)>0: self.message.setText(self.messageStack[-1][1]) #print 'updateMessage',text,parameter,self.messageStack def setDefaultParameters(self): # Reimplement in tasks to set initial parameters pass def setDefaultFiles(self): # Reimplement in tasks to set initial files # This is called after setFollowJobId() so can override # and files set by the system pass def setParamsFileName(self,fileName): self.paramsFileName = fileName def setSelection(self,selection): self.selection = selection def setFollowJobId(self,jobId,force=True): self._container.guiAdmin.followFrom = jobId widget = self.getWidget('followFrom') if widget is not None: widget.updateInputFiles(jobId,self._projectId,force) widget.updateViewFromModel() def isEditable(self): return self.folderAttributes.attribute('editable') def draw(self): rv = self.widget.draw() self.widget.show() return rv def visibleFolder(self): if self.layoutMode == 'TAB': return str(self.widget.tabText(self.widget.currentIndex())) else: return None def setVisibleFolder(self,title=None,index=None): if self.layoutMode != 'TAB': return if index is None: for ii in range(self.widget.count()): if title == str(self.widget.tabText(ii)): index = ii break if index is not None: self.widget.setCurrentIndex(index) def openFolder(self,folderFunction='general',title=None,toggle=[],toggleFunction=[],level=USER_NOVICE,autoSelection={}, drawFolder=None,**kw): #print 'CtaskWidget.openFolder',folderFunction,self.excludeInputData if self.excludeInputData and folderFunction == 'inputData': self.widget.ignoreInput = True return else: self.widget.ignoreInput = False if title == None: if folderFunction == 'protocol': title = self.title() elif folderFunction == 'inputData': title = 'Input data' elif folderFunction == 'outputData': title = 'Output data' attribs = self.folderAttributes.allAttributes(folderFunction) attribs['level'] = level rv = self.widget.openFolder(folderFunction=folderFunction,title=title,toggle=toggle, toggleFunction=toggleFunction,attributes=attribs,drawFolder=drawFolder,keywords=kw) if len(autoSelection)>0: self.autoGenerate(container=self.container.controlParameters,selection=autoSelection) return rv def closeFolder(self): self.widget.closeFolder() def createLine(self,definition=[],appendLine=None,toggle=[],toggleFunction=[]): return self.widget.createLine(definition=definition,appendLine=appendLine,toggle=toggle,toggleFunction=toggleFunction) def openStack(self,controlVar=None): return self.widget.openStack(controlVar=controlVar) def closeStack(self): self.widget.closeStack() def openTabFrame(self,title,toolTip=None): self.widget.openTabFrame(title=title,toolTip=toolTip) def closeTabFrame(self): self.widget.closeTabFrame() def createRadioGroup(self,label=None,itemList=[]): return self.widget.createRadioGroup(label=label,itemList=itemList) def createTitleLine(self,name='TITLE'): self.widget.createTitleLine(name=name) def openSubFrame(self,toggle=[],toggleFunction=[],frame=False,title=None): #print 'CTaskWidget.openSubFrame',args return self.widget.openSubFrame(toggle=toggle,toggleFunction=toggleFunction,frame=frame,title=title) def closeSubFrame(self): self.widget.closeSubFrame() def setContainer(self,container=None): self._container = container def getContainer(self): return self._container container = property(getContainer,setContainer) def setProjectId(self,projectId=None): self._projectId = projectId def projectId(self): return self._projectId def setJobId(self,jobId): self._jobId = jobId self._jobNumber= PROJECTSMANAGER().db().getJobInfo(jobId = jobId,mode='jobnumber') def jobId(self): return self._jobId def jobNumber(self): return self._jobNumber def taskName(self): return self.TASKNAME def setTitle(self,title): self._title = title def title(self): if self._title is not None: return self._title elif hasattr(self,'TASKTITLE'): return self.TASKTITLE else: return self.__class__.__name__ def isEditor(self): return self.EDITOR def autoPopulateInput(self): return self.AUTOPOPULATEINPUT def getParams(self,paramValues={}): import CCP4Data for key,value in paramValues.items(): widget = self.getWidget(key) if widget is not None: if isinstance(value,CCP4Data.CData): ret_value = widget.model.getDataObjects() else: ret_value = widget.getValue() paramValues[key] = ret_value def setDefaultParams(self): if self._container is not None: return 0 self.setParams(self._container.getDataObjects()) def setParams(self,paramValues={}): for key,value in paramValues.items(): widget = self.getWidget(key) if widget is not None: if isinstance(widget,CCP4Widgets.CViewWidget): widget.setModel(value) else: widget.setValue(value) def setProgramHelpFile(self,helpFile): self.programHelpFile = helpFile def setHelpFile(self,helpFile): self.helpFile = helpFile def populateContextMenu(self,name,helpFile,helpTarget,globalX,globalY): #print 'CTaskWidget.populateContextMenu',name,helpTarget,globalX,globalY import CCP4GuiUtils self.widgetWithContextMenu = [name,helpFile,helpTarget] self.contextMenuWidget.clear() CCP4GuiUtils.populateMenu(self,self.contextMenuWidget,['help'],default_icon='') self.contextMenuWidget.popup(QtCore.QPoint(globalX,globalY)) def getActionDef(self,name=''): if name == 'help': return dict ( text = 'Help', tip = 'Help', slot = self.help ) def help(self): #print 'CTaskWidget.help',self.widgetWithContextMenu import os try: helpPath = os.path.join(os.environ['CCP4'],'docs') except: QtGui.QMessageBox.warning(None,self.windowTitle(),'Can not access help files - CCP4 not setup') helpPath = os.path.join(helpPath,self.widgetWithContextMenu[1]+'.html') if not os.path.exists(helpPath): QtGui.QMessageBox.warning(None,self.windowTitle(),'Help file not found: '+helpPath) return HELPBROWSER().loadWebPage(helpPath) ''' def updateModelFromView(self,textOnly=False): # Not convinced this is needed and sledge-hammer updateModelFromView() of some # widgets (eg CImportUnmerged) very bad as trashes gui-generalted data (such as cell params) return def updateModelFromView(self,textOnly=False): rv = CErrorReport() from CCP4Widgets import CViewWidget from CCP4ContainerView import CContainerView toggledFrame = {} for t in self.widget.toggleList: toggledFrame[t.target] = t.getTargetVisibility() widgetList = self.findChildren(CViewWidget) #print 'CTaskWidget.updateModelFromView',textOnly,widgetList for widget in widgetList: #print widget.model.objectName(), w = widget.parent() isVis = True while isVis and not isinstance(w,(CTaskWidget,CContainerView,QtGui.QDialog,QtGui.QMainWindow)): #print w,toggledFrame.get(w,True) ,'*', if not toggledFrame.get(w,True): isVis = False w = w.parent() #print 'isVis',isVis,widget.getValue() if isVis: try: if textOnly: widget.updateModelFromText() else: widget.updateModelFromView() except: rv.append(self.__class__,102,str(widget.objectName()),stack=False) return rv ''' def updateModelFromView(self,textOnly=False): # Called when user clicks run - try to fix any text widget with focus that has not updated # the model since has not had the 'finished' signal from user hitting return or moving focus rv = CErrorReport() fW = QTAPPLICATION().focusWidget() if fW is not None: if isinstance(fW,CCP4Widgets.CLineEdit): fW.emit(QtCore.SIGNAL('editingFinished()')) elif isinstance(fW,CCP4Widgets.CTextEdit): fW.emit(QtCore.SIGNAL('textChanged()')) return rv ''' w = fW.parent() while w is not None: if isinstance(w,(CCP4Widgets.CStringView,CCP4Widgets.CFloatView,CCP4Widgets.CIntView)): try: print 'CTaskWidget.updateModelFromView updating model from view for',w.model.objectName(),'widget value:',w.getValue(),'old model value:',w.model w.updateModelFromView() except: pass return rv else: w = w.parent() ''' def updateViewFromModel(self): rv = CErrorReport() for param in self.paramsList: try: widgetList = self.findWidget(param) #print 'CTaskWidget.updateViewFromModel',widget,widget.model.get0() for widget in widgetList: widget.blockSignals(True) widget.updateViewFromModel() widget.blockSignals(False) except: rv.append(self.__class__,101,str(widget.objectName())) #print 'CTaskWidget.updateViewFromModel errors:',rv.report() return rv def setup(self): return 0 def createWidget(self,name=None,widgetQualifiers={},helpTarget=None): model = self._container.find(name) if model is None: raise CException(self.__class__,100,name) widget = None wQualifiers = {} wQualifiers.update(widgetQualifiers) wQualifiers.update(model.qualifiers()) #print 'widgetQualifiers',name,wQualifiers widget = DATAMANAGER().widget(model=model,parentWidget=self,qualifiers=wQualifiers,name=name) #print 'CTaskLine widget',name,widget if widget is not None: widget.setObjectName(name) #modelTip = model.qualifiers('toolTip') #if modelTip is not NotImplemented: # widget.setToolTip(modelTip) if model.qualifiers('toolTip') is not NotImplemented: widget.setToolTip(model.qualifiers('toolTip')) ''' if widget.STRETCH > 0: self.layout().setStretch(self.layout().count(),widget.stretchFactor()) doneStretch = True elif widgetQualifiers.get('charWidth',1) < 0: doneStretch = True ''' if helpTarget is not None: import CCP4Utils self.connect(widget,QtCore.SIGNAL('contextMenuRequest'),CCP4Utils.partialWithSignal(self.populateContextMenu,name,self.programHelpFile,helpTarget)) return widget def getWidget(self,name=None): return self.widgetLookup.get(name,[None])[0] def setMenuText(self,parameter=None,menuText=None): ''' Set data object qualifier menuText from Python parameter is the name of the data object menuText can be a list which should be same length as the enumerators qualifier or it can be a dict with the enumerator values as keys ''' dataObj = self._container.find(parameter) if dataObj is None: raise CException(self.__class__,101,str(parameter)) enumerators = dataObj.qualifiers('enumerators') #print 'setMenuText enumerators',parameter,dataObj,enumerators,len(enumerators),len(menuText) if isinstance(menuText,list): if len(menuText) != len(enumerators): raise CException(self.__class__,102,str(parameter),stack=False) dataObj.setQualifier('menuText',menuText) elif isinstance(menuText,dict): enums = [] menu = [] unrecog = [] for item in enumerators: if menuText.has_key(item): enums.append(item) menu.append(menuText[item]) else: unrecog.append(item) #print 'setMenuText new menu',enums,menu dataObj.setQualifiers({'enumerators' : enums, 'menuText': menu } ) if len(unrecog)>0: return CException(self.__class__,103,str(parameter)+' '+str(unrecog)) def setToolTip(self,parameter=None,toolTip=None): dataObj = self._container.find(parameter) if dataObj is None: raise CException(self.__class__,104,str(parameter)) dataObj.setQualifier('toolTip',toolTip) def setLabel(self,parameter=None,label=None): dataObj = self._container.find(parameter) if dataObj is None: raise CException(self.__class__,105,str(parameter)) dataObj.setQualifier('label',label) def validate(self): if self.isEditable(): return self.widget.validate() else: return 0 def resetJobCombos(self): return self.widget.resetJobCombos() def fix(self): # Dummy method to be reimplemented in sub-class # Called after user clicks run button and before validate() # Probably should be used mostly to ensure that if there are # possible alternate input files then only one has a set value # (this is to prevent unused files being recorded in database) self.emit(QtCore.SIGNAL('doFix')) rv = CErrorReport() for key,win in self.subJobTaskWidgets.items(): rv.extend(win.fix()) return rv def cootFix(self): import os import CCP4Modules,CCP4DataManager,CCP4Utils,CCP4FileBrowser path = str(CCP4Modules.PREFERENCES().COOT_EXECUTABLE) #print 'CTaskWidget.cootFix',path try: if path is not None and os.path.exists(path): return CErrorReport() except: pass ''' path = CCP4Utils.findDaBirdy() if path is not None: CCP4Modules.PREFERENCES().COOT_EXECUTABLE.set(fullPath=path) return CErrorReport() ''' self.cootFixDialog = CCP4FileBrowser.CFileDialog(self,'Find da Birdy',filters=[' (*)'],projectCombo=False) label = QtGui.QLabel("""Sorry - failed to find Coot. Please enter the Coot executable and then 'Run' again.\nBeware you are probably using a CCP4 nightly build that does not include Coot.\nThe Coot executable can also be set in Preferences.""",self) label.setStyleSheet( "QLabel { font-weight: bold; border: 2px solid} ") self.cootFixDialog.addWidget(label) self.connect(self.cootFixDialog,QtCore.SIGNAL('selectFile'),self.handleCootFix) self.cootFixDialog.show() self.cootFixDialog.raise_() return CErrorReport(self.__class__,103) def handleCootFix(self,filePath): #self.cootFixWidget.updateModelFromView() self.cootFixDialog.hide() self.cootFixDialog.deleteLater() import os if filePath is not None and os.path.exists(filePath): import CCP4Modules CCP4Modules.PREFERENCES().COOT_EXECUTABLE.set(filePath) CCP4Modules.PREFERENCES().save() else: pass def isValid(self): invalidList = [] for key,widgetList in self.widgetLookup.items(): for widget in widgetList: if widget.isValid is None: widget.validate() if widget.isValid is not None and not widget.isValid: if getattr(widget,'model',None) is not None: if widget.model.objectName() != 'fileContent': #print 'CTaskWidget.isValid',widget.model.objectName(),widget.isValid invalidList.append(widget.model) else: invalidList.append(str(widget)) # Apply to any sub-job widgets for key,win in self.subJobTaskWidgets.items(): invalidList.extend(win.isValid()) #print 'CTaskWidget.isValid',invalidList return invalidList def taskValidity(self): return CErrorReport() def getScrollDisplacement(self): scrollArea = getattr(self,'scrollArea',None) if scrollArea is None: return 0 else: return self.scrollArea.verticalScrollBar().value() def setScrollDisplacement(self,value): scrollArea = getattr(self,'scrollArea',None) if scrollArea is not None: self.scrollArea.verticalScrollBar().setValue(value) def autoGenerate(self,container=None,selection={},subFrame=False): import re import CCP4File import CCP4Data import CCP4Container label = container.qualifiers('guiLabel') defn = container.qualifiers('guiDefinition') if defn is None or defn is NotImplemented: defn = {} if subFrame: frame = self.widget.openSubFrame(frame=True) #print 'subFrame',frame,container.__dict__['_qualifiers'],label,defn, defn.get('toggleParameter',None) if defn.get('toggleParameter',None) is not None: self.widget.setToggle(target=frame,parameter=defn['toggleParameter'], state=defn.get('toggleState','open'),values =defn['toggleValues']) if label is not NotImplemented: self.widget.createLine(definition= [ 'advice' , label ]) #print 'autoGenerate container',repr(container),defn includeParameters = selection.get('includeParameters',[]) #print 'CTaskWidget.autoGenerate includeParameters',includeParameters includeWildcards = [] for item in includeParameters: if item.count('*'): includeWildcards.append(item) excludeParameters = selection.get('excludeParameters',[]) keyValues = selection.get('keyValues',{}) def matchesKeyValues(definition): if len(keyValues)==0: return True for key,value in keyValues.items(): if not definition.has_key(key) or definition[key] != value: return False return True def matchesWildcard(name): for wildcard in includeWildcards: if re.match(wildcard,name): return True return False #print 'CTaskWidget.autoGenerate includeWildcards',includeWildcards for name in container.dataOrder(): # If includeParameters is defined then name should be in that list or match a wildcard in that list # if includeParameters is not defined then name just needs to not be in excludeParameters list #print 'CTaskWidget.autoGenerate',name,len(includeParameters),name in includeParameters,matchesWildcard(name) if (len(includeParameters)>0 and (name in includeParameters or matchesWildcard(name))) or \ (len(includeParameters)==0 and name not in selection.get('excludeParameters',[])): model=getattr(container,name) if isinstance(model,CCP4Container.CContainer): self.autoGenerate(model,selection=selection,subFrame=True) else: label = model.qualifiers('guiLabel') defn = model.qualifiers('guiDefinition') if defn is None or defn is NotImplemented: defn = {} if label is None or label is NotImplemented: label = name #print 'autoGenerate',name,repr(model),label,defn if matchesKeyValues(defn): if isinstance(model,CCP4File.CDataFile): line = self.widget.createLine(definition= ['widget', name ]) widget = line.findChildren(QtGui.QWidget)[0] elif isinstance(model,CCP4Data.CBoolean): line = self.widget.createLine(definition= [ 'widget', name , 'label' , label ]) widget = line.findChildren(QtGui.QWidget)[0] else: line = self.widget.createLine(definition= [ 'label' , label, 'widget', name ]) widget = line.findChildren(QtGui.QWidget)[1] #widget.setMaximumWidth(WIDTH-116) if defn.get('toggleParameter',None) is not None: self.widget.setToggle(target=line,parameter=defn['toggleParameter'], state=defn.get('toggleState','open'),values =defn['toggleValues']) toolTip = model.qualifiers('toolTip') if toolTip is not None and toolTip is not NotImplemented: #print 'toolTip',widgetIndex,line.findChildren(QtGui.QWidget) widget.setToolTip(toolTip) if subFrame: self.closeSubFrame() def handleClosingSubTaskWindow(self,jobName): import os if self.subJobTaskWidgets.has_key(jobName): fileNameSplit = os.path.split(PROJECTSMANAGER().makeFileName(jobId=self._jobId,mode='JOB_INPUT')) self.subJobTaskWidgets[jobName].saveToXml(fileName=os.path.join(fileNameSplit[0],jobName+'_'+fileNameSplit[1])) del self.subJobTaskWidgets[jobName] def saveToXml(self,fileName=None,jobInfo={}): # Assume the updateModelFromView() has been called earlier by project viewer before the # validation of input #self.updateModelFromView() import CCP4File if fileName is None: if self.paramsFileName is not None: fileName= self.paramsFileName else: fileName = PROJECTSMANAGER().makeFileName(jobId=self._jobId,mode='JOB_INPUT') jobInfo = {} if self._jobId is not None: try: jobInfo = PROJECTSMANAGER().db().getJobInfo(jobId=self._jobId,mode=['taskname','jobnumber','projectname','status','projectid']) except: pass f = CCP4File.CI2XmlDataFile(fullPath=fileName) cHeader = self.container.getHeader() if cHeader is not None: f.header.set(cHeader) f.header.setCurrent() f.header.function = 'PARAMS' f.header.jobId.set(self._jobId) f.header.projectId.set(self._projectId) try: f.header.pluginName = TASKMANAGER().getTaskData(self.taskName())['taskName'] except: print 'Error getting plugin name for taskName',self.taskName() if jobInfo.get('jobnumber',None) is not None: f.header.jobNumber.set(jobInfo['jobnumber']) if jobInfo.get('projectname',None) is not None: f.header.projectName.set(jobInfo['projectname']) bodyEtree = self.container.getEtree() from lxml import etree f.saveFile(bodyEtree=bodyEtree) #print 'CTaskWidget.saveTofile DONE',fileName,jobInfo def handleLaunchedJob(self,jobId=None,status=None,taskWidget=None): print 'Dummy method for reimplementation in task that has launched a popout task',jobId,status,taskWidget pass def connectDataChanged(self,name,handle): obj = self.container.find(name) if obj is None: return self.connect(obj,QtCore.SIGNAL('dataChanged'),handle) def findWidget(self,name): return self.widgetLookup.get(name,None) #--------------------------------------------------------------------- class CFolderTaskWidget(QtGui.QFrame,CTaskWidgetDrawMethods): #--------------------------------------------------------------------- MARGIN = 4 ERROR_CODES = { 101 : { 'description' : 'Error updating GUI widget with model value' }, 105 : {'description' : 'Internal error handing file - no task container' } } def __init__(self,parent=None): QtGui.QFrame.__init__(self,parent) CTaskWidgetDrawMethods.__init__(self) layout = QtGui.QVBoxLayout() #layout.setSizeConstraint(QtGui.QLayout.SetMinAndMaxSize) layout.setContentsMargins(CFolderTaskWidget.MARGIN,CFolderTaskWidget.MARGIN,CFolderTaskWidget.MARGIN,CFolderTaskWidget.MARGIN) layout.setSpacing(CFolderTaskWidget.MARGIN) self.setLayout(layout) def parentTaskWidget(self): return self.parent().parent().parent() def draw(self): self.myException = CErrorReport() self.parentTaskWidget().drawContents() self.parentTaskWidget().updateViewFromModel() self.closeFolder() self.layout().addStretch(5) ''' for ii in range(0,self.layout().count()): w = self.layout().itemAt(ii).widget() print 'CTaskWidget.draw',ii,w if w is not None: w.contents.show() w.show() ''' #print 'CTaskWidget.finishDraw',self.isVisible() self.parentTaskWidget().setDefaultParams() self.applyToggles() e = CErrorReport() #print 'CTaskWidget.draw',len(e) e.extend(self.myException,stack=False) del self.myException return e def openFolder(self,folderFunction='general',title='CCP4 Task Folder',toggle=[],toggleFunction=[], attributes={},keywords={},drawFolder=None,**kw): import functools if self.subFrame is not None: self.closeSubFrame() self.closeFolder() self.currentFolder = CTaskFolder(self,folderFunction=folderFunction,title=title,toggle=toggle, toggleFunction=toggleFunction, attributes=attributes) self.currentFolderLayout = QtGui.QVBoxLayout() self.currentFolderLayout.setSpacing(CFolderTaskWidget.MARGIN) self.currentFolderLayout.setContentsMargins(CFolderTaskWidget.MARGIN,CFolderTaskWidget.MARGIN,CFolderTaskWidget.MARGIN,CFolderTaskWidget.MARGIN) self.connect(self.currentFolder,QtCore.SIGNAL('folderToggled'),functools.partial(self.folderToggled,self.currentFolder)) if folderFunction == 'inputData': self.createJobTitle(followFrom=keywords.get('followFrom',True)) return self.currentFolder def closeFolder(self): if self.subFrame is not None: self.closeSubFrame() if self.tabWidget is not None: self.closeTabFrame() if self.currentFolder is not None: if self.currentFolder.folderFunction == 'inputData': self.createPatchFrame() self.currentFolderLayout.addStretch(1) self.currentFolder.setContentsLayout(self.currentFolderLayout) self.layout().addWidget(self.currentFolder) self.currentFolder = None self.currentFolderLayout = None def folderToggled(self,folder): self.layout().update() def getWidget(self,name): # findChild only finds stuff in top tab?? return self.widgetLookup.get(name,[None])[0] def getFolderOpenStatus(self): status = [] for i in range(self.layout().count()): w = self.layout().itemAt(i).widget() #print 'getFolderOpenStatus',i,w if w is not None: status.append(w.isOpen()) return status def setFolderOpenStatus(self,openStatus): for i in range(min(len(openStatus),self.layout().count())): w = self.layout().itemAt(i).widget() if openStatus[i]: w.openFolder() else: w.closeFolder() #--------------------------------------------------------------------- class CToggle(QtCore.QObject): #--------------------------------------------------------------------- ERROR_CODES = { 101 : { 'description' : 'Can not set up toggle widget undefined for' }, 102 : { 'description' : 'Can not set up toggle model undefined for' }, 103 : { 'description' : 'Can not change visibility, widget undefined for' }, 104 : { 'description' : 'Can not change visibility, model undefined for' } } def __init__(self,parent,target=None,parameter=None,state='open',values=[],parameterList=[],toggleFunction=None): QtCore.QObject.__init__(self,parent) #print 'CToggle.__init__',parameter,parent,target self.target = target self.parameter = parameter self.state = state self.values = values self.parameterList = [] self.parameterList.extend(parameterList) self.toggleFunction = toggleFunction self.connected = False def makeConnection(self): ''' widget = self.parent().findChild(QtGui.QWidget,self.parameter) #print 'CToggle.makeConnection',self.parameter,widget,widget.model if widget is None: raise CException(self.__class__,101,self.parameter) elif widget.model is None: raise CException(self.__class__,102,self.parameter) self.parent().connect(widget.model,QtCore.SIGNAL('dataChanged'),self.handleSignal) ''' container = self.parent().parentTaskWidget().container if container is None: return if self.parameter is not None: obj = container.find(self.parameter) if obj is None: return self.parent().connect(obj,QtCore.SIGNAL('dataChanged'),self.handleSignal) else: for param in self.parameterList: obj = container.find(param) if obj is not None: self.parent().connect(obj,QtCore.SIGNAL('dataChanged'),self.handleSignal) self.connected = True def handleSignal(self,**kw): if self.parameter is not None: self.setTargetVisibility() else: self.applyVisibilityFunction() def setTargetVisibility(self): ''' widget = self.parent().findChild(QtGui.QWidget,self.parameter) #print 'setTargetVisibility',self.parent(),self.parameter,widget if widget is None: raise CException(self.__class__,103,self.parameter) if widget.model is None: raise CException(self.__class__,104,self.parameter) ''' obj = self.parent().parentTaskWidget().container.find(self.parameter) if obj is None: return value = obj.get() #print 'CToggle.setTargetVisibility',self.parameter,value,self.values,self.values.count(value),self.state #if isinstance(self.target,CTaskLine) or isinstance(self.target,CSubFrame) or isinstance(self.target,CTaskFolder): if 1: if self.values.count(value): if self.state == 'open': self.target.show() else: self.target.hide() else: if self.state == 'open': self.target.hide() else: self.target.show() def getTargetVisibility(self): try: obj = self.parent().parentTaskWidget().container.find(self.parameter) except: return True if obj is None: return True value = obj.get() if 1: if self.values.count(value): return self.state == 'open' else: return self.state != 'open' def applyVisibilityFunction(self): vis = self.toggleFunction() #print 'applyVisibilityFunction',vis if vis: self.target.show() else: self.target.hide() #--------------------------------------------------------------------- class CTaskFolder(CCP4Widgets.CFolder): #--------------------------------------------------------------------- def __init__(self,parent=None,folderFunction='general',title='Folder',open=1,toggle=[],toggleFunction=[],attributes={}): self.folderFunction = folderFunction if ['protocol'].count(folderFunction): titleBar = 0 else: titleBar = 1 #print 'CTaskFolder.__init__',title self._attributes = attributes CCP4Widgets.CFolder.__init__(self,parent,title,open,titleBar,toggle=toggle) import CCP4StyleSheet self.setTitleColour(CCP4StyleSheet.LOWLIGHTCOLOUR) if self.titleBar is not None: self.titleBar.setMaximumHeight(30) def setupUpdateStatus(self,*args): pass #--------------------------------------------------------------------- class CSubFrame(QtGui.QFrame): #--------------------------------------------------------------------- def __init__(self,parent): QtGui.QFrame.__init__(self,parent) #--------------------------------------------------------------------- class CTaskLine(QtGui.QFrame): #--------------------------------------------------------------------- ERROR_CODES = { 101 : { 'description' : 'No data container for task line' }, 102 : { 'description' : 'No model found for task line item' }, 103 : { 'description' : 'Error creating widget for task line item' } } MARGIN = 0 def __init__(self,parent=None): QtGui.QFrame.__init__(self,parent) self.setObjectName('taskLine') layout = QtGui.QHBoxLayout() layout.setSpacing(CTaskLine.MARGIN) layout.setContentsMargins(CTaskLine.MARGIN,CTaskLine.MARGIN,CTaskLine.MARGIN,CTaskLine.MARGIN) self.setLayout(layout) self.tip = None self.helpTarget = '' def parentTaskWidget(self): return self.parent().parentTaskWidget() def addWidget(self,widget): lastItem = self.layout().itemAt(self.layout().count()-1) #print 'CTaskLine.addWidget lastItem',lastItem if lastItem is not None and isinstance(lastItem,QtGui.QSpacerItem): self.layout().insertWidget(self.layout().count()-1,widget) else: self.layout().addWidget(widget) def draw(self,definition=[],dataContainer=None,setupFolder=None,attributes={}): #print 'CTaskLine.draw',definition doneStretch = False if dataContainer is None: raise CException(self.__class__,101) myException = CErrorReport() widgetQualifiers = {} widgetQualifiers.update(attributes) #print 'CTaskLine.draw widgetQualifiers',widgetQualifiers pDef = -1 definition.append('') ifFullLine = False while (pDef' + definition[pDef]+ '') if self.tip is not None: lab.setToolTip(self.tip) self.layout().addWidget(lab) if definition[pDef] == 'subtitle': pDef = pDef + 1 subtitle = QtGui.QLabel(definition[pDef]) pDef = pDef + 1 subtitle.setToolTip ( '' + definition[pDef] + '' ) subtitle.setObjectName ( 'subtitle' ) self.layout().addWidget ( subtitle ) if self.tip is not None: subtitle.setToolTip(self.tip) if definition[pDef] in [ 'advice','warning']: pDef = pDef + 1 label = QtGui.QLabel('' + definition[pDef] + '') label.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse) self.layout().setContentsMargins(CFolderTaskWidget.MARGIN,CFolderTaskWidget.MARGIN,CFolderTaskWidget.MARGIN,CFolderTaskWidget.MARGIN) self.layout().setSpacing(CFolderTaskWidget.MARGIN) if definition[pDef-1] == 'advice': label.setObjectName('italic') self.layout().addWidget(label) else: label.setObjectName('warning') label.setWordWrap(True) self.layout().addWidget(label) if self.tip is not None: lab.setToolTip(self.tip) if definition[pDef] == 'spacing': pDef = pDef + 1 self.layout().addSpacing( definition[pDef]) ifFullLine = True if definition[pDef] == 'stretch': self.layout().addStretch( 1) ifFullLine = True if definition[pDef] == 'launchButton': pDef = pDef + 1 taskName = definition[pDef] widget = QtGui.QPushButton(TASKMANAGER().getTaskAttribute(taskName,'TASKTITLE')) widget.setObjectName(taskName) if self.tip is not None: widget.setToolTip(self.tip) self.connect(widget,QtCore.SIGNAL('released()'),functools.partial(self.parentTaskWidget().emit,QtCore.SIGNAL('launchJobRequest'),taskName,{'launchJobId':self.parentTaskWidget().jobId()})) self.layout().addWidget(widget) if definition[pDef] == 'widget': pDef = pDef + 1 while definition[pDef][0] == '-': widgetQualifiers[definition[pDef][1:]] = definition[pDef+1] pDef = pDef + 2 model = dataContainer.find(definition[pDef]) #print 'CTaskLine.draw',model,definition[pDef] #if len(widgetQualifiers)>0: print 'CTaskLine.draw widgetQualifiers',definition[pDef],widgetQualifiers if model is None: myException.append(self.__class__,102,definition[pDef],stack=False) else: if not (self.parent().parent().paramsList.count(definition[pDef])): self.parent().parent().paramsList.append(definition[pDef]) widget = None qualifiers = {} qualifiers.update(model.qualifiers()) qualifiers.update(widgetQualifiers) #print 'widgetQualifiers',definition[pDef],model.qualifiers(),widgetQualifiers if DEVELOPER(): widget = DATAMANAGER().widget(model=model,parentWidget=self.parent(),qualifiers=widgetQualifiers,name=definition[pDef]) else: try: widget = DATAMANAGER().widget(model=model,parentWidget=self.parent(),qualifiers=widgetQualifiers,name=definition[pDef]) except CException as e: e.appendDetails(definition[pDef]) myException.extend(e) except: myException.append(self.__class__,103,definition[pDef]) #print 'CTaskLine widget',definition[pDef],widget,widget.STRETCH #widget = dataContainer.widget(name=par,parentWidget=self,widgetQualifiers=widgetQualifiers) if widget is not None: widget.setObjectName(definition[pDef]) #modelTip = model.qualifiers('toolTip') #if modelTip is not NotImplemented: # widget.setToolTip(modelTip) if self.tip is not None: widget.setToolTip(self.tip) else: tip = model.qualifiers('toolTip') if tip is not NotImplemented and tip is not None: widget.setToolTip(model.qualifiers('toolTip')) self.layout().addWidget(widget) if widget.STRETCH > 0: #print 'CTaskLine.draw stretching',model.objectName() self.layout().setStretch(self.layout().count()-1,widget.STRETCH) doneStretch = True elif widgetQualifiers.get('charWidth',1) < 0: doneStretch = True import CCP4Utils tW = self.parentTaskWidget() self.connect(widget,QtCore.SIGNAL('contextMenuRequest'),CCP4Utils.partialWithSignal(tW.populateContextMenu,definition[pDef],tW.programHelpFile,self.helpTarget)) if not tW.widgetLookup.has_key(definition[pDef]): tW.widgetLookup[definition[pDef]] = [] tW.widgetLookup[definition[pDef]].append(widget) if setupFolder is not None: setupFolder(model) if isinstance(widget,CCP4Widgets.CComplexLineWidget): ifFullLine = True if definition[pDef] == 'format': pass ''' if ['toggle','toggle_display'].count(definition[pDef]): if pDef+30: self.myException.report() self.currentFolder = None self.currentFolderLayout = None self.parentTaskWidget().updateViewFromModel() self.applyToggles() def parentTaskWidget(self): return self.parent() def draw(self): self.myException = CErrorReport() self.parentTaskWidget().drawContents() self.parentTaskWidget().updateViewFromModel() self.closeFolder() self.parentTaskWidget().setDefaultParams() self.applyToggles() e = CErrorReport() #print 'CTaskWidget.draw',len(e) e.extend(self.myException,stack=False) del self.myException return e def openFolder(self,folderFunction='general',title='CCP4 Task Folder',toggle=[],toggleFunction=[], attributes={},keywords={},drawFolder=None,**kw): import functools if self.subFrame is not None: self.closeSubFrame() self.closeFolder() self.currentFolder = CTabFrame(self,folderFunction=folderFunction,title=title,attributes=attributes,drawFolder=drawFolder) if len(toggle)>0: if len(toggle) == 1: self.setToggle(self.currentFolder,toggle[0],'open',[True]) elif len(toggle) == 2: self.setToggle(self.currentFolder,toggle[0],toggle[1],[True]) else: self.setToggle(self.currentFolder,toggle[0],toggle[1],toggle[2]) if len(toggleFunction)>0: self.setToggle(self.currentFolder,toggleFunction=toggle[0],parameterList=toggle[1]) self.currentFolderLayout = QtGui.QVBoxLayout() self.currentFolderLayout.setSpacing(MARGIN) self.currentFolderLayout.setContentsMargins(MARGIN,MARGIN,MARGIN,MARGIN) self.currentFolder.frame.setLayout(self.currentFolderLayout) if folderFunction == 'inputData': self.createJobTitle(followFrom=keywords.get('followFrom',True)) return self.currentFolder def closeFolder(self): if self.subFrame is not None: self.closeSubFrame() if self.tabWidget is not None: self.closeTabFrame() if self.currentFolder is not None: if self.currentFolder.folderFunction == 'inputData': self.createPatchFrame() self.currentFolderLayout.addStretch(1) self.currentFolder.frame.show() #self.currentFolder.setLayout(self.currentFolderLayout) self.addTab(self.currentFolder,self.currentFolder.title) self.setTabToolTip(self.count()-1,self.currentFolder.title) if ['inputData'].count(self.currentFolder.folderFunction) !=0: self.currentFolder.updateStatus() self.currentFolder = None self.currentFolderLayout = None def getWidget(self,name): # findChild only finds stuff in top tab?? return self.parent().getWidget(name) def validate(self): # This is probably broken!! totInvalid = 0 for i in range(self.count()): frame = self.widget(i) nInvalid = 0 widgetList = frame.findChildren(CCP4Widgets.CViewWidget) #print 'CTabFolder.validate widgetList',widgetList for widget in widgetList: if widget.validate() is not None: nInvalid + widget.validate() #print 'CTabFolder.validate nInvalid',nInvalid if nInvalid>0: print 'INVALID FRAME' frame.setTabColour('red') totInvalid = totInvalid + nInvalid else: frame.setTabColour('black') return totInvalid def resetJobCombos(self): import CCP4Widgets #print 'CTabTaskWidget.resetJobCombos' for i in range(self.count()): frame = self.widget(i) widgetList = frame.findChildren(CCP4Widgets.CViewWidget) for widget in widgetList: if isinstance(widget,CCP4Widgets.CDataFileView): widget.loadJobCombo() widget.updateJobCombo() widget.updateModelFromView() #--------------------------------------------------------------------- class CTabFrame(QtGui.QFrame): #--------------------------------------------------------------------- def __init__(self,parent=None,folderFunction='general',title='Folder',attributes={},drawFolder=None): QtGui.QFrame.__init__(self,parent) self.setObjectName(title) self._drawFolder = drawFolder self.title = title self.folderFunction = folderFunction self._attributes = attributes self.dataObjects = {} self.setLayout(QtGui.QVBoxLayout()) self.layout().setContentsMargins(0,0,0,0) self.layout().setSpacing(0) self.scrollArea= QtGui.QScrollArea(self) self.layout().addWidget(self.scrollArea) self.frame = QtGui.QFrame() self.scrollArea.setWidget(self.frame) self.scrollArea.setWidgetResizable(1) self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) def hide(self): tab = self.parent().parent() indx = tab.indexOf(self) if tab.currentIndex() == indx: tab.setCurrentIndex(0) tab.setTabEnabled(indx,False) def show(self): tab = self.parent().parent() indx = tab.indexOf(self) tab.setTabEnabled(indx,True) def setTabColour(self,colour): tab = self.parent().parent() indx = tab.indexOf(self) tab.tabBar().setTabTextColor(indx,QtGui.QColor(colour)) def updateStatus(self,dataObjectName=None): #print 'CTabFrame.updateStatus',dataObjectName allSet = True for key,obj in self.dataObjects.items(): #print 'CTabFrame.updateStatus testing',key,obj.validity().report() if obj.validity(obj.get()).maxSeverity()>SEVERITY_WARNING: allSet = False break if allSet: self.setTabColour('black') else: self.setTabColour('red') #--------------------------------------------------------------------- class CStackedWidget(QtGui.QStackedWidget): #--------------------------------------------------------------------- # This did not work - nothing displayed despite all diagnostic output correct def __init__(self,parent=None,controlVar=None): self.controlVar = controlVar QtGui.QStackedWidget.__init__(self,parent) controlWidget = self.parent().getWidget(self.controlVar) #print 'CStackedWidget.__init__',controlWidget.model if controlWidget is not None: self.connect(controlWidget.model,QtCore.SIGNAL('dataChanged'),self.update) def parentTaskWidget(self): parent = self.parent() while 1: if isinstance(parent,CTaskWidget): return parent if isinstance(parent,QtGui.QMainWindow): return None parent=parent.parent() def update(self): # I'd not expected to have to go up so far - has Qt reparented? controlWidget = self.parentTaskWidget().getWidget(self.controlVar) #print 'CStackedWidget.update',self.controlVar,controlWidget if controlWidget is None: return value = controlWidget.model.get() valueList = controlWidget.model.qualifiers('enumerators') #print 'CStackedWidget.update',value,valueList if value in valueList: indx = valueList.index(value) #print 'CStackedWidget.update',value,indx self.setCurrentIndex(indx) #--------------------------------------------------------------------- class CStackedLayout(QtGui.QStackedLayout): #--------------------------------------------------------------------- def __init__(self,parent=None,controlVar=None): self.controlVar = controlVar QtGui.QStackedLayout.__init__(self) controlWidget = parent.getWidget(self.controlVar) #print 'CStackedLayout.__init__',controlWidget.model if controlWidget is not None: self.connect(controlWidget.model,QtCore.SIGNAL('dataChanged'),self.update) def parentTaskWidget(self): parent = self.parentWidget() while 1: if isinstance(parent,CTaskWidget): return parent if isinstance(parent,QtGui.QMainWindow): return None parent=parent.parent() def update(self): # I'd not expected to have to go up so far - has Qt reparented? #print 'CStackedLayout.update',self.parentWidget() controlWidget = self.parentTaskWidget().getWidget(self.controlVar) #print 'CStackedLayout.update',self.controlVar,controlWidget if controlWidget is None: return value = controlWidget.model.get() valueList = controlWidget.model.qualifiers('enumerators') #print 'CStackedWidget.update',value,valueList if value in valueList: indx = valueList.index(value) #print 'CStackedLayout.update',value,indx self.setCurrentIndex(indx) #=========================================================================================================== import unittest def TESTSUITE(): suite = unittest.defaultTestLoader.loadTestsFromTestCase(testTaskWidget) return suite def runAllTests(): suite = TESTSUITE() unittest.TextTestRunner(verbosity=2).run(suite) #------------------------------------------------------------------- class CSummatTask(CFolderTaskWidget): #------------------------------------------------------------------- # Subclass CTaskWidget to give specific task window def __init__(self,parent): CTaskWidget.__init__(self,parent=None) def drawContents(self): #self.setProgramHelpFile('fft') #self.openFolder(folderFunction='protocol') self.openFolder(title='Test folder') #self.createTitleLine() self.createLine( [ 'widget', 'nCycles', 'label','cycles with cutoff', 'widget','cutoff' ] ) self.createLine( [ 'label', 'Range of gubbins', 'widget', 'range' ] ) #class testTaskWidget(unittest.TestCase): class testTaskWidget(): def __init__(self): self.setUp() def setUp(self): from PyQt4 import QtGui from CCP4Modules import QTAPPLICATION import sys self.app = QTAPPLICATION() self.window = QtGui.QMainWindow() def test1(self): from CCP4Container import CContainer summat = CContainer(parent=self.app,definitionFile='/Users/lizp/Desktop/dev/ccp4i2/sandpit/summat.contents.xml') self.assertEqual(len(summat.CONTENTS),4,'Container - Wrong content length') self.assertEqual(summat.gubbins.startValue,12.0,'Container - sub-container CFloat wrong initial value') def test2(self): from CCP4Container import CContainer import sys self.container = CContainer(parent=self.app,definitionFile='/Users/lizp/Desktop/dev/ccp4i2/sandpit/summat.contents.xml') self.task = CSummatTask(self.window) self.task.setContainer(self.container) self.task.draw() self.window.setCentralWidget(self.task) self.window.show() sys.exit(self.app.exec_()) def tearDown(self): self.app.quit()