BIM: Smart removal of wall bases (#24550)

* BIM: Implement smart base removal for Walls

Previously, removing the Base object from an Arch Wall would cause the
wall to reset its position to the document origin and could lead to
unintended geometric changes for complex walls.

This commit introduces a "smart debasing" mechanism integrated into the
Component Task Panel's "Remove" button:

- For walls based on a single straight line, the operation now preserves
  the wall's global position and parametric `Length`, making it an
  independent object.
- For walls with complex bases (multi-segment, curved), a warning dialog
  is now presented to the user, explaining the consequences (shape
  alteration and position reset) before allowing the operation to
  proceed.

This is supported by new API functions `Arch.is_debasable()` and
`Arch.debaseWall()`, which contain the core logic for the feature.

Fixes: https://github.com/FreeCAD/FreeCAD/issues/24453

* BIM: Move wall debasing logic into ArchWall proxy

The logic for handling the removal of a wall's base object was previously
implemented directly within the generic `ComponentTaskPanel` in
`ArchComponent.py`. This created a tight coupling, forcing the generic
component UI to have specific knowledge about the `ArchWall` type.

This commit refactors the implementation to follow a more object-oriented
and polymorphic design:

1.  A new overridable method, `handleComponentRemoval(subobject)`, has been
    added to the base `ArchComponent` proxy class. Its default implementation
    maintains the standard removal behavior.

2.  The `_Wall` proxy class in `ArchWall.py` now overrides this method. All
    wall-specific debasing logic, including the eligibility check and the
    user-facing warning dialog, now resides entirely within this override.

3.  The `ComponentTaskPanel.removeElement` method has been simplified. It is
    now a generic dispatcher that calls `handleComponentRemoval` on the
    proxy of the object being edited, with no specific knowledge of object types.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* BIM: Correct user warning

The operation can indeed be undone.

Co-authored-by: Roy-043 <70520633+Roy-043@users.noreply.github.com>

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Roy-043 <70520633+Roy-043@users.noreply.github.com>
This commit is contained in:
Furgo
2025-11-18 14:58:59 +01:00
committed by GitHub
parent e4a2da86f5
commit 7fe944bf9f
5 changed files with 368 additions and 18 deletions

View File

@@ -835,6 +835,13 @@ class Component(ArchIFC.IfcProduct):
if o:
o.ViewObject.hide()
def handleComponentRemoval(self, obj, subobject):
"""
Default handler for when a component is removed via the Task Panel.
Subclasses can override this to provide special behavior.
"""
removeFromComponent(obj, subobject)
def processSubShapes(self, obj, base, placement=None):
"""Add Additions and Subtractions to a base shape.
@@ -2284,18 +2291,24 @@ class ComponentTaskPanel:
self.update()
def removeElement(self):
"""This method is run as a callback when the user selects the remove button.
Get the object selected in the tree widget. If there is an object in
the document with the same Name as the selected item in the tree,
remove it from the object being edited, with the removeFromComponent()
function.
"""
This method is run as a callback when the user selects the remove button.
It calls a handler on the object's proxy to perform the removal.
"""
element_selected = self.tree.currentItem()
if not element_selected:
return
element_to_remove = FreeCAD.ActiveDocument.getObject(str(element_selected.toolTip(0)))
# Call the polymorphic handler on the object's proxy.
# This is generic and works for any Arch object.
if hasattr(self.obj.Proxy, "handleComponentRemoval"):
self.obj.Proxy.handleComponentRemoval(self.obj, element_to_remove)
else:
# Fallback for older proxies that might not have the method
removeFromComponent(self.obj, element_to_remove)
it = self.tree.currentItem()
if it:
comp = FreeCAD.ActiveDocument.getObject(str(it.toolTip(0)))
removeFromComponent(self.obj, comp)
self.update()
def accept(self):