diff --git a/Orange/widgets/evaluate/owpredictions.py b/Orange/widgets/evaluate/owpredictions.py index 119409f54ed..21338127a2f 100644 --- a/Orange/widgets/evaluate/owpredictions.py +++ b/Orange/widgets/evaluate/owpredictions.py @@ -119,14 +119,14 @@ def __init__(self): childrenCollapsible=False, handleWidth=2, ) - self.dataview = QtGui.QTableView( + self.dataview = TableView( verticalScrollBarPolicy=Qt.ScrollBarAlwaysOn, horizontalScrollBarPolicy=Qt.ScrollBarAlwaysOn, horizontalScrollMode=QtGui.QTableView.ScrollPerPixel, selectionMode=QtGui.QTableView.NoSelection, focusPolicy=Qt.StrongFocus ) - self.predictionsview = QtGui.QTableView( + self.predictionsview = TableView( verticalScrollBarPolicy=Qt.ScrollBarAlwaysOff, horizontalScrollBarPolicy=Qt.ScrollBarAlwaysOn, horizontalScrollMode=QtGui.QTableView.ScrollPerPixel, @@ -286,7 +286,13 @@ def _update_predictions_model(self): predmodel.setDynamicSortFilter(True) self.predictionsview.setItemDelegate(PredictionsItemDelegate()) self.predictionsview.setModel(predmodel) - self.predictionsview.horizontalHeader().setSortIndicatorShown(False) + hheader = self.predictionsview.horizontalHeader() + hheader.setSortIndicatorShown(False) + # SortFilterProxyModel is slow due to large abstraction overhead + # (every comparison triggers multiple `model.index(...)`, + # model.rowCount(...), `model.parent`, ... calls) + hheader.setClickable(predmodel.rowCount() < 20000) + predmodel.layoutChanged.connect(self._update_data_sort_order) self._update_data_sort_order() self.predictionsview.resizeColumnsToContents() @@ -758,6 +764,52 @@ def headerData(self, section, orientation, role=Qt.DisplayRole): PredictionsModel = _TableModel +class TableView(QtGui.QTableView): + MaxSizeHintSamples = 1000 + + def sizeHintForColumn(self, column): + """ + Reimplemented from `QTableView.sizeHintForColumn` + + Note: This does not match the QTableView's implementation, + in particular size hints from editor/index widgets are not taken + into account. + + Parameters + ---------- + column : int + """ + # This is probably not needed in Qt5? + if self.model() is None: + return -1 + + self.ensurePolished() + model = self.model() + vheader = self.verticalHeader() + top = vheader.visualIndexAt(0) + bottom = vheader.visualIndexAt(self.viewport().height()) + if bottom < 0: + bottom = self.rowCount(column) + + options = self.viewOptions() + options.widget = self + + width = 0 + sample_count = 0 + + for row in range(top, bottom): + if not vheader.isSectionHidden(vheader.logicalIndex(row)): + index = model.index(row, column) + size = self.itemDelegate(index).sizeHint(options, index) + width = max(size.width(), width) + sample_count += 1 + + if sample_count >= TableView.MaxSizeHintSamples: + break + + return width + 1 if self.showGrid() else width + + class TableSortProxyModel(QtGui.QSortFilterProxyModel): def __init__(self, parent=None): super().__init__(parent)