Add BIM workbench to .pre-commit-config.yaml (#21591)
* Add BIM workbench to .pre-commit-config.yaml * pre-commit: ignore translations * pre-commit: add additional ignore pattern * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -22,9 +22,9 @@
|
||||
# * *
|
||||
# ***************************************************************************
|
||||
|
||||
__title__ = "FreeCAD Arch External Reference"
|
||||
__title__ = "FreeCAD Arch External Reference"
|
||||
__author__ = "Yorik van Havre"
|
||||
__url__ = "https://www.freecad.org"
|
||||
__url__ = "https://www.freecad.org"
|
||||
|
||||
## @package ArchReference
|
||||
# \ingroup ARCH
|
||||
@@ -50,15 +50,16 @@ if FreeCAD.GuiUp:
|
||||
from draftutils.translate import translate
|
||||
else:
|
||||
# \cond
|
||||
def translate(ctxt,txt):
|
||||
def translate(ctxt, txt):
|
||||
return txt
|
||||
def QT_TRANSLATE_NOOP(ctxt,txt):
|
||||
|
||||
def QT_TRANSLATE_NOOP(ctxt, txt):
|
||||
return txt
|
||||
|
||||
# \endcond
|
||||
|
||||
|
||||
class ArchReference:
|
||||
|
||||
"""The Arch Reference object"""
|
||||
|
||||
def __init__(self, obj):
|
||||
@@ -68,30 +69,35 @@ class ArchReference:
|
||||
ArchReference.setProperties(self, obj)
|
||||
self.reload = True
|
||||
|
||||
|
||||
def setProperties(self, obj):
|
||||
|
||||
pl = obj.PropertiesList
|
||||
if not "File" in pl:
|
||||
t = QT_TRANSLATE_NOOP("App::Property","The base file this component is built upon")
|
||||
obj.addProperty("App::PropertyFile","File","Reference",t, locked=True)
|
||||
t = QT_TRANSLATE_NOOP("App::Property", "The base file this component is built upon")
|
||||
obj.addProperty("App::PropertyFile", "File", "Reference", t, locked=True)
|
||||
if not "Part" in pl:
|
||||
t = QT_TRANSLATE_NOOP("App::Property","The part to use from the base file")
|
||||
obj.addProperty("App::PropertyString","Part","Reference",t, locked=True)
|
||||
t = QT_TRANSLATE_NOOP("App::Property", "The part to use from the base file")
|
||||
obj.addProperty("App::PropertyString", "Part", "Reference", t, locked=True)
|
||||
if not "ReferenceMode" in pl:
|
||||
t = QT_TRANSLATE_NOOP("App::Property","The way the referenced objects are included in the current document. 'Normal' includes the shape, 'Transient' discards the shape when the object is switched off (smaller filesize), 'Lightweight' does not import the shape but only the OpenInventor representation")
|
||||
obj.addProperty("App::PropertyEnumeration","ReferenceMode","Reference",t, locked=True)
|
||||
obj.ReferenceMode = ["Normal","Transient","Lightweight"]
|
||||
t = QT_TRANSLATE_NOOP(
|
||||
"App::Property",
|
||||
"The way the referenced objects are included in the current document. 'Normal' includes the shape, 'Transient' discards the shape when the object is switched off (smaller filesize), 'Lightweight' does not import the shape but only the OpenInventor representation",
|
||||
)
|
||||
obj.addProperty(
|
||||
"App::PropertyEnumeration", "ReferenceMode", "Reference", t, locked=True
|
||||
)
|
||||
obj.ReferenceMode = ["Normal", "Transient", "Lightweight"]
|
||||
if "TransientReference" in pl:
|
||||
if obj.TransientReference:
|
||||
obj.ReferenceMode = "Transient"
|
||||
obj.removeProperty("TransientReference")
|
||||
t = translate("Arch", "TransientReference property to ReferenceMode")
|
||||
FreeCAD.Console.PrintMessage(translate("Arch","Upgrading")+" "+obj.Label+" "+t+"\n")
|
||||
FreeCAD.Console.PrintMessage(
|
||||
translate("Arch", "Upgrading") + " " + obj.Label + " " + t + "\n"
|
||||
)
|
||||
if not "FuseArch" in pl:
|
||||
t = QT_TRANSLATE_NOOP("App::Property","Fuse objects of same material")
|
||||
obj.addProperty("App::PropertyBool","FuseArch", "Reference", t, locked=True)
|
||||
|
||||
t = QT_TRANSLATE_NOOP("App::Property", "Fuse objects of same material")
|
||||
obj.addProperty("App::PropertyBool", "FuseArch", "Reference", t, locked=True)
|
||||
|
||||
def onDocumentRestored(self, obj):
|
||||
|
||||
@@ -101,20 +107,17 @@ class ArchReference:
|
||||
if obj.ViewObject and obj.ViewObject.Proxy:
|
||||
obj.ViewObject.Proxy.loadInventor(obj)
|
||||
|
||||
|
||||
def dumps(self):
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def loads(self, state):
|
||||
|
||||
self.Type = "Reference"
|
||||
|
||||
|
||||
def onChanged(self, obj, prop):
|
||||
|
||||
if prop in ["File","Part"]:
|
||||
if prop in ["File", "Part"]:
|
||||
self.reload = True
|
||||
elif prop == "ReferenceMode":
|
||||
if obj.ReferenceMode == "Normal":
|
||||
@@ -130,19 +133,20 @@ class ArchReference:
|
||||
elif obj.ReferenceMode == "Lightweight":
|
||||
self.reload = False
|
||||
import Part
|
||||
|
||||
pl = obj.Placement
|
||||
obj.Shape = Part.Shape()
|
||||
obj.Placement = pl
|
||||
if obj.ViewObject and obj.ViewObject.Proxy:
|
||||
obj.ViewObject.Proxy.loadInventor(obj)
|
||||
|
||||
|
||||
def execute(self, obj):
|
||||
|
||||
import Part
|
||||
|
||||
pl = obj.Placement
|
||||
filename = self.getFile(obj)
|
||||
if filename and self.reload and obj.ReferenceMode in ["Normal","Transient"]:
|
||||
if filename and self.reload and obj.ReferenceMode in ["Normal", "Transient"]:
|
||||
self.parts = self.getPartsList(obj)
|
||||
if self.parts:
|
||||
if filename.lower().endswith(".fcstd"):
|
||||
@@ -156,21 +160,21 @@ class ArchReference:
|
||||
shapedata = f.read()
|
||||
f.close()
|
||||
shapedata = shapedata.decode("utf8")
|
||||
shape = self.cleanShape(shapedata,obj,self.parts[obj.Part][2])
|
||||
shape = self.cleanShape(shapedata, obj, self.parts[obj.Part][2])
|
||||
self.shapes.append(shape)
|
||||
obj.Shape = shape
|
||||
if not pl.isIdentity():
|
||||
obj.Placement = pl
|
||||
else:
|
||||
t = translate("Arch","Part not found in file")
|
||||
FreeCAD.Console.PrintError(t+"\n")
|
||||
t = translate("Arch", "Part not found in file")
|
||||
FreeCAD.Console.PrintError(t + "\n")
|
||||
else:
|
||||
for part in self.parts.values():
|
||||
f = zdoc.open(part[1])
|
||||
shapedata = f.read()
|
||||
f.close()
|
||||
shapedata = shapedata.decode("utf8")
|
||||
shape = self.cleanShape(shapedata,obj)
|
||||
shape = self.cleanShape(shapedata, obj)
|
||||
self.shapes.append(shape)
|
||||
if self.shapes:
|
||||
obj.Shape = Part.makeCompound(self.shapes)
|
||||
@@ -182,8 +186,10 @@ class ArchReference:
|
||||
from nativeifc import ifc_tools
|
||||
from nativeifc import ifc_generator
|
||||
except:
|
||||
t = translate("Arch","NativeIFC not available - unable to process IFC files")
|
||||
FreeCAD.Console.PrintError(t+"\n")
|
||||
t = translate(
|
||||
"Arch", "NativeIFC not available - unable to process IFC files"
|
||||
)
|
||||
FreeCAD.Console.PrintError(t + "\n")
|
||||
return
|
||||
elements = self.getIFCElements(obj, ifcfile)
|
||||
shape, colors = ifc_generator.generate_shape(ifcfile, elements, cached=True)
|
||||
@@ -208,6 +214,7 @@ class ArchReference:
|
||||
doc = obj.Document
|
||||
oldobjs = list(doc.Objects)
|
||||
import Import
|
||||
|
||||
Import.readDXF(filename, doc.Name, True, loc + "/RefDxfImport")
|
||||
newobjs = [o for o in doc.Objects if o not in oldobjs]
|
||||
shapes = [o.Shape for o in newobjs if o.isDerivedFrom("Part::Feature")]
|
||||
@@ -220,16 +227,14 @@ class ArchReference:
|
||||
doc.removeObject(n)
|
||||
self.reload = False
|
||||
|
||||
|
||||
def getIFCElements(self, obj, ifcfile):
|
||||
|
||||
"""returns IFC elements for this object"""
|
||||
|
||||
try:
|
||||
from nativeifc import ifc_generator
|
||||
except:
|
||||
t = translate("Arch","NativeIFC not available - unable to process IFC files")
|
||||
FreeCAD.Console.PrintError(t+"\n")
|
||||
t = translate("Arch", "NativeIFC not available - unable to process IFC files")
|
||||
FreeCAD.Console.PrintError(t + "\n")
|
||||
return
|
||||
if obj.Part:
|
||||
element = ifcfile[int(obj.Part)]
|
||||
@@ -239,12 +244,11 @@ class ArchReference:
|
||||
elements = ifc_generator.filter_types(elements)
|
||||
return elements
|
||||
|
||||
|
||||
def cleanShape(self, shapedata, obj, materials=None):
|
||||
|
||||
"""cleans the imported shape"""
|
||||
|
||||
import Part
|
||||
|
||||
shape = Part.Shape()
|
||||
shape.importBrepFromString(shapedata)
|
||||
if obj.FuseArch and materials:
|
||||
@@ -263,8 +267,8 @@ class ArchReference:
|
||||
break
|
||||
else:
|
||||
shapes.append(edge)
|
||||
#print("solids:",len(shape.Solids),"mattable:",materials)
|
||||
for key,solindexes in materials.items():
|
||||
# print("solids:",len(shape.Solids),"mattable:",materials)
|
||||
for key, solindexes in materials.items():
|
||||
if key == "Undefined":
|
||||
# do not join objects with no defined material
|
||||
for solindex in [int(i) for i in solindexes.split(",")]:
|
||||
@@ -282,13 +286,11 @@ class ArchReference:
|
||||
try:
|
||||
shape = shape.removeSplitter()
|
||||
except Exception:
|
||||
t = translate("Arch","Error removing splitter")
|
||||
FreeCAD.Console.PrintError(obj.Label+": "+t+"\n")
|
||||
t = translate("Arch", "Error removing splitter")
|
||||
FreeCAD.Console.PrintError(obj.Label + ": " + t + "\n")
|
||||
return shape
|
||||
|
||||
|
||||
def exists(self,filepath):
|
||||
|
||||
def exists(self, filepath):
|
||||
"""case-insensitive version of os.path.exists. Returns the actual file path or None"""
|
||||
|
||||
if os.path.exists(filepath):
|
||||
@@ -301,9 +303,7 @@ class ArchReference:
|
||||
return p + e.upper()
|
||||
return None
|
||||
|
||||
|
||||
def getFile(self,obj,filename=None):
|
||||
|
||||
def getFile(self, obj, filename=None):
|
||||
"""gets a valid file, if possible"""
|
||||
|
||||
if not filename:
|
||||
@@ -318,7 +318,7 @@ class ArchReference:
|
||||
# search for the file in the current directory if not found
|
||||
basename = os.path.basename(filename)
|
||||
currentdir = os.path.dirname(obj.Document.FileName)
|
||||
altfile = os.path.join(currentdir,basename)
|
||||
altfile = os.path.join(currentdir, basename)
|
||||
if altfile == obj.Document.FileName:
|
||||
return None
|
||||
elif self.exists(altfile):
|
||||
@@ -328,16 +328,14 @@ class ArchReference:
|
||||
altfile = None
|
||||
subdirs = self.splitall(os.path.dirname(filename))
|
||||
for i in range(len(subdirs)):
|
||||
subpath = [currentdir]+subdirs[-i:]+[basename]
|
||||
subpath = [currentdir] + subdirs[-i:] + [basename]
|
||||
altfile = os.path.join(*subpath)
|
||||
if self.exists(altfile):
|
||||
return self.exists(altfile)
|
||||
return None
|
||||
return self.exists(filename)
|
||||
|
||||
|
||||
def getPartsList(self, obj, filename=None):
|
||||
|
||||
"""returns a list of Part-based objects in a file"""
|
||||
|
||||
filename = self.getFile(obj, filename)
|
||||
@@ -350,19 +348,15 @@ class ArchReference:
|
||||
elif filename.lower().endswith(".dxf"):
|
||||
return self.getPartsListDXF(obj, filename)
|
||||
|
||||
|
||||
def getPartsListDXF(self, obj, filename):
|
||||
|
||||
"""returns a list of Part-based objects in a DXF file"""
|
||||
|
||||
# support layers
|
||||
#with open(filename) as f:
|
||||
# with open(filename) as f:
|
||||
# txt = f.read()
|
||||
return {}
|
||||
|
||||
|
||||
def getPartsListIFC(self, obj, filename):
|
||||
|
||||
"""returns a list of Part-based objects in a IFC file"""
|
||||
|
||||
ifcfile = self.getIfcFile(filename)
|
||||
@@ -378,9 +372,7 @@ class ArchReference:
|
||||
res[str(s.id())] = [name, s, None]
|
||||
return res
|
||||
|
||||
|
||||
def getPartsListFCSTD(self, obj, filename):
|
||||
|
||||
"""returns a list of Part-based objects in a FCStd file"""
|
||||
|
||||
parts = {}
|
||||
@@ -395,35 +387,35 @@ class ArchReference:
|
||||
for line in docf:
|
||||
line = line.decode("utf8")
|
||||
if "<Object name=" in line:
|
||||
n = re.findall(r'name=\"(.*?)\"',line)
|
||||
n = re.findall(r"name=\"(.*?)\"", line)
|
||||
if n:
|
||||
name = n[0]
|
||||
elif "<Property name=\"Label\"" in line:
|
||||
elif '<Property name="Label"' in line:
|
||||
writemode = True
|
||||
elif writemode and "<String value=" in line:
|
||||
n = re.findall(r'value=\"(.*?)\"',line)
|
||||
n = re.findall(r"value=\"(.*?)\"", line)
|
||||
if n:
|
||||
label = n[0]
|
||||
writemode = False
|
||||
elif "<Property name=\"Shape\" type=\"Part::PropertyPartShape\"" in line:
|
||||
elif '<Property name="Shape" type="Part::PropertyPartShape"' in line:
|
||||
writemode = True
|
||||
elif writemode and "<Part" in line and "file=" in line:
|
||||
n = re.findall(r'file=\"(.*?)\"',line)
|
||||
n = re.findall(r"file=\"(.*?)\"", line)
|
||||
if n:
|
||||
part = n[0]
|
||||
writemode = False
|
||||
elif "<Property name=\"MaterialsTable\" type=\"App::PropertyMap\"" in line:
|
||||
elif '<Property name="MaterialsTable" type="App::PropertyMap"' in line:
|
||||
writemode = True
|
||||
elif writemode and "<Item key=" in line:
|
||||
n = re.findall(r'key=\"(.*?)\"',line)
|
||||
v = re.findall(r'value=\"(.*?)\"',line)
|
||||
n = re.findall(r"key=\"(.*?)\"", line)
|
||||
v = re.findall(r"value=\"(.*?)\"", line)
|
||||
if n and v:
|
||||
materials[n[0]] = v[0]
|
||||
elif writemode and "</Map>" in line:
|
||||
writemode = False
|
||||
elif "</Object>" in line:
|
||||
if name and label and part:
|
||||
parts[name] = [label,part,materials]
|
||||
parts[name] = [label, part, materials]
|
||||
name = None
|
||||
label = None
|
||||
part = None
|
||||
@@ -431,24 +423,20 @@ class ArchReference:
|
||||
writemode = False
|
||||
return parts
|
||||
|
||||
|
||||
def getIfcFile(self, filename):
|
||||
|
||||
"""Gets an IfcOpenShell object"""
|
||||
|
||||
try:
|
||||
import ifcopenshell
|
||||
except:
|
||||
t = translate("Arch","NativeIFC not available - unable to process IFC files")
|
||||
FreeCAD.Console.PrintError(t+"\n")
|
||||
t = translate("Arch", "NativeIFC not available - unable to process IFC files")
|
||||
FreeCAD.Console.PrintError(t + "\n")
|
||||
return None
|
||||
if not getattr(self, "ifcfile", None):
|
||||
self.ifcfile = ifcopenshell.open(filename)
|
||||
return self.ifcfile
|
||||
|
||||
|
||||
def getColors(self, obj):
|
||||
|
||||
"""returns the Shape Appearance of the referenced object(s)"""
|
||||
|
||||
filename = self.getFile(obj)
|
||||
@@ -477,7 +465,6 @@ class ArchReference:
|
||||
|
||||
return totalcolors
|
||||
|
||||
|
||||
def _getColorsPart(self, filename, part):
|
||||
zdoc = zipfile.ZipFile(filename)
|
||||
if not "GuiDocument.xml" in zdoc.namelist():
|
||||
@@ -490,21 +477,21 @@ class ArchReference:
|
||||
writemode3 = False
|
||||
for line in docf:
|
||||
line = line.decode("utf8")
|
||||
if ("<ViewProvider name=\"" + part + "\"") in line:
|
||||
if ('<ViewProvider name="' + part + '"') in line:
|
||||
writemode1 = True
|
||||
elif writemode1 and ("<Property name=\"DiffuseColor\"" in line):
|
||||
elif writemode1 and ('<Property name="DiffuseColor"' in line):
|
||||
writemode1 = False
|
||||
writemode2 = True
|
||||
elif writemode1 and ("<Property name=\"ShapeAppearance\"" in line):
|
||||
elif writemode1 and ('<Property name="ShapeAppearance"' in line):
|
||||
writemode1 = False
|
||||
writemode3 = True
|
||||
elif writemode2 and ("<ColorList file=" in line):
|
||||
n = re.findall(r'file=\"(.*?)\"',line)
|
||||
n = re.findall(r"file=\"(.*?)\"", line)
|
||||
if n:
|
||||
colorfile = n[0]
|
||||
break
|
||||
elif writemode3 and ("<MaterialList file=" in line):
|
||||
n = re.findall(r'file=\"(.*?)\"',line)
|
||||
n = re.findall(r"file=\"(.*?)\"", line)
|
||||
if n:
|
||||
colorfile = n[0]
|
||||
break
|
||||
@@ -521,11 +508,11 @@ class ArchReference:
|
||||
|
||||
if writemode2:
|
||||
# Old DiffuseColor support:
|
||||
for i in range(1, int(len(buf)/4)):
|
||||
for i in range(1, int(len(buf) / 4)):
|
||||
# ShapeAppearance material with default v0.21 properties:
|
||||
material = FreeCAD.Material()
|
||||
color = self._processColor(buf, i*4)
|
||||
material.DiffuseColor = color[:3] + (255, )
|
||||
color = self._processColor(buf, i * 4)
|
||||
material.DiffuseColor = color[:3] + (255,)
|
||||
material.Transparency = color[3] / 255.0
|
||||
colors.append(material)
|
||||
|
||||
@@ -542,7 +529,7 @@ class ArchReference:
|
||||
# - transparency
|
||||
# - Tail of file: unknown repetition of bytes
|
||||
for face_idx in range(buf[0]):
|
||||
face_buf = buf[face_idx*24+4:face_idx*24+28]
|
||||
face_buf = buf[face_idx * 24 + 4 : face_idx * 24 + 28]
|
||||
# ShapeAppearance material with default v0.21 properties:
|
||||
material = FreeCAD.Material()
|
||||
material.AmbientColor = self._processColor(face_buf, 0)
|
||||
@@ -555,19 +542,15 @@ class ArchReference:
|
||||
|
||||
return colors
|
||||
|
||||
|
||||
def _processColor(self, buf, i):
|
||||
"""returns a tuple with 4 ints (0-255)"""
|
||||
return (buf[i+3], buf[i+2], buf[i+1], buf[i])
|
||||
|
||||
return (buf[i + 3], buf[i + 2], buf[i + 1], buf[i])
|
||||
|
||||
def _processNumber(self, buf, i):
|
||||
"""returns a float"""
|
||||
return struct.unpack("f", buf[i:i+4])[0]
|
||||
|
||||
|
||||
def splitall(self,path):
|
||||
return struct.unpack("f", buf[i : i + 4])[0]
|
||||
|
||||
def splitall(self, path):
|
||||
"""splits a path between its components"""
|
||||
|
||||
allparts = []
|
||||
@@ -576,7 +559,7 @@ class ArchReference:
|
||||
if parts[0] == path: # sentinel for absolute paths
|
||||
allparts.insert(0, parts[0])
|
||||
break
|
||||
elif parts[1] == path: # sentinel for relative paths
|
||||
elif parts[1] == path: # sentinel for relative paths
|
||||
allparts.insert(0, parts[1])
|
||||
break
|
||||
else:
|
||||
@@ -586,94 +569,85 @@ class ArchReference:
|
||||
|
||||
|
||||
class ViewProviderArchReference:
|
||||
|
||||
|
||||
"""A View Provider for the Arch Reference object"""
|
||||
|
||||
|
||||
def __init__(self,vobj):
|
||||
def __init__(self, vobj):
|
||||
|
||||
vobj.Proxy = self
|
||||
self.setProperties(vobj)
|
||||
|
||||
|
||||
def setProperties(self,vobj):
|
||||
def setProperties(self, vobj):
|
||||
|
||||
pl = vobj.PropertiesList
|
||||
if not "TimeStamp" in pl:
|
||||
t = QT_TRANSLATE_NOOP("App::Property","The latest time stamp of the linked file")
|
||||
vobj.addProperty("App::PropertyFloat","TimeStamp","Reference",t, locked=True)
|
||||
vobj.setEditorMode("TimeStamp",2)
|
||||
t = QT_TRANSLATE_NOOP("App::Property", "The latest time stamp of the linked file")
|
||||
vobj.addProperty("App::PropertyFloat", "TimeStamp", "Reference", t, locked=True)
|
||||
vobj.setEditorMode("TimeStamp", 2)
|
||||
if not "UpdateColors" in pl:
|
||||
t = QT_TRANSLATE_NOOP("App::Property","If true, the colors from the linked file will be kept updated")
|
||||
vobj.addProperty("App::PropertyBool","UpdateColors","Reference",t, locked=True)
|
||||
t = QT_TRANSLATE_NOOP(
|
||||
"App::Property", "If true, the colors from the linked file will be kept updated"
|
||||
)
|
||||
vobj.addProperty("App::PropertyBool", "UpdateColors", "Reference", t, locked=True)
|
||||
vobj.UpdateColors = True
|
||||
|
||||
|
||||
def getIcon(self):
|
||||
|
||||
import Arch_rc
|
||||
|
||||
return ":/icons/Arch_Reference.svg"
|
||||
|
||||
|
||||
def attach(self,vobj):
|
||||
def attach(self, vobj):
|
||||
|
||||
self.Object = vobj.Object
|
||||
# Check for file change every minute
|
||||
self.timer = QtCore.QTimer()
|
||||
self.timer.timeout.connect(self.checkChanges)
|
||||
s = params.get_param_arch("ReferenceCheckInterval")
|
||||
self.timer.start(1000*s)
|
||||
|
||||
self.timer.start(1000 * s)
|
||||
|
||||
def dumps(self):
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def loads(self,state):
|
||||
def loads(self, state):
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def updateData(self,obj,prop):
|
||||
if (prop == "Shape"):
|
||||
if hasattr(obj.ViewObject,"UpdateColors") and obj.ViewObject.UpdateColors:
|
||||
def updateData(self, obj, prop):
|
||||
if prop == "Shape":
|
||||
if hasattr(obj.ViewObject, "UpdateColors") and obj.ViewObject.UpdateColors:
|
||||
if obj.Shape and not obj.Shape.isNull():
|
||||
colors = obj.Proxy.getColors(obj)
|
||||
if colors:
|
||||
obj.ViewObject.ShapeAppearance = colors
|
||||
|
||||
|
||||
def checkChanges(self):
|
||||
|
||||
"checks if the linked file has changed"
|
||||
|
||||
if hasattr(self,"Object") and self.Object:
|
||||
if hasattr(self, "Object") and self.Object:
|
||||
try:
|
||||
f = self.Object.File
|
||||
except ReferenceError:
|
||||
f = None
|
||||
if hasattr(self,"timer"):
|
||||
if hasattr(self, "timer"):
|
||||
self.timer.stop()
|
||||
del self.timer
|
||||
if f:
|
||||
filename = self.Object.Proxy.getFile(self.Object)
|
||||
if filename:
|
||||
st_mtime = os.stat(filename).st_mtime
|
||||
if hasattr(self.Object.ViewObject,"TimeStamp"):
|
||||
if hasattr(self.Object.ViewObject, "TimeStamp"):
|
||||
if self.Object.ViewObject.TimeStamp:
|
||||
if self.Object.ViewObject.TimeStamp != st_mtime:
|
||||
self.Object.Proxy.reload = True
|
||||
self.Object.touch()
|
||||
self.Object.ViewObject.TimeStamp = st_mtime
|
||||
|
||||
|
||||
def onChanged(self,vobj,prop):
|
||||
def onChanged(self, vobj, prop):
|
||||
|
||||
if prop == "ShapeColor":
|
||||
# prevent ShapeColor from overriding DiffuseColor
|
||||
if hasattr(vobj,"DiffuseColor") and hasattr(vobj,"UpdateColors"):
|
||||
if hasattr(vobj, "DiffuseColor") and hasattr(vobj, "UpdateColors"):
|
||||
if vobj.DiffuseColor and vobj.UpdateColors:
|
||||
vobj.DiffuseColor = vobj.DiffuseColor
|
||||
elif prop == "Visibility":
|
||||
@@ -682,23 +656,22 @@ class ViewProviderArchReference:
|
||||
vobj.Object.Proxy.reload = True
|
||||
vobj.Object.Proxy.execute(vobj.Object)
|
||||
else:
|
||||
if hasattr(vobj.Object,"ReferenceMode"):
|
||||
if hasattr(vobj.Object, "ReferenceMode"):
|
||||
if vobj.Object.ReferenceMode == "Transient":
|
||||
vobj.Object.Proxy.reload = False
|
||||
import Part
|
||||
|
||||
pl = vobj.Object.Placement
|
||||
vobj.Object.Shape = Part.Shape()
|
||||
vobj.Object.Placement = pl
|
||||
|
||||
def onDelete(self, obj, doc):
|
||||
|
||||
def onDelete(self,obj,doc):
|
||||
|
||||
if hasattr(self,"timer"):
|
||||
if hasattr(self, "timer"):
|
||||
self.timer.stop()
|
||||
del self.timer
|
||||
return True
|
||||
|
||||
|
||||
def setEdit(self, vobj, mode):
|
||||
if mode != 0:
|
||||
return None
|
||||
@@ -707,7 +680,6 @@ class ViewProviderArchReference:
|
||||
FreeCADGui.Control.showDialog(taskd)
|
||||
return True
|
||||
|
||||
|
||||
def unsetEdit(self, vobj, mode):
|
||||
if mode != 0:
|
||||
return None
|
||||
@@ -715,62 +687,47 @@ class ViewProviderArchReference:
|
||||
FreeCADGui.Control.closeDialog()
|
||||
return True
|
||||
|
||||
|
||||
def setupContextMenu(self, vobj, menu):
|
||||
|
||||
if FreeCADGui.activeWorkbench().name() != 'BIMWorkbench':
|
||||
if FreeCADGui.activeWorkbench().name() != "BIMWorkbench":
|
||||
return
|
||||
|
||||
actionEdit = QtGui.QAction(translate("Arch", "Edit"),
|
||||
menu)
|
||||
QtCore.QObject.connect(actionEdit,
|
||||
QtCore.SIGNAL("triggered()"),
|
||||
self.edit)
|
||||
actionEdit = QtGui.QAction(translate("Arch", "Edit"), menu)
|
||||
QtCore.QObject.connect(actionEdit, QtCore.SIGNAL("triggered()"), self.edit)
|
||||
menu.addAction(actionEdit)
|
||||
|
||||
actionOnReload = QtGui.QAction(QtGui.QIcon(":/icons/view-refresh.svg"),
|
||||
translate("Arch", "Reload reference"),
|
||||
menu)
|
||||
QtCore.QObject.connect(actionOnReload,
|
||||
QtCore.SIGNAL("triggered()"),
|
||||
self.onReload)
|
||||
actionOnReload = QtGui.QAction(
|
||||
QtGui.QIcon(":/icons/view-refresh.svg"), translate("Arch", "Reload reference"), menu
|
||||
)
|
||||
QtCore.QObject.connect(actionOnReload, QtCore.SIGNAL("triggered()"), self.onReload)
|
||||
menu.addAction(actionOnReload)
|
||||
|
||||
actionOnOpen = QtGui.QAction(QtGui.QIcon(":/icons/document-open.svg"),
|
||||
translate("Arch", "Open reference"),
|
||||
menu)
|
||||
QtCore.QObject.connect(actionOnOpen,
|
||||
QtCore.SIGNAL("triggered()"),
|
||||
self.onOpen)
|
||||
actionOnOpen = QtGui.QAction(
|
||||
QtGui.QIcon(":/icons/document-open.svg"), translate("Arch", "Open reference"), menu
|
||||
)
|
||||
QtCore.QObject.connect(actionOnOpen, QtCore.SIGNAL("triggered()"), self.onOpen)
|
||||
menu.addAction(actionOnOpen)
|
||||
|
||||
|
||||
def edit(self):
|
||||
|
||||
FreeCADGui.ActiveDocument.setEdit(self.Object, 0)
|
||||
|
||||
|
||||
def onReload(self):
|
||||
|
||||
"reloads the reference object"
|
||||
|
||||
if hasattr(self,"Object") and self.Object:
|
||||
if hasattr(self, "Object") and self.Object:
|
||||
self.Object.Proxy.reload = True
|
||||
self.Object.touch()
|
||||
FreeCAD.ActiveDocument.recompute()
|
||||
|
||||
|
||||
def onOpen(self):
|
||||
|
||||
"opens the reference file"
|
||||
|
||||
if hasattr(self,"Object") and self.Object:
|
||||
if hasattr(self, "Object") and self.Object:
|
||||
if self.Object.File:
|
||||
FreeCAD.openDocument(self.Object.File)
|
||||
|
||||
|
||||
def loadInventor(self, obj):
|
||||
|
||||
"loads an openinventor file and replace the root node of this object"
|
||||
|
||||
filename = obj.Proxy.getFile(obj)
|
||||
@@ -783,20 +740,21 @@ class ViewProviderArchReference:
|
||||
# check inventor contents
|
||||
ivstring = self.getInventorString(obj)
|
||||
if not ivstring:
|
||||
t = translate("Arch","Unable to get lightWeight node for object referenced in")
|
||||
FreeCAD.Console.PrintWarning(t+" "+obj.Label+"\n")
|
||||
t = translate("Arch", "Unable to get lightWeight node for object referenced in")
|
||||
FreeCAD.Console.PrintWarning(t + " " + obj.Label + "\n")
|
||||
return
|
||||
from pivy import coin
|
||||
|
||||
inputnode = coin.SoInput()
|
||||
inputnode.setBuffer(ivstring)
|
||||
lwnode = coin.SoDB.readAll(inputnode)
|
||||
if not isinstance(lwnode,coin.SoSeparator):
|
||||
t = translate("Arch","Invalid lightWeight node for object referenced in")
|
||||
FreeCAD.Console.PrintError(t+" "+obj.Label+"\n")
|
||||
if not isinstance(lwnode, coin.SoSeparator):
|
||||
t = translate("Arch", "Invalid lightWeight node for object referenced in")
|
||||
FreeCAD.Console.PrintError(t + " " + obj.Label + "\n")
|
||||
return
|
||||
if lwnode.getNumChildren() < 2:
|
||||
t = translate("Arch","Invalid lightWeight node for object referenced in")
|
||||
FreeCAD.Console.PrintError(t+" "+obj.Label+"\n")
|
||||
t = translate("Arch", "Invalid lightWeight node for object referenced in")
|
||||
FreeCAD.Console.PrintError(t + " " + obj.Label + "\n")
|
||||
return
|
||||
flatlines = lwnode
|
||||
shaded = lwnode.getChild(0)
|
||||
@@ -805,11 +763,15 @@ class ViewProviderArchReference:
|
||||
# check node contents
|
||||
rootnode = obj.ViewObject.RootNode
|
||||
if rootnode.getNumChildren() < 3:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Invalid root node in")+" "+obj.Label+"\n")
|
||||
FreeCAD.Console.PrintError(
|
||||
translate("Arch", "Invalid root node in") + " " + obj.Label + "\n"
|
||||
)
|
||||
return
|
||||
switch = rootnode.getChild(2)
|
||||
if switch.getNumChildren() != 4:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Invalid root node in")+" "+obj.Label+"\n")
|
||||
FreeCAD.Console.PrintError(
|
||||
translate("Arch", "Invalid root node in") + " " + obj.Label + "\n"
|
||||
)
|
||||
return
|
||||
|
||||
# keep a copy of the original nodes
|
||||
@@ -818,45 +780,45 @@ class ViewProviderArchReference:
|
||||
self.orig_wireframe = switch.getChild(2).copy()
|
||||
|
||||
# replace root node of object
|
||||
switch.replaceChild(0,flatlines)
|
||||
switch.replaceChild(1,shaded)
|
||||
switch.replaceChild(2,wireframe)
|
||||
|
||||
|
||||
def unloadInventor(self,obj):
|
||||
switch.replaceChild(0, flatlines)
|
||||
switch.replaceChild(1, shaded)
|
||||
switch.replaceChild(2, wireframe)
|
||||
|
||||
def unloadInventor(self, obj):
|
||||
"restore original nodes"
|
||||
|
||||
if (not hasattr(self,"orig_flatlines")) or (not self.orig_flatlines):
|
||||
if (not hasattr(self, "orig_flatlines")) or (not self.orig_flatlines):
|
||||
return
|
||||
if (not hasattr(self,"orig_shaded")) or (not self.orig_shaded):
|
||||
if (not hasattr(self, "orig_shaded")) or (not self.orig_shaded):
|
||||
return
|
||||
if (not hasattr(self,"orig_wireframe")) or (not self.orig_wireframe):
|
||||
if (not hasattr(self, "orig_wireframe")) or (not self.orig_wireframe):
|
||||
return
|
||||
|
||||
# check node contents
|
||||
rootnode = obj.ViewObject.RootNode
|
||||
if rootnode.getNumChildren() < 3:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Invalid root node in")+" "+obj.Label+"\n")
|
||||
FreeCAD.Console.PrintError(
|
||||
translate("Arch", "Invalid root node in") + " " + obj.Label + "\n"
|
||||
)
|
||||
return
|
||||
switch = rootnode.getChild(2)
|
||||
if switch.getNumChildren() != 4:
|
||||
FreeCAD.Console.PrintError(translate("Arch","Invalid root node in")+" "+obj.Label+"\n")
|
||||
FreeCAD.Console.PrintError(
|
||||
translate("Arch", "Invalid root node in") + " " + obj.Label + "\n"
|
||||
)
|
||||
return
|
||||
|
||||
# replace root node of object
|
||||
switch.replaceChild(0,self.orig_flatlines)
|
||||
switch.replaceChild(1,self.orig_shaded)
|
||||
switch.replaceChild(2,self.orig_wireframe)
|
||||
switch.replaceChild(0, self.orig_flatlines)
|
||||
switch.replaceChild(1, self.orig_shaded)
|
||||
switch.replaceChild(2, self.orig_wireframe)
|
||||
|
||||
# discard old content
|
||||
self.orig_flatlines = None
|
||||
self.orig_shaded = None
|
||||
self.orig_wireframe = None
|
||||
|
||||
|
||||
def getInventorString(self,obj):
|
||||
|
||||
def getInventorString(self, obj):
|
||||
"locates and loads an iv file saved together with an object, if existing"
|
||||
|
||||
filename = obj.Proxy.getFile(obj)
|
||||
@@ -876,11 +838,11 @@ class ViewProviderArchReference:
|
||||
line = line.decode("utf8")
|
||||
if ("<Object name=" in line) and (part in line):
|
||||
writemode1 = True
|
||||
elif writemode1 and ("<Property name=\"SavedInventor\"" in line):
|
||||
elif writemode1 and ('<Property name="SavedInventor"' in line):
|
||||
writemode1 = False
|
||||
writemode2 = True
|
||||
elif writemode2 and ("<FileIncluded file=" in line):
|
||||
n = re.findall(r'file=\"(.*?)\"',line)
|
||||
n = re.findall(r"file=\"(.*?)\"", line)
|
||||
if n:
|
||||
ivfile = n[0]
|
||||
break
|
||||
@@ -892,20 +854,18 @@ class ViewProviderArchReference:
|
||||
buf = f.read()
|
||||
buf = buf.decode("utf8")
|
||||
f.close()
|
||||
buf = buf.replace("lineWidth 2","lineWidth "+str(int(obj.ViewObject.LineWidth)))
|
||||
buf = buf.replace("lineWidth 2", "lineWidth " + str(int(obj.ViewObject.LineWidth)))
|
||||
return buf
|
||||
|
||||
|
||||
def setIFCNode(self, obj, filename):
|
||||
|
||||
"""Sets the coin node of this object from an IFC file"""
|
||||
|
||||
try:
|
||||
from nativeifc import ifc_tools
|
||||
from nativeifc import ifc_generator
|
||||
except:
|
||||
t = translate("Arch","NativeIFC not available - unable to process IFC files")
|
||||
FreeCAD.Console.PrintError(t+"\n")
|
||||
t = translate("Arch", "NativeIFC not available - unable to process IFC files")
|
||||
FreeCAD.Console.PrintError(t + "\n")
|
||||
return
|
||||
ifcfile = obj.Proxy.getIfcFile(filename)
|
||||
elements = obj.Proxy.getIFCElements(obj, ifcfile)
|
||||
@@ -922,47 +882,45 @@ class ViewProviderArchReference:
|
||||
|
||||
|
||||
class ArchReferenceTaskPanel:
|
||||
"""The editmode TaskPanel for Reference objects"""
|
||||
|
||||
|
||||
'''The editmode TaskPanel for Reference objects'''
|
||||
|
||||
def __init__(self,obj):
|
||||
def __init__(self, obj):
|
||||
|
||||
self.obj = obj
|
||||
self.filename = None
|
||||
self.form = QtGui.QWidget()
|
||||
self.form.setWindowTitle(translate("Arch","External reference"))
|
||||
self.form.setWindowTitle(translate("Arch", "External reference"))
|
||||
layout = QtGui.QVBoxLayout(self.form)
|
||||
label1 = QtGui.QLabel(translate("Arch","External file")+":")
|
||||
label1 = QtGui.QLabel(translate("Arch", "External file") + ":")
|
||||
layout.addWidget(label1)
|
||||
self.fileButton = QtGui.QPushButton(self.form)
|
||||
self.openButton = QtGui.QPushButton(self.form)
|
||||
self.openButton.setText(translate("Arch","Open"))
|
||||
self.openButton.setText(translate("Arch", "Open"))
|
||||
if not self.obj.File:
|
||||
self.openButton.setEnabled(False)
|
||||
l2 = QtGui.QHBoxLayout()
|
||||
layout.addLayout(l2)
|
||||
l2.addWidget(self.fileButton)
|
||||
l2.addWidget(self.openButton)
|
||||
label2 = QtGui.QLabel(translate("Arch","Part to use:"))
|
||||
label2 = QtGui.QLabel(translate("Arch", "Part to use:"))
|
||||
layout.addWidget(label2)
|
||||
if self.obj.File:
|
||||
self.fileButton.setText(os.path.basename(self.obj.File))
|
||||
else:
|
||||
self.fileButton.setText(translate("Arch","Choose File"))
|
||||
self.fileButton.setText(translate("Arch", "Choose File"))
|
||||
self.partCombo = QtGui.QComboBox(self.form)
|
||||
self.partCombo.setEnabled(False)
|
||||
layout.addWidget(self.partCombo)
|
||||
if hasattr(self.obj.Proxy,"parts"):
|
||||
if hasattr(self.obj.Proxy, "parts"):
|
||||
parts = self.obj.Proxy.parts
|
||||
else:
|
||||
parts = self.obj.Proxy.getPartsList(self.obj)
|
||||
if parts:
|
||||
self.partCombo.setEnabled(True)
|
||||
sortedkeys = sorted(parts)
|
||||
self.partCombo.addItem(translate("Arch","None (Use whole object)"),"")
|
||||
self.partCombo.addItem(translate("Arch", "None (Use whole object)"), "")
|
||||
for k in sortedkeys:
|
||||
self.partCombo.addItem(parts[k][0],k)
|
||||
self.partCombo.addItem(parts[k][0], k)
|
||||
if self.obj.Part:
|
||||
if self.obj.Part in sortedkeys:
|
||||
self.partCombo.setCurrentIndex(sortedkeys.index(self.obj.Part) + 1)
|
||||
@@ -986,7 +944,7 @@ class ArchReferenceTaskPanel:
|
||||
self.obj.Part = self.partCombo.itemData(i)
|
||||
else:
|
||||
self.obj.Part = ""
|
||||
QtCore.QTimer.singleShot(0,FreeCAD.ActiveDocument.recompute)
|
||||
QtCore.QTimer.singleShot(0, FreeCAD.ActiveDocument.recompute)
|
||||
if self.filename and self.obj.Label == "External Reference":
|
||||
self.obj.Label = os.path.basename(self.filename)
|
||||
FreeCADGui.ActiveDocument.resetEdit()
|
||||
@@ -1011,22 +969,21 @@ class ArchReferenceTaskPanel:
|
||||
pass
|
||||
else:
|
||||
filters += " *.ifc"
|
||||
filters = translate("Arch","Reference files")+" ("+filters+")"
|
||||
f = QtGui.QFileDialog.getOpenFileName(self.form,
|
||||
translate("Arch","Choose reference file"),
|
||||
loc,
|
||||
filters)
|
||||
filters = translate("Arch", "Reference files") + " (" + filters + ")"
|
||||
f = QtGui.QFileDialog.getOpenFileName(
|
||||
self.form, translate("Arch", "Choose reference file"), loc, filters
|
||||
)
|
||||
if f:
|
||||
self.filename = f[0]
|
||||
self.fileButton.setText(os.path.basename(self.filename))
|
||||
parts = self.obj.Proxy.getPartsList(self.obj,self.filename)
|
||||
parts = self.obj.Proxy.getPartsList(self.obj, self.filename)
|
||||
self.partCombo.clear()
|
||||
if parts:
|
||||
self.partCombo.setEnabled(True)
|
||||
sortedkeys = sorted(parts)
|
||||
self.partCombo.addItem(translate("Arch","None (Use whole object)"),"")
|
||||
self.partCombo.addItem(translate("Arch", "None (Use whole object)"), "")
|
||||
for k in sortedkeys:
|
||||
self.partCombo.addItem(parts[k][0],k)
|
||||
self.partCombo.addItem(parts[k][0], k)
|
||||
if self.obj.Part:
|
||||
if self.obj.Part in sortedkeys:
|
||||
self.partCombo.setCurrentIndex(sortedkeys.index(self.obj.Part) + 1)
|
||||
|
||||
Reference in New Issue
Block a user