Пример #1
0
    def __init__(self, parent=None, plot=None):
        TableWidget.__init__(self, parent)
        _StatsWidgetBase.__init__(self,
                                  statsOnVisibleData=False,
                                  displayOnlyActItem=False)

        # Init for _displayOnlyActItem == False
        assert self._displayOnlyActItem is False
        self.setSelectionBehavior(qt.QAbstractItemView.SelectRows)
        self.setSelectionMode(qt.QAbstractItemView.SingleSelection)
        self.currentItemChanged.connect(self._currentItemChanged)

        self.setRowCount(0)
        self.setColumnCount(2)

        # Init headers
        headerItem = qt.QTableWidgetItem('Legend')
        headerItem.setData(qt.Qt.UserRole, self._LEGEND_HEADER_DATA)
        self.setHorizontalHeaderItem(0, headerItem)
        headerItem = qt.QTableWidgetItem('Kind')
        headerItem.setData(qt.Qt.UserRole, self._KIND_HEADER_DATA)
        self.setHorizontalHeaderItem(1, headerItem)

        self.setSortingEnabled(True)
        self.setPlot(plot)
Пример #2
0
    def __init__(self, parent, plot):
        TableWidget.__init__(self, parent)
        _StatsWidgetBase.__init__(self,
                                  statsOnVisibleData=False,
                                  displayOnlyActItem=False)
        self.__region_edition_callback = {}
        """We need to keep trace of the roi signals connection because
        the roi emits the sigChanged during roi edition"""
        self._items = {}
        self.setRowCount(0)
        self.setColumnCount(3)

        # Init headers
        headerItem = qt.QTableWidgetItem(self._LEGEND_HEADER_DATA.title())
        headerItem.setData(qt.Qt.UserRole, self._LEGEND_HEADER_DATA)
        self.setHorizontalHeaderItem(0, headerItem)
        headerItem = qt.QTableWidgetItem(self._KIND_HEADER_DATA.title())
        headerItem.setData(qt.Qt.UserRole, self._KIND_HEADER_DATA)
        self.setHorizontalHeaderItem(1, headerItem)
        headerItem = qt.QTableWidgetItem(self._ROI_HEADER_DATA.title())
        headerItem.setData(qt.Qt.UserRole, self._ROI_HEADER_DATA)
        self.setHorizontalHeaderItem(2, headerItem)

        self.setSortingEnabled(True)
        self.setPlot(plot)

        self.__plotItemToItems = {}
        """Key is plotItem, values is list of __RoiStatsItemWidget"""
        self.__roiToItems = {}
        """Key is roi, values is list of __RoiStatsItemWidget"""
        self.__roisKeyToRoi = {}
Пример #3
0
    def _getItem(self, name, legend, kind, indexTable):
        if (legend, kind) not in self._lgdAndKindToItems:
            self._lgdAndKindToItems[(legend, kind)] = {}
        if not (name in self._lgdAndKindToItems[(legend, kind)]
                and self._lgdAndKindToItems[(legend, kind)]):
            if name in ('legend', 'kind'):
                _item = qt.QTableWidgetItem(type=qt.QTableWidgetItem.Type)
                if name == 'legend':
                    _item.setText(legend)
                else:
                    assert name == 'kind'
                    _item.setText(kind)
            else:
                if self._statsHandler.formatters[name]:
                    _item = self._statsHandler.formatters[
                        name].tabWidgetItemClass()
                else:
                    _item = qt.QTableWidgetItem()
                tooltip = self._statsHandler.stats[name].getToolTip(kind=kind)
                if tooltip is not None:
                    _item.setToolTip(tooltip)

            _item.setFlags(qt.Qt.ItemIsEnabled | qt.Qt.ItemIsSelectable)
            self.setItem(indexTable, self._columns_index[name], _item)
            self._lgdAndKindToItems[(legend, kind)][name] = _item

        return self._lgdAndKindToItems[(legend, kind)][name]
Пример #4
0
    def addRecord(self):
        currentRow = self.table.currentRow()
        self.table.insertRow(currentRow + 1)
        item = qt.QTableWidgetItem("SampleName")
        item.setTextAlignment(qt.Qt.AlignCenter | qt.Qt.AlignVCenter)
        self.table.setItem(currentRow + 1, 0, item)

        for n, data in enumerate([1, 1]):
            item = qt.QTableWidgetItem(str(data))
            item.setTextAlignment(qt.Qt.AlignCenter | qt.Qt.AlignVCenter)
            self.table.setItem(currentRow + 1, n + 1, item)

        self.table.itemChanged.connect(self.check_validity)
Пример #5
0
    def __fillScansInfos(self):
        """
        Fills the QTableWidget with info found in the input file
        """
        converter = self.__converter
        if converter is None:
            return

        scans = converter.scans
        scansTable = self.__scansTable
        scansTable.setRowCount(len(scans))
        for row, scan in enumerate(scans):
            params = converter.scan_params(scan)
            item = Qt.QTableWidgetItem(scan)
            item.setFlags(item.flags() ^ Qt.Qt.ItemIsEditable)
            scansTable.setItem(row, 0, item)
            item = Qt.QTableWidgetItem(str(params['angle']))
            item.setFlags(item.flags() ^ Qt.Qt.ItemIsEditable)
            scansTable.setItem(row, 1, item)

        scansTable.resizeColumnsToContents()
        width = (sum([
            scansTable.columnWidth(i) for i in range(scansTable.columnCount())
        ]) + scansTable.verticalHeader().width() + 20)
        # TODO : the size is wrong when the
        # verticalScrollBar isnt displayed yet
        # scans_table.verticalScrollBar().width())
        size = scansTable.minimumSize()
        size.setWidth(width)
        scansTable.setMinimumSize(size)

        # TODO : warning if the ROI is empty (too small to contain images)
        params = converter.scan_params(scans[0])
        roi = converter.roi
        if roi is None:
            xMin = xMax = yMin = yMax = 'ns'
        else:
            xMin, xMax, yMin, yMax = roi

        self.__roiXMinEdit.setText(str(xMin))
        self.__roiXMaxEdit.setText(str(xMax))
        self.__roiYMinEdit.setText(str(yMin))
        self.__roiYMaxEdit.setText(str(yMax))

        indices = converter.sample_indices
        nImgTxt = '{0} / {1}'.format(len(indices), params['n_images'])
        self.__nImgLabel.setText(nImgTxt)

        nEntries = len(XsocsH5(self.__params['xsocsH5_f']).entries())
        self.__nAnglesLabel.setText('{0} / {1}'.format(len(scans), nEntries))
Пример #6
0
    def addUrl(self, url, **kwargs):
        """

        :param url: 
        :param args: 
        :return: index of the created items row
        :rtype int
        """
        assert isinstance(url, DataUrl)
        row = self.rowCount()
        self.setRowCount(row + 1)

        _item = qt.QTableWidgetItem()
        _item.setText(os.path.basename(url.path()))
        _item.setFlags(qt.Qt.ItemIsEnabled | qt.Qt.ItemIsSelectable)
        self.setItem(row, self.COLUMS_INDEX['url'], _item)

        widgetImgA = qt.QRadioButton(parent=self)
        widgetImgA.setAutoExclusive(False)
        self.setCellWidget(row, self.COLUMS_INDEX['img A'], widgetImgA)
        callbackImgA = functools.partial(self._activeImgAChanged, url.path())
        widgetImgA.toggled.connect(callbackImgA)

        widgetImgB = qt.QRadioButton(parent=self)
        widgetImgA.setAutoExclusive(False)
        self.setCellWidget(row, self.COLUMS_INDEX['img B'], widgetImgB)
        callbackImgB = functools.partial(self._activeImgBChanged, url.path())
        widgetImgB.toggled.connect(callbackImgB)

        self._checkBoxes[url.path()] = {
            'img A': widgetImgA,
            'img B': widgetImgB
        }
        self.resizeColumnsToContents()
        return row
Пример #7
0
    def setStats(self, statsHandler):
        """Set which stats to display and the associated formatting.

        :param StatsHandler statsHandler:
            Set the statistics to be displayed and how to format them using
        """
        self._removeAllItems()
        _StatsWidgetBase.setStats(self, statsHandler)

        self.setRowCount(0)
        self.setColumnCount(len(self._statsHandler.stats) +
                            2)  # + legend and kind

        for index, stat in enumerate(self._statsHandler.stats.values()):
            headerItem = qt.QTableWidgetItem(stat.name.capitalize())
            headerItem.setData(qt.Qt.UserRole, stat.name)
            if stat.description is not None:
                headerItem.setToolTip(stat.description)
            self.setHorizontalHeaderItem(2 + index, headerItem)

        horizontalHeader = self.horizontalHeader()
        if hasattr(horizontalHeader, 'setSectionResizeMode'):  # Qt5
            horizontalHeader.setSectionResizeMode(
                qt.QHeaderView.ResizeToContents)
        else:  # Qt4
            horizontalHeader.setResizeMode(qt.QHeaderView.ResizeToContents)

        self._updateItemObserve()
    def updatePlotItems(self):
        self._clear()

        nrows = len(
            self.plot._getItems(kind=self.plot_item_kinds, just_legend=True))
        self.setRowCount(nrows)

        # respect order of kinds as set in method setKindsFilter
        i = 0
        for kind in self.plot_item_kinds:
            for plot_item in self.plot._getItems(kind=kind):
                legend_twitem = qt.QTableWidgetItem(plot_item.getLegend())
                self.setItem(i, 0, legend_twitem)

                kind_twitem = qt.QTableWidgetItem(kind)
                self.setItem(i, 1, kind_twitem)
                i += 1
Пример #9
0
    def updatePlotItems(self):
        self._clear()

        # respect order of kinds as set in method setKindsFilter
        itemsAndKind = []
        for kind in self.plot_item_kinds:
            itemClasses = self.plot._KIND_TO_CLASSES[kind]
            for item in self.plot.getItems():
                if isinstance(item, itemClasses) and item.isVisible():
                    itemsAndKind.append((item, kind))

        self.setRowCount(len(itemsAndKind))

        for index, (item, kind) in enumerate(itemsAndKind):
            legend_twitem = qt.QTableWidgetItem(item.getName())
            self.setItem(index, 0, legend_twitem)

            kind_twitem = qt.QTableWidgetItem(kind)
            self.setItem(index, 1, kind_twitem)
Пример #10
0
    def __init__(self, merger, **kwargs):
        super(_ScansInfoDialog, self).__init__(**kwargs)
        layout = Qt.QVBoxLayout(self)

        no_match = merger.no_match_ids
        no_img = merger.no_img_ids

        table_widget = Qt.QTableWidget(len(no_match) + len(no_img), 2)

        for num, scan_id in enumerate(no_match):
            item = Qt.QTableWidgetItem(scan_id)
            table_widget.setItem(num, 0, item)

            item = Qt.QTableWidgetItem('Image file not found.')
            item.setFlags(item.flags() ^ Qt.Qt.ItemIsEditable)
            table_widget.setItem(num, 1, item)

        offset = len(no_match)

        for num, scan_id in enumerate(no_img):
            item = Qt.QTableWidgetItem(scan_id)
            item.setFlags(item.flags() ^ Qt.Qt.ItemIsEditable)
            table_widget.setItem(num + offset, 0, item)

            item = Qt.QTableWidgetItem('No image info in header.')
            item.setFlags(item.flags() ^ Qt.Qt.ItemIsEditable)
            table_widget.setItem(num + offset, 1, item)

        table_widget.resizeColumnsToContents()
        table_widget.resizeRowsToContents()
        table_widget.sortByColumn(0, Qt.Qt.AscendingOrder)

        layout.addWidget(table_widget)

        bn_box = Qt.QDialogButtonBox(Qt.QDialogButtonBox.Close)

        layout.addWidget(bn_box)
        bn_box.rejected.connect(self.reject)
Пример #11
0
    def setData(self):
        try:
            self.table.itemChanged.disconnect()
        except:
            pass

        # Delete data
        self.table.setRowCount(0)

        self.table.setColumnCount(len(self.column_labels))
        self.table.setHorizontalHeaderLabels(self.column_labels)

        for row, label in enumerate(self.lbl):
            self.table.insertRow(row)
            item = qt.QTableWidgetItem(label)
            item.setTextAlignment(qt.Qt.AlignCenter | qt.Qt.AlignVCenter)
            self.table.setItem(row, 0, item)

            for n, data in enumerate(self.data[row]):
                item = qt.QTableWidgetItem(str(data))
                item.setTextAlignment(qt.Qt.AlignCenter | qt.Qt.AlignVCenter)
                self.table.setItem(row, n + 1, item)

        self.table.itemChanged.connect(self.highlight)
    def setField(self, parameter, fields, edit_flags):
        """Set text and flags in a table cell.

        :param parameter: Fit parameter names identifying the rows
        :type parameter: str or list[str]
        :param fields: Field names identifying the columns
        :type fields: str or list[str]
        :param edit_flags: Flag combination, e.g::

            qt.Qt.ItemIsSelectable | qt.Qt.ItemIsEnabled |
            qt.Qt.ItemIsEditable
        """
        if isinstance(parameter, list) or \
           isinstance(parameter, tuple):
            paramlist = parameter
        else:
            paramlist = [parameter]
        if isinstance(fields, list) or \
           isinstance(fields, tuple):
            fieldlist = fields
        else:
            fieldlist = [fields]

        # Set _configuring flag to ignore cellChanged signals in
        # self.onCellChanged
        _oldvalue = self.__configuring
        self.__configuring = True

        # 2D loop through parameter list and field list
        # to update their cells
        for param in paramlist:
            row = list(self.parameters.keys()).index(param)
            for field in fieldlist:
                col = self.columnIndexByField(field)
                if field != 'code':
                    key = field + "_item"
                    item = self.item(row, col)
                    if item is None:
                        item = qt.QTableWidgetItem()
                        item.setText(self.parameters[param][field])
                        self.setItem(row, col, item)
                    else:
                        item.setText(self.parameters[param][field])
                    self.parameters[param][key] = item
                    item.setFlags(edit_flags)

        # Restore previous _configuring flag
        self.__configuring = _oldvalue
Пример #13
0
    def _addItem(self, item):
        """
        Add a _RoiStatsItemWidget item to the table.
        
        :param item: 
        :return: True if successfully added.
        """
        if not isinstance(item, ROIStatsItemHelper):
            # skipped because also receive all new plot item (Marker...) that
            # we don't want to manage in this case.
            return
        # plotItem = item.getItem()
        # roi = item.getROI()
        kind = item.item_kind()
        if kind not in statsmdl.BASIC_COMPATIBLE_KINDS:
            _logger.info("Item has not a supported type: %s", item)
            return False

        # register the roi and the kind
        self._registerPlotItem(item)
        self._registerROI(item)

        # Prepare table items
        tableItems = [
            qt.QTableWidgetItem(),  # Legend
            qt.QTableWidgetItem(),  # Kind
            qt.QTableWidgetItem()
        ]  # roi

        for column in range(3, self.columnCount()):
            header = self.horizontalHeaderItem(column)
            name = header.data(qt.Qt.UserRole)

            formatter = self._statsHandler.formatters[name]
            if formatter:
                tableItem = formatter.tabWidgetItemClass()
            else:
                tableItem = qt.QTableWidgetItem()

            tooltip = self._statsHandler.stats[name].getToolTip(kind=kind)
            if tooltip is not None:
                tableItem.setToolTip(tooltip)

            tableItems.append(tableItem)

        # Disable sorting while adding table items
        with self._disableSorting():
            # Add a row to the table
            self.setRowCount(self.rowCount() + 1)

            # Add table items to the last row
            row = self.rowCount() - 1
            for column, tableItem in enumerate(tableItems):
                tableItem.setData(qt.Qt.UserRole, _Container(item))
                tableItem.setFlags(qt.Qt.ItemIsEnabled
                                   | qt.Qt.ItemIsSelectable)
                self.setItem(row, column, tableItem)

            # Update table items content
            self._updateStats(item, data_changed=True)

        # Listen for item changes
        # Using queued connection to avoid issue with sender
        # being that of the signal calling the signal
        item._plot_item.sigItemChanged.connect(self._plotItemChanged,
                                               qt.Qt.QueuedConnection)
        return True
Пример #14
0
    def __init__(self, merger, **kwargs):
        super(_ScansSelectDialog, self).__init__(**kwargs)
        layout = Qt.QGridLayout(self)

        matched = merger.matched_ids
        selected = merger.selected_ids

        table_widget = Qt.QTableWidget(len(matched), self.COL_COUNT)
        table_widget.setHorizontalHeaderLabels([
            '', 'ID', 'M0', 'start', 'end', 'step', 'M1', 'start', 'end',
            'step', 'Image File'
        ])

        def _sizeHint(self):
            width = (
                sum([self.columnWidth(i) for i in range(self.columnCount())]) +
                self.verticalHeader().width() + 20)
            return Qt.QSize(width, self.height())

        table_widget.sizeHint = MethodType(_sizeHint, table_widget)
        table_widget.minimumSize = MethodType(_sizeHint, table_widget)
        table_widget.maximumSize = MethodType(_sizeHint, table_widget)
        self.setSizePolicy(
            Qt.QSizePolicy(Qt.QSizePolicy.Fixed, Qt.QSizePolicy.Minimum))

        for num, scan_id in enumerate(matched):
            command = merger.get_scan_command(scan_id)

            item = Qt.QTableWidgetItem()
            item.setFlags(Qt.Qt.ItemIsUserCheckable | Qt.Qt.ItemIsEditable
                          | Qt.Qt.ItemIsSelectable | Qt.Qt.ItemIsEnabled)
            state = Qt.Qt.Checked if scan_id in selected else Qt.Qt.Unchecked
            item.setCheckState(state)
            table_widget.setItem(num, self.SEL_COL, item)

            def _add_col(value, col_idx):
                item = Qt.QTableWidgetItem(value)
                item.setFlags(item.flags() ^ Qt.Qt.ItemIsEditable)
                item.setTextAlignment(Qt.Qt.AlignRight)
                table_widget.setItem(num, col_idx, item)

            _add_col(str(scan_id), self.ID_COL)
            _add_col(command['motor_0'], self.M0_COL)
            _add_col(command['motor_0_start'], self.M0_START_COL)
            _add_col(command['motor_0_end'], self.M0_END_COL)
            _add_col(command['motor_0_steps'], self.M0_STEP_COL)
            _add_col(command['motor_1'], self.M1_COL)
            _add_col(command['motor_1_start'], self.M1_START_COL)
            _add_col(command['motor_1_end'], self.M1_END_COL)
            _add_col(command['motor_1_steps'], self.M1_STEP_COL)

            img_file = merger.get_scan_image(scan_id)
            item = Qt.QTableWidgetItem(os.path.basename(img_file))
            item.setFlags(item.flags() ^ Qt.Qt.ItemIsEditable)
            item.setToolTip(img_file)
            table_widget.setItem(num, self.IMG_FILE_COL, item)

        table_widget.resizeColumnsToContents()
        table_widget.resizeRowsToContents()
        layout.addWidget(table_widget, 0, 0, Qt.Qt.AlignLeft)

        table_widget.setColumnHidden(self.M0_COL, True)
        table_widget.setColumnHidden(self.M0_START_COL, True)
        table_widget.setColumnHidden(self.M0_END_COL, True)
        table_widget.setColumnHidden(self.M0_STEP_COL, True)
        table_widget.setColumnHidden(self.M1_COL, True)
        table_widget.setColumnHidden(self.M1_START_COL, True)
        table_widget.setColumnHidden(self.M1_END_COL, True)
        table_widget.setColumnHidden(self.M1_STEP_COL, True)

        bnLayout = Qt.QGridLayout()
        layout.addLayout(bnLayout, 1, 0)

        selBn = Qt.QPushButton('Select')
        unselBn = Qt.QPushButton('Unselect')
        bnLayout.addWidget(selBn, 0, 0, Qt.Qt.AlignLeft)
        bnLayout.addWidget(unselBn, 0, 1, Qt.Qt.AlignLeft)
        selBn.clicked.connect(self.__selectClicked)
        unselBn.clicked.connect(self.__unselectClicked)
        bnLayout.setColumnStretch(2, 1)

        more_bn = FixedSizePushButon('More')
        bnLayout.addWidget(more_bn, 0, 3, Qt.Qt.AlignRight)

        bn_box = Qt.QDialogButtonBox(Qt.QDialogButtonBox.Ok
                                     | Qt.QDialogButtonBox.Cancel)
        bn_box.button(Qt.QDialogButtonBox.Ok).setText('Apply')

        layout.addWidget(bn_box, 2, 0)
        bn_box.accepted.connect(self.__onAccept)
        bn_box.rejected.connect(self.reject)
        more_bn.clicked.connect(self.__showMore)

        self.__table_widget = table_widget
        self.__more_bn = more_bn
        self.__merger = merger
    def __init__(self, parent=None, paramlist=None):
        TableWidget.__init__(self, parent)
        self.setContentsMargins(0, 0, 0, 0)

        labels = [
            'Parameter', 'Estimation', 'Fit Value', 'Sigma', 'Constraints',
            'Min/Parame', 'Max/Factor/Delta'
        ]
        tooltips = [
            "Fit parameter name",
            "Estimated value for fit parameter. You can edit this column.",
            "Actual value for parameter, after fit",
            "Uncertainty (same unit as the parameter)",
            "Constraint to be applied to the parameter for fit",
            "First parameter for constraint (name of another param or min value)",
            "Second parameter for constraint (max value, or factor/delta)"
        ]

        self.columnKeys = [
            'name', 'estimation', 'fitresult', 'sigma', 'code', 'val1', 'val2'
        ]
        """This list assigns shorter keys to refer to columns than the
        displayed labels."""

        self.__configuring = False

        # column headers and associated tooltips
        self.setColumnCount(len(labels))

        for i, label in enumerate(labels):
            item = self.horizontalHeaderItem(i)
            if item is None:
                item = qt.QTableWidgetItem(label, qt.QTableWidgetItem.Type)
                self.setHorizontalHeaderItem(i, item)

            item.setText(label)
            if tooltips is not None:
                item.setToolTip(tooltips[i])

        # resize columns
        for col_key in ["name", "estimation", "sigma", "val1", "val2"]:
            col_idx = self.columnIndexByField(col_key)
            self.resizeColumnToContents(col_idx)

        # Initialize the table with one line per supplied parameter
        paramlist = paramlist if paramlist is not None else []
        self.parameters = OrderedDict()
        """This attribute stores all the data in an ordered dictionary.
        New data can be added using :meth:`newParameterLine`.
        Existing data can be modified using :meth:`configureLine`

        Keys of the dictionary are:

            -  'name': parameter name
            -  'line': line index for the parameter in the table
            -  'estimation'
            -  'fitresult'
            -  'sigma'
            -  'code': constraint code (one of the elements of
                :attr:`code_options`)
            -  'val1': first parameter related to constraint, formatted
                as a string, as typed in the table
            -  'val2': second parameter related to constraint, formatted
                as a string, as typed in the table
            -  'cons1': scalar representation of 'val1'
                (e.g. when val1 is the name of a fit parameter, cons1
                will be the line index of this parameter)
            -  'cons2': scalar representation of 'val2'
            -  'vmin': equal to 'val1' when 'code' is "QUOTED"
            -  'vmax': equal to 'val2' when 'code' is "QUOTED"
            -  'relatedto': name of related parameter when this parameter
                is constrained to another parameter (same as 'val1')
            -  'factor': same as 'val2' when 'code' is 'FACTOR'
            -  'delta': same as 'val2' when 'code' is 'DELTA'
            -  'sum': same as 'val2' when 'code' is 'SUM'
            -  'group': group index for the parameter
            -  'xmin': data range minimum
            -  'xmax': data range maximum
        """
        for line, param in enumerate(paramlist):
            self.newParameterLine(param, line)

        self.code_options = [
            "FREE", "POSITIVE", "QUOTED", "FIXED", "FACTOR", "DELTA", "SUM",
            "IGNORE", "ADD"
        ]
        """Possible values in the combo boxes in the 'Constraints' column.
        """

        # connect signal
        self.cellChanged[int, int].connect(self.onCellChanged)
Пример #16
0
 def _add_col(value, col_idx):
     item = Qt.QTableWidgetItem(value)
     item.setFlags(item.flags() ^ Qt.Qt.ItemIsEditable)
     item.setTextAlignment(Qt.Qt.AlignRight)
     table_widget.setItem(num, col_idx, item)
Пример #17
0
    def _addItem(self, item):
        """Add a plot item to the table

        If item is not supported, it is ignored.

        :param item: The plot item
        :returns: True if the item is added to the widget.
        :rtype: bool
        """
        if self._itemToRow(item) is not None:
            _logger.info("Item already present in the table")
            self._updateStats(item)
            return True

        kind = self._plotWrapper.getKind(item)
        if kind not in statsmdl.BASIC_COMPATIBLE_KINDS:
            _logger.info("Item has not a supported type: %s", item)
            return False

        # Prepare table items
        tableItems = [
            qt.QTableWidgetItem(),  # Legend
            qt.QTableWidgetItem()
        ]  # Kind

        for column in range(2, self.columnCount()):
            header = self.horizontalHeaderItem(column)
            name = header.data(qt.Qt.UserRole)

            formatter = self._statsHandler.formatters[name]
            if formatter:
                tableItem = formatter.tabWidgetItemClass()
            else:
                tableItem = qt.QTableWidgetItem()

            tooltip = self._statsHandler.stats[name].getToolTip(kind=kind)
            if tooltip is not None:
                tableItem.setToolTip(tooltip)

            tableItems.append(tableItem)

        # Disable sorting while adding table items
        with self._disableSorting():
            # Add a row to the table
            self.setRowCount(self.rowCount() + 1)

            # Add table items to the last row
            row = self.rowCount() - 1
            for column, tableItem in enumerate(tableItems):
                tableItem.setData(qt.Qt.UserRole, _Container(item))
                tableItem.setFlags(qt.Qt.ItemIsEnabled
                                   | qt.Qt.ItemIsSelectable)
                self.setItem(row, column, tableItem)

            # Update table items content
            self._updateStats(item)

        # Listen for item changes
        # Using queued connection to avoid issue with sender
        # being that of the signal calling the signal
        item.sigItemChanged.connect(self._plotItemChanged,
                                    qt.Qt.QueuedConnection)

        return True