コード例 #1
0
ファイル: clsgui.py プロジェクト: chiffa/gathode
 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)
コード例 #2
0
ファイル: clsgui.py プロジェクト: chiffa/gathode
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)