From 843be488a5ec56d8b371ad6c7a7485b108eea8b4 Mon Sep 17 00:00:00 2001 From: Marius Stanciu Date: Thu, 24 Feb 2022 00:14:58 +0200 Subject: [PATCH] - some changes to the Preferences --- CHANGELOG.md | 8 ++- appEditors/AppTextEditor.py | 2 +- appGUI/MainGUI.py | 24 +++---- appGUI/preferences/PreferencesUIManager.py | 4 +- appPlugins/ToolFilm.py | 4 +- appPlugins/ToolPcbWizard.py | 2 +- appTranslation.py | 1 + app_Main.py | 63 +++++++++--------- defaults.py | 74 +++++++++++++++++++++- tclCommands/TclCommandExportDXF.py | 2 +- tclCommands/TclCommandExportExcellon.py | 2 +- tclCommands/TclCommandExportGerber.py | 2 +- 12 files changed, 133 insertions(+), 55 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21300596..11b349e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ CHANGELOG for FlatCAM beta ================================================= +24.02.2022 + +- some changes to the Preferences + 23.02.2022 - in Gerber Editor: in Eraser tool now the intersected shapes are stored properly such that when exporting the edited Gerber, it is done properly @@ -2006,7 +2010,7 @@ RELEASE 8.994 18.10.2020 -- fixed issue with calling the inform signal in the FlatCAMDefaults.load method +- fixed issue with calling the inform signal in the AppDefaults.load method - fixed macro parsing in Gerber files generated by KiCAD 4.99 (KiCAD 5.0) 17.10.2020 @@ -2863,7 +2867,7 @@ RELEASE 8.993 8.05.2020 -- added a parameter to the FlatCAMDefaults class, whenever a value in the self.defaults dict change it will call a callback function and send to it the modified key +- added a parameter to the AppDefaults class, whenever a value in the self.defaults dict change it will call a callback function and send to it the modified key - optimized and fixed some issues in the self.on_toggle_units() method - the Exclusion areas will have all the orange color but the color of the outline will differ according to the type of the object from where it was added (cosmetic use only as the Exclusion areas will be applied globally) - removed the Apply theme button in the Preferences; it is now replaced by the more general buttons (either Save or Apply) diff --git a/appEditors/AppTextEditor.py b/appEditors/AppTextEditor.py index de63d42e..d30de3ab 100644 --- a/appEditors/AppTextEditor.py +++ b/appEditors/AppTextEditor.py @@ -253,7 +253,7 @@ class AppTextEditor(QtWidgets.QWidget): try: filename = str(FCFileSaveDialog.get_saved_filename( caption=_("Export Code ..."), - directory=self.app.defaults["global_last_folder"] + '/' + str(obj_name), + directory=self.app.options["global_last_folder"] + '/' + str(obj_name), ext_filter=_filter_ )[0]) except TypeError: diff --git a/appGUI/MainGUI.py b/appGUI/MainGUI.py index 8bdb0927..d0b30c1c 100644 --- a/appGUI/MainGUI.py +++ b/appGUI/MainGUI.py @@ -2164,20 +2164,20 @@ class MainGUI(QtWidgets.QMainWindow): :return: None """ - self.app.defaults["global_def_win_x"] = x - self.app.defaults["global_def_win_y"] = y - self.app.defaults["global_def_win_w"] = width - self.app.defaults["global_def_win_h"] = height - self.app.defaults["global_def_notebook_width"] = notebook_width - self.app.preferencesUiManager.save_defaults() + self.app.options["global_def_win_x"] = x + self.app.options["global_def_win_y"] = y + self.app.options["global_def_win_w"] = width + self.app.options["global_def_win_h"] = height + self.app.options["global_def_notebook_width"] = notebook_width + # self.app.preferencesUiManager.save_defaults() def restore_main_win_geom(self): try: - self.setGeometry(self.app.defaults["global_def_win_x"], - self.app.defaults["global_def_win_y"], - self.app.defaults["global_def_win_w"], - self.app.defaults["global_def_win_h"]) - self.splitter.setSizes([self.app.defaults["global_def_notebook_width"], 0]) + self.setGeometry(self.app.options["global_def_win_x"], + self.app.options["global_def_win_y"], + self.app.options["global_def_win_w"], + self.app.options["global_def_win_h"]) + self.splitter.setSizes([self.app.options["global_def_notebook_width"], 0]) except KeyError as e: self.app.log.debug("appGUI.MainGUI.restore_main_win_geom() --> %s" % str(e)) @@ -2188,7 +2188,7 @@ class MainGUI(QtWidgets.QMainWindow): :return: None """ - tb = self.app.defaults["global_toolbar_view"] + tb = self.app.options["global_toolbar_view"] if tb & 1: self.toolbarfile.setVisible(True) diff --git a/appGUI/preferences/PreferencesUIManager.py b/appGUI/preferences/PreferencesUIManager.py index 3f318b90..b5d39508 100644 --- a/appGUI/preferences/PreferencesUIManager.py +++ b/appGUI/preferences/PreferencesUIManager.py @@ -1,7 +1,7 @@ import os from PyQt6 import QtGui, QtCore, QtWidgets from PyQt6.QtCore import QSettings -from defaults import FlatCAMDefaults +from defaults import AppDefaults from appGUI.GUIElements import FCMessageBox @@ -16,7 +16,7 @@ if '_' not in builtins.__dict__: class PreferencesUIManager: - def __init__(self, defaults: FlatCAMDefaults, data_path: str, ui, inform, options): + def __init__(self, defaults: AppDefaults, data_path: str, ui, inform, options): """ Class that control the Preferences Tab diff --git a/appPlugins/ToolFilm.py b/appPlugins/ToolFilm.py index 7cdd2d95..88a2dd18 100644 --- a/appPlugins/ToolFilm.py +++ b/appPlugins/ToolFilm.py @@ -599,7 +599,7 @@ class Film(AppTool): self.app.defaults.report_usage("export_negative()") if filename is None: - filename = self.app.defaults["global_last_save_folder"] + filename = self.app.options["global_last_save_folder"] self.app.log.debug("Film.export_svg() negative") @@ -949,7 +949,7 @@ class Film(AppTool): self.app.defaults.report_usage("export_positive()") if filename is None: - filename = self.app.defaults["global_last_save_folder"] + filename = self.app.options["global_last_save_folder"] self.app.log.debug("Film.export_positive() black") diff --git a/appPlugins/ToolPcbWizard.py b/appPlugins/ToolPcbWizard.py index cadb5033..27b9e4a9 100644 --- a/appPlugins/ToolPcbWizard.py +++ b/appPlugins/ToolPcbWizard.py @@ -331,7 +331,7 @@ class PcbWizard(AppTool): self.process_finished = True # Register recent file - self.app.defaults["global_last_folder"] = os.path.split(str(filename))[0] + self.app.options["global_last_folder"] = os.path.split(str(filename))[0] def on_import_excellon(self, signal=None, excellon_fileobj=None): self.app.log.debug("import_2files_excellon()") diff --git a/appTranslation.py b/appTranslation.py index f9599aa0..9ed40ed6 100644 --- a/appTranslation.py +++ b/appTranslation.py @@ -233,6 +233,7 @@ def restart_program(app, ask=None): if response == bt_yes: app.f_handlers.on_file_saveprojectas(use_thread=True, quit_action=True) + app.defaults.update(app.options) app.preferencesUiManager.save_defaults() try: diff --git a/app_Main.py b/app_Main.py index eb7a0ef6..c4ac2e65 100644 --- a/app_Main.py +++ b/app_Main.py @@ -62,7 +62,8 @@ from vispy.gloo.util import _screenshot from vispy.io import write_png # App defaults (preferences) -from defaults import FlatCAMDefaults +from defaults import AppDefaults +from defaults import AppOptions # App Objects from appGUI.preferences.OptionsGroupUI import OptionsGroupUI @@ -556,7 +557,7 @@ class App(QtCore.QObject): f.close() # the factory defaults are written only once at the first launch of the application after installation - FlatCAMDefaults.save_factory_defaults(self.factory_defaults_path(), self.version) + AppDefaults.save_factory_defaults(self.factory_defaults_path(), self.version) # create a recent files json file if there is none rec_f_path = self.recent_files_path() @@ -596,7 +597,7 @@ class App(QtCore.QObject): # ############################################################################################################ # ################################# DEFAULTS - PREFERENCES STORAGE ########################################### # ############################################################################################################ - self.defaults = FlatCAMDefaults(beta=self.beta, version=self.version) + self.defaults = AppDefaults(beta=self.beta, version=self.version) # current_defaults_path = os.path.join(self.data_path, "current_defaults.FlatConfig") current_defaults_path = self.defaults_path() @@ -606,7 +607,7 @@ class App(QtCore.QObject): # ########################################################################################################### # ######################################## UPDATE THE OPTIONS ############################################### # ########################################################################################################### - self.options = LoudDict() + self.options = AppOptions(version=self.version) # ----------------------------------------------------------------------------------------------------------- # Update the self.options from the self.defaults # The self.options holds the application defaults while the self.options holds the object defaults @@ -1077,8 +1078,8 @@ class App(QtCore.QObject): # ########################################################################################################### # ##################################### UPDATE PREFERENCES GUI FORMS ######################################## # ########################################################################################################### - self.preferencesUiManager = PreferencesUIManager(defaults=self.defaults, data_path=self.data_path, ui=self.ui, - inform=self.inform, options=self.options) + self.preferencesUiManager = PreferencesUIManager(data_path=self.data_path, ui=self.ui, inform=self.inform, + options=self.options, defaults=self.defaults) self.preferencesUiManager.defaults_write_form() @@ -1092,8 +1093,8 @@ class App(QtCore.QObject): # ###################################### CREATE UNIQUE SERIAL NUMBER ######################################## # ########################################################################################################### chars = 'abcdefghijklmnopqrstuvwxyz0123456789' - if self.defaults['global_serial'] == 0 or len(str(self.defaults['global_serial'])) < 10: - self.defaults['global_serial'] = ''.join([random.choice(chars) for __ in range(20)]) + if self.options['global_serial'] == 0 or len(str(self.options['global_serial'])) < 10: + self.options['global_serial'] = ''.join([random.choice(chars) for __ in range(20)]) self.preferencesUiManager.save_defaults(silent=True, first_time=True) self.defaults.propagate_defaults() @@ -1359,7 +1360,7 @@ class App(QtCore.QObject): # ##################################### FIRST RUN SECTION ################################################### # ################################ It's done only once after install ##################################### # ########################################################################################################### - if self.defaults["first_run"] is True: + if self.options["first_run"] is True: # ONLY AT FIRST STARTUP INIT THE GUI LAYOUT TO 'minimal' self.log.debug("-> First Run: Setting up the first Layout") initial_lay = 'minimal' @@ -1370,7 +1371,7 @@ class App(QtCore.QObject): self.ui.general_pref_form.general_gui_group.layout_combo.setCurrentIndex(idx) # after the first run, this object should be False - self.defaults["first_run"] = False + self.options["first_run"] = False self.log.debug("-> First Run: Updating the Defaults file with Factory Defaults") self.preferencesUiManager.save_defaults(silent=True) @@ -1764,6 +1765,7 @@ class App(QtCore.QObject): elif 'save'.lower() in argument.lower(): self.log.debug("App.on_startup_args() --> Save event. App Defaults saved.") + self.defaults.update(self.options) self.preferencesUiManager.save_defaults() else: exc_list = self.ui.util_pref_form.fa_excellon_group.exc_list_text.get_value().split(',') @@ -2401,12 +2403,11 @@ class App(QtCore.QObject): except Exception as c_err: self.log.error("App.connect_toolbar_signals() tools signals -> %s" % str(c_err)) - def on_layout(self, index=None, lay=None, connect_signals=True): + def on_layout(self, lay=None, connect_signals=True): """ Set the toolbars layout (location). :param connect_signals: Useful when used in the App.__init__(); bool - :param index: :param lay: Type of layout to be set on the toolbard :return: None """ @@ -2981,16 +2982,16 @@ class App(QtCore.QObject): Get the folder path from where the last file was opened. :return: String, last opened folder path """ - return self.defaults["global_last_folder"] + return self.options["global_last_folder"] def get_last_save_folder(self): """ Get the folder path from where the last file was saved. :return: String, last saved folder path """ - loc = self.defaults["global_last_save_folder"] + loc = self.options["global_last_save_folder"] if loc is None: - loc = self.defaults["global_last_folder"] + loc = self.options["global_last_folder"] if loc is None: loc = os.path.dirname(__file__) return loc @@ -3077,8 +3078,8 @@ class App(QtCore.QObject): date = date.replace(' ', '_') filter__ = "HTML File .html (*.html);;TXT File .txt (*.txt);;All Files (*.*)" - path_to_save = self.defaults["global_last_save_folder"] if \ - self.defaults["global_last_save_folder"] is not None else self.data_path + path_to_save = self.options["global_last_save_folder"] if \ + self.options["global_last_save_folder"] is not None else self.data_path final_path = os.path.join(path_to_save, 'file_%s' % str(date)) try: @@ -8339,7 +8340,7 @@ class App(QtCore.QObject): :param filename: the last folder is extracted from the filename :return: None """ - self.defaults["global_last_folder"] = os.path.split(str(filename))[0] + self.options["global_last_folder"] = os.path.split(str(filename))[0] def register_save_folder(self, filename): """ @@ -8348,7 +8349,7 @@ class App(QtCore.QObject): :param filename: the last folder is extracted from the filename :return: None """ - self.defaults["global_last_save_folder"] = os.path.split(str(filename))[0] + self.options["global_last_save_folder"] = os.path.split(str(filename))[0] # def set_progress_bar(self, percentage, text=""): # """ @@ -10317,6 +10318,7 @@ class MenuFileHandlers(QtCore.QObject): response = msgbox.clickedButton() if response == bt_yes: + self.app.defaults.update(self.app.options) self.app.preferencesUiManager.save_defaults() if response == bt_no: pass @@ -10799,8 +10801,8 @@ class MenuFileHandlers(QtCore.QObject): :return: """ if filename is None: - filename = self.app.defaults["global_last_save_folder"] if \ - self.app.defaults["global_last_save_folder"] is not None else self.app.defaults["global_last_folder"] + filename = self.app.options["global_last_save_folder"] if \ + self.app.options["global_last_save_folder"] is not None else self.app.options["global_last_folder"] self.log.debug("export_svg()") @@ -10941,10 +10943,10 @@ class MenuFileHandlers(QtCore.QObject): """ if filename is None: - if self.app.defaults["global_last_save_folder"]: - filename = self.app.defaults["global_last_save_folder"] + '/' + 'exported_excellon' + if self.app.options["global_last_save_folder"]: + filename = self.app.options["global_last_save_folder"] + '/' + 'exported_excellon' else: - filename = self.app.defaults["global_last_folder"] + '/' + 'exported_excellon' + filename = self.app.options["global_last_folder"] + '/' + 'exported_excellon' self.log.debug("export_excellon()") @@ -11099,8 +11101,8 @@ class MenuFileHandlers(QtCore.QObject): :return: """ if filename is None: - filename = self.app.defaults["global_last_save_folder"] if \ - self.app.defaults["global_last_save_folder"] is not None else self.app.defaults["global_last_folder"] + filename = self.app.options["global_last_save_folder"] if \ + self.app.options["global_last_save_folder"] is not None else self.app.options["global_last_folder"] self.log.debug("export_gerber()") @@ -11233,8 +11235,8 @@ class MenuFileHandlers(QtCore.QObject): :return: """ if filename is None: - filename = self.app.defaults["global_last_save_folder"] if \ - self.app.defaults["global_last_save_folder"] is not None else self.app.defaults["global_last_folder"] + filename = self.app.options["global_last_save_folder"] if \ + self.app.options["global_last_save_folder"] is not None else self.app.options["global_last_folder"] self.log.debug("export_dxf()") @@ -12069,8 +12071,8 @@ class MenuFileHandlers(QtCore.QObject): """ if filename is None: - filename = self.app.defaults["global_last_save_folder"] if \ - self.app.defaults["global_last_save_folder"] is not None else self.app.defaults["global_last_folder"] + filename = self.app.options["global_last_save_folder"] if \ + self.app.options["global_last_save_folder"] is not None else self.app.options["global_last_folder"] self.log.debug("save_source_file()") @@ -12107,6 +12109,7 @@ class MenuFileHandlers(QtCore.QObject): :return: None """ + self.app.defaults.update(self.app.options) self.app.preferencesUiManager.save_defaults() diff --git a/defaults.py b/defaults.py index 1b6b2695..360d6ecd 100644 --- a/defaults.py +++ b/defaults.py @@ -16,11 +16,11 @@ from appParsers.ParseGerber import Gerber fcTranslate.apply_language('strings') if '_' not in builtins.__dict__: _ = gettext.gettext -# log = logging.getLogger('FlatCAMDefaults') +# log = logging.getLogger('AppDefaults') log = logging.getLogger('base') -class FlatCAMDefaults: +class AppDefaults: factory_defaults = { # Global @@ -1048,3 +1048,73 @@ class FlatCAMDefaults: self.defaults['global_stats'][resource] += 1 else: self.defaults['global_stats'][resource] = 1 + + +class AppOptions: + def __init__(self, version, callback=lambda x: None): + """ + Class that holds the options parameters used throughout the app. + + :param callback: A method called each time that one of the values are changed in the self.defaults LouDict + """ + self.options = LoudDict() + self.current_options = {} # copy used for restoring after cancelled prefs changes + self.version = version + self.options.set_change_callback(callback) + + # #### Pass-through to the defaults LoudDict ##### + def __len__(self): + return self.options.__len__() + + def __getitem__(self, item): + return self.options.__getitem__(item) + + def __setitem__(self, key, value): + return self.options.__setitem__(key, value) + + def __delitem__(self, key): + return self.options.__delitem__(key) + + def __iter__(self): + return self.options.__iter__() + + def __getattr__(self, item): + # Unfortunately this method alone is not enough to pass through the other magic methods above. + return self.options.__getattribute__(item) + + def load(self, filename: str, inform): + """ + Loads the options from a file on disk, performing migration if required. + + :param filename: a path to the file that is to be loaded + :param inform: a pyqtSignal used to display information's in the StatusBar of the GUI + """ + + # Read in the file + try: + f = open(filename) + options = f.read() + f.close() + except IOError: + log.error("Could not load defaults file.") + inform.emit('[ERROR] %s' % _("Could not load the file.")) + # in case the defaults file can't be loaded, show all toolbars + self.options["global_toolbar_view"] = 511 + return + + # Parse the JSON + try: + options = simplejson.loads(options) + except Exception: + # in case the defaults file can't be loaded, show all toolbars + self.defaults["global_toolbar_view"] = 511 + e = sys.exc_info()[0] + log.error(str(e)) + inform.emit('[ERROR] %s' % _("Failed to parse defaults file.")) + return + if options is None: + return + + # Save the resulting defaults + self.options.update(options) + self.current_options.update(self.options) diff --git a/tclCommands/TclCommandExportDXF.py b/tclCommands/TclCommandExportDXF.py index 9b255473..4e20a7d7 100644 --- a/tclCommands/TclCommandExportDXF.py +++ b/tclCommands/TclCommandExportDXF.py @@ -61,7 +61,7 @@ class TclCommandExportDXF(TclCommand): source_obj_name = args['name'] if 'filename' not in args: - filename = self.app.defaults["global_last_save_folder"] + '/' + args['name'] + filename = self.app.options["global_last_save_folder"] + '/' + args['name'] else: filename = args['filename'] diff --git a/tclCommands/TclCommandExportExcellon.py b/tclCommands/TclCommandExportExcellon.py index 4c20a65f..9b78bc05 100644 --- a/tclCommands/TclCommandExportExcellon.py +++ b/tclCommands/TclCommandExportExcellon.py @@ -48,5 +48,5 @@ class TclCommandExportExcellon(TclCommand): :return: """ if 'filename' not in args: - args['filename'] = self.app.defaults["global_last_save_folder"] + '/' + args['name'] + args['filename'] = self.app.options["global_last_save_folder"] + '/' + args['name'] self.app.f_handlers.export_excellon(use_thread=False, **args) diff --git a/tclCommands/TclCommandExportGerber.py b/tclCommands/TclCommandExportGerber.py index 64a9c046..de219ebe 100644 --- a/tclCommands/TclCommandExportGerber.py +++ b/tclCommands/TclCommandExportGerber.py @@ -48,5 +48,5 @@ class TclCommandExportGerber(TclCommand): :return: """ if 'filename' not in args: - args['filename'] = self.app.defaults["global_last_save_folder"] + '/' + args['name'] + args['filename'] = self.app.options["global_last_save_folder"] + '/' + args['name'] self.app.f_handlers.export_gerber(use_thread=False, **args)