mirror of
https://github.com/CopterExpress/clever-show.git
synced 2026-05-26 15:13:26 +00:00
Added drop support for config cells
This commit is contained in:
@@ -60,7 +60,7 @@ class CopterTableWidget(QTableView):
|
||||
self.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectItems)
|
||||
self.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
|
||||
self.doubleClicked.connect(self.on_double_click)
|
||||
self.setDragEnabled(True)
|
||||
self.setDragDropMode(QAbstractItemView.DragDrop)
|
||||
|
||||
def moved(self, logical_index, old_index, new_index):
|
||||
name = self.current_columns.pop(old_index)
|
||||
|
||||
@@ -9,10 +9,13 @@ from functools import partialmethod
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
from PyQt5.QtCore import Qt as Qt, QUrl, QDir
|
||||
|
||||
from config import ConfigManager
|
||||
|
||||
# Additional custom roles to interact with various table data
|
||||
ModelDataRole = 998
|
||||
ModelStateRole = 999
|
||||
|
||||
|
||||
def get_git_version(): # TODO import from animation
|
||||
return subprocess.check_output("git log --pretty=format:%h -n 1").decode('UTF-8')
|
||||
|
||||
@@ -111,6 +114,7 @@ def check_pos(item):
|
||||
return False
|
||||
return not math.isnan(item[0])
|
||||
|
||||
|
||||
# @ModelChecks.column_check("last_task")
|
||||
# def check_task(item):
|
||||
# return True
|
||||
@@ -137,13 +141,13 @@ def check_start_pos(item, context):
|
||||
def get_position(position):
|
||||
if position != 'NO_POS' and position[0] != 'nan': # float('nan')?
|
||||
return position
|
||||
return [float('nan')]*3
|
||||
return [float('nan')] * 3
|
||||
|
||||
|
||||
def get_distance(pos1, pos2): # todo as common function
|
||||
if any(math.isnan(x) for x in pos1+pos2):
|
||||
if any(math.isnan(x) for x in pos1 + pos2):
|
||||
return float('nan')
|
||||
return math.sqrt(sum(map(lambda p: p[0] - p[1], zip(pos1, pos2)))**2) # point distance formula
|
||||
return math.sqrt(sum(map(lambda p: p[0] - p[1], zip(pos1, pos2))) ** 2) # point distance formula
|
||||
|
||||
|
||||
class CopterData:
|
||||
@@ -234,6 +238,7 @@ class ModelFormatter:
|
||||
place_formatter = partialmethod(column_formatter, formatter_type=PLACE_FORMATTER)
|
||||
view_formatter = partialmethod(column_formatter, formatter_type=VIEW_FORMATTER)
|
||||
|
||||
|
||||
@ModelFormatter.place_formatter("copter_id")
|
||||
def place_id(value):
|
||||
value = str(value).strip()
|
||||
@@ -262,6 +267,7 @@ def place_battery(value):
|
||||
return "NO_INFO"
|
||||
return value
|
||||
|
||||
|
||||
@ModelFormatter.view_formatter("battery")
|
||||
def view_battery(value):
|
||||
if isinstance(value, list):
|
||||
@@ -315,6 +321,7 @@ def view_time_delta(value):
|
||||
class CopterDataModel(QtCore.QAbstractTableModel):
|
||||
columns_dict = {'copter_id': 'copter ID',
|
||||
'git_version': 'version',
|
||||
'config_version': 'configuration',
|
||||
'animation_id': ' animation ID ',
|
||||
'battery': ' battery ',
|
||||
'fcu_status': 'FCU status',
|
||||
@@ -325,7 +332,6 @@ class CopterDataModel(QtCore.QAbstractTableModel):
|
||||
'start_position': ' start x y z ',
|
||||
'last_task': 'last task',
|
||||
'time_delta': 'dt',
|
||||
'config_version': 'configuration',
|
||||
}
|
||||
|
||||
columns = list(columns_dict.keys())
|
||||
@@ -385,7 +391,7 @@ class CopterDataModel(QtCore.QAbstractTableModel):
|
||||
|
||||
def selected_check(self, f, selected=()):
|
||||
selected = selected or set(self.user_selected())
|
||||
return bool(selected) and all(f(item) for item in selected) #selected.issubset(self.filter(f))
|
||||
return bool(selected) and all(f(item) for item in selected) # selected.issubset(self.filter(f))
|
||||
|
||||
def get_row_data(self, index):
|
||||
row = index.row()
|
||||
@@ -488,14 +494,14 @@ class CopterDataModel(QtCore.QAbstractTableModel):
|
||||
if index.column() == 0:
|
||||
roles |= Qt.ItemIsUserCheckable | Qt.ItemIsEditable
|
||||
if self.is_column(index, "config_version"):
|
||||
roles |= Qt.ItemIsDragEnabled # | Qt.ItemIsDropEnabled
|
||||
roles |= Qt.ItemIsDragEnabled | Qt.ItemIsDropEnabled
|
||||
return roles
|
||||
|
||||
def supportedDropActions(self):
|
||||
return QtCore.Qt.CopyAction
|
||||
return Qt.CopyAction | Qt.MoveAction
|
||||
|
||||
def mimeTypes(self):
|
||||
return ['text/plain']
|
||||
return ['text/uri-list']
|
||||
|
||||
def mimeData(self, indexes):
|
||||
index = indexes[0]
|
||||
@@ -513,10 +519,36 @@ class CopterDataModel(QtCore.QAbstractTableModel):
|
||||
os.remove(path)
|
||||
|
||||
self.data_contents[index.row()].client.get_file("config/client.ini", path, )
|
||||
mimedata.setData("application/copter_row_info",
|
||||
bytes(self.data_contents[index.row()].copter_id, encoding="UTF-8"))
|
||||
mimedata.setUrls([QUrl.fromLocalFile(path)])
|
||||
|
||||
return mimedata
|
||||
|
||||
def dropMimeData(self, mimedata, action, row, column, index):
|
||||
if action == Qt.IgnoreAction:
|
||||
return True
|
||||
|
||||
if self.is_column(index, "config_version"):
|
||||
if not mimedata.hasUrls():
|
||||
return False
|
||||
if str(mimedata.data("application/copter_row_info")) == self.data_contents[index.row()].copter_id:
|
||||
return False # to protect from dropping to the same cell
|
||||
|
||||
# print(mimedata.hasUrls(), mimedata.urls, mimedata.formats())
|
||||
return self.drop_config(mimedata.urls()[0].toLocalFile(), index.row())
|
||||
|
||||
return True
|
||||
|
||||
def drop_config(self, path, row):
|
||||
if not ConfigManager.config_exists(path):
|
||||
return False
|
||||
config = ConfigManager()
|
||||
config.load_only_config(path)
|
||||
self.data_contents[row].client.send_message("config", kwargs={
|
||||
"config": config.full_dict(include_defaults=False), "mode": "rewrite"})
|
||||
return False
|
||||
|
||||
# Thread-safe wrappers
|
||||
def add_client(self, **kwargs):
|
||||
default_states = {"checked": 0, "copter_id": True}
|
||||
@@ -567,9 +599,10 @@ def flip_checks(copter_item):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
# for col in checklist:
|
||||
# if not copter_item.state[col]: # ModelChecks.check(col, copter_item):
|
||||
# return False
|
||||
# if not copter_item.state[col]: # ModelChecks.check(col, copter_item):
|
||||
# return False
|
||||
|
||||
def calibrating_check(copter_item):
|
||||
return copter_item["calibration_status"] == "CALIBRATING"
|
||||
@@ -637,15 +670,15 @@ if __name__ == '__main__':
|
||||
msg = "[{}]: Failure: {}".format("FCU connection2", "Angular velocities estimation is not available")
|
||||
msgs.append(msg)
|
||||
|
||||
#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(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")
|
||||
# myModel.setData(myModel.index(0, 1), "test")
|
||||
|
||||
# t = threading.Thread(target=timer, daemon=True)
|
||||
#t.start()
|
||||
# t.start()
|
||||
print(QtCore.QT_VERSION_STR)
|
||||
print(get_git_version())
|
||||
myModel.update_data(0, 3, [1, 2], role=Qt.EditRole)
|
||||
app.exec_()
|
||||
app.exec_()
|
||||
|
||||
@@ -508,7 +508,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
||||
|
||||
config = cfg.ConfigManager()
|
||||
config.load_only_config(path)
|
||||
data = config.full_dict()
|
||||
data = config.full_dict(include_defaults=False)
|
||||
logging.info(f"Loaded config from {path}")
|
||||
|
||||
copters = self.model.user_selected()
|
||||
|
||||
14
config.py
14
config.py
@@ -155,7 +155,7 @@ class ConfigManager:
|
||||
self.__dict__[key] = value
|
||||
|
||||
@staticmethod
|
||||
def _config_exists(path):
|
||||
def config_exists(path):
|
||||
return os.path.isfile(path) and os.path.splitext(path)[1] == '.ini'
|
||||
|
||||
@staticmethod
|
||||
@@ -169,14 +169,14 @@ class ConfigManager:
|
||||
filename.replace('configspec_', ''))
|
||||
|
||||
def load_from_file(self, path):
|
||||
if not self._config_exists(path):
|
||||
if not self.config_exists(path):
|
||||
raise ValueError('Config file do not exist!')
|
||||
|
||||
f_path, filename = os.path.split(path)
|
||||
if filename.startswith('configspec_'):
|
||||
config_path = self._get_config_path(path)
|
||||
|
||||
if self._config_exists(config_path):
|
||||
if self.config_exists(config_path):
|
||||
return self.load_config_and_spec(config_path)
|
||||
|
||||
generate_file = parent_dir(f_path) == 'spec'
|
||||
@@ -187,7 +187,7 @@ class ConfigManager:
|
||||
|
||||
else:
|
||||
spec_path = self._get_spec_path(path)
|
||||
if self._config_exists(spec_path):
|
||||
if self.config_exists(spec_path):
|
||||
return self.load_config_and_spec(path)
|
||||
|
||||
return self.load_only_config(path)
|
||||
@@ -212,7 +212,7 @@ class ConfigManager:
|
||||
|
||||
@classmethod
|
||||
def generate_default_config(cls, cfg_path):
|
||||
if cls._config_exists(cfg_path):
|
||||
if cls.config_exists(cfg_path):
|
||||
return False
|
||||
|
||||
vdt = Validator()
|
||||
@@ -269,10 +269,10 @@ class ConfigManager:
|
||||
kwargs.update({'configspec': configspec})
|
||||
elif isinstance(configspec, str):
|
||||
spec_path = self._get_spec_path(configspec)
|
||||
if self._config_exists(spec_path): # when 'configspec' points to configuration file and configspec exists
|
||||
if self.config_exists(spec_path): # when 'configspec' points to configuration file and configspec exists
|
||||
kwargs.update({'configspec': spec_path})
|
||||
filename = configspec
|
||||
elif self._config_exists(configspec): # when 'configspec' points to configspec file
|
||||
elif self.config_exists(configspec): # when 'configspec' points to configspec file
|
||||
kwargs.update({'configspec': configspec})
|
||||
if parent_dir(configspec) == 'spec':
|
||||
filename = self._get_config_path(configspec)
|
||||
|
||||
Reference in New Issue
Block a user