def __init__(self): self.tableModel=None self.clsView=DeselectableTreeView() self.mplcnvs=MyMplCanvas() self.mainstack=QtGui.QStackedWidget() self.mainstack.addWidget(self.mplcnvs) self.navigationWidget=QtGui.QWidget() self.ntb=NavigationToolbar(self.mplcnvs,self.navigationWidget) self.statusbar=None self.statusbarWidgets=[] self.clear()
class ClsWidgets(object): """ Plot widgets, dialogs an the like needed for Chronological Life Span analysis """ def __init__(self): self.tableModel=None self.clsView=DeselectableTreeView() self.mplcnvs=MyMplCanvas() self.mainstack=QtGui.QStackedWidget() self.mainstack.addWidget(self.mplcnvs) self.navigationWidget=QtGui.QWidget() self.ntb=NavigationToolbar(self.mplcnvs,self.navigationWidget) self.statusbar=None self.statusbarWidgets=[] self.clear() def clear(self): self.mplcnvs.fig.clear() self.mplcnvs.draw() self.statusToStatusBar(None) self.clsView.setModel(EmptyModel()) self.tableModel=None self.platefiles=[] self.days=[] self.cls=None def disconnect(self): """ NOTE this cannot be inside clear as disconnect fails if nothing is bound """ if self.tableModel is not None: self.tableModel.dataChanged.disconnect() def setCls(self,cls,select={'row0': 0,'row1': None}): self.cls=cls self.tableModel=ODplateModel(self.cls) self.tableModel.dataChanged.connect(self.updatePlateFig) self.clsView.setModel(self.tableModel) self.clsView.header().setResizeMode(0, Qt.QHeaderView.ResizeToContents) self.clsView.header().setResizeMode(1, Qt.QHeaderView.ResizeToContents) self.clsView.selectionModel().selectionChanged.connect(self.selectionChanged) self.clsView.setFocus() self._setSample(self.cls) if select is not None: if select['row1'] is None: selectIndex=self.tableModel.index(select['row0'],0,self.clsView.currentIndex()) else: parentIndex=self.tableModel.index(select['row0'],0,self.clsView.currentIndex()) selectIndex=self.tableModel.index(select['row1'],0,parentIndex) self.clsView.setCurrentIndex(selectIndex) def loadSerialisedCls(self,catfilename): try: self.cls=Cls(None,None,serialisedFilename=catfilename) self.platefiles=self.cls.files self.days=self.cls.days self.setCls(self.cls) except Exception as err: self.cls=None self.platefiles=None self.days=None raise def loadCls(self,files,days,select={'row0': 0,'row1': None}): if files is None or days is None: return if len(files) != len(days): QtGui.QMessageBox.warning(Qt.qApp.activeWindow(),'Could not load plates', 'Could not load plates because number of plates does not equal number of days') else: self.platefiles=files self.days=days self.cls=Cls(files,days) self.setCls(self.cls,select) def currentViewSelectionAsDict(self): sel=self.clsView.selectedIndexes() select=None if sel is not None and len(sel) > 0: if sel[0].parent().isValid(): select={ 'row0': sel[0].parent().row(), 'row1': sel[0].row()} else: select={ 'row0': sel[0].row(), 'row1': None} return select def reload(self): # let mouse cursor appear busy QtGui.QApplication.setOverrideCursor(Qt.QCursor(QtCore.Qt.WaitCursor)) # store selection of QTreeView select=self.currentViewSelectionAsDict() self.disconnect() # store state of QTreeView expState=storeViewExpandState(self.clsView,self.tableModel) # reload and restore selection self.cls.reload() self.setCls(self.cls,select) # restore state of QTreeView restoreViewExpandState(self.clsView,self.tableModel,expState) # mouse cursor should not be busy anymore QtGui.QApplication.restoreOverrideCursor() def selectionChanged(self,selected,deselected): """ the model view selection changed """ if len(selected.indexes()): selindex=selected.indexes()[0] tc=selindex.internalPointer()._itemData self._setSample(tc) else: self._setSample(self.cls) def _setSample(self,tc): self.selectedClsObject=tc self.updatePlateFig() def statusToStatusBar(self,status): if self.statusbar is None: return # clear previous statuses for st in self.statusbarWidgets: self.statusbar.removeWidget(st) self.statusbarWidgets=[] if status is None: return type2status=status.type2status() thekeys=list(type2status.keys()) thekeys.sort() for sttype in thekeys: if type2status[sttype].severity() is Severity.warning: continue # handled below ql=QtGui.QLabel() ql.setText(type2status[sttype].shortmessage()) ql.setToolTip(type2status[sttype].longmessage()) self.statusbar.addPermanentWidget(ql) self.statusbarWidgets.append(ql) for sttype in thekeys: if type2status[sttype].severity() is not Severity.warning: continue # handled above ql=QtGui.QLabel() ql.setText(type2status[sttype].shortmessage()) ql.setToolTip(type2status[sttype].longmessage()) ql.setStyleSheet("color: red") self.statusbar.addPermanentWidget(ql) self.statusbarWidgets.append(ql) def updatePlateFig(self): self.mplcnvs.fig.clear() self.statusToStatusBar(None) if self.selectedClsObject is None: return QtGui.QApplication.setOverrideCursor(Qt.QCursor(QtCore.Qt.WaitCursor)) try: status=StatusMessage() if isinstance(self.selectedClsObject, ClsReplicate): status=platereader.clsplot.viabilityToMatplotlib(self.selectedClsObject,self.mplcnvs.fig) self.mplcnvs.fig.tight_layout() self.mplcnvs.draw() self.statusToStatusBar(status) QtGui.QApplication.restoreOverrideCursor() except Exception as err: msg=str(err)+"\n" if msg is None: msg='' exc_type, exc_value, exc_tb = sys.exc_info() for line in traceback.format_exception(exc_type, exc_value, exc_tb): msg+=line self.mplcnvs.fig.clear() self.mplcnvs.draw() self.statusToStatusBar(None) QtGui.QApplication.restoreOverrideCursor() QtGui.QMessageBox.warning(self.mainstack,'Unknown error',msg) return class ClsFromPlateFilesDialog(QtGui.QDialog): def __init__(self,clswidgets,files=[],days=[]): super(ClsWidgets.ClsFromPlateFilesDialog, self).__init__() self.setWindowTitle('CLS files and days') self.clswidgets=clswidgets self.platefiles=files self.days=days self.lastSelectedDirectory=RememberLastVisistedDirectory('') # self.tableOfFileNDayLayout=QtGui.QVBoxLayout() self.setupTableOfFiles() self.addButtonLayout=QtGui.QHBoxLayout() self.addButton=QtGui.QPushButton("+") self.addButton.setMinimumWidth(40) self.addButton.setMinimumWidth(40) self.addButton.clicked.connect(self.addFileDay) self.addButtonLayout.addWidget(self.addButton) self.addButtonLayout.addStretch() self.cancelButton=QtGui.QPushButton("Cancel") self.okButton=QtGui.QPushButton("Ok") self.cancelButton.setMinimumWidth(80) self.cancelButton.setMaximumWidth(80) self.okButton.setMinimumWidth(80) self.okButton.setMaximumWidth(80) self.cancelButton.clicked.connect(self.close) self.okButton.clicked.connect(self.saveSettingsAndClose) self.okCancelLayout=QtGui.QHBoxLayout() self.okCancelLayout.addStretch() self.okCancelLayout.addWidget(self.cancelButton) self.okCancelLayout.addWidget(self.okButton) self.mainlayout=QtGui.QVBoxLayout() self.mainlayout.addLayout(self.tableOfFileNDayLayout) self.mainlayout.addLayout(self.addButtonLayout) self.mainlayout.addLayout(self.okCancelLayout) self.setLayout(self.mainlayout) def setupTableOfFiles(self): if self.platefiles is not None and self.days is not None and len(self.platefiles) == len(self.days): for idx in range(0,len(self.platefiles)): self.tableOfFileNDayLayout.addLayout(FileLineEditChooserNDayEdit(self.lastSelectedDirectory, self.platefiles[idx], str(self.days[idx]))) if os.path.exists(self.platefiles[idx]): self.lastSelectedDirectory.setDir(os.path.dirname(self.platefiles[idx])) self.tableOfFileNDayLayout.addLayout(FileLineEditChooserNDayEdit(self.lastSelectedDirectory)) def addFileDay(self): self.tableOfFileNDayLayout.addLayout(FileLineEditChooserNDayEdit(self.lastSelectedDirectory)) def saveSettingsAndClose(self): self.platefiles=[] self.days=[] for i in range(0,self.tableOfFileNDayLayout.count()): filename=str(self.tableOfFileNDayLayout.itemAt(i).fileLineEdit.existingFilename()) day, ok=self.tableOfFileNDayLayout.itemAt(i).dayEdit.text().toDouble() if filename is not None and ok: self.platefiles.append(filename) self.days.append(day) self.accept() class PdfDialog(QtGui.QDialog): def __init__(self): super(ClsWidgets.PdfDialog, self).__init__() self.setWindowTitle('Save pdf options') self.currentOrAllRadios=QtGui.QButtonGroup() r1=QtGui.QRadioButton('Current selection') r2=QtGui.QRadioButton('All') r1.setChecked(True) self.currentOrAllRadios.addButton(r1) self.currentOrAllRadios.addButton(r2) self.currentOrAllRadios.setId(r1,0) self.currentOrAllRadios.setId(r2,1) currentOrAllGroupbox=QtGui.QGroupBox('CLS to export') grly=QtGui.QVBoxLayout() grly.addWidget(r1) grly.addWidget(r2) currentOrAllGroupbox.setLayout(grly) self.showTitle=QtGui.QCheckBox("Add title") self.showTitle.setToolTip("Add a title consisting of 'sample-condition' to figures.") showLayout=QtGui.QVBoxLayout() showLayout.addWidget(self.showTitle) showGroup=QtGui.QGroupBox('Figure options') showGroup.setLayout(showLayout) allLayout=QtGui.QHBoxLayout() allLayout.addWidget(currentOrAllGroupbox) allLayout.addWidget(showGroup) allGroup=QtGui.QGroupBox('') allGroup.setLayout(allLayout) buttonlayout=QtGui.QHBoxLayout() okButton=QtGui.QPushButton("Ok") okButton.setDefault(True) cancelButton=QtGui.QPushButton("Cancel") buttonlayout.addWidget(cancelButton) buttonlayout.addWidget(okButton) cancelButton.clicked.connect(self.reject) okButton.clicked.connect(self.accept) self.mainlayout=QtGui.QVBoxLayout() self.mainlayout.addWidget(allGroup) self.mainlayout.addLayout(buttonlayout) self.setLayout(self.mainlayout)