[supervision] Adds documentation tab. (#2972)

* [supervision] Adds documentation tab.

* [generator] add a target option to dump modules by target with load type

* [supervision] doc: handle modules type.

* [supervision] modules doc: add filter.

* [supervision] Use internet doc by default.

* [supervision] Move the header out of the configuration tab.

* [supervision] Add target label.

* [supervision] Gracefully handle Ctrl-C.

* [supervision] Add new session to combobox.

* Update sw/supervision/python/doc_panel.py

---------

Co-authored-by: Gautier Hattenberger <gautier.hattenberger@enac.fr>
This commit is contained in:
Fabien-B
2023-02-07 15:51:55 +01:00
committed by GitHub
parent 902f9adf65
commit 8833bb4fc5
38 changed files with 1024 additions and 371 deletions
+21 -15
View File
@@ -1,19 +1,25 @@
# Copyright (C) 2008-2022 The Paparazzi Team # Copyright (C) 2008-2022 The Paparazzi Team
# released under GNU GPLv2 or later. See COPYING file. # released under GNU GPLv2 or later. See COPYING file.
all:
mkdir -p generated
pyuic5 ui/conf_header.ui -o generated/ui_conf_header.py
pyuic5 ui/conf_item.ui -o generated/ui_conf_item.py
pyuic5 ui/build.ui -o generated/ui_build.py
pyuic5 ui/configuration_panel.ui -o generated/ui_configuration_panel.py
pyuic5 ui/new_ac_dialog.ui -o generated/ui_new_ac_dialog.py
pyuic5 ui/session.ui -o generated/ui_session.py
pyuic5 ui/program.ui -o generated/ui_program.py
pyuic5 ui/operation_panel.ui -o generated/ui_operation_panel.py
pyuic5 ui/console.ui -o generated/ui_console.py
pyuic5 ui/tools_list.ui -o generated/ui_tools_list.py
pyuic5 ui/app_settings.ui -o generated/ui_app_settings.py
pyuic5 ui/conf_settings.ui -o generated/ui_conf_settings.py
clean_ui: SOURCEDIR = ui
BUILDDIR = generated
SOURCES = $(wildcard $(SOURCEDIR)/*.ui)
OBJECTS = $(patsubst $(SOURCEDIR)/%.ui,$(BUILDDIR)/%.py,$(SOURCES))
CC = pyuic5
all: $(BUILDDIR) $(OBJECTS)
$(OBJECTS): $(BUILDDIR)/%.py : $(SOURCEDIR)/%.ui
$(CC) -o $@ $<;
$(BUILDDIR):
mkdir -p $@
clean:
rm -r generated rm -r generated
.PHONY: build_dir
+4 -6
View File
@@ -1,3 +1,5 @@
# Copyright (C) 2008-2022 The Paparazzi Team
# released under GNU GPLv2 or later. See COPYING file.
from dataclasses import dataclass, field from dataclasses import dataclass, field
from typing import List, Dict from typing import List, Dict
import lxml.etree as ET import lxml.etree as ET
@@ -65,11 +67,6 @@ class Aircraft:
completed = subprocess.run([MOD_DEP, "-ac", self.name, "-af", self.airframe, "-fp", self.flight_plan], completed = subprocess.run([MOD_DEP, "-ac", self.name, "-af", self.airframe, "-fp", self.flight_plan],
capture_output=True) capture_output=True)
if completed.returncode == 0: if completed.returncode == 0:
def remove_prefix(s):
if s.startswith(utils.CONF_DIR):
return s[len(utils.CONF_DIR):]
else:
return s
def make_setting(m): def make_setting(m):
setting = Setting(m, True) setting = Setting(m, True)
@@ -80,7 +77,7 @@ class Aircraft:
new_settings_modules = [] new_settings_modules = []
for module_path in completed.stdout.decode().strip().split(): for module_path in completed.stdout.decode().strip().split():
module = remove_prefix(module_path) module = utils.remove_prefix(module_path, utils.CONF_DIR)
xml = ET.parse(module_path) xml = ET.parse(module_path)
for xml_setting in xml.getroot().findall("settings"): for xml_setting in xml.getroot().findall("settings"):
name = xml_setting.get("name") name = xml_setting.get("name")
@@ -215,6 +212,7 @@ class Conf:
self.tree_orig = self.to_xml_tree() self.tree_orig = self.to_xml_tree()
def restore_conf(self): def restore_conf(self):
print("conf restored.")
self.parse(self.tree_orig) self.parse(self.tree_orig)
def to_string(self): def to_string(self):
@@ -21,7 +21,7 @@ class ConfSettingsWidget(QWidget, Ui_SettingsConf):
base_settings_path = os.path.join(utils.CONF_DIR, "settings") base_settings_path = os.path.join(utils.CONF_DIR, "settings")
filenames, _ = QFileDialog.getOpenFileNames(self, "Add settings", base_settings_path, "Settings (*.xml)") filenames, _ = QFileDialog.getOpenFileNames(self, "Add settings", base_settings_path, "Settings (*.xml)")
for filename in filenames: for filename in filenames:
name = utils.removeprefix(filename, utils.CONF_DIR) name = utils.remove_prefix(filename, utils.CONF_DIR)
print(name) print(name)
item = QListWidgetItem(name) item = QListWidgetItem(name)
item.setCheckState(QtCore.Qt.Checked) item.setCheckState(QtCore.Qt.Checked)
+15 -209
View File
@@ -1,114 +1,44 @@
import os, sys, copy
from PyQt5.QtWidgets import * from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
import utils import utils
from generated.ui_configuration_panel import Ui_ConfigurationPanel from generated.ui_configuration_panel import Ui_ConfigurationPanel
from generated.ui_new_ac_dialog import Ui_Dialog
from program_widget import ProgramWidget from program_widget import ProgramWidget
from conf import * from conf import *
from programs_conf import parse_tools from programs_conf import parse_tools
import subprocess import subprocess
PAPARAZZI_SRC = os.getenv("PAPARAZZI_SRC")
PAPARAZZI_HOME = os.getenv("PAPARAZZI_HOME", PAPARAZZI_SRC)
lib_path = os.path.normpath(os.path.join(PAPARAZZI_SRC, 'sw', 'lib', 'python'))
sys.path.append(lib_path)
import paparazzi
# TODO make a setting ? # TODO make a setting ?
REMOVE_PROGRAMS_FINISHED = True REMOVE_PROGRAMS_FINISHED = True
class ConfigurationPanel(QWidget, Ui_ConfigurationPanel): class ConfigurationPanel(QWidget, Ui_ConfigurationPanel):
msg_error = QtCore.pyqtSignal(str)
clear_error = QtCore.pyqtSignal() clear_error = QtCore.pyqtSignal()
ac_changed = QtCore.pyqtSignal(Aircraft) ac_edited = QtCore.pyqtSignal(Aircraft)
def __init__(self, parent=None, *args, **kwargs): def __init__(self, parent=None, *args, **kwargs):
QWidget.__init__(self, parent=parent, *args, **kwargs) QWidget.__init__(self, parent=parent, *args, **kwargs)
self.setupUi(self) self.setupUi(self)
self.console_widget.filter_widget.hide() self.console_widget.filter_widget.hide()
self.conf = None # type: conf.Conf self.currentAC = None # type: Aircraft
self.currentAC = None # type: str
self.flight_plan_editor = None self.flight_plan_editor = None
self.header.set_changed.connect(self.handle_set_changed)
self.header.ac_changed.connect(self.update_ac)
self.header.id_changed.connect(self.handle_id_changed)
self.header.refresh_button.clicked.connect(self.refresh_ac)
self.header.color_button.clicked.connect(self.change_color)
self.header.save_button.clicked.connect(lambda: self.conf.save())
self.addAction(self.save_conf_action)
self.save_conf_action.triggered.connect(lambda: self.conf.save())
self.conf_widget.conf_changed.connect(self.handle_conf_changed) self.conf_widget.conf_changed.connect(self.handle_conf_changed)
self.conf_widget.setting_changed.connect(self.handle_setting_changed) self.conf_widget.setting_changed.connect(self.handle_setting_changed)
self.conf_widget.flight_plan.edit_alt.connect(self.edit_flightplan_gcs) self.conf_widget.flight_plan.edit_alt.connect(self.edit_flightplan_gcs)
self.header.rename_action.triggered.connect(self.rename_ac)
self.header.new_ac_action.triggered.connect(self.new_ac)
self.header.duplicate_action.triggered.connect(self.duplicate_ac)
self.header.remove_ac_action.triggered.connect(self.remove_ac)
self.build_widget.spawn_program.connect(self.launch_program) self.build_widget.spawn_program.connect(self.launch_program)
def init(self): def init(self):
sets = paparazzi.get_list_of_conf_files()
settings = utils.get_settings() settings = utils.get_settings()
self.header.set_sets(sets, conf_init=Conf.get_current_conf())
last_ac: QtCore.QVariant = settings.value("ui/last_AC", None, str)
last_target: QtCore.QVariant = settings.value("ui/last_target", None, str)
if last_ac is not None:
self.header.ac_combo.setCurrentText(last_ac)
if last_target is not None:
self.build_widget.target_combo.setCurrentText(last_target)
window_size: QtCore.QSize = settings.value("ui/window_size", QtCore.QSize(1000, 600), QtCore.QSize) window_size: QtCore.QSize = settings.value("ui/window_size", QtCore.QSize(1000, 600), QtCore.QSize)
lpw = settings.value("ui/left_pane_width", 100, int) lpw = settings.value("ui/left_pane_width", 100, int)
self.splitter.setSizes([lpw, window_size.width() - lpw]) self.splitter.setSizes([lpw, window_size.width() - lpw])
def handle_set_changed(self, conf_file): def set_ac(self, ac: Aircraft):
self.conf = Conf(conf_file) if ac is None:
Conf.set_current_conf(conf_file)
self.build_widget.set_conf(self.conf)
acs = [ac.name for ac in self.conf.aircrafts]
self.header.set_acs(acs)
def disable_sets(self):
self.header.set_combo.setDisabled(True)
def enable_sets(self):
self.header.set_combo.setDisabled(False)
def update_ac(self, ac_name):
ac = self.conf[ac_name]
if ac_name != "" and ac is not None:
self.conf_widget.setDisabled(False)
self.currentAC = ac_name
status, stderr = ac.update()
if status != 0:
self.msg_error.emit(stderr.decode().strip())
else:
self.clear_error.emit()
self.header.set_ac(ac)
self.conf_widget.set_ac(ac)
self.build_widget.update_targets(self.conf[ac_name])
self.ac_changed.emit(self.conf[ac_name])
else:
# self.conf_widget.reset()
self.conf_widget.setDisabled(True) self.conf_widget.setDisabled(True)
self.currentAC = ac
def get_current_ac(self) -> str: self.conf_widget.set_ac(ac)
""" self.build_widget.update_targets(ac)
:return: name of the current AC
"""
return self.currentAC
def refresh_ac(self):
self.update_ac(self.currentAC)
def handle_id_changed(self, id):
self.conf[self.currentAC].ac_id = id
if len(self.conf.get_all(id)) > 1:
self.header.id_spinBox.setStyleSheet("background-color: red;")
else:
self.header.id_spinBox.setStyleSheet("background-color: white;")
def handle_setting_changed(self): def handle_setting_changed(self):
def make_setting(item: QListWidgetItem): def make_setting(item: QListWidgetItem):
@@ -125,142 +55,18 @@ class ConfigurationPanel(QWidget, Ui_ConfigurationPanel):
else: else:
settings.append(s) settings.append(s)
self.conf[self.currentAC].settings_modules = modules self.currentAC.settings_modules = modules
self.conf[self.currentAC].settings = settings self.currentAC.settings = settings
self.ac_edited.emit(self.currentAC)
# should we save each time a tiny change is made ? very inefficient ! # should we save each time a tiny change is made ? very inefficient !
# self.conf.save() # self.conf.save()
def handle_conf_changed(self): def handle_conf_changed(self):
self.conf[self.currentAC].airframe = self.conf_widget.airframe.path self.currentAC.airframe = self.conf_widget.airframe.path
self.conf[self.currentAC].flight_plan = self.conf_widget.flight_plan.path self.currentAC.flight_plan = self.conf_widget.flight_plan.path
self.conf[self.currentAC].radio = self.conf_widget.radio.path self.currentAC.radio = self.conf_widget.radio.path
self.conf[self.currentAC].telemetry = self.conf_widget.telemetry.path self.currentAC.telemetry = self.conf_widget.telemetry.path
# reload settings modules, and update UI self.ac_edited.emit(self.currentAC)
self.update_ac(self.currentAC)
def add_ac(self, ac: Aircraft):
self.conf.append(ac)
self.header.add_ac(ac.name)
def new_ac(self):
orig = Aircraft()
self.create_ac(orig)
def remove_ac(self):
button = QMessageBox.question(self, "Remove AC", "Remove AC <strong>{}</strong>?".format(self.currentAC))
if button == QMessageBox.Yes:
self.conf.remove(self.conf[self.currentAC])
self.header.remove_current()
def duplicate_ac(self):
orig = self.conf[self.currentAC]
self.create_ac(orig)
def create_ac(self, orig):
ui_dialog = Ui_Dialog()
dialog = QDialog(parent=self)
ui_dialog.setupUi(dialog)
def verify():
ok = True
id = ui_dialog.id_spinbox.value()
name = ui_dialog.name_edit.text()
if self.conf[id] is not None or id == 0:
ui_dialog.id_spinbox.setStyleSheet("background-color: red;")
ok = False
else:
ui_dialog.id_spinbox.setStyleSheet("")
if self.conf[name] is not None or name == "":
ui_dialog.name_edit.setStyleSheet("background-color: red;")
ok = False
else:
ui_dialog.name_edit.setStyleSheet("")
return ok
def accept():
if verify():
dialog.accept()
def reject():
dialog.reject()
def duplicate(result):
if result:
new_ac = copy.deepcopy(orig)
name = ui_dialog.name_edit.text()
ac_id = ui_dialog.id_spinbox.value()
new_ac.name = name
new_ac.ac_id = ac_id
self.add_ac(new_ac)
self.header.set_current(name)
ui_dialog.id_spinbox.setValue(self.conf.get_free_id())
ui_dialog.buttonBox.accepted.connect(accept)
ui_dialog.buttonBox.rejected.connect(reject)
ui_dialog.id_spinbox.valueChanged.connect(verify)
ui_dialog.name_edit.textChanged.connect(verify)
dialog.finished.connect(duplicate)
dialog.open()
def rename_ac(self):
orig = self.conf[self.currentAC]
ui_dialog = Ui_Dialog()
dialog = QDialog(parent=self)
ui_dialog.setupUi(dialog)
ui_dialog.name_edit.setText(orig.name)
ui_dialog.id_spinbox.setValue(orig.ac_id)
def verify():
ok = True
id = ui_dialog.id_spinbox.value()
name = ui_dialog.name_edit.text()
acs_name = self.conf.get_all(name)
if len(acs_name) > 1 or (len(acs_name) == 1 and acs_name[0] != orig):
ui_dialog.name_edit.setStyleSheet("background-color: red;")
ok = False
else:
ui_dialog.name_edit.setStyleSheet("")
acs_id = self.conf.get_all(id)
if len(acs_id) > 1 or (len(acs_id) == 1 and acs_id[0] != orig):
ui_dialog.id_spinbox.setStyleSheet("background-color: red;")
ok = False
else:
ui_dialog.id_spinbox.setStyleSheet("")
return ok
def accept():
if verify():
dialog.accept()
def reject():
dialog.reject()
def rename(result):
if result:
orig.name = ui_dialog.name_edit.text()
orig.ac_id = ui_dialog.id_spinbox.value()
self.header.rename_ac(orig.name)
ui_dialog.buttonBox.accepted.connect(accept)
ui_dialog.buttonBox.rejected.connect(reject)
ui_dialog.id_spinbox.valueChanged.connect(verify)
ui_dialog.name_edit.textChanged.connect(verify)
dialog.finished.connect(rename)
dialog.open()
def change_color(self):
ac = self.conf[self.currentAC]
initial = QtGui.QColor(ac.get_color())
color = QColorDialog.getColor(initial, self, "AC color")
if color.isValid():
color_name = color.name()
ac.set_color(color_name)
self.header.set_color(color_name)
def edit_flightplan_gcs(self, path): def edit_flightplan_gcs(self, path):
if self.flight_plan_editor is None: if self.flight_plan_editor is None:
+125
View File
@@ -0,0 +1,125 @@
# Copyright (C) 2008-2022 The Paparazzi Team
# released under GNU GPLv2 or later. See COPYING file.
from generated.ui_doc_viewer import Ui_DocPanel
from PyQt5.QtWidgets import *
from PyQt5.QtCore import QUrl
from PyQt5.QtGui import QDesktopServices
import utils
import os
import subprocess
import conf
LOCAL_DOC_ROOT = os.path.join(utils.PAPARAZZI_HOME, "doc/sphinx/build/html/")
INTERNET_DOC_ROOT = "https://paparazzi-uav.readthedocs.io/en/latest/"
class DocPanel(QWidget, Ui_DocPanel):
def __init__(self, parent=None):
QWidget.__init__(self, parent=parent)
self.setupUi(self)
self.current_ac = None
self.doc_source_combo.currentTextChanged.connect(self.change_doc_source)
self.open_browser_button.clicked.connect(lambda: QDesktopServices.openUrl(self.webView.url()))
self.urlLineEdit.returnPressed.connect(lambda: self.webView.setUrl(QUrl(self.urlLineEdit.text())))
self.webView.loadFinished.connect(self.load_finished)
self.webView.loadProgress.connect(self.load_progress)
self.modules_list.currentTextChanged.connect(self.handle_select_module)
self.depends_modules_list.currentTextChanged.connect(self.handle_select_module)
self.unloaded_modules_list.currentTextChanged.connect(self.handle_select_module)
self.searchLineEdit.textChanged.connect(self.filter_modules)
self.target_combo.currentTextChanged.connect(self.target_changed)
self.backButton.clicked.connect(self.webView.back)
self.webView.urlChanged.connect(lambda u: self.urlLineEdit.setText(u.toString()))
url = self.make_url("index.html")
self.webView.load(url)
def load_finished(self, finished):
# print(f"load finished: {finished}")
...
# if not finished:
# self.webView.setHtml("<h1>Doc not found!</h1>"
# "<p>Documentation not found! Please build it first.</p>")
def load_progress(self, progress):
# print(f"load progress: {progress}")
...
def set_aircraft(self, ac: conf.Aircraft):
self.current_ac = ac
targets = ac.boards.keys()
self.target_combo.clear()
self.target_combo.addItem("all")
self.target_combo.addItems(targets)
def target_changed(self, target):
self.modules_list.clear()
self.depends_modules_list.clear()
self.unloaded_modules_list.clear()
if target != "":
modules = self.get_all_modules(self.current_ac, target)
for module_path, module_type in modules:
if module_type == "U" or module_type == "_":
self.modules_list.addItem(module_path)
elif module_type == "N":
self.unloaded_modules_list.addItem(module_path)
else:
self.depends_modules_list.addItem(module_path)
self.filter_modules(self.searchLineEdit.text())
def filter_modules(self, filter_txt):
def filter_list(list):
for i in range(list.count()):
if filter_txt != "":
txt = list.item(i).text()
list.item(i).setHidden(filter_txt not in txt)
else:
list.item(i).setHidden(False)
filter_list(self.modules_list)
filter_list(self.depends_modules_list)
filter_list(self.unloaded_modules_list)
def make_url(self, doc):
if self.doc_source_combo.currentText() == "Local":
path = os.path.join(LOCAL_DOC_ROOT, doc)
return QUrl.fromLocalFile(path)
else:
path = INTERNET_DOC_ROOT + doc
return QUrl(path)
def change_doc_source(self, source):
current_url = self.webView.url().toString()
lu = QUrl.fromLocalFile(LOCAL_DOC_ROOT).toString()
iu = QUrl(INTERNET_DOC_ROOT).toString()
url = QUrl("http://perdu.com")
if source == "Internet" and lu in current_url:
url = QUrl(current_url.replace(lu, iu))
if source == "Local" and iu in current_url:
url = QUrl(current_url.replace(iu, lu))
self.webView.load(url)
def handle_select_module(self, txt):
if txt == "":
return
url = self.make_url("modules/{}.html".format(txt))
self.webView.load(url)
def get_all_modules(self, ac: conf.Aircraft, target: str):
args = [conf.MOD_DEP, "-ac", ac.name, "-af", ac.airframe, "-fp", ac.flight_plan]
if target != "all":
args.extend(["-t", target])
completed = subprocess.run(args, capture_output=True)
if completed.returncode != 0:
return completed.returncode, completed.stderr
modules_list = []
module_lines = completed.stdout.decode().strip().split("\n")
for module_line in module_lines:
args = module_line.split(" ")
module_path = args[0]
module = utils.remove_prefix(args[0], os.path.join(utils.CONF_DIR, "modules/"))
module = utils.remove_suffix(module, ".xml")
module_type = args[1] if len(args) > 1 else "_"
modules_list.append((module, module_type))
return modules_list
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/app_settings.ui' # Form implementation generated from reading ui file 'ui/ui_app_settings.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.14.1
# #
+1 -1
View File
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/build.ui' # Form implementation generated from reading ui file 'ui/ui_build.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.14.1
# #
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/conf_header.ui' # Form implementation generated from reading ui file 'ui/ui_conf_header.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.14.1
# #
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/conf_item.ui' # Form implementation generated from reading ui file 'ui/ui_conf_item.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.14.1
# #
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/conf_settings.ui' # Form implementation generated from reading ui file 'ui/ui_conf_settings.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.14.1
# #
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/configuration_panel.ui' # Form implementation generated from reading ui file 'ui/ui_configuration_panel.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.14.1
# #
@@ -16,19 +16,6 @@ class Ui_ConfigurationPanel(object):
ConfigurationPanel.resize(562, 480) ConfigurationPanel.resize(562, 480)
self.verticalLayout_2 = QtWidgets.QVBoxLayout(ConfigurationPanel) self.verticalLayout_2 = QtWidgets.QVBoxLayout(ConfigurationPanel)
self.verticalLayout_2.setObjectName("verticalLayout_2") self.verticalLayout_2.setObjectName("verticalLayout_2")
self.header = HeaderWidget(ConfigurationPanel)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.header.sizePolicy().hasHeightForWidth())
self.header.setSizePolicy(sizePolicy)
self.header.setObjectName("header")
self.verticalLayout_2.addWidget(self.header)
self.line = QtWidgets.QFrame(ConfigurationPanel)
self.line.setFrameShape(QtWidgets.QFrame.HLine)
self.line.setFrameShadow(QtWidgets.QFrame.Sunken)
self.line.setObjectName("line")
self.verticalLayout_2.addWidget(self.line)
self.splitter = QtWidgets.QSplitter(ConfigurationPanel) self.splitter = QtWidgets.QSplitter(ConfigurationPanel)
self.splitter.setOrientation(QtCore.Qt.Horizontal) self.splitter.setOrientation(QtCore.Qt.Horizontal)
self.splitter.setObjectName("splitter") self.splitter.setObjectName("splitter")
@@ -74,4 +61,3 @@ class Ui_ConfigurationPanel(object):
from build_widget import BuildWidget from build_widget import BuildWidget
from conf_widget import ConfWidget from conf_widget import ConfWidget
from console_widget import ConsoleWidget from console_widget import ConsoleWidget
from header_widget import HeaderWidget
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/console.ui' # Form implementation generated from reading ui file 'ui/ui_console.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.14.1
# #
@@ -0,0 +1,142 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/ui_doc_viewer.ui'
#
# Created by: PyQt5 UI code generator 5.14.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_DocPanel(object):
def setupUi(self, DocPanel):
DocPanel.setObjectName("DocPanel")
DocPanel.resize(654, 658)
self.verticalLayout_5 = QtWidgets.QVBoxLayout(DocPanel)
self.verticalLayout_5.setObjectName("verticalLayout_5")
self.splitter_2 = QtWidgets.QSplitter(DocPanel)
self.splitter_2.setOrientation(QtCore.Qt.Horizontal)
self.splitter_2.setObjectName("splitter_2")
self.conf = QtWidgets.QWidget(self.splitter_2)
self.conf.setLayoutDirection(QtCore.Qt.LeftToRight)
self.conf.setObjectName("conf")
self.verticalLayout = QtWidgets.QVBoxLayout(self.conf)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.verticalLayout_4 = QtWidgets.QVBoxLayout()
self.verticalLayout_4.setObjectName("verticalLayout_4")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.label_4 = QtWidgets.QLabel(self.conf)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth())
self.label_4.setSizePolicy(sizePolicy)
self.label_4.setObjectName("label_4")
self.horizontalLayout_2.addWidget(self.label_4)
self.target_combo = QtWidgets.QComboBox(self.conf)
self.target_combo.setObjectName("target_combo")
self.horizontalLayout_2.addWidget(self.target_combo)
self.verticalLayout_4.addLayout(self.horizontalLayout_2)
self.searchLineEdit = QtWidgets.QLineEdit(self.conf)
self.searchLineEdit.setClearButtonEnabled(True)
self.searchLineEdit.setObjectName("searchLineEdit")
self.verticalLayout_4.addWidget(self.searchLineEdit)
self.verticalLayout.addLayout(self.verticalLayout_4)
self.momo = QtWidgets.QWidget(self.conf)
self.momo.setObjectName("momo")
self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.momo)
self.verticalLayout_8.setObjectName("verticalLayout_8")
self.splitter = QtWidgets.QSplitter(self.momo)
self.splitter.setOrientation(QtCore.Qt.Vertical)
self.splitter.setObjectName("splitter")
self.layoutWidget = QtWidgets.QWidget(self.splitter)
self.layoutWidget.setObjectName("layoutWidget")
self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.layoutWidget)
self.verticalLayout_3.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_3.setObjectName("verticalLayout_3")
self.label = QtWidgets.QLabel(self.layoutWidget)
self.label.setObjectName("label")
self.verticalLayout_3.addWidget(self.label)
self.modules_list = QtWidgets.QListWidget(self.layoutWidget)
self.modules_list.setObjectName("modules_list")
self.verticalLayout_3.addWidget(self.modules_list)
self.layoutWidget1 = QtWidgets.QWidget(self.splitter)
self.layoutWidget1.setObjectName("layoutWidget1")
self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.layoutWidget1)
self.verticalLayout_6.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_6.setObjectName("verticalLayout_6")
self.label_2 = QtWidgets.QLabel(self.layoutWidget1)
self.label_2.setObjectName("label_2")
self.verticalLayout_6.addWidget(self.label_2)
self.depends_modules_list = QtWidgets.QListWidget(self.layoutWidget1)
self.depends_modules_list.setObjectName("depends_modules_list")
self.verticalLayout_6.addWidget(self.depends_modules_list)
self.layoutWidget2 = QtWidgets.QWidget(self.splitter)
self.layoutWidget2.setObjectName("layoutWidget2")
self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.layoutWidget2)
self.verticalLayout_7.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_7.setObjectName("verticalLayout_7")
self.label_3 = QtWidgets.QLabel(self.layoutWidget2)
self.label_3.setObjectName("label_3")
self.verticalLayout_7.addWidget(self.label_3)
self.unloaded_modules_list = QtWidgets.QListWidget(self.layoutWidget2)
self.unloaded_modules_list.setObjectName("unloaded_modules_list")
self.verticalLayout_7.addWidget(self.unloaded_modules_list)
self.verticalLayout_8.addWidget(self.splitter)
self.verticalLayout.addWidget(self.momo)
self.verticalLayout.setStretch(1, 1)
self.layoutWidget3 = QtWidgets.QWidget(self.splitter_2)
self.layoutWidget3.setObjectName("layoutWidget3")
self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.layoutWidget3)
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
self.verticalLayout_2.setObjectName("verticalLayout_2")
self.horizontalLayout = QtWidgets.QHBoxLayout()
self.horizontalLayout.setObjectName("horizontalLayout")
self.backButton = QtWidgets.QPushButton(self.layoutWidget3)
self.backButton.setText("")
icon = QtGui.QIcon.fromTheme("go-previous")
self.backButton.setIcon(icon)
self.backButton.setObjectName("backButton")
self.horizontalLayout.addWidget(self.backButton)
self.urlLineEdit = QtWidgets.QLineEdit(self.layoutWidget3)
self.urlLineEdit.setObjectName("urlLineEdit")
self.horizontalLayout.addWidget(self.urlLineEdit)
self.open_browser_button = QtWidgets.QToolButton(self.layoutWidget3)
icon = QtGui.QIcon.fromTheme("applications-internet")
self.open_browser_button.setIcon(icon)
self.open_browser_button.setObjectName("open_browser_button")
self.horizontalLayout.addWidget(self.open_browser_button)
self.doc_source_combo = QtWidgets.QComboBox(self.layoutWidget3)
self.doc_source_combo.setObjectName("doc_source_combo")
self.doc_source_combo.addItem("")
self.doc_source_combo.addItem("")
self.horizontalLayout.addWidget(self.doc_source_combo)
self.verticalLayout_2.addLayout(self.horizontalLayout)
self.webView = QtWebKitWidgets.QWebView(self.layoutWidget3)
self.webView.setUrl(QtCore.QUrl("about:blank"))
self.webView.setObjectName("webView")
self.verticalLayout_2.addWidget(self.webView)
self.verticalLayout_5.addWidget(self.splitter_2)
self.retranslateUi(DocPanel)
QtCore.QMetaObject.connectSlotsByName(DocPanel)
def retranslateUi(self, DocPanel):
_translate = QtCore.QCoreApplication.translate
DocPanel.setWindowTitle(_translate("DocPanel", "Form"))
self.label_4.setText(_translate("DocPanel", "Target:"))
self.searchLineEdit.setPlaceholderText(_translate("DocPanel", "search..."))
self.label.setText(_translate("DocPanel", "Modules"))
self.label_2.setText(_translate("DocPanel", "Modules Dependencies"))
self.label_3.setText(_translate("DocPanel", "Modules Unloaded"))
self.backButton.setToolTip(_translate("DocPanel", "Go back"))
self.open_browser_button.setToolTip(_translate("DocPanel", "Open in Browser"))
self.open_browser_button.setText(_translate("DocPanel", "..."))
self.doc_source_combo.setToolTip(_translate("DocPanel", "source"))
self.doc_source_combo.setItemText(0, _translate("DocPanel", "Internet"))
self.doc_source_combo.setItemText(1, _translate("DocPanel", "Local"))
from PyQt5 import QtWebKitWidgets
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/new_ac_dialog.ui' # Form implementation generated from reading ui file 'ui/ui_new_ac_dialog.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.14.1
# #
@@ -10,38 +10,38 @@
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object): class Ui_NewACDialog(object):
def setupUi(self, Dialog): def setupUi(self, NewACDialog):
Dialog.setObjectName("Dialog") NewACDialog.setObjectName("NewACDialog")
Dialog.resize(187, 106) NewACDialog.resize(187, 106)
self.gridLayout = QtWidgets.QGridLayout(Dialog) self.gridLayout = QtWidgets.QGridLayout(NewACDialog)
self.gridLayout.setObjectName("gridLayout") self.gridLayout.setObjectName("gridLayout")
self.label = QtWidgets.QLabel(Dialog) self.label = QtWidgets.QLabel(NewACDialog)
self.label.setObjectName("label") self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1) self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.name_edit = QtWidgets.QLineEdit(Dialog) self.name_edit = QtWidgets.QLineEdit(NewACDialog)
self.name_edit.setPlaceholderText("") self.name_edit.setPlaceholderText("")
self.name_edit.setObjectName("name_edit") self.name_edit.setObjectName("name_edit")
self.gridLayout.addWidget(self.name_edit, 0, 1, 1, 1) self.gridLayout.addWidget(self.name_edit, 0, 1, 1, 1)
self.label_2 = QtWidgets.QLabel(Dialog) self.label_2 = QtWidgets.QLabel(NewACDialog)
self.label_2.setObjectName("label_2") self.label_2.setObjectName("label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
self.id_spinbox = QtWidgets.QSpinBox(Dialog) self.id_spinbox = QtWidgets.QSpinBox(NewACDialog)
self.id_spinbox.setMinimum(1) self.id_spinbox.setMinimum(1)
self.id_spinbox.setMaximum(255) self.id_spinbox.setMaximum(255)
self.id_spinbox.setObjectName("id_spinbox") self.id_spinbox.setObjectName("id_spinbox")
self.gridLayout.addWidget(self.id_spinbox, 1, 1, 1, 1) self.gridLayout.addWidget(self.id_spinbox, 1, 1, 1, 1)
self.buttonBox = QtWidgets.QDialogButtonBox(Dialog) self.buttonBox = QtWidgets.QDialogButtonBox(NewACDialog)
self.buttonBox.setOrientation(QtCore.Qt.Horizontal) self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
self.buttonBox.setObjectName("buttonBox") self.buttonBox.setObjectName("buttonBox")
self.gridLayout.addWidget(self.buttonBox, 2, 0, 1, 2) self.gridLayout.addWidget(self.buttonBox, 2, 0, 1, 2)
self.retranslateUi(Dialog) self.retranslateUi(NewACDialog)
QtCore.QMetaObject.connectSlotsByName(Dialog) QtCore.QMetaObject.connectSlotsByName(NewACDialog)
def retranslateUi(self, Dialog): def retranslateUi(self, NewACDialog):
_translate = QtCore.QCoreApplication.translate _translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog")) NewACDialog.setWindowTitle(_translate("NewACDialog", "Aircraft"))
self.label.setText(_translate("Dialog", "Name")) self.label.setText(_translate("NewACDialog", "Name"))
self.label_2.setText(_translate("Dialog", "ID")) self.label_2.setText(_translate("NewACDialog", "ID"))
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/operation_panel.ui' # Form implementation generated from reading ui file 'ui/ui_operation_panel.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.14.1
# #
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/program.ui' # Form implementation generated from reading ui file 'ui/ui_program.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.14.1
# #
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/session.ui' # Form implementation generated from reading ui file 'ui/ui_session.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.14.1
# #
@@ -0,0 +1,74 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/ui_supervision_window.ui'
#
# Created by: PyQt5 UI code generator 5.14.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_SupervisionWindow(object):
def setupUi(self, SupervisionWindow):
SupervisionWindow.setObjectName("SupervisionWindow")
SupervisionWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(SupervisionWindow)
self.centralwidget.setObjectName("centralwidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
self.verticalLayout.setObjectName("verticalLayout")
self.header = HeaderWidget(self.centralwidget)
self.header.setObjectName("header")
self.verticalLayout.addWidget(self.header)
self.tabwidget = QtWidgets.QTabWidget(self.centralwidget)
self.tabwidget.setObjectName("tabwidget")
self.configuration_panel = ConfigurationPanel()
self.configuration_panel.setObjectName("configuration_panel")
self.tabwidget.addTab(self.configuration_panel, "")
self.operation_panel = OperationPanel()
self.operation_panel.setObjectName("operation_panel")
self.tabwidget.addTab(self.operation_panel, "")
self.doc_panel = DocPanel()
self.doc_panel.setObjectName("doc_panel")
self.tabwidget.addTab(self.doc_panel, "")
self.verticalLayout.addWidget(self.tabwidget)
SupervisionWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(SupervisionWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
self.menuHelp = QtWidgets.QMenu(self.menubar)
self.menuHelp.setObjectName("menuHelp")
SupervisionWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(SupervisionWindow)
self.statusbar.setObjectName("statusbar")
SupervisionWindow.setStatusBar(self.statusbar)
self.settings_action = QtWidgets.QAction(SupervisionWindow)
self.settings_action.setObjectName("settings_action")
self.about_action = QtWidgets.QAction(SupervisionWindow)
self.about_action.setObjectName("about_action")
self.menuFile.addAction(self.settings_action)
self.menuHelp.addAction(self.about_action)
self.menubar.addAction(self.menuFile.menuAction())
self.menubar.addAction(self.menuHelp.menuAction())
self.retranslateUi(SupervisionWindow)
self.tabwidget.setCurrentIndex(0)
QtCore.QMetaObject.connectSlotsByName(SupervisionWindow)
def retranslateUi(self, SupervisionWindow):
_translate = QtCore.QCoreApplication.translate
SupervisionWindow.setWindowTitle(_translate("SupervisionWindow", "Paparazzi Center"))
self.tabwidget.setTabText(self.tabwidget.indexOf(self.configuration_panel), _translate("SupervisionWindow", "Configuration"))
self.tabwidget.setTabText(self.tabwidget.indexOf(self.operation_panel), _translate("SupervisionWindow", "Operation"))
self.tabwidget.setTabText(self.tabwidget.indexOf(self.doc_panel), _translate("SupervisionWindow", "Documentation"))
self.menuFile.setTitle(_translate("SupervisionWindow", "File"))
self.menuHelp.setTitle(_translate("SupervisionWindow", "Help"))
self.settings_action.setText(_translate("SupervisionWindow", "Edit Settings"))
self.about_action.setText(_translate("SupervisionWindow", "About"))
from configuration_panel import ConfigurationPanel
from doc_panel import DocPanel
from header_widget import HeaderWidget
from operation_panel import OperationPanel
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui/tools_list.ui' # Form implementation generated from reading ui file 'ui/ui_tools_list.ui'
# #
# Created by: PyQt5 UI code generator 5.14.1 # Created by: PyQt5 UI code generator 5.14.1
# #
+64 -22
View File
@@ -3,53 +3,95 @@
from PyQt5.QtWidgets import * from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtCore, QtGui, QtWidgets
from generated.ui_conf_header import Ui_ConfHeader from generated.ui_conf_header import Ui_ConfHeader
import conf from conf import Aircraft, Conf
import utils
import os
import sys
lib_path = os.path.normpath(os.path.join(utils.PAPARAZZI_SRC, 'sw', 'lib', 'python'))
sys.path.append(lib_path)
import paparazzi
from typing import List
class HeaderWidget(QWidget, Ui_ConfHeader): class HeaderWidget(QWidget, Ui_ConfHeader):
set_changed = QtCore.pyqtSignal(str) set_changed = QtCore.pyqtSignal(str)
ac_changed = QtCore.pyqtSignal(str) ac_changed = QtCore.pyqtSignal(str)
id_changed = QtCore.pyqtSignal(int) ac_edited = QtCore.pyqtSignal(Aircraft)
ac_rename = QtCore.pyqtSignal(Aircraft)
ac_delete = QtCore.pyqtSignal(Aircraft)
ac_duplicate = QtCore.pyqtSignal(Aircraft)
ac_save = QtCore.pyqtSignal(Aircraft)
ac_new = QtCore.pyqtSignal()
def __init__(self, parent=None): def __init__(self, parent=None):
QWidget.__init__(self, parent=parent) QWidget.__init__(self, parent=parent)
self.setupUi(self) self.setupUi(self)
self.currentAc: Aircraft = None
self.set_combo.currentTextChanged.connect(self.set_changed) self.set_combo.currentTextChanged.connect(self.set_changed)
self.ac_combo.currentTextChanged.connect(self.ac_changed) self.ac_combo.currentTextChanged.connect(self.ac_changed)
self.id_spinBox.valueChanged.connect(self.id_changed) self.id_spinBox.valueChanged.connect(self.handle_id_changed)
self.menu_button.addAction(self.rename_action)
self.menu_button.addAction(self.new_ac_action)
self.menu_button.addAction(self.duplicate_action)
self.menu_button.addAction(self.remove_ac_action)
def set_sets(self, sets, conf_init: str = None): self.refresh_button.clicked.connect(lambda: self.ac_edited.emit(self.currentAc))
self.color_button.clicked.connect(self.change_color)
self.save_button.clicked.connect(lambda: self.ac_save.emit(self.currentAc))
self.menu_button.addAction(self.rename_action)
self.rename_action.triggered.connect(lambda: self.ac_rename.emit(self.currentAc))
self.menu_button.addAction(self.remove_ac_action)
self.remove_ac_action.triggered.connect(lambda: self.ac_delete.emit(self.currentAc))
self.menu_button.addAction(self.duplicate_action)
self.duplicate_action.triggered.connect(lambda: self.ac_duplicate.emit(self.currentAc))
self.menu_button.addAction(self.new_ac_action)
self.new_ac_action.triggered.connect(self.ac_new)
def handle_id_changed(self, new_id):
self.currentAc.ac_id = new_id
self.ac_edited.emit(self.currentAc)
def update_sets(self):
sets = paparazzi.get_list_of_conf_files()
conf_init = Conf.get_current_conf()
self.set_combo.addItems(sets) self.set_combo.addItems(sets)
if conf_init in sets: if conf_init in sets:
self.set_combo.setCurrentText(conf_init) self.set_combo.setCurrentText(conf_init)
def set_acs(self, acs): def set_acs(self, acs: List[str]):
self.ac_combo.clear() self.ac_combo.clear()
self.ac_combo.addItems(acs) self.ac_combo.addItems(acs)
def set_ac(self, ac: conf.Aircraft): def set_ac(self, ac: Aircraft):
self.currentAc = ac
self.id_spinBox.blockSignals(True)
self.id_spinBox.setValue(ac.ac_id) self.id_spinBox.setValue(ac.ac_id)
self.set_color(ac.get_color()) self.id_spinBox.blockSignals(False)
self.color_button.setStyleSheet("background-color: {};".format(ac.get_color()))
self.ac_combo.setCurrentText(ac.name)
def remove_current(self): def add_ac(self, ac: Aircraft):
i = self.ac_combo.currentIndex() self.ac_combo.addItem(ac.name)
self.ac_combo.removeItem(i)
def set_current(self, ac_name): def remove_ac(self, ac):
self.ac_combo.setCurrentText(ac_name) for i in range(self.ac_combo.count()):
if self.ac_combo.itemText(i) == ac.name:
def add_ac(self, ac_name): self.ac_combo.removeItem(i)
self.ac_combo.addItem(ac_name) break
self.set_current(ac_name)
def rename_ac(self, new_name): def rename_ac(self, new_name):
i = self.ac_combo.currentIndex() i = self.ac_combo.currentIndex()
self.ac_combo.setItemText(i, new_name) self.ac_combo.setItemText(i, new_name)
def set_color(self, color: str): def change_color(self):
self.color_button.setStyleSheet("background-color: {};".format(color)) initial = QtGui.QColor(self.currentAc.get_color())
color = QColorDialog.getColor(initial, self, "AC color")
if color.isValid():
color_name = color.name()
self.currentAc.set_color(color_name)
self.color_button.setStyleSheet("background-color: {};".format(color_name))
self.ac_edited.emit(self.currentAc)
def disable_sets(self):
self.set_combo.setDisabled(True)
def enable_sets(self):
self.set_combo.setDisabled(False)
+214 -48
View File
@@ -2,92 +2,244 @@
# Copyright (C) 2008-2022 The Paparazzi Team # Copyright (C) 2008-2022 The Paparazzi Team
# released under GNU GPLv2 or later. See COPYING file. # released under GNU GPLv2 or later. See COPYING file.
import os import os
import conf import sys
import signal
import copy
from PyQt5.QtWidgets import * from PyQt5.QtWidgets import *
from PyQt5 import QtCore, QtGui from PyQt5 import QtCore, QtGui
from configuration_panel import ConfigurationPanel
from operation_panel import OperationPanel
import utils import utils
from typing import Dict
from lxml import etree as ET from lxml import etree as ET
from conf import Conf, Aircraft
from app_settings import AppSettings from app_settings import AppSettings
from generated.ui_supervision_window import Ui_SupervisionWindow
from generated.ui_new_ac_dialog import Ui_NewACDialog
class PprzCenter(QMainWindow): class PprzCenter(QMainWindow, Ui_SupervisionWindow):
def __init__(self, parent=None): def __init__(self, parent=None):
QMainWindow.__init__(self, parent=parent) QMainWindow.__init__(self, parent=parent)
self.setWindowTitle("Paparazzi Center") self.setupUi(self)
self.conf: Conf = None
self.currentAc: Aircraft = None
icon = QtGui.QIcon(os.path.join(utils.PAPARAZZI_HOME, "data", "pictures", "penguin_logo.svg")) icon = QtGui.QIcon(os.path.join(utils.PAPARAZZI_HOME, "data", "pictures", "penguin_logo.svg"))
self.setWindowIcon(icon) self.setWindowIcon(icon)
self.addMenu()
self.tabwidget = QTabWidget(parent=self) self.settings_action.triggered.connect(self.edit_settings)
self.setCentralWidget(self.tabwidget) self.about_action.triggered.connect(lambda: QMessageBox.about(self, "About Paparazzi", utils.ABOUT_TEXT))
self.configuration_panel = ConfigurationPanel(self.tabwidget)
self.operation_panel = OperationPanel(self.tabwidget)
self.tabwidget.addTab(self.configuration_panel, "Configuration")
self.tabwidget.addTab(self.operation_panel, "Operation")
self.status_msg = QLabel() self.status_msg = QLabel()
self.statusBar().addWidget(self.status_msg) self.statusBar().addWidget(self.status_msg)
self.fill_status_bar() self.fill_status_bar()
self.statusBar().show()
self.configuration_panel.msg_error.connect(self.handle_error) self.header.set_changed.connect(self.handle_set_changed)
self.configuration_panel.clear_error.connect(self.clear_error) self.header.ac_changed.connect(self.handle_ac_changed)
self.operation_panel.session.program_spawned.connect(self.configuration_panel.disable_sets) self.header.ac_edited.connect(self.handle_ac_edited)
self.operation_panel.session.programs_all_stopped.connect(self.configuration_panel.enable_sets) self.header.ac_rename.connect(self.handle_rename_ac)
self.configuration_panel.ac_changed.connect(self.operation_panel.session.set_aircraft) self.header.ac_delete.connect(self.handle_remove_ac)
self.header.ac_duplicate.connect(self.handle_new_ac)
self.header.ac_save.connect(lambda _: self.conf.save())
self.header.ac_new.connect(self.handle_new_ac)
self.operation_panel.session.program_spawned.connect(self.header.disable_sets)
self.operation_panel.session.programs_all_stopped.connect(self.header.enable_sets)
self.configuration_panel.splitter.splitterMoved.connect(self.update_left_pane_width) self.configuration_panel.splitter.splitterMoved.connect(self.update_left_pane_width)
settings = utils.get_settings() settings = utils.get_settings()
window_size = settings.value("ui/window_size", QtCore.QSize(1000, 600), QtCore.QSize) window_size = settings.value("ui/window_size", QtCore.QSize(1000, 600), QtCore.QSize)
self.resize(window_size) self.resize(window_size)
self.configuration_panel.init() self.configuration_panel.init()
self.operation_panel.session.init() self.operation_panel.session.init()
self.header.update_sets()
def addMenu(self): def handle_set_changed(self, conf_file):
menubar = QMenuBar() self.conf = Conf(conf_file)
file_menu = QMenu("&File", menubar) Conf.set_current_conf(conf_file)
help_menu = QMenu("&Help", menubar) self.configuration_panel.build_widget.set_conf(self.conf)
menubar.addMenu(file_menu) acs = [ac.name for ac in self.conf.aircrafts]
menubar.addMenu(help_menu) self.header.set_acs(acs)
settings_action = QAction("&Edit Settings", file_menu)
file_menu.addAction(settings_action)
about_action = QAction("&About", help_menu)
help_menu.addAction(about_action)
def edit_settings(): # set last AC as current if it exits in the current conf
settings_dialog = AppSettings(self) settings = utils.get_settings()
settings_dialog.show() last_ac: QtCore.QVariant = settings.value("ui/last_AC", None, str)
settings_action.triggered.connect(edit_settings) if last_ac in acs:
about_action.triggered.connect(lambda: QMessageBox.about(self, "About Paparazzi", utils.ABOUT_TEXT)) self.handle_ac_changed(last_ac)
last_target: QtCore.QVariant = settings.value("ui/last_target", None, str)
if last_target:
self.configuration_panel.build_widget.target_combo.setCurrentText(last_target)
self.setMenuBar(menubar) def handle_ac_edited(self, ac: Aircraft):
# check AC ID
if len(self.conf.get_all(ac.ac_id)) > 1:
self.header.id_spinBox.setStyleSheet("background-color: red;")
else:
self.header.id_spinBox.setStyleSheet("background-color: white;")
# update ac, then update all widgets
status, stderr = ac.update()
if status != 0:
self.handle_error(stderr.decode().strip())
else:
self.clear_error()
pass
self.change_ac(ac)
def closeEvent(self, e: QtGui.QCloseEvent) -> None: def handle_ac_changed(self, ac_name):
ac = self.conf[ac_name]
if ac is not None:
# self.handle_ac_edited(ac) # update AC ?
self.change_ac(ac)
def handle_remove_ac(self, ac: Aircraft):
button = QMessageBox.question(self, "Remove AC", "Remove AC <strong>{}</strong>?".format(ac.name))
if button == QMessageBox.Yes:
self.conf.remove(ac)
self.header.remove_ac(ac)
def handle_new_ac(self, orig: Aircraft = None):
if orig is None:
orig = Aircraft()
ui_dialog = Ui_NewACDialog()
dialog = QDialog(parent=self)
ui_dialog.setupUi(dialog)
def verify():
ok = True
id = ui_dialog.id_spinbox.value()
name = ui_dialog.name_edit.text()
if self.conf[id] is not None or id == 0:
ui_dialog.id_spinbox.setStyleSheet("background-color: red;")
ok = False
else:
ui_dialog.id_spinbox.setStyleSheet("")
if self.conf[name] is not None or name == "":
ui_dialog.name_edit.setStyleSheet("background-color: red;")
ok = False
else:
ui_dialog.name_edit.setStyleSheet("")
return ok
def accept():
if verify():
dialog.accept()
def reject():
dialog.reject()
def duplicate(result):
if result:
new_ac = copy.deepcopy(orig)
name = ui_dialog.name_edit.text()
ac_id = ui_dialog.id_spinbox.value()
new_ac.name = name
new_ac.ac_id = ac_id
self.conf.append(new_ac)
self.header.add_ac(new_ac)
self.change_ac(new_ac)
ui_dialog.id_spinbox.setValue(self.conf.get_free_id())
ui_dialog.buttonBox.accepted.connect(accept)
ui_dialog.buttonBox.rejected.connect(reject)
ui_dialog.id_spinbox.valueChanged.connect(verify)
ui_dialog.name_edit.textChanged.connect(verify)
dialog.finished.connect(duplicate)
dialog.open()
def change_ac(self, ac):
self.currentAc = ac
self.header.set_ac(ac)
self.configuration_panel.set_ac(ac)
self.operation_panel.session.set_aircraft(ac)
self.doc_panel.set_aircraft(ac)
def handle_rename_ac(self, orig: Aircraft):
ui_dialog = Ui_NewACDialog()
dialog = QDialog(parent=self)
ui_dialog.setupUi(dialog)
ui_dialog.name_edit.setText(orig.name)
ui_dialog.id_spinbox.setValue(orig.ac_id)
def verify():
ok = True
id = ui_dialog.id_spinbox.value()
name = ui_dialog.name_edit.text()
acs_name = self.conf.get_all(name)
if len(acs_name) > 1 or (len(acs_name) == 1 and acs_name[0] != orig):
ui_dialog.name_edit.setStyleSheet("background-color: red;")
ok = False
else:
ui_dialog.name_edit.setStyleSheet("")
acs_id = self.conf.get_all(id)
if len(acs_id) > 1 or (len(acs_id) == 1 and acs_id[0] != orig):
ui_dialog.id_spinbox.setStyleSheet("background-color: red;")
ok = False
else:
ui_dialog.id_spinbox.setStyleSheet("")
return ok
def accept():
if verify():
dialog.accept()
def reject():
dialog.reject()
def rename(result):
if result:
orig.name = ui_dialog.name_edit.text()
orig.ac_id = ui_dialog.id_spinbox.value()
self.header.rename_ac(orig.name)
ui_dialog.buttonBox.accepted.connect(accept)
ui_dialog.buttonBox.rejected.connect(reject)
ui_dialog.id_spinbox.valueChanged.connect(verify)
ui_dialog.name_edit.textChanged.connect(verify)
dialog.finished.connect(rename)
dialog.open()
def edit_settings(self):
settings_dialog = AppSettings(self)
settings_dialog.show()
def quit(self, interactive=True):
quit_accepted = True
if self.operation_panel.session.any_program_running(): if self.operation_panel.session.any_program_running():
quit_accepted = False
self.operation_panel.session.programs_all_stopped.connect(self.close) self.operation_panel.session.programs_all_stopped.connect(self.close)
self.operation_panel.session.stop_all() self.operation_panel.session.stop_all()
e.ignore()
self.operation_panel.session.programs_all_stopped.connect(self.close) self.operation_panel.session.programs_all_stopped.connect(self.close)
else: else:
restore_conf = True
if utils.get_settings().value("always_keep_changes", False, bool): if utils.get_settings().value("always_keep_changes", False, bool):
self.configuration_panel.conf.save() restore_conf = False
else: else:
conf_tree_orig = self.configuration_panel.conf.tree_orig conf_tree_orig = self.conf.tree_orig
conf_tree = self.configuration_panel.conf.to_xml_tree() conf_tree = self.conf.to_xml_tree()
if ET.tostring(conf_tree) != ET.tostring(conf_tree_orig): if ET.tostring(conf_tree) != ET.tostring(conf_tree_orig) and interactive:
buttons = QMessageBox.question(self, "Save configuration?", buttons = QMessageBox.question(self, "Save configuration?",
"The configuration has changed, do you want to save it?") "The configuration has changed, do you want to save it?")
if buttons == QMessageBox.Yes: if buttons == QMessageBox.Yes:
self.configuration_panel.conf.save() restore_conf = False
else: if restore_conf:
self.configuration_panel.conf.restore_conf() self.conf.restore_conf()
self.configuration_panel.conf.save() self.conf.save()
self.save_gconf() self.save_gconf()
return quit_accepted
def closeEvent(self, e: QtGui.QCloseEvent) -> None:
if self.quit():
e.accept() e.accept()
else:
e.ignore()
def save_gconf(self): def save_gconf(self):
settings = utils.get_settings() settings = utils.get_settings()
settings.setValue("ui/window_size", self.size()) settings.setValue("ui/window_size", self.size())
settings.setValue("ui/last_AC", self.configuration_panel.get_current_ac()) settings.setValue("ui/last_AC", self.currentAc.name)
settings.setValue("ui/last_session", self.operation_panel.session.get_current_session()) settings.setValue("ui/last_session", self.operation_panel.session.get_current_session())
def update_left_pane_width(self, pos, index): def update_left_pane_width(self, pos, index):
@@ -119,10 +271,24 @@ class PprzCenter(QMainWindow):
if __name__ == "__main__": if __name__ == "__main__":
import sys
app = QApplication(sys.argv) app = QApplication(sys.argv)
timer = QtCore.QTimer()
timer.start(100)
timer.timeout.connect(lambda: None) # Let the interpreter run each 100 ms.
main_window = PprzCenter() main_window = PprzCenter()
main_window.show() main_window.show()
# qApp.aboutToQuit.connect(main_window.quit) # qApp.aboutToQuit.connect(main_window.quit)
sys.exit(app.exec_())
def sigint_handler(*args):
"""Handler for the SIGINT signal."""
print("catched SIGINT")
sys.stderr.write('\r')
if main_window.quit(False):
QApplication.quit()
signal.signal(signal.SIGINT, sigint_handler)
sys.exit(app.exec_())
+2
View File
@@ -215,6 +215,8 @@ class SessionWidget(QWidget, Ui_Session):
return return
programs = self.get_programs() programs = self.get_programs()
session = Session(session_name, programs) session = Session(session_name, programs)
self.sessions_combo.addItem(session_name)
self.sessions_combo.setCurrentText(session_name)
self.sessions.append(session) self.sessions.append(session)
self.save_sessions() self.save_sessions()
@@ -14,23 +14,6 @@
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout_2"> <layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="HeaderWidget" name="header" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="Line" name="line">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</widget>
</item>
<item> <item>
<widget class="QSplitter" name="splitter"> <widget class="QSplitter" name="splitter">
<property name="orientation"> <property name="orientation">
@@ -96,12 +79,6 @@
<header>build_widget.h</header> <header>build_widget.h</header>
<container>1</container> <container>1</container>
</customwidget> </customwidget>
<customwidget>
<class>HeaderWidget</class>
<extends>QWidget</extends>
<header>header_widget.h</header>
<container>1</container>
</customwidget>
<customwidget> <customwidget>
<class>ConsoleWidget</class> <class>ConsoleWidget</class>
<extends>QWidget</extends> <extends>QWidget</extends>
+196
View File
@@ -0,0 +1,196 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>DocPanel</class>
<widget class="QWidget" name="DocPanel">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>654</width>
<height>658</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QSplitter" name="splitter_2">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<widget class="QWidget" name="conf" native="true">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
<item>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Target:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="target_combo"/>
</item>
</layout>
</item>
<item>
<widget class="QLineEdit" name="searchLineEdit">
<property name="placeholderText">
<string>search...</string>
</property>
<property name="clearButtonEnabled">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QWidget" name="momo" native="true">
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Modules</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="modules_list"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string>Modules Dependencies</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="depends_modules_list"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string>Modules Unloaded</string>
</property>
</widget>
</item>
<item>
<widget class="QListWidget" name="unloaded_modules_list"/>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="backButton">
<property name="toolTip">
<string>Go back</string>
</property>
<property name="text">
<string/>
</property>
<property name="icon">
<iconset theme="go-previous">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="urlLineEdit"/>
</item>
<item>
<widget class="QToolButton" name="open_browser_button">
<property name="toolTip">
<string>Open in Browser</string>
</property>
<property name="text">
<string>...</string>
</property>
<property name="icon">
<iconset theme="applications-internet">
<normaloff>.</normaloff>.</iconset>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="doc_source_combo">
<property name="toolTip">
<string>source</string>
</property>
<item>
<property name="text">
<string>Internet</string>
</property>
</item>
<item>
<property name="text">
<string>Local</string>
</property>
</item>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QWebView" name="webView">
<property name="url">
<url>
<string>about:blank</string>
</url>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QWebView</class>
<extends>QWidget</extends>
<header location="global">QtWebKitWidgets/QWebView</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"> <ui version="4.0">
<class>Dialog</class> <class>NewACDialog</class>
<widget class="QDialog" name="Dialog"> <widget class="QDialog" name="NewACDialog">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>
@@ -11,7 +11,7 @@
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Dialog</string> <string>Aircraft</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="0" column="0"> <item row="0" column="0">
@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>SupervisionWindow</class>
<widget class="QMainWindow" name="SupervisionWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Paparazzi Center</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="HeaderWidget" name="header" native="true"/>
</item>
<item>
<widget class="QTabWidget" name="tabwidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="ConfigurationPanel" name="configuration_panel">
<attribute name="title">
<string>Configuration</string>
</attribute>
</widget>
<widget class="OperationPanel" name="operation_panel">
<attribute name="title">
<string>Operation</string>
</attribute>
</widget>
<widget class="DocPanel" name="doc_panel">
<attribute name="title">
<string>Documentation</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>22</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<addaction name="settings_action"/>
</widget>
<widget class="QMenu" name="menuHelp">
<property name="title">
<string>Help</string>
</property>
<addaction name="about_action"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuHelp"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="settings_action">
<property name="text">
<string>Edit Settings</string>
</property>
</action>
<action name="about_action">
<property name="text">
<string>About</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>
<class>HeaderWidget</class>
<extends>QWidget</extends>
<header>header_widget.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>ConfigurationPanel</class>
<extends>QWidget</extends>
<header>configuration_panel.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>OperationPanel</class>
<extends>QWidget</extends>
<header>operation_panel.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>DocPanel</class>
<extends>QWidget</extends>
<header>doc_panel.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
+9 -1
View File
@@ -18,12 +18,20 @@ PAPARAZZI_HOME = os.getenv("PAPARAZZI_HOME", PAPARAZZI_SRC)
CONF_DIR = os.path.join(PAPARAZZI_HOME, "conf/") CONF_DIR = os.path.join(PAPARAZZI_HOME, "conf/")
def removeprefix(string: str, prefix: str, /) -> str: def remove_prefix(string: str, prefix: str, /) -> str:
if string.startswith(prefix): if string.startswith(prefix):
return string[len(prefix):] return string[len(prefix):]
else: else:
return string[:] return string[:]
def remove_suffix(s: str, suffix: str, /) -> str:
if s.endswith(suffix):
return s[:-len(suffix)]
else:
return s
# TODO: make it work with shell program such as vim. # TODO: make it work with shell program such as vim.
def edit_file(file_path, prefix=CONF_DIR): def edit_file(file_path, prefix=CONF_DIR):
path = prefix + file_path path = prefix + file_path
+17 -1
View File
@@ -24,16 +24,24 @@ let (//) = Filename.concat
let conf_dir = Env.paparazzi_home // "conf" let conf_dir = Env.paparazzi_home // "conf"
let conf_xml_file = conf_dir // "conf.xml" let conf_xml_file = conf_dir // "conf.xml"
let letter_of_load_tyoe = function
| Aircraft.UserLoad -> "U"
| Aircraft.Depend -> "D"
| Aircraft.AutoLoad -> "A"
| Aircraft.Unloaded -> "N"
let () = let () =
let ac_name = ref None let ac_name = ref None
and af_xml = ref None and af_xml = ref None
and fp_xml = ref None and fp_xml = ref None
and target = ref None
and output = ref None in and output = ref None in
let options = [ let options = [
"-ac", Arg.String (fun x -> ac_name := Some x), "Aircraft name (mandatory)"; "-ac", Arg.String (fun x -> ac_name := Some x), "Aircraft name (mandatory)";
"-af", Arg.String (fun x -> af_xml := Some x), "Airframe XML file (optinal)"; "-af", Arg.String (fun x -> af_xml := Some x), "Airframe XML file (optinal)";
"-fp", Arg.String (fun x -> fp_xml := Some x), "Flight_plan XML file (optional)"; "-fp", Arg.String (fun x -> fp_xml := Some x), "Flight_plan XML file (optional)";
"-t", Arg.String (fun x -> target := Some x), "Target name (optional)";
"-o", Arg.String (fun x -> output := Some x), "Output file name (stdout if not specified)" "-o", Arg.String (fun x -> output := Some x), "Output file name (stdout if not specified)"
] in ] in
Arg.parse options (fun _ -> ()) "Usage:"; Arg.parse options (fun _ -> ()) "Usage:";
@@ -56,7 +64,15 @@ let () =
in in
let ac = Aircraft.parse_aircraft ~parse_af:true ~parse_ap:true ~parse_fp:true "" aircraft_xml in let ac = Aircraft.parse_aircraft ~parse_af:true ~parse_ap:true ~parse_fp:true "" aircraft_xml in
let modules_filenames = List.map (fun m -> m.Module.xml_filename) ac.Aircraft.all_modules in let modules_filenames = match !target with
| None -> List.map (fun m -> m.Module.xml_filename) ac.Aircraft.all_modules
| Some t ->
try
let selected = Hashtbl.find ac.Aircraft.config_by_target t in
List.map (fun (load_type, m) -> Printf.sprintf "%s %s" m.Module.xml_filename (letter_of_load_tyoe load_type))
selected.Aircraft.modules
with Not_found -> failwith "Dump modules: unknown target"
in
let modules_filenames = String.concat "\n" modules_filenames in let modules_filenames = String.concat "\n" modules_filenames in
match !output with match !output with