diff --git a/Server/copter_table_models.py b/Server/copter_table_models.py index b5f9e53..5b0ca27 100644 --- a/Server/copter_table_models.py +++ b/Server/copter_table_models.py @@ -1,32 +1,67 @@ import sys import re import collections +import indexed from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtCore import Qt as Qt class CopterData: - class_attrs = collections.OrderedDict([('copter_id', None), ('anim_id', None), ('batt_v', None), ('batt_p', None), - ('sys_status', None), ('cal_status', None), ('selfcheck', None), ('position', None), ("time_delta", None), - ("client", None), ("checked", 0)], ) + class_basic_attrs = indexed.IndexedOrderedDict([('copter_id', None), ('anim_id', None), + ('batt_v', None), ('batt_p', None), + ('sys_status', None), ('cal_status', None), ('selfcheck', None), + ('position', None), ("time_delta", None), + ("client", None), ]) def __init__(self, **kwargs): - self.attrs = self.class_attrs.copy() - self.attrs.update(kwargs) + self.attrs_dict = self.class_basic_attrs.copy() + self.attrs_dict.update(kwargs) - for attr, value in self.attrs.items(): + for attr, value in self.attrs_dict.items(): setattr(self, attr, value) def __getitem__(self, key): - return getattr(self, list(self.attrs.keys())[key]) + return getattr(self, self.attrs_dict.keys()[key]) def __setitem__(self, key, value): - setattr(self, list(self.attrs.keys())[key], value) + setattr(self, self.attrs_dict.keys()[key], value) + + +class StatedCopterData(CopterData): + class_basic_states = indexed.IndexedOrderedDict([("checked", 0), ("selfchecked", None), ("takeoff_ready", None), + ("copter_id", True), ]) + + def __init__(self, **kwargs): + self.states = CopterData(**self.class_basic_states) + + super(StatedCopterData, self).__init__(**kwargs) + + def __setattr__(self, key, value): + self.__dict__[key] = value + + if key in self.class_basic_attrs.keys(): + try: + self.states.__dict__[key] = \ + Checks.all_checks[self.attrs_dict.keys().index(key)](value) + except KeyError: # No check present for that col + pass + else: # update selfchecked and takeoff_ready + self.states.__dict__["selfchecked"] = all( + [self.states[i] for i in Checks.all_checks.keys()] + ) + + self.states.__dict__["takeoff_ready"] = all( + [self.states[i] for i in Checks.takeoff_checklist] + ) + + +class Checks: + all_checks = {} + takeoff_checklist = (2, 3, 4, 5, 6) class CopterDataModel(QtCore.QAbstractTableModel): - checks = {} selected_ready_signal = QtCore.pyqtSignal(bool) selected_takeoff_ready_signal = QtCore.pyqtSignal(bool) selected_flip_ready_signal = QtCore.pyqtSignal(bool) @@ -35,7 +70,8 @@ class CopterDataModel(QtCore.QAbstractTableModel): def __init__(self, parent=None): super(CopterDataModel, self).__init__(parent) - self.headers = ('copter ID', ' animation ID ', 'batt V', 'batt %', ' system ', 'calibration', 'selfcheck', 'current x y z yaw frame_id', 'time delta') + self.headers = ('copter ID', ' animation ID ', 'batt V', 'batt %', ' system ', + 'calibration', 'selfcheck', 'current x y z yaw frame_id', 'time delta') self.data_contents = [] self.first_col_is_checked = False @@ -48,20 +84,21 @@ class CopterDataModel(QtCore.QAbstractTableModel): self.endInsertRows() - def user_selected(self): - return filter(lambda x: x.checked == Qt.Checked, self.data_contents) + def user_selected(self, contents=()): + contents = contents or self.data_contents + return filter(lambda x: x.states.checked == Qt.Checked, contents) def selfchecked_ready(self, contents=()): contents = contents or self.data_contents - return filter(lambda x: all_checks(x), contents) + return filter(lambda x: x.states.selfchecked, contents) def takeoff_ready(self, contents=()): contents = contents or self.data_contents - return filter(lambda x: takeoff_checks(x), contents) + return filter(lambda x: x.states.takeoff_ready, contents) def flip_ready(self, contents=()): contents = contents or self.data_contents - return filter(lambda x: flip_checks(x), contents) + return filter(lambda x: flip_checks(x), contents) # possibly change as takeoff checks def calibrating(self, contents=()): contents = contents or self.data_contents @@ -85,15 +122,16 @@ class CopterDataModel(QtCore.QAbstractTableModel): def data(self, index, role=Qt.DisplayRole): row = index.row() col = index.column() - #print('row {}, col {}, role {}'.format(row, col, role)) if role == Qt.DisplayRole: - #print(self.data_contents[row][col]) return self.data_contents[row][col] or "" elif role == Qt.BackgroundRole: - if col in self.checks.keys(): - item = self.data_contents[row][col] - result = self.checks[col](item) + 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: @@ -102,19 +140,22 @@ class CopterDataModel(QtCore.QAbstractTableModel): return QtGui.QBrush(Qt.red) elif role == Qt.CheckStateRole and col == 0: - return self.data_contents[row].checked + return self.data_contents[row].states.checked if role == QtCore.Qt.TextAlignmentRole and col != 0: return QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter - def update_model(self, index=QtCore.QModelIndex()): - #self.modelReset.emit() - self.selected_ready_signal.emit(set(self.user_selected()).issubset(self.selfchecked_ready())) - self.selected_takeoff_ready_signal.emit(set(self.user_selected()).issubset(self.takeoff_ready())) - self.selected_flip_ready_signal.emit(set(self.user_selected()).issubset(self.flip_ready())) - self.selected_calibrating_signal.emit(set(self.user_selected()).issubset(self.calibrating())) - self.selected_calibration_ready_signal.emit(set(self.user_selected()).issubset(self.calibration_ready())) - self.dataChanged.emit(index, index, (QtCore.Qt.EditRole,)) + def update_model(self, index=QtCore.QModelIndex(), role=QtCore.Qt.EditRole): + selected = set(self.user_selected()) + + self.selected_ready_signal.emit(selected.issubset(self.selfchecked_ready())) + self.selected_takeoff_ready_signal.emit(selected.issubset(self.takeoff_ready())) + + self.selected_flip_ready_signal.emit(selected.issubset(self.flip_ready())) + self.selected_calibrating_signal.emit(selected.issubset(self.calibrating())) + self.selected_calibration_ready_signal.emit(selected.issubset(self.calibration_ready())) + + self.dataChanged.emit(index, index, (role,)) @QtCore.pyqtSlot() def setData(self, index, value, role=Qt.EditRole): @@ -122,27 +163,26 @@ class CopterDataModel(QtCore.QAbstractTableModel): return False if role == Qt.CheckStateRole: - self.data_contents[index.row()].checked = value + self.data_contents[index.row()].states.checked = value elif role == Qt.EditRole: self.data_contents[index.row()][index.column()] = value - self.update_model(index) else: return False + self.update_model(index, role) return True def select_all(self): self.first_col_is_checked = not self.first_col_is_checked - for copter in self.data_contents: - copter.checked = int(self.first_col_is_checked)*2 - for row in range(len(self.data_contents)): - self.update_model(self.index(row, 0)) + 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 + roles |= Qt.ItemIsUserCheckable #| Qt.ItemIsEditable return roles @QtCore.pyqtSlot(int, int, QtCore.QVariant) @@ -156,7 +196,7 @@ class CopterDataModel(QtCore.QAbstractTableModel): def col_check(col): def inner(f): - CopterDataModel.checks[col] = f + Checks.all_checks[col] = f def wrapper(*args, **kwargs): return f(*args, **kwargs) @@ -172,42 +212,49 @@ def check_anim(item): return None return str(item) != 'No animation' + @col_check(2) def check_bat_v(item): if not item: return None return float(item) > 3.2 + @col_check(3) def check_bat_p(item): if not item: return None return float(item) > 30 + @col_check(4) def check_sys_status(item): if not item: return None return item == "STANDBY" + @col_check(5) def check_cal_status(item): if not item: return None return item == "OK" + @col_check(6) def check_selfcheck(item): if not item: return None return item == "OK" + @col_check(7) def check_cal_status(item): if not item: return None return True + @col_check(8) def check_time_delta(item): if not item: @@ -216,35 +263,40 @@ def check_time_delta(item): def all_checks(copter_item): - for col, check in CopterDataModel.checks.items(): + for col, check in Checks.all_checks.items(): if not check(copter_item[col]): return False return True + def takeoff_checks(copter_item): - for i in range(5): - if not CopterDataModel.checks[2+i](copter_item[2+i]): + for col in Checks.takeoff_checklist: + if not Checks.all_checks[col](copter_item[col]): return False return True + def flip_checks(copter_item): - for i in range(5): - if 2+i != 4: - if not CopterDataModel.checks[2+i](copter_item[2+i]): + for col in Checks.takeoff_checklist: + if col != 4: + if not Checks.all_checks[col](copter_item[col]): return False else: if copter_item[4] != "ACTIVE": return False return True + def calibrating_check(copter_item): return copter_item[5] == "CALIBRATING" + def calibration_ready_check(copter_item): - if not CopterDataModel.checks[4](copter_item[4]): + if not Checks.all_checks[4](copter_item[4]): return False return not calibrating_check(copter_item) + class CopterProxyModel(QtCore.QSortFilterProxyModel): def __init__(self, parent=None): super(CopterProxyModel, self).__init__(parent) @@ -296,9 +348,9 @@ if __name__ == '__main__': tableView.setSortingEnabled(True) tableView.show() - myModel.add_client(CopterData(copter_id=1000, checked=0, time_utc=1)) - myModel.add_client(CopterData(checked=2, selfcheck="OK", time_utc=2)) - myModel.add_client(CopterData(checked=2, selfcheck="not ok", time_utc="no")) + myModel.add_client(StatedCopterData(copter_id=1000, checked=0, 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.setData(myModel.index(0, 1), "test") diff --git a/Server/server_qt.py b/Server/server_qt.py index ced01f4..28ac877 100644 --- a/Server/server_qt.py +++ b/Server/server_qt.py @@ -109,7 +109,7 @@ class MainWindow(QtWidgets.QMainWindow): self.ui.action_select_all_rows.triggered.connect(self.model.select_all) def new_client_connected(self, client: Client): - self.signals.add_client_signal.emit(CopterData(copter_id=client.copter_id, client=client)) + self.signals.add_client_signal.emit(StatedCopterData(copter_id=client.copter_id, client=client)) def init_ui(self): # Connecting