Skip to content

Commit

Permalink
Lock system
Browse files Browse the repository at this point in the history
  • Loading branch information
yorikvanhavre committed Mar 18, 2024
1 parent be713ee commit b739b77
Show file tree
Hide file tree
Showing 5 changed files with 255 additions and 39 deletions.
2 changes: 1 addition & 1 deletion ifc_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def open(filename):
doc = FreeCAD.newDocument()
doc.Label = name
FreeCAD.setActiveDocument(doc.Name)
insert(filename, doc.Name)
insert(filename, doc.Name, singledoc=True)
del FreeCAD.IsOpeningIFC
return doc

Expand Down
50 changes: 24 additions & 26 deletions ifc_observer.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,10 @@ def slotDeletedObject(self, obj):
def slotChangedDocument(self, doc, prop):
"""Watch document IFC properties"""

if prop == "Schema" and "IfcFilePath" in doc.PropertiesList:
import ifc_tools # lazy import
import ifc_tools # lazy import
import ifc_status

if prop == "Schema" and "IfcFilePath" in doc.PropertiesList:
schema = doc.Schema
ifcfile = ifc_tools.get_ifcfile(doc)
if ifcfile:
Expand All @@ -88,6 +89,9 @@ def slotChangedDocument(self, doc, prop):
]
if len(child) == 1:
child[0].StepId = new_id
ifc_status.toggle_lock(True)
else:
ifc_status.toggle_lock(False)

def slotCreatedObject(self, obj):
"""If this is an IFC document, turn the object into IFC"""
Expand All @@ -103,26 +107,16 @@ def slotCreatedObject(self, obj):
QtCore.QTimer.singleShot(100, self.convert)

def slotActivateDocument(self, doc):
"""Check if we need to display a ghost"""
"""Check if we need to lock"""

from PySide2 import QtCore # lazy loading
import ifc_status

if hasattr(doc, "Proxy"):
if hasattr(doc.Proxy, "ifcfile"):
# this runs when loading a file
if getattr(doc, "Objects", ""):
for obj in doc.Objects:
if getattr(obj, "ShapeMode", None) == "Coin":
obj.Proxy.cached = True
QtCore.QTimer.singleShot(100, obj.touch)
QtCore.QTimer.singleShot(100, doc.recompute)
QtCore.QTimer.singleShot(100, self.fit_all)
else:
if not hasattr(doc.Proxy, "ghost"):
import ifc_generator

ifc_generator.create_ghost(doc)
if hasattr(doc, "IfcFilePath"):
ifc_status.toggle_lock(True)
else:
ifc_status.toggle_lock(False)
if not hasattr(doc, "Proxy"):
# this is a new file, wait a bit to make sure all components are populated
QtCore.QTimer.singleShot(1000, self.propose_conversion)

Expand Down Expand Up @@ -193,19 +187,20 @@ def convert(self):
return
del self.docname
del self.objname
if obj.isDerivedFrom("Part::Feature"):
if "IfcType" in obj.PropertiesList:
print("Converting", obj.Label, "to IFC")
import ifc_tools # lazy loading
import ifc_geometry # lazy loading
if obj.isDerivedFrom("Part::Feature") or "IfcType" in obj.PropertiesList:
FreeCAD.Console.PrintLog("Converting" + obj.Label + "to IFC\n")
import ifc_tools # lazy loading
import ifc_geometry # lazy loading

newobj = ifc_tools.aggregate(obj, doc)
ifc_geometry.add_geom_properties(newobj)
doc.recompute()
newobj = ifc_tools.aggregate(obj, doc)
ifc_geometry.add_geom_properties(newobj)
doc.recompute()

def propose_conversion(self):
"""Propose a conversion of the current document"""

import ifc_status # lazy loading

doc = FreeCAD.ActiveDocument
if not getattr(FreeCAD, "IsOpeningIFC", False):
if not hasattr(doc, "Proxy"):
Expand All @@ -226,6 +221,7 @@ def propose_conversion(self):
)
return
else:
ifc_status.toggle_lock(False)
return
d = os.path.dirname(__file__)
dlg = FreeCADGui.PySideUic.loadUi(
Expand All @@ -250,6 +246,7 @@ def convert_document(self):
"""Converts the active document"""

import ifc_tools # lazy loading
import ifc_status

doc = FreeCAD.ActiveDocument
ifc_tools.convert_document(doc, strategy=2, silent=True)
Expand All @@ -259,4 +256,5 @@ def convert_document(self):
site = ifc_tools.aggregate(Arch.makeSite(), doc)
building = ifc_tools.aggregate(Arch.makeBuilding(), site)
storey = ifc_tools.aggregate(Arch.makeFloor(), building)
ifc_status.toggle_lock(True)
doc.recompute()
187 changes: 187 additions & 0 deletions ifc_status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
# -*- coding: utf8 -*-
# ***************************************************************************
# * *
# * Copyright (c) 2024 Yorik van Havre <[email protected]> *
# * *
# * This program is free software; you can redistribute it and/or modify *
# * it under the terms of the GNU General Public License (GPL) *
# * as published by the Free Software Foundation; either version 3 of *
# * the License, or (at your option) any later version. *
# * for detail see the LICENCE text file. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU General Public License for more details. *
# * *
# * You should have received a copy of the GNU Library General Public *
# * License along with this program; if not, write to the Free Software *
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
# * USA *
# * *
# ***************************************************************************

"""This contains nativeifc status widgets and functionality"""


import os
import FreeCAD
import FreeCADGui


translate = FreeCAD.Qt.translate
params = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/NativeIFC")
text_on = translate("BIM", "Strict IFC mode is ON (all objects are IFC)")
text_off = translate("BIM", "Strict IFC mode is OFF (IFC and non-IFC objects allowed)")


def set_status_widget(statuswidget):
"""Adds the needed controls to the status bar"""

from PySide import QtGui # lazy import

# lock button
lock_button = QtGui.QAction()
path = os.path.dirname(os.path.dirname(__file__))
icon = QtGui.QIcon(os.path.join(path, "icons", "IFC.svg"))
lock_button.setIcon(icon)
lock_button.setCheckable(True)
doc = FreeCAD.ActiveDocument
if doc and "IfcFilePath" in doc.PropertiesList:
checked = True
else:
checked = params.GetBool("SingleDoc", False)
lock_button.setChecked(checked)
if checked:
lock_button.setText("🔒")
lock_button.setToolTip(text_on)
else:
lock_button.setText(" ")
lock_button.setToolTip(text_off)
lock_button.triggered.connect(do_lock)
lock_button.triggered.connect(toggle_lock)
statuswidget.addAction(lock_button)
statuswidget.lock_button = lock_button


def toggle_lock(checked):
"""Sets the lock button on/off"""

from PySide import QtGui # lazy loading

mw = FreeCADGui.getMainWindow()
statuswidget = mw.findChild(QtGui.QToolBar, "BIMStatusWidget")
if hasattr(statuswidget, "lock_button"):
if checked:
statuswidget.lock_button.setChecked(True)
statuswidget.lock_button.setText("🔒")
statuswidget.lock_button.setToolTip(text_on)
else:
statuswidget.lock_button.setChecked(False)
statuswidget.lock_button.setText(" ")
statuswidget.lock_button.setToolTip(text_off)


def do_lock(checked):
"""Locks or unlocks the document"""

if checked:
lock_document()
else:
unlock_document()


def unlock_document():
"""Unlocks the active document"""

import ifc_tools # lazy loading

doc = FreeCAD.ActiveDocument
if "IfcFilePath" in doc.PropertiesList:
# this is a locked document
doc.openTransaction("Unlock document")
children = [ifc_tools.get_object(o) for o in ifc_tools.get_children(doc)]
if children:
project = ifc_tools.create_document_object(doc, filename = doc.IfcFilePath, silent = True)
project.Group = children
props = ["IfcFilePath", "Modified", "Proxy", "Schema"]
props += [p for p in doc.PropertiesList if doc.getGroupOfProperty(p) == "IFC"]
for prop in props:
doc.removeProperty(prop)
doc.commitTransaction()
doc.recompute()


def lock_document():
"""Locks the active document"""

import ifc_tools # lazy loading
import exportIFC
import ifc_geometry

doc = FreeCAD.ActiveDocument
products = []
spatial = []
if "IfcFilePath" not in doc.PropertiesList:
# this is not a locked document
projects = [o for o in doc.Objects if getattr(o,"Class",None) == "IfcProject"]
if len(projects) == 1:
# 1 there is a project already
project = projects[0]
children = project.OutListRecursive
rest = [o for o in doc.Objects if o not in children and o != project]
doc.openTransaction("Lock document")
ifc_tools.convert_document(doc, filename=project.IfcFilePath, strategy=3, silent=True)
ifcfile = doc.Proxy.ifcfile
if rest:
# 1b some objects are outside
objs = find_toplevel(rest)
prefs, context = ifc_tools.get_export_preferences(ifcfile)
products = exportIFC.export(objs, ifcfile, preferences=prefs)
for product in products.values():
if not getattr(product, "ContainedInStructure", None):
if not getattr(product, "FillsVoids", None):
if not getattr(product, "VoidsElements", None):
if not getattr(product, "Decomposes", None):
new = ifc_tools.create_object(product, doc, ifcfile)
children = ifc_tools.create_children(new, ifcfile, recursive=True)
for o in [new] + children:
ifc_geometry.add_geom_properties(o)
for n in [o.Name for o in rest]:
doc.removeObject(n)
else:
# 1a all objects are already inside a project
pass
doc.removeObject(project.Name)
doc.commitTransaction()
doc.recompute()
elif len(projects) > 1:
# 2 there is more than one project
FreeCAD.Console.PrintError("Unable to lock this document because it contains several IFC documents\n")
toggle_lock(False)
else:
# 3 there is no project
doc.openTransaction("Lock document")
ifc_tools.convert_document(doc, silent=True)
ifcfile = doc.Proxy.ifcfile
objs = find_toplevel(doc.Objects)
exportIFC.export(objs, ifcfile)
for n in [o.Name for o in doc.Objects]:
doc.removeObject(n)
ifc_tools.create_children(doc, ifcfile, recursive=True)
doc.commitTransaction()
doc.recompute()


def find_toplevel(objs):
"""Finds the top-level objects from the list"""

# filter out any object that depend on another from the list
nobjs = []
for obj in objs:
for parent in obj.InListRecursive:
if parent in objs:
break
else:
nobjs.append(obj)
return nobjs
Loading

0 comments on commit b739b77

Please sign in to comment.