# -*- 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]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
# 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()