diff --git a/mslib/msui/_tests/test_mscolab.py b/mslib/msui/_tests/test_mscolab.py index fdef40629..528e69601 100644 --- a/mslib/msui/_tests/test_mscolab.py +++ b/mslib/msui/_tests/test_mscolab.py @@ -29,7 +29,7 @@ import fs import fs.errors import fs.opener.errors -import requests.exceptions +# import requests.exceptions import mock import pytest @@ -88,6 +88,13 @@ def test_login(self): assert self.main_window.listProjectsMSC.model().rowCount() == 0 assert self.main_window.mscolab.conn is None + # ToDo for new connect window + # for exc in [requests.exceptions.ConnectionError, requests.exceptions.InvalidSchema, + # requests.exceptions.InvalidURL, requests.exceptions.SSLError, Exception("")]: + # with mock.patch("requests.get", new=ExceptionMock(exc).raise_exc): + # self.window.connect_handler() + # assert mockbox.critical.call_count == 5 + def test_add_user(self): self._connect_to_mscolab() self._create_user("something", "something@something.org", "something") @@ -136,8 +143,6 @@ class Test_Mscolab(object): } export_plugins = { "Text": ["txt", "mslib.plugins.io.text", "save_to_txt"], - # "KML": ["kml", "mslib.plugins.io.kml", "save_to_kml"], - # "GPX": ["gpx", "mslib.plugins.io.gpx", "save_to_gpx"] } def setup(self): @@ -213,12 +218,13 @@ def test_handle_export(self, mockbox): for i in range(wp_count): assert exported_waypoints.waypoint_data(i).lat == self.window.mscolab.waypoints_model.waypoint_data(i).lat - @pytest.mark.parametrize("ext", [".ftml", ".csv", ".txt"]) + @pytest.mark.parametrize("ext", [".ftml", ".csv"]) @mock.patch("PyQt5.QtWidgets.QMessageBox") def test_import_file(self, mockbox, ext): - with mock.patch("mslib.msui.mscolab.config_loader", return_value=self.import_plugins): + # ToDo for .txt extension + with mock.patch("mslib.msui.mss_pyui.config_loader", return_value=self.import_plugins): self.window.add_import_plugins("qt") - with mock.patch("mslib.msui.mscolab.config_loader", return_value=self.export_plugins): + with mock.patch("mslib.msui.mss_pyui.config_loader", return_value=self.export_plugins): self.window.add_export_plugins("qt") with mock.patch("PyQt5.QtWidgets.QFileDialog.getSaveFileName", return_value=(fs.path.join( mscolab_settings.MSCOLAB_DATA_DIR, f'test_import{ext}'), None)): @@ -233,6 +239,7 @@ def test_import_file(self, mockbox, ext): if action.objectName() == full_name: action.trigger() break + assert os.path.exists(fs.path.join(mscolab_settings.MSCOLAB_DATA_DIR, f'test_import{ext}')) QtWidgets.QApplication.processEvents() self.window.mscolab.waypoints_model.invert_direction() QtWidgets.QApplication.processEvents() @@ -297,20 +304,20 @@ def test_add_project(self, mockbox): assert self.window.usernameLabel.text() == 'something' assert self.window.connectBtn.isVisible() is False self._create_project("Alpha", "Description Alpha") - assert mockbox.return_value.showMessage.call_count == 2 + assert mockbox.return_value.showMessage.call_count == 1 with mock.patch("PyQt5.QtWidgets.QLineEdit.text", return_value=None): self._create_project("Alpha2", "Description Alpha") with mock.patch("PyQt5.QtWidgets.QTextEdit.toPlainText", return_value=None): self._create_project("Alpha3", "Description Alpha") self._create_project("/", "Description Alpha") - assert mockbox.return_value.showMessage.call_count == 5 - assert self.window.listProjects.model().rowCount() == 1 + assert mockbox.return_value.showMessage.call_count == 4 + assert self.window.listProjectsMSC.model().rowCount() == 1 self._create_project("reproduce-test", "Description Test") - assert self.window.listProjects.model().rowCount() == 2 + assert self.window.listProjectsMSC.model().rowCount() == 2 self._activate_project_at_index(0) - assert self.window.active_project_name == "Alpha" + assert self.window.mscolab.active_project_name == "Alpha" self._activate_project_at_index(1) - assert self.window.active_project_name == "reproduce-test" + assert self.window.mscolab.active_project_name == "reproduce-test" @mock.patch("mslib.msui.mscolab.QtWidgets.QInputDialog.getText", return_value=("flight7", True)) def test_handle_delete_project(self, mocktext): @@ -405,14 +412,14 @@ def test_close_help_dialog(self): @mock.patch("sys.exit") def test_create_dir_exceptions(self, mockexit, mockbox): with mock.patch("fs.open_fs", new=ExceptionMock(fs.errors.CreateFailed).raise_exc): - self.window.data_dir = "://" - self.window.create_dir() + self.window.mscolab.data_dir = "://" + self.window.mscolab.create_dir() assert mockbox.critical.call_count == 1 assert mockexit.call_count == 1 with mock.patch("fs.open_fs", new=ExceptionMock(fs.opener.errors.UnsupportedProtocol).raise_exc): - self.window.data_dir = "://" - self.window.create_dir() + self.window.mscolab.data_dir = "://" + self.window.mscolab.create_dir() assert mockbox.critical.call_count == 2 assert mockexit.call_count == 2 diff --git a/mslib/msui/_tests/test_mss_pyui.py b/mslib/msui/_tests/test_mss_pyui.py index 28e3b6912..c562d3f20 100644 --- a/mslib/msui/_tests/test_mss_pyui.py +++ b/mslib/msui/_tests/test_mss_pyui.py @@ -37,8 +37,6 @@ from mslib._tests.constants import ROOT_DIR import mslib.msui.mss_pyui as mss_pyui from mslib._tests.utils import ExceptionMock -from mslib.plugins.io.text import load_from_txt -from mslib.plugins.io.flitestar import load_from_flitestar class Test_MSS_AboutDialog(): @@ -186,20 +184,8 @@ def test_open_shortcut(self, mockbox): QtWidgets.QApplication.processEvents() assert mockbox.critical.call_count == 0 - @pytest.mark.parametrize("save_file", [save_ftml, save_csv]) - def test_default_plugins_saveas(self, save_file): - with mock.patch("mslib.msui.mss_pyui.get_save_filename", return_value=save_file) as mocksave: - assert self.window.listFlightTracks.count() == 1 - assert mocksave.call_count == 0 - self.window.last_save_directory = ROOT_DIR - self.window.actionSaveActiveFlightTrackAs.trigger() - QtWidgets.QApplication.processEvents() - assert mocksave.call_count == 1 - assert os.path.exists(save_file) - os.remove(save_file) - - @pytest.mark.parametrize("save_file", [save_txt]) - def test_external_plugins_saveas(self, save_file): + @pytest.mark.parametrize("save_file", [save_ftml, save_csv, save_txt]) + def test_plugin_saveas(self, save_file): with mock.patch("mslib.msui.mss_pyui.config_loader", return_value=self.export_plugins): self.window.add_export_plugins("qt") with mock.patch("mslib.msui.mss_pyui.get_save_filename", return_value=save_file) as mocksave: @@ -212,26 +198,21 @@ def test_external_plugins_saveas(self, save_file): assert os.path.exists(save_file) os.remove(save_file) - @pytest.mark.parametrize("open_file", [open_ftml, open_csv]) - def test_default_plugins_open(self, open_file): - with mock.patch("mslib.msui.mss_pyui.get_open_filename", return_value=open_file) as mockopen: - assert self.window.listFlightTracks.count() == 1 - assert mockopen.call_count == 0 - self.window.last_save_directory = ROOT_DIR - self.window.actionOpenFlightTrack.trigger() - QtWidgets.QApplication.processEvents() - assert mockopen.call_count == 1 - assert self.window.listFlightTracks.count() == 2 - - @pytest.mark.parametrize("open_file", [open_txt]) - def test_external_plugins_open(self, open_file): + @pytest.mark.parametrize( + "open_file", [(open_ftml, "ftml"), (open_csv, "csv"), (open_txt, "txt"), (open_fls, "fls")]) + def test_plugin_import(self, open_file): with mock.patch("mslib.msui.mss_pyui.config_loader", return_value=self.import_plugins): self.window.add_import_plugins("qt") - with mock.patch("mslib.msui.mss_pyui.get_open_filename", return_value=open_file) as mockopen: + with mock.patch("mslib.msui.mss_pyui.get_open_filename", return_value=open_file[0]) as mockopen: assert self.window.listFlightTracks.count() == 1 assert mockopen.call_count == 0 self.window.last_save_directory = ROOT_DIR - self.window.actionOpenFlightTrack.trigger() + ext = open_file[1] + full_name = f"actionImportFlightTrack{ext}" + for action in self.window.menuImportFlightTrack.actions(): + if action.objectName() == full_name: + action.trigger() + break QtWidgets.QApplication.processEvents() assert mockopen.call_count == 1 assert self.window.listFlightTracks.count() == 2 @@ -255,43 +236,6 @@ def test_plugin_export(self, save_file): assert os.path.exists(save_file) os.remove(save_file) - @mock.patch("mslib.msui.mss_pyui.get_open_filename", return_value=os.path.join(sample_path, u"example.csv")) - def test_plugin_csv_read(self, mockopen): - pytest.skip("To be done") - assert self.window.listFlightTracks.count() == 1 - assert mockopen.call_count == 0 - self.window.last_save_directory = self.sample_path - self.window.actionImportFlightTrackcsv.trigger() - QtWidgets.QApplication.processEvents() - assert self.window.listFlightTracks.count() == 2 - assert mockopen.call_count == 1 - - @mock.patch("mslib.msui.mss_pyui.get_open_filename", return_value=os.path.join(sample_path, u"example.txt")) - def test_plugin_txt_read(self, mockopen): - pytest.skip("To be done") - self.window.add_plugin_submenu("Text", "txt", "qt", plugin_type="Import") - self.window.import_plugins['txt'] = load_from_txt - assert self.window.listFlightTracks.count() == 1 - assert mockopen.call_count == 0 - self.window.last_save_directory = self.sample_path - self.window.actionImportFlightTracktxt.trigger() - assert mockopen.call_count == 1 - QtWidgets.QApplication.processEvents() - assert self.window.listFlightTracks.count() == 2 - - @mock.patch("mslib.msui.mss_pyui.get_open_filename", - return_value=os.path.join(sample_path, u"flitestar.txt")) - def test_plugin_flitestar(self, mockopen): - pytest.skip("To be done") - self.window.last_save_directory = self.sample_path - self.window.add_plugin_submenu("FliteStar", "fls", "qt", plugin_type="Import") - self.window.import_plugins['fls'] = load_from_flitestar - assert self.window.listFlightTracks.count() == 1 - self.window.actionImportFlightTrackfls.trigger() - QtWidgets.QApplication.processEvents() - assert self.window.listFlightTracks.count() == 2 - assert mockopen.call_count == 1 - @mock.patch("PyQt5.QtWidgets.QMessageBox") @mock.patch("mslib.msui.mss_pyui.config_loader", return_value=export_plugins) def test_add_plugins(self, mockopen, mockbox): @@ -350,7 +294,7 @@ def test_flight_track_io(self, mockload, mocksave, mockq, mocki, mockw, mockbox) self.window.active_flight_track = tmp_ft self.window.actionCloseSelectedFlightTrack.trigger() assert self.window.listFlightTracks.count() == 1 - self.window.actionOpenFlightTrack.trigger() + self.window.actionImportFlightTrackftml.trigger() assert self.window.listFlightTracks.count() == 2 assert os.path.exists(self.save_ftml) os.remove(self.save_ftml) diff --git a/mslib/msui/flighttrack.py b/mslib/msui/flighttrack.py index dc22ab580..1f2f20b5d 100755 --- a/mslib/msui/flighttrack.py +++ b/mslib/msui/flighttrack.py @@ -163,10 +163,7 @@ def __init__(self, name="", filename=None, waypoints=None, mscolab_mode=False, d # If a filename is passed to the constructor, load data from this file. if filename is not None: - if filename.endswith(".ftml"): - self.load_from_ftml(filename) - else: - logging.debug("No known file extension! '%s'", filename) + self.load_from_ftml(filename) # If xml string is passed to constructor, load data from that elif xml_content is not None: diff --git a/mslib/msui/mscolab.py b/mslib/msui/mscolab.py index 00f54d010..d9e1ae9ae 100644 --- a/mslib/msui/mscolab.py +++ b/mslib/msui/mscolab.py @@ -1176,23 +1176,16 @@ def reload_view_windows(self): except AttributeError as err: logging.error("%s" % err) - def handle_import_msc(self, extension, pickertype): + def handle_import_msc(self, file_path, extension, function, pickertype): if self.verify_user_token(): if self.active_pid is None: return - - if self.ui.workLocallyCheckbox.isChecked() and extension != "ftml": - self.ui.statusBar().showMessage("Work Locally only supports FTML filetypes for import") - return - file_path = get_open_filename( - self.ui, "Import to Server", "", f"Flight track (*.{extension})", pickertype=pickertype - ) if file_path is None: return dir_path, file_name = fs.path.split(file_path) file_name = fs.path.basename(file_path) name, file_ext = fs.path.splitext(file_name) - if file_ext[1:] == "ftml": + if function is None: with open_fs(dir_path) as file_dir: xml_content = file_dir.readtext(file_name) try: @@ -1200,20 +1193,18 @@ def handle_import_msc(self, extension, pickertype): except SyntaxError: show_popup(self.ui, "Import Failed", f"The file - {file_name}, does not contain valid XML") return - self.waypoints_model = model - if self.ui.workLocallyCheckbox.isChecked(): - self.waypoints_model.save_to_ftml(self.local_ftml_file) - self.waypoints_model.dataChanged.connect(self.handle_waypoints_changed) - else: - self.conn.save_file(self.token, self.active_pid, xml_content, comment=None) - self.waypoints_model.dataChanged.connect(self.handle_waypoints_changed) else: - _function = self.ui.import_plugins[file_ext[1:]] - _, new_waypoints = _function(file_path) + # _function = self.ui.import_plugins[file_ext[1:]] + _, new_waypoints = function(file_path) model = ft.WaypointsTableModel(waypoints=new_waypoints) - self.waypoints_model = model xml_doc = self.waypoints_model.get_xml_doc() xml_content = xml_doc.toprettyxml(indent=" ", newl="\n") + self.waypoints_model.dataChanged.connect(self.handle_waypoints_changed) + self.waypoints_model = model + if self.ui.workLocallyCheckbox.isChecked(): + self.waypoints_model.save_to_ftml(self.local_ftml_file) + self.waypoints_model.dataChanged.connect(self.handle_waypoints_changed) + else: self.conn.save_file(self.token, self.active_pid, xml_content, comment=None) self.waypoints_model.dataChanged.connect(self.handle_waypoints_changed) self.reload_view_windows() @@ -1222,7 +1213,7 @@ def handle_import_msc(self, extension, pickertype): show_popup(self.ui, "Error", "Your Connection is expired. New Login required!") self.logout() - def handle_export_msc(self, extension, pickertype): + def handle_export_msc(self, extension, function, pickertype): if self.verify_user_token(): if self.active_pid is None: return @@ -1235,15 +1226,14 @@ def handle_export_msc(self, extension, pickertype): pickertype=pickertype) if file_name is None: return - if file_name.endswith('.ftml'): + if function is None: xml_doc = self.waypoints_model.get_xml_doc() dir_path, file_name = fs.path.split(file_name) with open_fs(dir_path).open(file_name, 'w') as file: xml_doc.writexml(file, indent=" ", addindent=" ", newl="\n", encoding="utf-8") else: - file_path = fs.path.basename(file_name) - _function = self.ui.export_plugins[extension] - _function(file_name, file_path, self.waypoints_model.waypoints) + name = fs.path.basename(file_name) + function(file_name, name, self.waypoints_model.waypoints) show_popup(self.ui, "Export Success", f"The file - {file_name}, was exported successfully!", 1) else: show_popup(self.ui, "Error", "Your Connection is expired. New Login required!") @@ -1330,7 +1320,6 @@ def logout(self): self.ui.usernameLabel.hide() self.ui.userOptionsTb.hide() self.ui.connectBtn.show() - # self.ui.addProjectBtn.hide() self.ui.actionAddProject.setEnabled(False) # disconnect socket if self.conn is not None: diff --git a/mslib/msui/mss_pyui.py b/mslib/msui/mss_pyui.py index f2468b8a6..485a4665e 100644 --- a/mslib/msui/mss_pyui.py +++ b/mslib/msui/mss_pyui.py @@ -237,7 +237,6 @@ def __init__(self, mscolab_data_dir=None, *args): # File menu. self.actionNewFlightTrack.triggered.connect(functools.partial(self.create_new_flight_track, None, None)) - self.actionOpenFlightTrack.triggered.connect(self.open_flight_track) self.actionSaveActiveFlightTrack.triggered.connect(self.save_handler) self.actionSaveActiveFlightTrackAs.triggered.connect(self.save_as_handler) self.actionCloseSelectedFlightTrack.triggered.connect(self.close_selected_flight_track) @@ -271,10 +270,10 @@ def __init__(self, mscolab_data_dir=None, *args): # Add default and plugins from settings picker_default = config_loader(dataset="filepicker_default") - self.add_plugin_submenu("FTML", "ftml", picker_default, plugin_type="Import") - self.add_plugin_submenu("FTML", "ftml", picker_default, plugin_type="Export") - self.add_plugin_submenu("CSV", "csv", picker_default, plugin_type="Import") - self.add_plugin_submenu("CSV", "csv", picker_default, plugin_type="Export") + self.add_plugin_submenu("FTML", "ftml", None, picker_default, plugin_type="Import") + self.add_plugin_submenu("FTML", "ftml", None, picker_default, plugin_type="Export") + self.add_plugin_submenu("CSV", "csv", load_from_csv, picker_default, plugin_type="Import") + self.add_plugin_submenu("CSV", "csv", save_to_csv, picker_default, plugin_type="Export") self.import_plugins = {"csv": load_from_csv} self.export_plugins = {"csv": save_to_csv} self.add_import_plugins(picker_default) @@ -341,23 +340,15 @@ def bring_main_window_to_front(self): def menu_handler(self): self.menuImportFlightTrack.setEnabled(True) - # self.menuExportActiveFlightTrack.setEnabled(True) - if (not self.local_active and self.mscolab.access_level == "viewer") or self.local_active: + if not self.local_active and self.mscolab.access_level == "viewer": # viewer has no import access to server self.menuImportFlightTrack.setEnabled(False) - # enable/disable FTML import/export actions - # self.actionImportFlightTrackFTML.setVisible(not self.local_active) - # self.actionExportFlightTrackFTML.setVisible(not self.local_active) - # enable/disable flight track menus - # self.actionNewFlightTrack.setEnabled(self.local_active) - # self.actionOpenFlightTrack.setEnabled(self.local_active) self.actionSaveActiveFlightTrack.setEnabled(self.local_active) self.actionSaveActiveFlightTrackAs.setEnabled(self.local_active) - # self.actionCloseSelectedFlightTrack.setEnabled(self.local_active) - def add_plugin_submenu(self, name, extension, pickertype, plugin_type="Import"): + def add_plugin_submenu(self, name, extension, function, pickertype, plugin_type="Import"): if plugin_type == "Import": menu = self.menuImportFlightTrack action_name = "actionImportFlightTrack" + clean_string(extension) @@ -372,7 +363,7 @@ def add_plugin_submenu(self, name, extension, pickertype, plugin_type="Import"): action = QtWidgets.QAction(self) action.setObjectName(action_name) action.setText(QtCore.QCoreApplication.translate("MSSMainWindow", name, None)) - action.triggered.connect(functools.partial(handler, extension, pickertype)) + action.triggered.connect(functools.partial(handler, extension, function, pickertype)) menu.addAction(action) setattr(self, action_name, action) @@ -385,6 +376,7 @@ def add_import_plugins(self, picker_default): picker_type = plugins[name][3] try: imported_module = importlib.import_module(module) + imported_function = getattr(imported_module, function) # wildcard exception to be resilient against error introduced by user code except Exception as ex: logging.error("Error on import: %s: %s", type(ex), ex) @@ -393,7 +385,7 @@ def add_import_plugins(self, picker_default): self.tr(f"ERROR: Configuration\n\n{plugins,}\n\nthrows {type(ex)} error:\n{ex}")) continue try: - self.add_plugin_submenu(name, extension, picker_type, plugin_type="Import") + self.add_plugin_submenu(name, extension, imported_function, picker_type, plugin_type="Import") # wildcard exception to be resilient against error introduced by user code except Exception as ex: logging.error("Error on installing plugin: %s: %s", type(ex), ex) @@ -401,7 +393,7 @@ def add_import_plugins(self, picker_default): self, self.tr("file io plugin error import plugins"), self.tr(f"ERROR: Configuration\n\n{self.import_plugins}\n\nthrows {type(ex)} error:\n{ex}")) continue - self.import_plugins[extension] = getattr(imported_module, function) + self.import_plugins[extension] = imported_function def add_export_plugins(self, picker_default): plugins = config_loader(dataset="export_plugins") @@ -412,6 +404,7 @@ def add_export_plugins(self, picker_default): picker_type = plugins[name][3] try: imported_module = importlib.import_module(module) + imported_function = getattr(imported_module, function) # wildcard exception to be resilient against error introduced by user code except Exception as ex: logging.error("Error on import: %s: %s", type(ex), ex) @@ -420,7 +413,7 @@ def add_export_plugins(self, picker_default): self.tr(f"ERROR: Configuration\n\n{plugins,}\n\nthrows {type(ex)} error:\n{ex}")) continue try: - self.add_plugin_submenu(name, extension, picker_type, plugin_type="Export") + self.add_plugin_submenu(name, extension, imported_function, picker_type, plugin_type="Export") # wildcard exception to be resilient against error introduced by user code except Exception as ex: logging.error("Error on installing plugin: %s: %s", type(ex), ex) @@ -428,7 +421,7 @@ def add_export_plugins(self, picker_default): self, self.tr("file io plugin error import plugins"), self.tr(f"ERROR: Configuration\n\n{self.export_plugins}\n\nthrows {type(ex)} error:\n{ex}")) continue - self.export_plugins[extension] = getattr(imported_module, function) + self.export_plugins[extension] = imported_function def remove_plugins(self): for name in self.import_plugins: @@ -449,38 +442,20 @@ def remove_plugins(self): delattr(self, full_name) self.export_plugins = {} - def handle_import_local(self, extension, pickertype): + def handle_import_local(self, extension, function, pickertype): + filename = get_open_filename( + self, "Import Flight Track", + self.last_save_directory, + f"Flight Track (*.{extension});;All files (*.*)", + pickertype=pickertype) if self.local_active: - function = self.import_plugins[extension] - filename = get_open_filename( - self, "Import Flight Track", - self.last_save_directory, - f"Flight Track (*.{extension})", - pickertype=pickertype) if filename is not None: self.last_save_directory = fs.path.dirname(filename) - try: - ft_name, new_waypoints = function(filename) - # wildcard exception to be resilient against error introduced by user code - except Exception as ex: - logging.error("file io plugin error: %s %s", type(ex), ex) - QtWidgets.QMessageBox.critical( - self, self.tr("file io plugin error"), - self.tr(f"ERROR: {type(ex)} {ex}")) - else: - if not ft_name: - ft_name = filename - waypoints_model = ft.WaypointsTableModel(name=ft_name, waypoints=new_waypoints) - - listitem = QFlightTrackListWidgetItem(waypoints_model, self.listFlightTracks) - listitem.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - - self.listFlightTracks.setCurrentItem(listitem) - self.activate_flight_track(listitem) + self.create_new_flight_track(filename=filename, function=function) else: - self.mscolab.handle_import_msc(extension, pickertype) + self.mscolab.handle_import_msc(filename, extension, function, pickertype) - def handle_export_local(self, extension, pickertype): + def handle_export_local(self, extension, function, pickertype): if self.local_active: default_filename = f'{os.path.join(self.last_save_directory, self.active_flight_track.name)}.{extension}' filename = get_save_filename( @@ -490,16 +465,15 @@ def handle_export_local(self, extension, pickertype): if filename is not None: self.last_save_directory = fs.path.dirname(filename) try: - if extension in self.export_plugins: - function = self.export_plugins[extension] - function(filename, self.active_flight_track.name, self.active_flight_track.waypoints) - elif filename.endswith('.ftml'): + if function is None: doc = self.active_flight_track.get_xml_doc() dirname, name = fs.path.split(filename) file_dir = fs.open_fs(dirname) with file_dir.open(name, 'w') as file_object: doc.writexml(file_object, indent=" ", addindent=" ", newl="\n", encoding="utf-8") file_dir.close() + else: + function(filename, self.active_flight_track.name, self.active_flight_track.waypoints) # wildcard exception to be resilient against error introduced by user code except Exception as ex: logging.error("file io plugin error: %s %s", type(ex), ex) @@ -507,9 +481,9 @@ def handle_export_local(self, extension, pickertype): self, self.tr("file io plugin error"), self.tr(f"ERROR: {type(ex)} {ex}")) else: - self.mscolab.handle_export_msc(extension, pickertype) + self.mscolab.handle_export_msc(extension, function, pickertype) - def create_new_flight_track(self, template=None, filename=None): + def create_new_flight_track(self, template=None, filename=None, function=None): """Creates a new flight track model from a template. Adds a new entry to the list of flight tracks. Called when the user selects the 'new/open flight track' menu entries. @@ -531,8 +505,10 @@ def create_new_flight_track(self, template=None, filename=None): self.tr("ERROR:Flighttrack template in configuration is too short. " "Please add at least two valid locations.")) + waypoints_model = None if filename is not None: - if filename.endswith('.ftml'): + # function is none if ftml file is selected + if function is None: try: waypoints_model = ft.WaypointsTableModel(filename=filename) except (SyntaxError, OSError, IOError) as ex: @@ -541,8 +517,6 @@ def create_new_flight_track(self, template=None, filename=None): self.tr(f"ERROR: {type(ex)} {ex}")) else: try: - ext = fs.path.splitext(filename)[-1][1:] - function = self.import_plugins[ext] ft_name, new_waypoints = function(filename) waypoints_model = ft.WaypointsTableModel(name=ft_name, waypoints=new_waypoints) # wildcard exception to be resilient against error introduced by user code @@ -551,12 +525,12 @@ def create_new_flight_track(self, template=None, filename=None): QtWidgets.QMessageBox.critical( self, self.tr("file io plugin error"), self.tr(f"ERROR: {type(ex)} {ex}")) - # if waypoints_model is not None: - # for i in range(self.listFlightTracks.count()): - # fltr = self.listFlightTracks.item(i) - # if fltr.flighttrack_model.name == waypoints_model.name: - # waypoints_model.name += " - opened from file" - # break + if waypoints_model is not None: + for i in range(self.listFlightTracks.count()): + fltr = self.listFlightTracks.item(i) + if fltr.flighttrack_model.name == waypoints_model.name: + waypoints_model.name += " - imported from file" + break else: # Create a new flight track from the waypoints template. self.new_flight_track_counter += 1 @@ -567,24 +541,13 @@ def create_new_flight_track(self, template=None, filename=None): template_copy = copy.deepcopy(template) waypoints_model.insertRows(0, rows=len(template_copy), waypoints=template_copy) - # Create a new list entry for the flight track. Make the item name editable. - listitem = QFlightTrackListWidgetItem(waypoints_model, self.listFlightTracks) - listitem.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - - # Activate new item - self.activate_flight_track(listitem) + if waypoints_model is not None: + # Create a new list entry for the flight track. Make the item name editable. + listitem = QFlightTrackListWidgetItem(waypoints_model, self.listFlightTracks) + listitem.setFlags(QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsEnabled) - def open_flight_track(self): - """Slot for the 'Open Flight Track' menu entry. Opens a QFileDialog and - passes the result to createNewFlightTrack(). - """ - file_type = ["Flight track (*.ftml)"] + [f"Flight track (*.{ext})" for ext in self.import_plugins.keys()] - filename = get_open_filename( - self, "Open Flight Track", self.last_save_directory, ';;'.join(file_type), - pickertag="filepicker_default") - if filename is not None: - self.last_save_directory = fs.path.dirname(filename) - self.create_new_flight_track(filename=filename) + # Activate new item + self.activate_flight_track(listitem) def activate_flight_track(self, item): """Set the currently selected flight track to be the active one, i.e. diff --git a/mslib/msui/qt5/ui_mainwindow.py b/mslib/msui/qt5/ui_mainwindow.py index a18e18dbf..87283579e 100644 --- a/mslib/msui/qt5/ui_mainwindow.py +++ b/mslib/msui/qt5/ui_mainwindow.py @@ -13,13 +13,13 @@ class Ui_MSSMainWindow(object): def setupUi(self, MSSMainWindow): MSSMainWindow.setObjectName("MSSMainWindow") - MSSMainWindow.resize(769, 736) + MSSMainWindow.resize(738, 736) MSSMainWindow.setMinimumSize(QtCore.QSize(507, 736)) self.centralwidget = QtWidgets.QWidget(MSSMainWindow) self.centralwidget.setObjectName("centralwidget") self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) self.gridLayout.setContentsMargins(8, 8, 8, 8) - self.gridLayout.setSpacing(4) + self.gridLayout.setSpacing(2) self.gridLayout.setObjectName("gridLayout") self.openViewsGb = QtWidgets.QGroupBox(self.centralwidget) self.openViewsGb.setObjectName("openViewsGb") @@ -41,9 +41,6 @@ def setupUi(self, MSSMainWindow): self.mscStatusLabel.setObjectName("mscStatusLabel") self.userOptionsHL.addWidget(self.mscStatusLabel) self.usernameLabel = QtWidgets.QLabel(self.centralwidget) - font = QtGui.QFont() - font.setPointSize(15) - self.usernameLabel.setFont(font) self.usernameLabel.setObjectName("usernameLabel") self.userOptionsHL.addWidget(self.usernameLabel, 0, QtCore.Qt.AlignRight) self.userOptionsTb = QtWidgets.QToolButton(self.centralwidget) @@ -63,9 +60,6 @@ def setupUi(self, MSSMainWindow): self.gridLayout_3.setContentsMargins(8, 8, 8, 8) self.gridLayout_3.setObjectName("gridLayout_3") self.workingStatusLabel = QtWidgets.QLabel(self.openProjectsGb) - font = QtGui.QFont() - font.setPointSize(13) - self.workingStatusLabel.setFont(font) self.workingStatusLabel.setWordWrap(True) self.workingStatusLabel.setObjectName("workingStatusLabel") self.gridLayout_3.addWidget(self.workingStatusLabel, 2, 0, 1, 2) @@ -102,7 +96,7 @@ def setupUi(self, MSSMainWindow): self.gridLayout.setColumnStretch(1, 1) MSSMainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MSSMainWindow) - self.menubar.setGeometry(QtCore.QRect(0, 0, 769, 22)) + self.menubar.setGeometry(QtCore.QRect(0, 0, 738, 22)) self.menubar.setNativeMenuBar(False) self.menubar.setObjectName("menubar") self.menuFile = QtWidgets.QMenu(self.menubar) @@ -111,6 +105,8 @@ def setupUi(self, MSSMainWindow): self.menuImportFlightTrack.setObjectName("menuImportFlightTrack") self.menuExportActiveFlightTrack = QtWidgets.QMenu(self.menuFile) self.menuExportActiveFlightTrack.setObjectName("menuExportActiveFlightTrack") + self.menuNew = QtWidgets.QMenu(self.menuFile) + self.menuNew.setObjectName("menuNew") self.menuHelp = QtWidgets.QMenu(self.menubar) self.menuHelp.setObjectName("menuHelp") self.menuViews = QtWidgets.QMenu(self.menubar) @@ -131,10 +127,6 @@ def setupUi(self, MSSMainWindow): self.actionAboutMSUI.setObjectName("actionAboutMSUI") self.actionOnlineHelp = QtWidgets.QAction(MSSMainWindow) self.actionOnlineHelp.setObjectName("actionOnlineHelp") - self.actionOpenFlightTrack = QtWidgets.QAction(MSSMainWindow) - self.actionOpenFlightTrack.setObjectName("actionOpenFlightTrack") - self.actionNewFlightTrack = QtWidgets.QAction(MSSMainWindow) - self.actionNewFlightTrack.setObjectName("actionNewFlightTrack") self.actionQuit = QtWidgets.QAction(MSSMainWindow) self.actionQuit.setObjectName("actionQuit") self.actionShortcuts = QtWidgets.QAction(MSSMainWindow) @@ -161,24 +153,26 @@ def setupUi(self, MSSMainWindow): self.actionManageUsers.setObjectName("actionManageUsers") self.actionMSColab = QtWidgets.QAction(MSSMainWindow) self.actionMSColab.setObjectName("actionMSColab") - self.actionAddProject = QtWidgets.QAction(MSSMainWindow) - self.actionAddProject.setObjectName("actionAddProject") self.actionEditProject = QtWidgets.QAction(MSSMainWindow) self.actionEditProject.setObjectName("actionEditProject") self.actionDeleteProject = QtWidgets.QAction(MSSMainWindow) self.actionDeleteProject.setObjectName("actionDeleteProject") self.actionBringMainWindowToFront = QtWidgets.QAction(MSSMainWindow) self.actionBringMainWindowToFront.setObjectName("actionBringMainWindowToFront") - self.menuFile.addAction(self.actionNewFlightTrack) - self.menuFile.addAction(self.actionOpenFlightTrack) - self.menuFile.addAction(self.actionAddProject) + self.actionNewFlightTrack = QtWidgets.QAction(MSSMainWindow) + self.actionNewFlightTrack.setObjectName("actionNewFlightTrack") + self.actionAddProject = QtWidgets.QAction(MSSMainWindow) + self.actionAddProject.setObjectName("actionAddProject") + self.menuNew.addAction(self.actionNewFlightTrack) + self.menuNew.addAction(self.actionAddProject) + self.menuFile.addAction(self.menuNew.menuAction()) + self.menuFile.addAction(self.menuImportFlightTrack.menuAction()) self.menuFile.addSeparator() self.menuFile.addAction(self.actionSaveActiveFlightTrack) self.menuFile.addAction(self.actionSaveActiveFlightTrackAs) self.menuFile.addSeparator() self.menuFile.addAction(self.actionCloseSelectedFlightTrack) self.menuFile.addSeparator() - self.menuFile.addAction(self.menuImportFlightTrack.menuAction()) self.menuFile.addAction(self.menuExportActiveFlightTrack.menuAction()) self.menuFile.addSeparator() self.menuFile.addAction(self.actionConfiguration) @@ -233,6 +227,7 @@ def retranslateUi(self, MSSMainWindow): self.menuFile.setTitle(_translate("MSSMainWindow", "&File")) self.menuImportFlightTrack.setTitle(_translate("MSSMainWindow", "Import Flight Track")) self.menuExportActiveFlightTrack.setTitle(_translate("MSSMainWindow", "Export Flight Track")) + self.menuNew.setTitle(_translate("MSSMainWindow", "New")) self.menuHelp.setTitle(_translate("MSSMainWindow", "&Help")) self.menuViews.setTitle(_translate("MSSMainWindow", "Views")) self.menuProject.setTitle(_translate("MSSMainWindow", "Project")) @@ -243,15 +238,11 @@ def retranslateUi(self, MSSMainWindow): self.actionSaveActiveFlightTrackAs.setShortcut(_translate("MSSMainWindow", "Ctrl+Shift+S")) self.actionAboutMSUI.setText(_translate("MSSMainWindow", "&About MSUI")) self.actionOnlineHelp.setText(_translate("MSSMainWindow", "&Online Help")) - self.actionOpenFlightTrack.setText(_translate("MSSMainWindow", "&Open Flight Track")) - self.actionOpenFlightTrack.setShortcut(_translate("MSSMainWindow", "Ctrl+O")) - self.actionNewFlightTrack.setText(_translate("MSSMainWindow", "&New Flight Track")) - self.actionNewFlightTrack.setShortcut(_translate("MSSMainWindow", "Ctrl+N")) self.actionQuit.setText(_translate("MSSMainWindow", "&Quit")) self.actionQuit.setShortcut(_translate("MSSMainWindow", "Ctrl+Q")) self.actionShortcuts.setText(_translate("MSSMainWindow", "&Shortcuts")) self.actionShortcuts.setShortcut(_translate("MSSMainWindow", "Alt+S")) - self.actionCloseSelectedFlightTrack.setText(_translate("MSSMainWindow", "&Close Selected Flight Track")) + self.actionCloseSelectedFlightTrack.setText(_translate("MSSMainWindow", "&Close Selected Local Flight Track")) self.actionUpdater.setText(_translate("MSSMainWindow", "&Updater")) self.actionConfiguration.setText(_translate("MSSMainWindow", "&Configuration")) self.actionConfiguration.setShortcut(_translate("MSSMainWindow", "Ctrl+,")) @@ -267,8 +258,9 @@ def retranslateUi(self, MSSMainWindow): self.actionVersionHistory.setText(_translate("MSSMainWindow", "&Version History")) self.actionManageUsers.setText(_translate("MSSMainWindow", "&Manage Users")) self.actionMSColab.setText(_translate("MSSMainWindow", "&MSColab")) - self.actionAddProject.setText(_translate("MSSMainWindow", "&Add Project")) self.actionEditProject.setText(_translate("MSSMainWindow", "&Edit Project")) self.actionDeleteProject.setText(_translate("MSSMainWindow", "&Delete Project")) self.actionBringMainWindowToFront.setText(_translate("MSSMainWindow", "Bring Main Window To Front")) self.actionBringMainWindowToFront.setShortcut(_translate("MSSMainWindow", "Ctrl+Up")) + self.actionNewFlightTrack.setText(_translate("MSSMainWindow", "&Local Flight Track")) + self.actionAddProject.setText(_translate("MSSMainWindow", "&MSColab Project")) diff --git a/mslib/msui/ui/ui_mainwindow.ui b/mslib/msui/ui/ui_mainwindow.ui index 1a650d888..0718fbf86 100644 --- a/mslib/msui/ui/ui_mainwindow.ui +++ b/mslib/msui/ui/ui_mainwindow.ui @@ -6,7 +6,7 @@ 0 0 - 769 + 738 736 @@ -34,7 +34,7 @@ 8 - 4 + 2 @@ -84,11 +84,6 @@ - - - 15 - - User @@ -136,11 +131,6 @@ - - - 13 - - No projects selected @@ -226,7 +216,7 @@ 0 0 - 769 + 738 22 @@ -247,16 +237,21 @@ Export Flight Track - - - + + + New + + + + + + - @@ -331,22 +326,6 @@ &Online Help - - - &Open Flight Track - - - Ctrl+O - - - - - &New Flight Track - - - Ctrl+N - - &Quit @@ -365,7 +344,7 @@ - &Close Selected Flight Track + &Close Selected Local Flight Track @@ -433,11 +412,6 @@ &MSColab - - - &Add Project - - &Edit Project @@ -456,6 +430,16 @@ Ctrl+Up + + + &Local Flight Track + + + + + &MSColab Project + + connectBtn