Extract default preferences from ui file? Feasible or not?

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
User avatar
Roy_043
Veteran
Posts: 8450
Joined: Thu Dec 27, 2018 12:28 pm

Extract default preferences from ui file? Feasible or not?

Post by Roy_043 »

The ui files used for the preferences also contain default values. In the Draft WB we have the issue that there are sometimes inconsistencies between the default values in the ui files and those used elsewhere in the code. One way this might be solved is to extract the defaults from the ui files, but them in a dictionary and then reference that dictionary whenever a default value is required. Is this idea feasible?
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Extract default preferences from ui file? Feasible or not?

Post by onekk »

as ui files are text files, probably some regex or other parsers could be useful.

But probably you have to write them for scratch, or maybe searching for "qt ui files parsing"

https://github.com/ordovician/QtUIParser.jl

It seems to be an xml file, so probably standard python tools could be used.

Hope it helps

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
User avatar
Roy_043
Veteran
Posts: 8450
Joined: Thu Dec 27, 2018 12:28 pm

Re: Extract default preferences from ui file? Feasible or not?

Post by Roy_043 »

Thanks. Very early beginnings, but here is my code so far:

Code: Select all

# Preferences ui files are stored in resource files.
# For the Draft Workbench: /Mod/Draft/Draft_rc.py

import Draft_rc
import PySide.QtCore as QtCore
import xml.etree.ElementTree as ET

fnm = ":/ui/preferences-draftsnap.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()

# https://docs.python.org/3/library/xml.etree.elementtree.html
root = ET.fromstring(text)
pref_widgets = [wid for wid in root.iter('widget') if "Gui::Pref" in wid.attrib["class"]]
User avatar
Roy_043
Veteran
Posts: 8450
Joined: Thu Dec 27, 2018 12:28 pm

Re: Extract default preferences from ui file? Feasible or not?

Post by Roy_043 »

I have a question regarding this. Where should I put this preferences dictionary to make it available for all code in the Draft and Arch workbenches?

Add it as a property to the FreeCAD module, the same as is done for the DraftWorkingPlane, perhaps?

Code: Select all

if not hasattr(FreeCAD, "DraftWorkingPlane"):
    FreeCAD.DraftWorkingPlane = WorkingPlane.plane()
User avatar
Roy_043
Veteran
Posts: 8450
Joined: Thu Dec 27, 2018 12:28 pm

Re: Extract default preferences from ui file? Feasible or not?

Post by Roy_043 »

FWIW the current code (still WIP):

Code: Select all

# Preferences ui files are stored in resource files.
# For the Draft Workbench: /Mod/Draft/Draft_rc.py

import Draft_rc
import PySide.QtCore as QtCore
import xml.etree.ElementTree as ET

# fnm = ":/ui/preferences-draft.ui"
# fnm = ":/ui/preferences-draftinterface.ui"
# fnm = ":/ui/preferences-draftsnap.ui"
# fnm = ":/ui/preferences-drafttexts.ui"
fnm = ":/ui/preferences-draftvisual.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):
    str = QtCore.QTextStream(fd).readAll()
    fd.close()

# https://docs.python.org/3/library/xml.etree.elementtree.html
root = ET.fromstring(str)
# pref_widgets = [wid for wid in root.iter('widget') if "Gui::Pref" in wid.attrib["class"]]


def pref_from_PrefCheckBox(widget):
    val = False
    for elem in list(widget):
        att_name = elem.attrib["name"]
        if att_name == "checked": # Can be missing.
            val = elem.find("bool").text == "true"
        elif att_name == "prefEntry":
            pref = elem.find("cstring").text
        elif att_name == "prefPath":
            path = elem.find("cstring").text
    return [pref, path, val]


def pref_from_PrefComboBox(widget):
    idx = 0
    vals = []
    for elem in list(widget):
        if elem.tag == "property":
            att_name = elem.attrib["name"]
            if att_name == "currentIndex": # Can be missing.
                idx = int(elem.find("number").text)
            elif att_name == "prefEntry":
                pref = elem.find("cstring").text
            elif att_name == "prefPath":
                path = elem.find("cstring").text
        elif elem.tag == "item":
            val = list(elem)[0].find("string").text
            vals.append(val)
    return [pref, path, vals[idx]]


def pref_from_PrefSpinBox(widget):
    val = 0
    for elem in list(widget):
        att_name = elem.attrib["name"]
        if att_name == "value": # Can be missing.
            val = int(elem.find("number").text)
        elif att_name == "prefEntry":
            pref = elem.find("cstring").text
        elif att_name == "prefPath":
            path = elem.find("cstring").text
    return [pref, path, val]


def pref_from_PrefDoubleSpinBox(widget):
    val = 0.0
    for elem in list(widget):
        att_name = elem.attrib["name"]
        if att_name == "value": # Can be missing.
            val = float(elem.find("double").text)
        elif att_name == "prefEntry":
            pref = elem.find("cstring").text
        elif att_name == "prefPath":
            path = elem.find("cstring").text
    return [pref, path, val]


def pref_from_PrefQuantitySpinBox(widget):
    val = "0"
    for elem in list(widget):
        att_name = elem.attrib["name"]
        if att_name == "rawValue": # Not sure if this can be missing.
            val = elem.find("double").text.rstrip(".0")
        elif att_name == "unit":
            unit = elem.find("string").text
        elif att_name == "prefEntry":
            pref = elem.find("cstring").text
        elif att_name == "prefPath":
            path = elem.find("cstring").text
    return [pref, path, val + " " + unit]


def pref_from_PrefColorButton(widget):
    for elem in list(widget):
        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":
            pref = elem.find("cstring").text
        elif att_name == "prefPath":
            path = elem.find("cstring").text
    val = (r << 24) + (g << 16) + (b << 8) + 255
    return [pref, path, val]


def pref_from_PrefLineEdit(widget):
    val = None
    for elem in list(widget):
        att_name = elem.attrib["name"]
        if att_name == "text":             # Can be missing.
            val = elem.find("string").text # If text is missing val will be None here.
        elif att_name == "prefEntry":
            pref = elem.find("cstring").text
        elif att_name == "prefPath":
            path = elem.find("cstring").text
    if val is None:
        val = ""
    return [pref, path, val]


def pref_from_PrefFileChooser(widget):
    for elem in list(widget):
        att_name = elem.attrib["name"]
        if att_name == "prefEntry":
            pref = elem.find("cstring").text
        elif att_name == "prefPath":
            path = elem.find("cstring").text
    return [pref, path, ""]


i = 0
for widget in root.iter('widget'):
    att_class = widget.attrib["class"]
    if att_class == "Gui::PrefCheckBox":
        print(pref_from_PrefCheckBox(widget))
        i = i + 1
    elif att_class == "Gui::PrefComboBox":
        print(pref_from_PrefComboBox(widget))
        i = i + 1
    elif att_class == "Gui::PrefSpinBox":
        print(pref_from_PrefSpinBox(widget))
        i = i + 1
    elif att_class == "Gui::PrefDoubleSpinBox":
        print(pref_from_PrefDoubleSpinBox(widget))
        i = i + 1
    elif att_class == "Gui::PrefQuantitySpinBox":
        print(pref_from_PrefQuantitySpinBox(widget))
        i = i + 1
    elif att_class == "Gui::PrefColorButton":
        print(pref_from_PrefColorButton(widget))
        i = i + 1
    elif att_class == "Gui::PrefLineEdit":
        print(pref_from_PrefLineEdit(widget))
        i = i + 1
    elif att_class == "Gui::PrefFileChooser":
        print(pref_from_PrefFileChooser(widget))
        i = i + 1

print(i)
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Extract default preferences from ui file? Feasible or not?

Post by onekk »

Roy_043 wrote: Wed Jul 06, 2022 8:50 am I have a question regarding this. Where should I put this preferences dictionary to make it available for all code in the Draft and Arch workbenches?

Add it as a property to the FreeCAD module, the same as is done for the DraftWorkingPlane, perhaps?
...

I have seen that if you set it in the InitGui it is spreaded all over FC.

Not surprisingly, as it is normal behaviour for Python, once I have done this:

1) I have set some "global" variables in the InitGui module, thinking there will be some "separation" between WB, so I have set something like WB_Name and sone it for two WB one real and one "test WB".

2) I have found that the second WB loaded will overwrite the WB_Name for the whole FC instance.

Probably this could be a way, or maybe making some WB wide "global variable module", in other work a module that contains all the variables that is imported in all other modules, say maybe using something similar to:

Code: Select all

import draft_vars as draft_v 
and then refers using:

Code: Select all

draft_v.something
It usually works, and it is clear what is a "global module variable" and what is not.

But it is not "very polite" but it will not use globals and locals explicitly, that is generally considered "bad practice"

Hope it helps

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
User avatar
Roy_043
Veteran
Posts: 8450
Joined: Thu Dec 27, 2018 12:28 pm

Re: Extract default preferences from ui file? Feasible or not?

Post by Roy_043 »

Thanks. To keep things simple I have decided to use this:
https://docs.python.org/3/faq/programmi ... en-objects

Code: Select all

# pref_default("Mod/Draft", "gridSpacing")
# pref_default("Mod/Arch", "WallHeight")
def pref_default(path, pref, pref_dict=pref_dictionary()):
    if path not in pref_dict.keys():
        return None
    elif pref not in pref_dict[path].keys():
        return None
    else:
        return pref_dict[path][pref]
Full code attached.
Attachments
prefs.py
(7.68 KiB) Downloaded 8 times
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Extract default preferences from ui file? Feasible or not?

Post by onekk »


Many Thanks, interesting reading, now I have to rewrite most of my code. :lol:

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
Post Reply