From 4262da5fc119e6ef6e10e3267c63a3b5f657dc5c Mon Sep 17 00:00:00 2001 From: Roy-043 Date: Thu, 7 Dec 2023 11:18:22 +0100 Subject: [PATCH] Draft: new get_param function with defaults This PR introduces a new get_param function. For its default values it checks a dictionary largely filled by reading the preferences UI files. The goal is to have all defaults in one place to avoid inconsistencies. The dictionary is created once and then stored in a global variable. Once merged this function will be implemented in Draft and Arch. The get_param function in utils.py will become obsolete. Related issue: #10176 --- src/Mod/Draft/draftutils/params.py | 345 ++++++++++++++++++++++++++++- 1 file changed, 340 insertions(+), 5 deletions(-) diff --git a/src/Mod/Draft/draftutils/params.py b/src/Mod/Draft/draftutils/params.py index a8427953ed..4e87e24caa 100644 --- a/src/Mod/Draft/draftutils/params.py +++ b/src/Mod/Draft/draftutils/params.py @@ -21,17 +21,23 @@ # * * # *************************************************************************** -""" Contains a parameter observer class and several related functions.""" +""" Contains a parameter observer class and parameter related functions.""" + +import PySide.QtCore as QtCore +import xml.etree.ElementTree as ET import FreeCAD as App -import FreeCADGui as Gui -from PySide import QtGui +import Draft_rc +import Arch_rc from draftutils import init_draft_statusbar from draftutils import utils from draftutils.translate import translate from draftviewproviders import view_base +if App.GuiUp: + import FreeCADGui as Gui + from PySide import QtGui class ParamObserverDraft: @@ -193,8 +199,9 @@ of existing objects in all opened documents?""") def _param_observer_start(): - _param_observer_start_draft() - _param_observer_start_view() + if App.GuiUp: + _param_observer_start_draft() + _param_observer_start_view() def _param_observer_start_draft(param_grp = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")): @@ -203,3 +210,331 @@ def _param_observer_start_draft(param_grp = App.ParamGet("User parameter:BaseApp def _param_observer_start_view(param_grp = App.ParamGet("User parameter:BaseApp/Preferences/View")): param_grp.AttachManager(ParamObserverView()) + + +def _param_from_PrefCheckBox(widget): + value = False + for elem in list(widget): + if "name" in elem.keys(): + att_name = elem.attrib["name"] + if att_name == "checked": # Can be missing. + value = elem.find("bool").text == "true" + elif att_name == "prefEntry": + entry = elem.find("cstring").text + elif att_name == "prefPath": + path = elem.find("cstring").text + return path, entry, value + + +def _param_from_PrefRadioButton(widget): + return _param_from_PrefCheckBox(widget) + + +def _param_from_PrefComboBox(widget): + value = 0 + for elem in list(widget): + if "name" in elem.keys(): + att_name = elem.attrib["name"] + if att_name == "currentIndex": # Can be missing. + value = int(elem.find("number").text) + elif att_name == "prefEntry": + entry = elem.find("cstring").text + elif att_name == "prefPath": + path = elem.find("cstring").text + return path, entry, value + + +def _param_from_PrefSpinBox(widget): + value = 0 + for elem in list(widget): + if "name" in elem.keys(): + att_name = elem.attrib["name"] + if att_name == "value": # Can be missing. + value = int(elem.find("number").text) + elif att_name == "prefEntry": + entry = elem.find("cstring").text + elif att_name == "prefPath": + path = elem.find("cstring").text + return path, entry, value + + +def _param_from_PrefDoubleSpinBox(widget): + value = 0.0 + for elem in list(widget): + if "name" in elem.keys(): + att_name = elem.attrib["name"] + if att_name == "value": # Can be missing. + value = float(elem.find("double").text) + elif att_name == "prefEntry": + entry = elem.find("cstring").text + elif att_name == "prefPath": + path = elem.find("cstring").text + return path, entry, value + + +def _param_from_PrefUnitSpinBox(widget): + return _param_from_PrefDoubleSpinBox(widget) + + +def _param_from_PrefQuantitySpinBox(widget): + value = "0" + for elem in list(widget): + if "name" in elem.keys(): + att_name = elem.attrib["name"] + if att_name == "rawValue": # Not sure if this can be missing. + value = elem.find("double").text.rstrip(".0") + elif att_name == "unit": + unit = elem.find("string").text + elif att_name == "prefEntry": + entry = elem.find("cstring").text + elif att_name == "prefPath": + path = elem.find("cstring").text + value = value + " " + unit + return path, entry, value + + +def _param_from_PrefColorButton(widget): + for elem in list(widget): + if "name" in elem.keys(): + att_name = elem.attrib["name"] + if att_name == "color": + sub = list(elem)[0] + r = int(sub.find("red").text) + g = int(sub.find("green").text) + b = int(sub.find("blue").text) + elif att_name == "prefEntry": + entry = elem.find("cstring").text + elif att_name == "prefPath": + path = elem.find("cstring").text + value = (r << 24) + (g << 16) + (b << 8) + 255 + return path, entry, value + + +def _param_from_PrefLineEdit(widget): + value = None + for elem in list(widget): + if "name" in elem.keys(): + att_name = elem.attrib["name"] + if att_name == "text": # Can be missing. + value = elem.find("string").text # If text is missing value will be None here. + elif att_name == "prefEntry": + entry = elem.find("cstring").text + elif att_name == "prefPath": + path = elem.find("cstring").text + if value is None: + value = "" + return path, entry, value + + +def _param_from_PrefFileChooser(widget): + for elem in list(widget): + if "name" in elem.keys(): + att_name = elem.attrib["name"] + if att_name == "prefEntry": + entry = elem.find("cstring").text + elif att_name == "prefPath": + path = elem.find("cstring").text + return path, entry, "" + + +def _get_param_dictionary(): + + # print("Creating preferences dictionary...") + + param_dict = {} + + # Draft parameters that are not in the preferences: + param_dict["Mod/Draft"] = { + "DefaultAnnoDisplayMode": ("int", 0), + "DefaultDisplayMode": ("int", 0), + "DefaultDrawStyle": ("int", 0), + "Draft_array_fuse": ("bool", False), + "Draft_array_Link": ("bool", True), + "fillmode": ("bool", True), + "HatchPatternResolution": ("int", 128), + "labeltype": ("string", "Custom"), + "snapModes": ("string", "100000000000000"), + "snapRange": ("int", 8), + + + } + + # Arch parameters that are not in the preferences: + param_dict["Mod/Arch"] = { + + + } + + # For the View parameters we do not check the preferences: + param_dict["View"] = { + "DefaultShapeColor": ("unsigned", 3435973887), + "DefaultShapeLineColor": ("unsigned", 255), + "DefaultShapeLineWidth": ("int", 2), + "DefaultShapePointSize": ("int", 2), + "DefaultShapeTransparency": ("int", 0), + "DefaultShapeVertexColor": ("unsigned", 255), + } + + # Preferences ui files are stored in resource files. + # For the Draft Workbench: /Mod/Draft/Draft_rc.py + # For the Arch Workbench: /Mod/Arch/Arch_rc.py + for fnm in (":/ui/preferences-draft.ui", + ":/ui/preferences-draftinterface.ui", + ":/ui/preferences-draftsnap.ui", + ":/ui/preferences-drafttexts.ui", + ":/ui/preferences-draftvisual.ui", + ":/ui/preferences-dwg.ui", + ":/ui/preferences-dxf.ui", + ":/ui/preferences-oca.ui", + ":/ui/preferences-svg.ui", + ":/ui/preferences-arch.ui", + ":/ui/preferences-archdefaults.ui", + ":/ui/preferences-dae.ui", + ":/ui/preferences-ifc.ui", + ":/ui/preferences-ifc-export.ui"): + + # https://stackoverflow.com/questions/14750997/load-txt-file-from-resources-in-python + fd = QtCore.QFile(fnm) + if fd.open(QtCore.QIODevice.ReadOnly | QtCore.QFile.Text): + text = QtCore.QTextStream(fd).readAll() + fd.close() + else: + print("Preferences file " + fnm + " not found") + continue + + # https://docs.python.org/3/library/xml.etree.elementtree.html + root = ET.fromstring(text) + + # Get all preference widgets: + # pref_widgets = [wid for wid in root.iter("widget") if "Gui::Pref" in wid.attrib["class"]] + + for widget in root.iter("widget"): + if "class" in widget.keys(): + path = None + att_class = widget.attrib["class"] + + if att_class == "Gui::PrefCheckBox": + path, entry, value = _param_from_PrefCheckBox(widget) + typ = "bool" + elif att_class == "Gui::PrefRadioButton": + path, entry, value = _param_from_PrefRadioButton(widget) + typ = "bool" + elif att_class == "Gui::PrefComboBox": + path, entry, value = _param_from_PrefComboBox(widget) + typ = "int" + elif att_class == "Gui::PrefSpinBox": + path, entry, value = _param_from_PrefSpinBox(widget) + typ = "int" + elif att_class == "Gui::PrefDoubleSpinBox": + path, entry, value = _param_from_PrefDoubleSpinBox(widget) + typ = "float" + elif att_class == "Gui::PrefUnitSpinBox": + path, entry, value = _param_from_PrefUnitSpinBox(widget) + typ = "float" + elif att_class == "Gui::PrefQuantitySpinBox": + path, entry, value = _param_from_PrefQuantitySpinBox(widget) + typ = "string" + elif att_class == "Gui::PrefColorButton": + path, entry, value = _param_from_PrefColorButton(widget) + typ = "unsigned" + elif att_class == "Gui::PrefLineEdit": + path, entry, value = _param_from_PrefLineEdit(widget) + typ = "string" + elif att_class == "Gui::PrefFileChooser": + path, entry, value = _param_from_PrefFileChooser(widget) + typ = "string" + + if path is not None: + if path in param_dict: + param_dict[path][entry] = (typ, value) + else: + param_dict[path] = {entry: (typ, value)} + + return param_dict + + +PARAM_DICT = _get_param_dictionary() + + +# get_param("gridSpacing") +def get_param(entry, path="Mod/Draft"): + """Return a stored parameter value or its default. + + Parameters + ---------- + entry: str + Name of the parameter. + path: str, optional + Defaults to "Mod/Draft". + The path where the parameter can be found. + This string is appended to "User parameter:BaseApp/Preferences/". + + Returns + ------- + bool, float, int or str (if successful) or `None`. + """ + if path not in PARAM_DICT: + return None + if entry not in PARAM_DICT[path]: + return None + param = App.ParamGet("User parameter:BaseApp/Preferences/" + path) + typ, default = PARAM_DICT[path][entry] + if typ == "bool": + return param.GetBool(entry, default) + if typ == "float": + return param.GetFloat(entry, default) + if typ == "int": + return param.GetInt(entry, default) + if typ == "string": + return param.GetString(entry, default) + if typ == "unsigned": + return param.GetUnsigned(entry, default) + return None + + +def get_param_arch(entry): + return get_param(entry, path="Mod/Arch") + + +def set_param(entry, value, path="Mod/Draft"): + """Store a parameter value. + + Parameters + ---------- + entry: str + Name of the parameter. + value: bool, float, int or str + New value of the correct type. + path: str, optional + Defaults to "Mod/Draft". + The path where the parameter can be found. + This string is appended to "User parameter:BaseApp/Preferences/". + + Returns + ------- + `True` (if successful) or `False`. + """ + if path not in PARAM_DICT: + return False + if entry not in PARAM_DICT[path]: + return False + param = App.ParamGet("User parameter:BaseApp/Preferences/" + path) + typ = PARAM_DICT[path][entry][0] + ret = True + if typ == "bool": + param.SetBool(entry, value) + elif typ == "float": + param.SetFloat(entry, value) + elif typ == "int": + param.SetInt(entry, value) + elif typ == "string": + param.SetString(entry, value) + elif typ == "unsigned": + param.SetUnsigned(entry, value) + else: + ret = False + return ret + + +def set_param_arch(entry, value): + return set_param(entry, value, path="Mod/Arch")