1
# ***************************************************************************
3
# * Copyright (c) 2017 Yorik van Havre <yorik@uncreated.net> *
5
# * This program is free software; you can redistribute it and/or modify *
6
# * it under the terms of the GNU Lesser General Public License (LGPL) *
7
# * as published by the Free Software Foundation; either version 2 of *
8
# * the License, or (at your option) any later version. *
9
# * for detail see the LICENCE text file. *
11
# * This program is distributed in the hope that it will be useful, *
12
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14
# * GNU Library General Public License for more details. *
16
# * You should have received a copy of the GNU Library General Public *
17
# * License along with this program; if not, write to the Free Software *
18
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
21
# ***************************************************************************
23
"""The BIM workbench"""
30
class BIMWorkbench(Workbench):
34
def QT_TRANSLATE_NOOP(context, text):
37
bdir = os.path.join(FreeCAD.getResourceDir(), "Mod", "BIM")
38
tt = QT_TRANSLATE_NOOP("BIM","The BIM workbench is used to model buildings")
39
self.__class__.MenuText = QT_TRANSLATE_NOOP("BIM", "BIM")
40
self.__class__.ToolTip = tt
41
self.__class__.Icon = os.path.join(bdir,"Resources", "icons",
46
# add translations and icon paths
47
FreeCADGui.addIconPath(":/icons")
48
FreeCADGui.addLanguagePath(":/translations")
50
# Create menus and toolbars
53
# Load Arch & Draft preference pages
54
self.loadPreferences()
56
Log("Loading BIM module... done\n")
57
FreeCADGui.updateLocale()
60
def createTools(self):
62
"Create tolbars and menus"
64
def QT_TRANSLATE_NOOP(context, text):
67
# Import Draft & BIM commands
70
from nativeifc import ifc_commands
72
# build menus and toolbars
73
self.draftingtools = [
86
"Draft_CubicBezCurve",
90
self.annotationtools = [
93
"BIM_DimensionAligned",
94
"BIM_DimensionHorizontal",
95
"BIM_DimensionVertical",
123
"Arch_PipeConnector",
134
self.generictools = [
160
"Draft_Draft2Sketch",
182
self.modify = self.modify_gen + sep + self.modify_2d + sep + self.modify_obj + sep + self.modify_3d
187
"BIM_ProjectManager",
192
"BIM_Classification",
197
"Draft_AnnotationStyleEditor",
206
"Draft_WorkingPlaneProxy",
207
"Draft_AddConstruction",
210
"Arch_SelectNonSolidMeshes",
215
"Arch_ToggleIfcBrepFlag",
220
"Arch_IfcSpreadsheet",
227
"Arch_StructureTools",
236
"BIM_Nudge_RotateLeft",
237
"BIM_Nudge_RotateRight",
244
from draftutils import init_tools
245
self.snapbar = init_tools.get_draft_snap_commands()
246
self.snapmenu = self.snapbar + [
252
# create generic tools command
254
class BIM_GenericTools:
255
def __init__(self, tools):
257
def GetCommands(self):
259
def GetResources(self):
260
t = QT_TRANSLATE_NOOP("BIM_GenericTools", "Generic 3D tools")
261
return { "MenuText": t, "ToolTip": t, "Icon": "BIM_Box"}
263
v = hasattr(FreeCADGui.getMainWindow().getActiveWindow(), "getSceneGraph")
265
FreeCADGui.addCommand("BIM_GenericTools", BIM_GenericTools(self.generictools))
266
self.bimtools.append("BIM_GenericTools")
268
# load rebar tools (Reinforcement addon)
275
# create popup group for Rebar tools
276
class RebarGroupCommand:
277
def GetCommands(self):
278
return tuple(["Arch_Rebar"] + RebarTools.RebarCommands)
280
def GetResources(self):
282
"MenuText": QT_TRANSLATE_NOOP(
283
"Arch_RebarTools", "Reinforcement tools"
285
"ToolTip": QT_TRANSLATE_NOOP(
286
"Arch_RebarTools", "Reinforcement tools"
288
"Icon": "Arch_Rebar",
292
v = hasattr(FreeCADGui.getMainWindow().getActiveWindow(), "getSceneGraph")
295
FreeCADGui.addCommand("Arch_RebarTools", RebarGroupCommand())
296
self.bimtools[self.bimtools.index("Arch_Rebar")] = "Arch_RebarTools"
297
RebarTools.load_translations()
298
Log("Load Reinforcement Module...done\n")
299
if hasattr(RebarTools, "updateLocale"):
300
RebarTools.updateLocale()
301
#self.rebar = RebarTools.RebarCommands + ["Arch_Rebar"]
310
if "Report_Create" in Gui.listCommands():
311
self.manage[self.manage.index("Arch_Schedule")] = "Report_Create"
316
import BIMServer, Git, Sketchfab
323
"WebTools_BimServer",
324
"WebTools_Sketchfab",
331
import CommandsPolar, CommandsFrame, CommandsPipe
361
"extend2intersection",
362
"extend1intersection",
370
import FastenerBase, FastenersCmd
376
for c in FastenerBase.FSGetCommands("screws")
377
if not isinstance(c, tuple)
380
# load nativeifc tools
382
ifctools = ifc_commands.get_commands()
386
t1 = QT_TRANSLATE_NOOP("Workbench", "Drafting tools")
387
t2 = QT_TRANSLATE_NOOP("Workbench", "Draft snap")
388
t3 = QT_TRANSLATE_NOOP("Workbench", "3D/BIM tools")
389
t4 = QT_TRANSLATE_NOOP("Workbench", "Annotation tools")
390
t5 = QT_TRANSLATE_NOOP("Workbench", "2D modification tools")
391
t6 = QT_TRANSLATE_NOOP("Workbench", "Manage tools")
392
t7 = QT_TRANSLATE_NOOP("Workbench", "General modification tools")
393
t8 = QT_TRANSLATE_NOOP("Workbench", "Object modification tools")
394
t9 = QT_TRANSLATE_NOOP("Workbench", "3D modification tools")
395
self.appendToolbar(t1, self.draftingtools)
396
self.appendToolbar(t2, self.snapbar)
397
self.appendToolbar(t3, self.bimtools)
398
self.appendToolbar(t4, self.annotationtools)
399
self.appendToolbar(t7, self.modify_gen)
400
self.appendToolbar(t5, self.modify_2d)
401
self.appendToolbar(t8, self.modify_obj)
402
self.appendToolbar(t9, self.modify_3d)
403
self.appendToolbar(t6, self.manage)
407
t1 = QT_TRANSLATE_NOOP("Workbench", "&2D Drafting")
408
t2 = QT_TRANSLATE_NOOP("Workbench", "&3D/BIM")
409
t3 = QT_TRANSLATE_NOOP("Workbench", "Reinforcement tools")
410
t4 = QT_TRANSLATE_NOOP("Workbench", "&Annotation")
411
t5 = QT_TRANSLATE_NOOP("Workbench", "&Snapping")
412
t6 = QT_TRANSLATE_NOOP("Workbench", "&Modify")
413
t7 = QT_TRANSLATE_NOOP("Workbench", "&Manage")
414
#t8 = QT_TRANSLATE_NOOP("Workbench", "&IFC")
415
t9 = QT_TRANSLATE_NOOP("Workbench", "&Flamingo")
416
t10 = QT_TRANSLATE_NOOP("Workbench", "&Fasteners")
417
t11 = QT_TRANSLATE_NOOP("Workbench", "&Utils")
418
t12 = QT_TRANSLATE_NOOP("Workbench", "Nudge")
420
#self.bimtools_menu = list(self.bimtools)
421
#if "Arch_RebarTools" in self.bimtools_menu:
422
# self.bimtools_menu.remove("Arch_RebarTools")
423
self.appendMenu(t1, self.draftingtools)
424
self.appendMenu(t2, self.bimtools)
426
# self.appendMenu([t2, t3], self.rebar)
427
self.appendMenu(t4, self.annotationtools)
428
self.appendMenu(t5, self.snapmenu)
429
self.appendMenu(t6, self.modify)
430
self.appendMenu(t7, self.manage)
432
# self.appendMenu(t8, ifctools)
434
self.appendMenu(t9, flamingo)
436
self.appendMenu(t10, fasteners)
437
self.appendMenu(t11, self.utils + ifctools)
438
self.appendMenu([t11, t12], nudge)
440
def loadPreferences(self):
442
"""Set up preferences pages"""
444
def QT_TRANSLATE_NOOP(context, text):
447
t1 = QT_TRANSLATE_NOOP("QObject", "BIM")
448
t2 = QT_TRANSLATE_NOOP("QObject", "Draft")
449
FreeCADGui.addPreferencePage(":/ui/preferences-arch.ui", t1)
450
FreeCADGui.addPreferencePage(":/ui/preferences-archdefaults.ui", t1)
451
FreeCADGui.addPreferencePage(":/ui/preferencesNativeIFC.ui", t1)
452
if hasattr(FreeCADGui, "draftToolBar"):
453
if hasattr(FreeCADGui.draftToolBar, "loadedPreferences"):
455
from draftutils import params
456
params._param_observer_start()
457
FreeCADGui.addPreferencePage(":/ui/preferences-draft.ui", t2)
458
FreeCADGui.addPreferencePage(":/ui/preferences-draftinterface.ui", t2)
459
FreeCADGui.addPreferencePage(":/ui/preferences-draftsnap.ui", t2)
460
FreeCADGui.addPreferencePage(":/ui/preferences-draftvisual.ui", t2)
461
FreeCADGui.addPreferencePage(":/ui/preferences-drafttexts.ui", t2)
462
FreeCADGui.draftToolBar.loadedPreferences = True
464
def setupMultipleObjectSelection(self):
468
if hasattr(FreeCADGui, "addDocumentObserver") and not hasattr(
469
self, "BimSelectObserver"
471
self.BimSelectObserver = BimSelect.Setup()
472
FreeCADGui.addDocumentObserver(self.BimSelectObserver)
477
from DraftGui import todo
479
from nativeifc import ifc_observer
480
from draftutils import grid_observer
482
PARAMS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/BIM")
484
if hasattr(FreeCADGui, "draftToolBar"):
485
FreeCADGui.draftToolBar.Activated()
486
if hasattr(FreeCADGui, "Snapper"):
487
FreeCADGui.Snapper.show()
488
WorkingPlane._view_observer_start()
489
grid_observer._view_observer_setup()
491
if PARAMS.GetBool("FirstTime", True) and (not hasattr(FreeCAD, "TestEnvironment")):
492
todo.delay(FreeCADGui.runCommand, "BIM_Welcome")
493
todo.delay(BimStatus.setStatusIcons, True)
494
FreeCADGui.Control.clearTaskWatcher()
497
def __init__(self, cmds, name, invert=False):
502
def shouldShow(self):
504
return (FreeCAD.ActiveDocument != None) and (
505
FreeCADGui.Selection.getSelection() != []
508
return (FreeCAD.ActiveDocument != None) and (
509
not FreeCADGui.Selection.getSelection()
512
FreeCADGui.Control.addTaskWatcher(
514
BimWatcher(self.draftingtools + self.annotationtools, "2D geometry"),
515
BimWatcher(self.bimtools, "3D/BIM geometry"),
516
BimWatcher(self.modify, "Modify", invert=True),
520
# restore views widget if needed
521
if PARAMS.GetBool("RestoreBimViews", True):
522
from bimcommands import BimViews
524
w = BimViews.findWidget()
526
FreeCADGui.runCommand("BIM_Views")
529
w.toggleViewAction().setVisible(True)
531
self.setupMultipleObjectSelection()
533
# add NativeIFC document observer
534
ifc_observer.add_observer()
536
# adding a Help menu manipulator
537
# https://github.com/FreeCAD/FreeCAD/pull/10933
538
class BIM_WBManipulator:
539
def modifyMenuBar(self):
541
{"insert": "BIM_Examples", "menuItem": "Std_ReportBug", "after": ""},
542
{"insert": "BIM_Tutorial", "menuItem": "Std_ReportBug", "after": ""},
543
{"insert": "BIM_Help", "menuItem": "Std_ReportBug", "after": ""},
544
{"insert": "BIM_Welcome", "menuItem": "Std_ReportBug", "after": ""},
546
if not hasattr(Gui, "BIM_WBManipulator"):
547
Gui.BIM_WBManipulator = BIM_WBManipulator()
548
Gui.addWorkbenchManipulator(Gui.BIM_WBManipulator)
550
Log("BIM workbench activated\n")
553
def Deactivated(self):
555
from DraftGui import todo
557
from bimcommands import BimViews
559
from nativeifc import ifc_observer
560
from draftutils import grid_observer
562
PARAMS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/BIM")
564
if hasattr(self, "BimSelectObserver"):
565
FreeCADGui.removeDocumentObserver(self.BimSelectObserver)
566
del self.BimSelectObserver
568
if hasattr(FreeCADGui, "draftToolBar"):
569
FreeCADGui.draftToolBar.Deactivated()
570
if hasattr(FreeCADGui, "Snapper"):
571
FreeCADGui.Snapper.hide()
572
WorkingPlane._view_observer_stop()
573
grid_observer._view_observer_setup()
575
# print("Deactivating status icon")
576
todo.delay(BimStatus.setStatusIcons, False)
577
FreeCADGui.Control.clearTaskWatcher()
579
# store views widget state and vertical size
580
w = BimViews.findWidget()
582
PARAMS.SetBool("RestoreBimViews", w.isVisible())
583
PARAMS.SetInt("BimViewsSize", w.height())
585
w.toggleViewAction().setVisible(False)
587
# add NativeIFC document observer
588
ifc_observer.remove_observer()
592
from nativeifc import ifc_status
593
ifc_status.toggle_lock(False)
598
if hasattr(Gui, "BIM_WBManipulator"):
599
Gui.removeWorkbenchManipulator(Gui.BIM_WBManipulator)
600
del Gui.BIM_WBManipulator
601
Gui.activeWorkbench().reloadActive()
603
Log("BIM workbench deactivated\n")
606
def ContextMenu(self, recipient):
609
translate = FreeCAD.Qt.translate
611
if recipient == "Tree":
614
for o in FreeCADGui.Selection.getSelection():
615
if o.isDerivedFrom("App::DocumentObjectGroup") or o.hasExtension(
616
"App::GroupExtension"
622
for o in FreeCADGui.Selection.getSelection():
623
for parent in o.InList:
624
if parent.isDerivedFrom(
625
"App::DocumentObjectGroup"
626
) or parent.hasExtension("App::GroupExtension"):
627
if o in parent.Group:
633
self.appendContextMenu("", ["Draft_SelectGroup"])
635
self.appendContextMenu("", ["BIM_Ungroup"])
636
if (len(FreeCADGui.Selection.getSelection()) == 1) and (
637
FreeCADGui.Selection.getSelection()[0].Name == "Trash"
639
self.appendContextMenu("", ["BIM_EmptyTrash"])
640
elif recipient == "View":
641
self.appendContextMenu(translate("BIM", "Snapping"), self.snapmenu)
642
if FreeCADGui.Selection.getSelection():
643
if FreeCADGui.Selection.getSelection()[0].Name != "Trash":
644
self.appendContextMenu("", ["BIM_Trash"])
645
self.appendContextMenu("", ["Draft_AddConstruction", "Draft_AddToGroup"])
647
for obj in FreeCADGui.Selection.getSelection():
648
if hasattr(obj, "CloneOf") and obj.CloneOf:
654
self.appendContextMenu("", ["BIM_ResetCloneColors"])
655
if len(FreeCADGui.Selection.getSelection()) == 1:
656
obj = FreeCADGui.Selection.getSelection()[0]
657
if hasattr(obj, "Group"):
658
if obj.getTypeIdOfProperty("Group") == "App::PropertyLinkList":
659
self.appendContextMenu("", ["BIM_Reorder"])
660
if obj.isDerivedFrom("TechDraw::DrawView"):
661
self.appendContextMenu("", ["BIM_MoveView"])
663
def GetClassName(self):
664
return "Gui::PythonWorkbench"
667
FreeCADGui.addWorkbench(BIMWorkbench)
669
# Preference pages for importing and exporting various file formats
670
# are independent of the loading of the workbench and can be loaded at startup
672
def QT_TRANSLATE_NOOP(context, text):
674
t = QT_TRANSLATE_NOOP("QObject", "Import-Export")
675
FreeCADGui.addPreferencePage(":/ui/preferences-ifc.ui", t)
676
FreeCADGui.addPreferencePage(":/ui/preferences-ifc-export.ui", t)
677
FreeCADGui.addPreferencePage(":/ui/preferences-dae.ui", t)
680
FreeCAD.__unit_test__ += ["TestArch"]
681
# The NativeIFC tests require internet connection and file download
682
# FreeCAD.__unit_test__ += ["nativeifc.ifc_selftest"]