BIM: Add an option to preload IFC types during document opening (#21450)

* BIM: Add an option to preload IFC types during document opening

Currently, IFC types are only possible to be loaded if user double
clicks an IFC object, and this has be done for optimization reasons.

But user can also want to preload IFC types, so this patch adds an
option to the dialog and Properties dialog to do just that.

* BIM: Remove cyclic import

---------

Co-authored-by: Yorik van Havre <yorik@uncreated.net>
This commit is contained in:
tetektoza
2025-07-07 16:06:43 +02:00
committed by GitHub
parent 4d7f03bf63
commit 2c82bfa150
5 changed files with 63 additions and 2 deletions

View File

@@ -113,6 +113,16 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="QCheckBox" name="checkLoadTypes">
<property name="toolTip">
<string>Preload IFC types that are connected to the objects. It is also possible to leave this setting disabled and double click later on the object to load the types</string>
</property>
<property name="text">
<string>Preload types</string>
</property>
</widget>
</item>
<item> <item>
<widget class="QCheckBox" name="checkLoadPsets"> <widget class="QCheckBox" name="checkLoadPsets">
<property name="toolTip"> <property name="toolTip">

View File

@@ -129,6 +129,22 @@
</property> </property>
</widget> </widget>
</item> </item>
<item>
<widget class="Gui::PrefCheckBox" name="checkBox_9">
<property name="toolTip">
<string>Load all types automatically when opening an IFC file</string>
</property>
<property name="text">
<string>Preload types</string>
</property>
<property name="prefEntry" stdset="0">
<cstring>LoadTypes</cstring>
</property>
<property name="prefPath" stdset="0">
<cstring>Mod/NativeIFC</cstring>
</property>
</widget>
</item>
<item> <item>
<widget class="Gui::PrefCheckBox" name="checkBox_8"> <widget class="Gui::PrefCheckBox" name="checkBox_8">
<property name="toolTip"> <property name="toolTip">

View File

@@ -32,6 +32,7 @@ from . import ifc_psets
from . import ifc_materials from . import ifc_materials
from . import ifc_layers from . import ifc_layers
from . import ifc_status from . import ifc_status
from . import ifc_types
if FreeCAD.GuiUp: if FreeCAD.GuiUp:
import FreeCADGui import FreeCADGui
@@ -101,6 +102,8 @@ def insert(
ifc_layers.load_layers(prj_obj) ifc_layers.load_layers(prj_obj)
if PARAMS.GetBool("LoadPsets", False): if PARAMS.GetBool("LoadPsets", False):
ifc_psets.load_psets(prj_obj) ifc_psets.load_psets(prj_obj)
if PARAMS.GetBool("LoadTypes", False):
ifc_types.load_types(prj_obj)
document.recompute() document.recompute()
# print a reference to the IFC file on the console # print a reference to the IFC file on the console
if FreeCAD.GuiUp and PARAMS.GetBool("IfcFileToConsole", False): if FreeCAD.GuiUp and PARAMS.GetBool("IfcFileToConsole", False):
@@ -133,6 +136,7 @@ def get_options(strategy=None, shapemode=None, switchwb=None, silent=False):
""" """
psets = PARAMS.GetBool("LoadPsets", False) psets = PARAMS.GetBool("LoadPsets", False)
types = PARAMS.GetBool("LoadTypes", False)
materials = PARAMS.GetBool("LoadMaterials", False) materials = PARAMS.GetBool("LoadMaterials", False)
layers = PARAMS.GetBool("LoadLayers", False) layers = PARAMS.GetBool("LoadLayers", False)
singledoc = PARAMS.GetBool("SingleDoc", False) singledoc = PARAMS.GetBool("SingleDoc", False)
@@ -155,6 +159,7 @@ def get_options(strategy=None, shapemode=None, switchwb=None, silent=False):
dlg.checkSwitchWB.setChecked(switchwb) dlg.checkSwitchWB.setChecked(switchwb)
dlg.checkAskAgain.setChecked(ask) dlg.checkAskAgain.setChecked(ask)
dlg.checkLoadPsets.setChecked(psets) dlg.checkLoadPsets.setChecked(psets)
dlg.checkLoadTypes.setChecked(types)
dlg.checkLoadMaterials.setChecked(materials) dlg.checkLoadMaterials.setChecked(materials)
dlg.checkLoadLayers.setChecked(layers) dlg.checkLoadLayers.setChecked(layers)
dlg.comboSingleDoc.setCurrentIndex(1 - int(singledoc)) dlg.comboSingleDoc.setCurrentIndex(1 - int(singledoc))
@@ -166,6 +171,7 @@ def get_options(strategy=None, shapemode=None, switchwb=None, silent=False):
switchwb = dlg.checkSwitchWB.isChecked() switchwb = dlg.checkSwitchWB.isChecked()
ask = dlg.checkAskAgain.isChecked() ask = dlg.checkAskAgain.isChecked()
psets = dlg.checkLoadPsets.isChecked() psets = dlg.checkLoadPsets.isChecked()
types = dlg.checkLoadTypes.isChecked()
materials = dlg.checkLoadMaterials.isChecked() materials = dlg.checkLoadMaterials.isChecked()
layers = dlg.checkLoadLayers.isChecked() layers = dlg.checkLoadLayers.isChecked()
singledoc = dlg.comboSingleDoc.currentIndex() singledoc = dlg.comboSingleDoc.currentIndex()
@@ -174,6 +180,7 @@ def get_options(strategy=None, shapemode=None, switchwb=None, silent=False):
PARAMS.SetBool("SwitchWB", switchwb) PARAMS.SetBool("SwitchWB", switchwb)
PARAMS.SetBool("AskAgain", ask) PARAMS.SetBool("AskAgain", ask)
PARAMS.SetBool("LoadPsets", psets) PARAMS.SetBool("LoadPsets", psets)
PARAMS.SetBool("LoadTypes", types)
PARAMS.SetBool("LoadMaterials", materials) PARAMS.SetBool("LoadMaterials", materials)
PARAMS.SetBool("LoadLayers", layers) PARAMS.SetBool("LoadLayers", layers)
PARAMS.SetBool("SingleDoc", bool(1 - singledoc)) PARAMS.SetBool("SingleDoc", bool(1 - singledoc))

View File

@@ -350,6 +350,7 @@ def create_children(
] ]
for window in windows: for window in windows:
subresult.extend(create_child(child, window)) subresult.extend(create_child(child, window))
if recursive: if recursive:
subresult.extend( subresult.extend(
create_children( create_children(

View File

@@ -51,6 +51,34 @@ def show_type(obj):
obj.Type = typeobj obj.Type = typeobj
def load_types(prj_obj):
"""
Loads IFC types for all objects in the project, used during
import of IFC files.
prj_obj is the project object, either a document or a document object.
"""
def process_object(obj):
"""Recursively process an object and its children"""
# Check if this object has IFC data and can have types
if hasattr(obj, 'StepId') and obj.StepId:
show_type(obj)
# Process children recursively
if hasattr(obj, 'Group'):
for child in obj.Group:
process_object(child)
if isinstance(prj_obj, FreeCAD.DocumentObject):
# Handle document object case
process_object(prj_obj)
else:
# Handle document case - process all IFC objects in the document
for obj in prj_obj.Objects:
if hasattr(obj, 'StepId') and obj.StepId:
show_type(obj)
def is_typable(obj): def is_typable(obj):
"""Checks if an object can become a type""" """Checks if an object can become a type"""
@@ -87,10 +115,9 @@ def convert_to_type(obj, keep_object=False):
original_text = dlg.label.text() original_text = dlg.label.text()
dlg.label.setText(original_text.replace("%1", obj.Class+"Type")) dlg.label.setText(original_text.replace("%1", obj.Class+"Type"))
# Set the initial state of the checkbox from the "always keep" preference # Set the initial state of the checkbox from the "always keep" preference
dlg.checkKeepObject.setChecked(always_keep) dlg.checkKeepObject.setChecked(always_keep)
result = dlg.exec_() result = dlg.exec_()
if not result: if not result:
return return