コード例 #1
0
class AbstractViewController(QWidget):
    """
    Provides a base class for the individual data views (plot/table/sensitiviy table).
    Each of the views can have its own UI. This class here is just a set of common methods.
    """

    def __init__(self, parent):
        super(AbstractViewController, self).__init__(parent)

    def _initialize(self):
        self.dataService = DataService()
        self.experimentalData = None
        self.simulationData = None
        self.dataSourceTableModel = None
        self.dataSourceIDs = []
        self.allData = None
        self.dataSources = None

    def updateDataSources(self, dataSources, dataID=None):
        """

        Gets the data files that were produced by the last integration run
        and invokes updating the data source table and the data tabs (plot/table).

        The data structure for the data model is a dict:
        {'source ID': [list of data IDs, e.g. GnrH, ...]}
        """
        self.dataSources = dataSources
        if not self.dataSources:
            logging.info("No data sources, nothing to be shown.")
            return
            
        logging.info("Updating data sources...")

        self.dataSourceIDs = []

        if type(self.dataSources) is list:
            try:
                combinedDataSource = OrderedDict()
                for source in self.dataSources:
                    for key, value in source.items():
                        if not value.isSelected():
                            continue
                        origin = value.getId()
                        if not origin in self.dataSourceIDs:
                            self.dataSourceIDs.append(origin)

                        if key in combinedDataSource:
                            logging.debug("AbstractViewController: Duplicate key encountered while merging data sources for display.")
                        combinedDataSource[key] = value
                self.dataSources = combinedDataSource
            except:
                logging.error("AbstractViewController: Could not combine several datasource dictionaries into one.")

        if dataID:
            singledataSource = OrderedDict()
            singledataSource[dataID] = self.dataSources[dataID]
            self.dataSources = singledataSource

        if self.dataSourceTableModel:
            self.dataSourceTableModel.dataChanged.disconnect(self.on_dataSourcesChanged)

        self.dataSourceTableModel = DataSourcesTableModel(self.dataSources)
        self.dataSourceTableView.setModel(self.dataSourceTableModel)

        # use header with checkboxes
        selectableTableHeaderHorizontal = SelectableTableHeader(Qt.Horizontal, self.dataSourceTableView)
        selectableTableHeaderHorizontal.setNonSelectableIndexes([0])
        selectableTableHeaderHorizontal.sectionSelectionChanged.connect(self.on_columnSelectionChanged)
#        selectableTableHeaderHorizontal.connectSelectionModel(self.dataSourceTableModel)
        self.dataSourceTableView.setHorizontalHeader(selectableTableHeaderHorizontal)

        selectableTableHeaderVertical = SelectableTableHeader(Qt.Vertical, self.dataSourceTableView)
        selectableTableHeaderVertical.sectionSelectionChanged.connect(self.on_rowSelectionChanged)
#        selectableTableHeaderVertical.connectSelectionModel(self.dataSourceTableModel)
        self.dataSourceTableView.setVerticalHeader(selectableTableHeaderVertical)

        self.dataSourceTableView.resizeColumnsToContents()

        self.dataSourceTableModel.dataChanged.connect(self.on_dataSourcesChanged)

        self.on_dataSourcesChanged(None, None)


    def on_dataSourcesChanged(self, upperLeftIndex, lowerRightIndex):
        # for now, we disregard lowerRightIndex
        self._updateDataView() # update everything

    def getNumberOfDataItems(self):
        if self.dataSourceTableModel:
            return self.dataSourceTableModel.getNumberOfDataItems()

    def getEntityIDs(self):
        if self.dataSourceTableModel:
            return self.dataSourceTableModel.getEntityIDs()



    def getSourceIDs(self):
        if self.dataSourceTableModel:
            return self.dataSourceTableModel.getSourceIDs()

    def getSelectedCombinations(self):
        if self.dataSourceTableModel:
            return self.dataSourceTableModel.getSelectedCombinations()

    def hasData(self, dataSet):
        if not self.dataSources:
            return False
        return True if dataSet in self.dataSources.values() else False


    def _updateDataView(self):
        if not self.dataSourceTableModel:
            return
        
        selectedData = self._getSelectedData()
        if not selectedData:
            logging.info("No data, nothing to be shown.")
            self._clearView()
            return

        self._updateView(selectedData)


    def _getSelectedData(self):
        """
        Returns an ordered dictionary view of the selected data
        items - the returned dictionary is a key-based sorted version
        of all data entries
        """
        if not self.allData:    # only get actual data the first time
            self.allData = OrderedDict()
            allData = self.dataService.get_all_data()
            # 23.07.12 td:
            # do a deep copy here; in order to get the different abstract views independent of each other!
            for key in allData.keys():
                self.allData[key] = allData[key]
            
        selectedIDs = self.dataSourceTableModel.getSelectedIDs() # this returns a dict {ID: ("Simulation", "filename1", ...)}
        selectedData = {}
        for i, (selectedID, sources) in enumerate(selectedIDs.items()):
            for source in sources:
                if not self.allData.has_key(source):
                    continue
                dataOfSource = self.allData[source]
                dataOfID = dataOfSource.getData(selectedID)
                if not dataOfID:
                    continue
                if selectedID in selectedData:
                    selectedData[selectedID].append(dataOfID)
                else:
                    selectedData[selectedID] = [dataOfID]

        return selectedData#OrderedDict(sorted(selectedData.items(), key=lambda t:t[0]))


    def _updateView(self, data):
        """
        Needs to be overridden.

        Should update the data view (plot, table, ...).
        """
        logging.debug("The _updateView method has not been overridden.")

    def _clearView(self):
        """
        Needs to be overridden.

        Should clear the data view (plot, table, ...).
        """
        logging.debug("The _clearView method has not been overridden.")

    def _selectAllSources(self, doSelect, column=None, row=None):
        if self.dataSourceTableModel:
            self.dataSourceTableModel.selectAllSources(doSelect, column, row)


    def _invertSourceSelection(self):
        if self.dataSourceTableModel:
            self.dataSourceTableModel.invertSelection()


    @Slot("")
    def on_actionSave_triggered(self):
        """
        Needs to be overriden.

        Should show a dialog to save the currently shown data (table, plot, ...).
        """
        logging.debug("The on_actionSave_triggered method has not been overridden.")


    @Slot("")
    def on_actionSelectAll_triggered(self):
        """
        Selects all sources.

        NOTE: Repeat this method in the actual class implementation!
        The self.setupUi() in the actual class doesn't seem to be able
        to wire the base classe (this class). This worked in PyQT but
        doesn't work in PySide.
        """
        self._selectAllSources(True)

    @Slot("")
    def on_actionDeselectAll_triggered(self):
        """
        Deselects all sources.

        NOTE: Repeat this method in the actual class implementation!
        The self.setupUi() in the actual class doesn't seem to be able
        to wire the base classe (this class). This worked in PyQT but
        doesn't work in PySide.
        """
        self._selectAllSources(False)

    @Slot("")
    def on_actionInvertSelection_triggered(self):
        """
        Inverts the current source selection.

        NOTE: Repeat this method in the actual class implementation!
        The self.setupUi() in the actual class doesn't seem to be able
        to wire the base classe (this class). This worked in PyQT but
        doesn't work in PySide.
        """
        self._invertSourceSelection()

    def on_columnSelectionChanged(self, index, selectionState):
        if selectionState == Qt.Checked:
            selected = True
        elif selectionState == Qt.Unchecked:
            selected = False
        else:   # selection is Qt.PartiallyChecked -> no update of selections here
            return
        self._selectAllSources(selected, column=index)

    def on_rowSelectionChanged(self, index, selectionState):
        if selectionState == Qt.Checked:
            selected = True
        elif selectionState == Qt.Unchecked:
            selected = False
        else:   # selection is Qt.PartiallyChecked -> no update of selections here
            return
        self._selectAllSources(selected, row=index)