Source code for wbia.guitool.guitool_tables

# -*- coding: utf-8 -*-
# DEPRICATE?
from __future__ import absolute_import, division, print_function
from wbia.guitool.__PYQT__ import QtCore, QtGui
from wbia.guitool.__PYQT__ import QtWidgets
from wbia.guitool.__PYQT__.QtCore import Qt
from wbia.guitool.guitool_delegates import ComboDelegate, ButtonDelegate
from wbia.guitool import qtype
from six.moves import range, map
import utool

(print, rrr, profile) = utool.inject2(__name__)


[docs]class ColumnListTableView(QtWidgets.QTableView): """ Table View for an AbstractItemModel """ def __init__(view, *args, **kwargs): super(ColumnListTableView, view).__init__(*args, **kwargs) view.setSortingEnabled(True) view.vertical_header = view.verticalHeader() view.vertical_header.setVisible(True) # view.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows) view.resizeColumnsToContents()
[docs] @QtCore.pyqtSlot() def cellButtonClicked(self): print(self.sender()) print(self.sender().text())
[docs]class ColumnListItemModel(QtCore.QAbstractTableModel): """ Item model for displaying a list of columns """ # # Non-Qt Init Functions def __init__( model, col_data_list=None, col_name_list=None, niceheader_list=None, col_type_list=None, col_edit_list=None, display_indices=False, col_sort_index=None, parent=None, *args, ): super(ColumnListItemModel, model).__init__() model.sortcolumn = None model.sortreverse = False model.display_indices = False # FIXME: Broken model._change_data( col_data_list, col_name_list, niceheader_list, col_type_list, col_edit_list, display_indices, col_sort_index, ) def _change_data( model, col_data_list=None, col_name_list=None, niceheader_list=None, col_type_list=None, col_edit_list=None, display_indices=False, col_sort_index=None, ): model.layoutAboutToBeChanged.emit() if col_name_list is None: col_name_list = [] if col_data_list is None: col_data_list = [] if len(col_data_list) > 0: model.sortcolumn = 0 # print('[model] Changing data') # Set the data to display (list of lists) model._change_columns(col_data_list, col_type_list) # Set the headers model._change_headers(col_name_list, niceheader_list) # Is editable model._change_editable(col_edit_list) # Make internal indices model.set_sorting(col_sort_index) model.display_indices = display_indices model._change_row_indices() # Make sure the user didn't do anything bad model._assert_feasibility() model.layoutChanged.emit() def _change_editable(model, col_edit_list=None): if col_edit_list is None: model.column_editable = [False] * len(model.col_data_list) else: model.column_editable = [ header in col_edit_list for header in model.col_name_list ] # print('[model] new column_editable = %r' % (model.column_editable,)) def _change_headers(model, col_name_list, niceheader_list=None): """ Internal header names """ model.col_name_list = col_name_list # Set user readable "nice" headers, default to internal ones if niceheader_list is None: model.niceheader_list = col_name_list else: model.niceheader_list = niceheader_list # print('[model] new col_name_list = %r' % (model.col_name_list,)) def _change_columns(model, col_data_list, col_type_list=None): model.col_data_list = col_data_list if col_type_list is not None: model.col_type_list = col_type_list else: model.col_type_list = qtype.infer_coltype(model.col_data_list) # print('[model] new col_type_list = %r' % (model.col_type_list,)) def _change_row_indices(model): """ Non-Qt Helper """ if model.sortcolumn is not None: print('using: sortcolumn=%r' % model.sortcolumn) column_data = model.col_data_list[model.sortcolumn] indices = list(range(len(column_data))) model.row_sortx = utool.sortedby( indices, column_data, reverse=model.sortreverse ) elif len(model.col_data_list) > 0: model.row_sortx = list(range(len(model.col_data_list[0]))) else: model.row_sortx = [] # print('[model] new len(row_sortx) = %r' % (len(model.row_sortx),)) def _assert_feasibility(model): assert len(model.col_name_list) == len(model.col_data_list) nrows = list(map(len, model.col_data_list)) assert all([nrows[0] == num for num in nrows]), 'inconsistent data' # print('[model] is feasible') # # # Non-Qt Helper function
[docs] def get_data(model, index): """ Non-Qt Helper """ row = index.row() column = index.column() row_data = model.col_data_list[column] data = row_data[model.row_sortx[row]] return data
[docs] def set_sorting(model, col_sort_index=None, order=Qt.DescendingOrder): model.sortreverse = order == Qt.DescendingOrder if col_sort_index is not None: if utool.is_str(col_sort_index): col_sort_index = model.col_name_list.index(col_sort_index) assert utool.is_int(col_sort_index), 'sort by an index not %r' % type( col_sort_index ) model.sortcolumn = col_sort_index assert model.sortcolumn < len(model.col_name_list), 'outofbounds' print('sortcolumn: %r' % model.sortcolumn)
[docs] def set_data(model, index, data): """ Non-Qt Helper """ row = index.row() column = index.column() row_data = model.col_data_list[column] row_data[model.row_sortx[row]] = data
[docs] def get_header(model, column): """ Non-Qt Helper """ return model.col_name_list[column]
[docs] def get_header_data(model, header, row): """ Non-Qt Helper """ column = model.col_name_list.index(header) index = model.index(row, column) data = model.get_data(index) return data
[docs] def get_coltype(model, column): type_ = model.col_type_list[column] return type_
[docs] def get_editable(model, column): return model.column_editable[column]
[docs] def get_niceheader(model, column): """ Non-Qt Helper """ return model.niceheader_list[column]
[docs] def get_column_alignment(model, column): coltype = model.get_coltype(column) if coltype in utool.VALID_FLOAT_TYPES: return Qt.AlignRight else: return Qt.AlignHCenter
# # # Qt AbstractItemTable Overrides
[docs] def rowCount(model, parent=QtCore.QModelIndex()): """ Qt Override """ return len(model.row_sortx)
[docs] def columnCount(model, parent=QtCore.QModelIndex()): """ Qt Override """ return len(model.col_name_list)
[docs] def index(model, row, column, parent=QtCore.QModelIndex()): """ Qt Override """ return model.createIndex(row, column)
[docs] def data(model, index, role=Qt.DisplayRole): """ Returns the data to display """ if not index.isValid(): return None flags = model.flags(index) if role == Qt.TextAlignmentRole: return model.get_column_alignment(index.column()) if role == Qt.BackgroundRole and ( flags & Qt.ItemIsEditable or flags & Qt.ItemIsUserCheckable ): return QtCore.QVariant(QtGui.QColor(250, 240, 240)) if role == Qt.DisplayRole or role == Qt.CheckStateRole: data = model.get_data(index) var = qtype.cast_into_qt(data, role, flags) return var else: return QtCore.QVariant()
[docs] def setData(model, index, var, role=Qt.EditRole): """ Sets the role data for the item at index to var. var is a QVariant (called data in documentation) """ print('[model] setData: %r' % (str(qtype.qindexinfo(index)))) try: if not index.isValid(): return None flags = model.flags(index) if not (flags & Qt.ItemIsEditable or flags & Qt.ItemIsUserCheckable): return None if role == Qt.CheckStateRole: type_ = 'QtCheckState' data = var == Qt.Checked elif role != Qt.EditRole: return False else: # Cast var into datatype type_ = model.get_coltype(index.column()) data = qtype.cast_from_qt(var, type_) # Do actual setting of data print(' * new_data = %s(%r)' % (utool.type_str(type_), data,)) model.set_data(index, data) # Emit that data was changed and return succcess model.dataChanged.emit(index, index) return True except Exception as ex: var_ = str(var.toString()) # NOQA utool.printex(ex, 'ignoring setData', '[model]', key_list=['var_']) # raise # print(' * ignoring setData: %r' % locals().get('var', None)) return False
[docs] def headerData(model, section, orientation, role=Qt.DisplayRole): """ Qt Override """ if role == Qt.DisplayRole and orientation == Qt.Horizontal: return model.get_niceheader(section) else: return QtCore.QVariant()
[docs] def sort(model, column, order): """ Qt Override """ model.layoutAboutToBeChanged.emit() model.set_sorting(column, order) model._change_row_indices() model.layoutChanged.emit()
[docs] def flags(model, index): """ Qt Override """ # return Qt.ItemFlag(0) column = index.column() if not model.get_editable(column): return Qt.ItemIsEnabled | Qt.ItemIsSelectable if model.get_coltype(column) in utool.VALID_BOOL_TYPES: return Qt.ItemIsEnabled | Qt.ItemIsUserCheckable else: return Qt.ItemIsEnabled | Qt.ItemIsEditable | Qt.ItemIsSelectable
[docs]class ColumnListTableWidget(QtWidgets.QWidget): """ ColumnList Table Main Widget """ def __init__( cltw, col_data_list=None, col_name_list=None, niceheader_list=None, col_type_list=None, col_edit_list=None, display_indices=False, col_sort_index=None, parent=None, ): super(ColumnListTableWidget, cltw).__init__(parent) # QtWidgets.QWidget.__init__(cltw, parent) # Create vertical layout for the table to go into cltw.vert_layout = QtWidgets.QVBoxLayout(cltw) # Instansiate the AbstractItemModel cltw.model = ColumnListItemModel(parent=cltw) # Create a ColumnListTableView for the AbstractItemModel cltw.view = ColumnListTableView(cltw) cltw.view.setModel(cltw.model) cltw.vert_layout.addWidget(cltw.view) # Make sure we don't call a childs method ColumnListTableWidget.change_data( cltw, col_data_list, col_name_list, niceheader_list, col_type_list, col_edit_list, display_indices, col_sort_index, )
[docs] def change_data( cltw, col_data_list=None, col_name_list=None, niceheader_list=None, col_type_list=None, col_edit_list=None, display_indices=False, col_sort_index=None, ): """ Checks for deligates """ marked_columns = [] # these will be persistantly editable if col_type_list is not None: print('cltw.change_data: %r' % len(col_type_list)) col_type_list = list(col_type_list) for column in range(len(col_type_list)): if isinstance(col_type_list[column], tuple): delegate_type, coltype = col_type_list[column] col_type_list[column] = coltype if cltw.set_column_as_delegate(column, delegate_type): marked_columns.append(column) else: print('cltw.change_data: None') cltw.model._change_data( col_data_list, col_name_list, niceheader_list, col_type_list, col_edit_list, display_indices, col_sort_index, ) # Set persistant editability after data is changed for column in marked_columns: cltw.set_column_persistant_editor(column)
[docs] def set_column_as_delegate(cltw, column, delegate_type): if delegate_type == 'COMBO': print('cltw.set_col_del %r %r' % (column, delegate_type)) cltw.view.setItemDelegateForColumn(column, ComboDelegate(cltw.view)) return True elif delegate_type == 'BUTTON': print('cltw.set_col_del %r %r' % (column, delegate_type)) cltw.view.setItemDelegateForColumn(column, ButtonDelegate(cltw.view)) return False
[docs] def set_column_persistant_editor(cltw, column): """ Set each row in a column as persistant """ num_rows = cltw.model.rowCount() print('cltw.set_persistant: %r rows' % num_rows) for row in range(num_rows): index = cltw.model.index(row, column) cltw.view.openPersistentEditor(index)
[docs] def is_index_clickable(cltw, index): model = index.model() clickable = not (model.flags(index) & QtCore.Qt.ItemIsSelectable) return clickable
[docs] def get_index_header_data(cltw, header, index): model = index.model() return model.get_header_data(header, index.row())
[docs]def make_listtable_widget( col_data_list, col_name_list, col_edit_list=None, show=True, raise_=True, on_click=None, ): widget = ColumnListTableWidget( col_data_list, col_name_list, col_edit_list=col_edit_list ) def on_doubleclick(index): # This is actually a release # print('DoubleClicked: ' + str(qtype.qindexinfo(index))) pass def on_pressed(index): # print('Pressed: ' + str(qtype.qindexinfo(index))) pass def on_activated(index): # print('Activated: ' + str(qtype.qindexinfo(index))) pass if on_click is not None: widget.view.clicked.connect(on_click) widget.view.doubleClicked.connect(on_doubleclick) widget.view.pressed.connect(on_doubleclick) widget.view.activated.connect(on_activated) widget.setGeometry(20, 50, 600, 800) if show: widget.show() if raise_: widget.raise_() return widget
# if __name__ == '__main__': # import sys # app = guitoo.ensure_qtapp() # widget = DummyWidget() # widget.show() # widget.raise_() # sys.exit(app.exec_()) if __name__ == '__main__': r""" CommandLine: python -m wbia.guitool.guitool_tables python -m wbia.guitool.guitool_tables --allexamples """ import multiprocessing multiprocessing.freeze_support() # for win32 import utool as ut # NOQA ut.doctest_funcs()