Added CheckStates to table model

To hold both bool representation and different colors
This commit is contained in:
Artem30801
2020-01-30 19:27:34 +03:00
parent 28a3586a82
commit cfcbfbe9a3
4 changed files with 62 additions and 41 deletions

View File

@@ -13,7 +13,7 @@ import copter_table_models as table
class CopterTableWidget(QTableView):
def __init__(self, model, config):
def __init__(self, model: table.CopterDataModel, config):
QTableView.__init__(self)
self.config = config
@@ -26,7 +26,7 @@ class CopterTableWidget(QTableView):
# Initiate table and table self.model
self.setModel(self.proxy_model)
self.columns = self.model.columns #[header.strip() for header in self.model.headers] # header keys
self.columns = self.model.columns # [header.strip() for header in self.model.headers] # header keys
self.current_columns = self.columns[:]
header = self.horizontalHeader()
@@ -75,6 +75,17 @@ class CopterTableWidget(QTableView):
for name, show in item_dict.items(): # for index, name in enumerate(self.columns):
self.setColumnHidden(self.columns.index(name), not show) # self.setColumnHidden(index, not item_dict.get(name, False))
def select_all(self, state):
for i in self.model.rowCount():
self.model.update_data(i, 0, state, Qt.CheckStateRole)
def toggle_select(self):
if len(list(self.model.user_selected())) == self.model.rowCount(): # if all items are selected
state = Qt.Unchecked
else:
state = Qt.Checked
self.select_all(state)
@pyqtSlot(QtCore.QModelIndex)
def on_double_click(self, index):
col = index.column()
@@ -95,7 +106,7 @@ class CopterTableWidget(QTableView):
def showHeaderMenu(self, event):
menu = QMenu(self)
header_view = HeaderEditWidget(self, self.config, menu_mode=True, parent=menu)
#header_view.setFixedHeight((header_view.geometry().height()-2) * len(header_view.columns))
# header_view.setFixedHeight((header_view.geometry().height()-2) * len(header_view.columns))
# box.setSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
action = QWidgetAction(menu)
action.setDefaultWidget(header_view)

View File

@@ -17,6 +17,23 @@ def get_git_version(): # TODO import from animation
return subprocess.check_output("git log --pretty=format:%h -n 1").decode('UTF-8')
class CheckState:
def __init__(self, bool_state, color):
self._bool = bool_state
self.color = color
self.brush = QtGui.QBrush(self.color)
def __bool__(self):
return self._bool
# State objects providing both boolean and color information for table
# Add more if required
true_state = CheckState(True, Qt.green)
false_state = CheckState(False, Qt.red)
missing_state = CheckState(False, Qt.yellow)
outdated_state = CheckState(False, Qt.magenta)
class ModelChecks:
checks_dict = {}
@@ -46,9 +63,13 @@ class ModelChecks:
column = context.columns[column]
item = context[column]
try:
return cls.checks_dict[column](item, context)
result = cls.checks_dict[column](item, context)
except KeyError: # When there is no check
return None if item is None else True # item is not None
return None if item is None else true_state # item is not None
else:
if isinstance(result, bool):
return true_state if result else false_state
return result
@classmethod
def all_checks(cls, copter_item):
@@ -125,7 +146,7 @@ def check_start_pos(item, context):
def get_position(position):
if position != 'NO_POS' and position[0] != 'nan':
if position != 'NO_POS' and position[0] != 'nan': # float('nan')?
return position
return [float('nan')]*3
@@ -156,6 +177,9 @@ class CopterData:
else:
setattr(self, self.columns[key], value)
def __repr__(self):
return str({key: self[key] for key in self.columns})
class StatedCopterData(CopterData):
def __init__(self, columns=(), checks_defaults=None, checks_class=ModelChecks, **kwargs):
@@ -332,9 +356,7 @@ class CopterDataModel(QtCore.QAbstractTableModel):
self.formatter = formatter
self.data_model = data_model
self.first_col_is_checked = False
self.update_data_signal.connect(self._update_item)
self.update_data_signal.connect(self._update_data)
self.add_client_signal.connect(self._add_client)
self.remove_row_signal.connect(self._remove_row)
self.remove_client_signal.connect(self._remove_row_data)
@@ -351,7 +373,7 @@ class CopterDataModel(QtCore.QAbstractTableModel):
self.beginRemoveRows(QtCore.QModelIndex(), position, position + rows - 1)
self.data_contents = self.data_contents[:position] + self.data_contents[position + rows:]
self.endRemoveRows()
self.emit_signals()
return True
@classmethod
@@ -367,7 +389,6 @@ class CopterDataModel(QtCore.QAbstractTableModel):
def selected_check(self, f, selected=()):
selected = selected or set(self.user_selected())
print(selected and all(f(item) for item in selected))
return bool(selected) and all(f(item) for item in selected) #selected.issubset(self.filter(f))
def get_row_data(self, index):
@@ -411,18 +432,10 @@ class CopterDataModel(QtCore.QAbstractTableModel):
return self.data_contents[row][col]
elif role == Qt.BackgroundRole:
try:
item = self.data_contents[row]
result = item.states[col]
except KeyError:
return QtGui.QBrush(Qt.white)
else:
if result is None:
return QtGui.QBrush(Qt.yellow)
if result:
return QtGui.QBrush(Qt.green)
else:
return QtGui.QBrush(Qt.red)
state = self.data_contents[row].states[col]
if state is None:
state = missing_state
return state.brush
elif role == Qt.CheckStateRole and col == 0:
return self.data_contents[row].states.checked
@@ -430,7 +443,7 @@ class CopterDataModel(QtCore.QAbstractTableModel):
if role == QtCore.Qt.TextAlignmentRole and col != 0:
return QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter
def update_model(self, index=QtCore.QModelIndex(), role=QtCore.Qt.EditRole):
def emit_signals(self):
selected = set(self.user_selected())
self.selected_ready_signal.emit(self.selected_check(lambda x: x.states.all_checks, selected))
@@ -439,8 +452,6 @@ class CopterDataModel(QtCore.QAbstractTableModel):
self.selected_calibrating_signal.emit(self.selected_check(calibrating_check, selected))
self.selected_calibration_ready_signal.emit(self.selected_check(calibration_ready_check, selected))
self.dataChanged.emit(index, index, (role,))
@QtCore.pyqtSlot()
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid():
@@ -470,22 +481,16 @@ class CopterDataModel(QtCore.QAbstractTableModel):
else:
return False
self.update_model(index, role)
self.emit_signals()
self.dataChanged.emit(index, index, (role,))
return True
def select_all(self): # probably NOT thread-safe! TODO remake
self.first_col_is_checked = not self.first_col_is_checked
for row_num, copter in enumerate(self.data_contents):
copter.states.checked = int(self.first_col_is_checked) * 2
self.update_model(self.index(row_num, 0), Qt.CheckStateRole)
def flags(self, index):
roles = Qt.ItemIsSelectable | Qt.ItemIsEnabled
if index.column() == 0:
roles |= Qt.ItemIsUserCheckable | Qt.ItemIsEditable
if self.is_column(index, "config_version"):
roles |= Qt.ItemIsDragEnabled # | Qt.ItemIsDropEnabled
return roles
def supportedDropActions(self):
@@ -529,7 +534,7 @@ class CopterDataModel(QtCore.QAbstractTableModel):
self.update_data_signal.emit(row, col, data, role)
@QtCore.pyqtSlot(int, int, QtCore.QVariant, QtCore.QVariant)
def _update_item(self, row, col, value, role=Qt.EditRole):
def _update_data(self, row, col, value, role=Qt.EditRole):
self.setData(self.index(row, col), value, role)
@QtCore.pyqtSlot(object)
@@ -555,20 +560,25 @@ def takeoff_checks(copter_item):
checklist = ("battery", "fcu_status", "mode", "selfcheck", "current_position")
return check_checklist(copter_item, checklist)
def flip_checks(copter_item):
checklist = ("battery", "mode", "current_position")
if not check_checklist(copter_item, checklist):
return False
if copter_item["fcu_status"] != "ACTIVE":
return False
return True
# for col in checklist:
# if not copter_item.state[col]: # ModelChecks.check(col, copter_item):
# return False
def calibrating_check(copter_item):
return copter_item["calibration_status"] == "CALIBRATING"
def calibration_ready_check(copter_item):
if not copter_item.states["fcu_status"]: # ModelChecks.check("fcu_status", copter_item):
return False
return not calibrating_check(copter_item)
@@ -632,9 +642,12 @@ if __name__ == '__main__':
#myModel._add_client(StatedCopterData(copter_id=1000, checked=0, selfcheck=msgs, time_utc=1))
#myModel._add_client(StatedCopterData(checked=2, selfcheck="OK", time_utc=2))
#myModel._add_client(StatedCopterData(checked=2, selfcheck="not ok", time_utc="no"))
myModel.add_client(copter_id=1000, client=None, git_version='11318ca', selfcheck=msgs)
#myModel.setData(myModel.index(0, 1), "test")
# t = threading.Thread(target=timer, daemon=True)
#t.start()
print(QtCore.QT_VERSION_STR)
print(get_git_version())
myModel.update_data(0, 3, [1, 2], role=Qt.EditRole)
app.exec_()

View File

@@ -144,11 +144,6 @@ class MainWindow(QtWidgets.QMainWindow):
self.init_table()
# Set most safety-important buttons disabled
self.ui.start_button.setEnabled(False)
self.ui.takeoff_button.setEnabled(False)
self.ui.flip_button.setEnabled(False)
def init_table(self):
# Remove standard table widget
self.ui.horizontalLayout.removeWidget(self.ui.tableView)
@@ -179,6 +174,9 @@ class MainWindow(QtWidgets.QMainWindow):
self.model.selected_calibration_ready_signal.connect(self.ui.calibrate_gyro.setEnabled)
self.model.selected_calibration_ready_signal.connect(self.ui.calibrate_level.setEnabled)
# Set most safety-important buttons disabled
self.model.emit_signals()
def show(self):
self.ui.copter_table.load_columns()
super().show()

View File

@@ -1,5 +1,4 @@
configobj==5.0.6
indexed.py==0.0.1
numpy==1.18.1
PyQt5==5.13.0
PyQt5-sip==4.19.18