def _setupLongrunningCalculation(self,msg,numForProgress): self.setEnabled(False) QtGui.QApplication.setOverrideCursor(Qt.QCursor(QtCore.Qt.WaitCursor)) # create a progress that is shown in the main stack (where usually the plot is shown) self.progresswidget=MyProgressWidget(msg,numForProgress) self.clswidgets.mainstack.addWidget(self.progresswidget) self.clswidgets.mainstack.setCurrentIndex(1) self.clswidgets.statusbar.setVisible(False)
class ODMainWindow(QtGui.QMainWindow): def __init__(self): super(ODMainWindow, self).__init__() self.initUI() def initUI(self): self.clswidgets=ClsWidgets() self.clswidgets.statusbar=self.statusBar() self.newAction = QtGui.QAction('&New', self) self.newAction.setShortcut(QtGui.QKeySequence.New) self.newAction.setStatusTip('Create new project from plate files.') self.newAction.triggered.connect(self.newClsFromPlatefilesChoose) self.openAction = QtGui.QAction('&Open', self) self.openAction.setShortcut(QtGui.QKeySequence.Open) self.openAction.setStatusTip('Open file.') self.openAction.triggered.connect(self.openSerialisedClsChoose) self.reloadAction = QtGui.QAction('&Reload', self) self.reloadAction.setShortcut(QtGui.QKeySequence.Refresh) self.reloadAction.setStatusTip('Reload plate files.') self.reloadAction.triggered.connect(self.clswidgets.reload) self.saveAsAction = QtGui.QAction('Save as', self) self.saveAsAction.setShortcut(QtGui.QKeySequence.SaveAs) self.saveAsAction.setStatusTip('Save data.') self.saveAsAction.triggered.connect(self.saveAs) self.saveAction = QtGui.QAction('Save', self) self.saveAction.setShortcut(QtGui.QKeySequence.Save) self.saveAction.setStatusTip('Save data.') self.saveAction.triggered.connect(self.save) self.savePdfAction = QtGui.QAction('Export &figure', self) self.savePdfAction.setStatusTip('Save a figure of viabilities/survival integrals.') self.savePdfAction.triggered.connect(self.savePdf) self.saveCsvAction = QtGui.QAction('Export &properties', self) self.saveCsvAction.setStatusTip('Save a table containing viabilities/survival integrals.') self.saveCsvAction.triggered.connect(self.saveCsv) self.closeAction = QtGui.QAction('&Close', self) self.closeAction.setShortcut(QtGui.QKeySequence.Close) self.closeAction.setStatusTip('Close file.') self.closeAction.triggered.connect(self.close) self.exitAction = QtGui.QAction('&Exit', self) self.exitAction.setShortcut(QtGui.QKeySequence.Quit) self.exitAction.setStatusTip('Exit.') self.exitAction.triggered.connect(self.quit) menubar = self.menuBar() fileMenu = menubar.addMenu('&File') fileMenu.addAction(self.newAction) fileMenu.addAction(self.openAction) fileMenu.addAction(self.reloadAction) fileMenu.addAction(self.saveAsAction) fileMenu.addAction(self.saveAction) fileMenu.addAction(self.saveCsvAction) fileMenu.addAction(self.savePdfAction) fileMenu.addAction(self.closeAction) fileMenu.addAction(self.exitAction) self.aboutAction = QtGui.QAction('&About', self) self.aboutAction.triggered.connect(self.showAbout) helpMenu = menubar.addMenu('&Help') helpMenu.addAction(self.aboutAction) self.mainwidget=QtGui.QWidget(self) mainwidgetLayout=QtGui.QVBoxLayout() self.mainwidget.setLayout(mainwidgetLayout) self.setCentralWidget(self.mainwidget) self.graphsnchooser = QtGui.QSplitter(QtCore.Qt.Horizontal,self.mainwidget) mainwidgetLayout.addWidget(self.graphsnchooser) self.graphsnchooser.setSizePolicy(Qt.QSizePolicy.Expanding, Qt.QSizePolicy.Expanding) self.graphsnchooser.addWidget(self.clswidgets.clsView) self.graphsnchooser.addWidget(self.clswidgets.mainstack) self.graphsnchooser.setStretchFactor(0,1) self.graphsnchooser.setStretchFactor(1,4) self.setGeometry(100, 100, 1024, 600) self.clear() self.show() def clear(self): self.newAction.setEnabled(True) self.openAction.setEnabled(True) self.reloadAction.setEnabled(False) self.saveAsAction.setEnabled(False) self.saveAction.setEnabled(False) self.saveCsvAction.setEnabled(False) self.savePdfAction.setEnabled(False) self.closeAction.setEnabled(False) self.exitAction.setEnabled(True) self.saveFilename=None self.clswidgets.clear() self._setWindowTitle() def enDisableActionsAfterLoading(self): self.newAction.setEnabled(False) self.openAction.setEnabled(False) self.reloadAction.setEnabled(True) self.saveAsAction.setEnabled(True) self.saveAction.setEnabled(True) self.saveCsvAction.setEnabled(True) self.savePdfAction.setEnabled(True) self.closeAction.setEnabled(True) self.exitAction.setEnabled(True) def _setWindowTitle(self): wtitle='' if self.clswidgets.cls is not None: if self.saveFilename is not None: wtitle=os.path.basename(self.saveFilename)+' - ' elif (self.clswidgets.platefiles is not None and len(self.clswidgets.platefiles) and self.clswidgets.days is not None and len(self.clswidgets.days)): wtitle=os.path.basename(self.clswidgets.platefiles[0])+' day '+'{:g}'.format(self.clswidgets.days[0])+', ... - ' self.setWindowTitle(wtitle+'Chronological life span Analysis Tool (CATHODE)') def newClsFromPlatefilesChoose(self): dialog=ClsWidgets.ClsFromPlateFilesDialog(self.clswidgets,self.clswidgets.platefiles,self.clswidgets.days) if dialog.exec_() == QtGui.QDialog.Accepted: self.newClsFromPlatefiles(dialog.platefiles,dialog.days) def newClsFromPlatefiles(self,platefiles,days): try: self.clswidgets.loadCls(platefiles,days) self.enDisableActionsAfterLoading() except Cls.Error as err: QtGui.QMessageBox.warning(self,'Error loading file',str(err)) return 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 QtGui.QMessageBox.warning(self,'Unknown error',msg) self._setWindowTitle() def openSerialisedClsChoose(self): self.close() fname = QtGui.QFileDialog.getOpenFileName(self, 'Open file', '', 'Cls data (*.cat)') if len(fname) == 0: return condition="" self.openSerialisedCls(str(fname)) def openSerialisedCls(self,catfilename): self.close() if not os.path.exists(catfilename): QtGui.QMessageBox.warning(self,'Error loading file',catfilename+' does not exist.') self.clear() return try: self.clswidgets.loadSerialisedCls(catfilename) self.saveFilename=catfilename self.enDisableActionsAfterLoading() except (Cls.Error, Plate.Error) as err: QtGui.QMessageBox.warning(self,'Error loading file',str(err)) return 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 QtGui.QMessageBox.warning(self,'Unknown error',msg) self._setWindowTitle() def saveAs(self): if self.clswidgets.cls is None: return fname = str(getSaveFileNameDialogWithDefaultSuffix(self, 'Save file', '', 'CLS data (*.cat)', 'cat')) if len(fname) == 0: return self.saveFilename=fname self.saveAction.setEnabled(True) self._setWindowTitle() return self._save() def save(self): if self.saveFilename is None: return self.saveAs() else: return self._save() def _save(self): try: savestatus=self.clswidgets.cls.saveLightweight(self.saveFilename) if savestatus is not None: QtGui.QMessageBox.warning(self,savestatus.messageType(),savestatus.longmessage()) return True except (Cls.Error, Plate.Error) as err: QtGui.QMessageBox.warning(self,'Error saving datafile',str(err)) odplate_=None 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 QtGui.QMessageBox.warning(self,'Unknown error',msg) odplate_=None return False def close(self): if self.clswidgets.cls is not None and self.clswidgets.cls.modified: ret=QtGui.QMessageBox.question(self,"CLS Analysis Tool (CATHODE)", "The document has been modified.\n" +"Do you want to save your changes?", QtGui.QMessageBox.Save | QtGui.QMessageBox.Discard | QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Save) if ret == QtGui.QMessageBox.Save: if not self.save(): return False elif ret == QtGui.QMessageBox.Cancel: return False #elif ret == QtGui.QMessageBox.Discard: self.clear() return True def quit(self): if self.close(): QtGui.qApp.quit() def saveCsv(self): if self.clswidgets.cls is None: return fname = str(getSaveFileNameDialogWithDefaultSuffix(self, 'Save file', '', 'csv (*.csv)', 'csv')) if len(fname) == 0: return # create progress bar, do not allow to press buttons, etc self._setupLongrunningCalculation('Saving table',len(self.clswidgets.cls.clsReplicateGroups)) # run the real calculation try: self.clswidgets.cls.survivalToCsv(fname,progressCall=self._updateProgress) except Exception as err: exc_type, exc_value, exc_tb = sys.exc_info() msg=str(err)+"\n" if msg is None: msg='' for line in traceback.format_exception(exc_type, exc_value, exc_tb): msg+=line QtGui.QMessageBox.warning(self,'An error occurred',msg) # clean up: remove progress bar, enable buttons etc self._longrunningCalculationFinished() def savePdf(self): if self.clswidgets.cls is None: return # ask what to export: currently selected one or all CLS replicate groups dialog=ClsWidgets.PdfDialog() dialog.show() if not dialog.exec_(): return # ask for filename fname = str(getSaveFileNameDialogWithDefaultSuffix(self, 'Save file', '', 'pdf (*.pdf)', 'pdf')) if len(fname) == 0: return if dialog.currentOrAllRadios.checkedId() == 0: # currently selected elementaryIndices=[] replicateGroupIndices=[] select=self.clswidgets.currentViewSelectionAsDict() addWellIdsToTitle=False if select['row1'] is None: replicateGroupIndices=[select['row0']] else: elementaryIndices=[self.clswidgets.cls.clsReplicateGroups[select['row0']].childWellIndices()[select['row1']]] addWellIdsToTitle=True platereader.clsplot.viabilitiesToPdf(self.clswidgets.cls, fname, showTitle=dialog.showTitle.checkState(), addWellIdsToTitle=addWellIdsToTitle, creator=os.path.basename(sys.argv[0]), replicateGroupIndices=replicateGroupIndices, elementaryIndices=elementaryIndices) elif dialog.currentOrAllRadios.checkedId() == 1: # all replicates # create progress bar, do not allow to press buttons, etc self._setupLongrunningCalculation('Saving figures',self.clswidgets.cls.numberOfNonBackgroundCls()) try: platereader.clsplot.viabilitiesToPdf(self.clswidgets.cls, fname, showTitle=dialog.showTitle.checkState(), creator=os.path.basename(sys.argv[0]), replicateGroupIndices=[], addWellIdsToTitle=False,progressCall=self._updateProgress) except Exception as err: exc_type, exc_value, exc_tb = sys.exc_info() msg=str(err)+"\n" if msg is None: msg='' for line in traceback.format_exception(exc_type, exc_value, exc_tb): msg+=line QtGui.QMessageBox.warning(self,'An error occurred',msg) # clean up: remove progress bar, enable buttons etc self._longrunningCalculationFinished() else: raise RuntimeError('PdfDialog: unknown selection') def _setupLongrunningCalculation(self,msg,numForProgress): self.setEnabled(False) QtGui.QApplication.setOverrideCursor(Qt.QCursor(QtCore.Qt.WaitCursor)) # create a progress that is shown in the main stack (where usually the plot is shown) self.progresswidget=MyProgressWidget(msg,numForProgress) self.clswidgets.mainstack.addWidget(self.progresswidget) self.clswidgets.mainstack.setCurrentIndex(1) self.clswidgets.statusbar.setVisible(False) def _longrunningCalculationFinished(self): self.clswidgets.statusbar.setVisible(True) self.clswidgets.mainstack.setCurrentIndex(0) self.clswidgets.mainstack.removeWidget(self.progresswidget) self.progresswidget=None self.setEnabled(True) self.enDisableActionsAfterLoading() QtGui.QApplication.restoreOverrideCursor() def _updateProgress(self,intval): self.progresswidget.updateProgress(intval) QtGui.QApplication.processEvents() def showAbout(self): agpllicense=("This program is free software: you can redistribute it and/or modify " +"it under the terms of the GNU Affero General Public License as " +"published by the Free Software Foundation, either version 3 of the " +"License, or (at your option) any later version.") msgBox=QtGui.QMessageBox.about(self,'Chronological life span Analysis Tool (CATHODE)', 'Chronological life span Analysis Tool for High-throughput Optical Density Experiments (CATHODE)\nversion ' +__version__ +'\nCopyright (C) 2014 Nils Christian\n'+ agpllicense)