Example #1
0
    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)
Example #2
0
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)