# SPDX-License-Identifier: LGPL-2.1-or-later

# ***************************************************************************
# *                                                                         *
# *   Copyright (c) 2018 Yorik van Havre <yorik@uncreated.net>              *
# *                                                                         *
# *   This file is part of FreeCAD.                                         *
# *                                                                         *
# *   FreeCAD is free software: you can redistribute it and/or modify it    *
# *   under the terms of the GNU Lesser General Public License as           *
# *   published by the Free Software Foundation, either version 2.1 of the  *
# *   License, or (at your option) any later version.                       *
# *                                                                         *
# *   FreeCAD 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      *
# *   Lesser General Public License for more details.                       *
# *                                                                         *
# *   You should have received a copy of the GNU Lesser General Public      *
# *   License along with FreeCAD. If not, see                               *
# *   <https://www.gnu.org/licenses/>.                                      *
# *                                                                         *
# ***************************************************************************

"""The BIM Classification command"""

import os

import FreeCAD
import FreeCADGui

QT_TRANSLATE_NOOP = FreeCAD.Qt.QT_TRANSLATE_NOOP
translate = FreeCAD.Qt.translate

PARAMS = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/BIM")


class BIM_Classification:

    def GetResources(self):
        return {
            "Pixmap": "BIM_Classification",
            "MenuText": QT_TRANSLATE_NOOP("BIM_Classification", "Manage Classification"),
            "ToolTip": QT_TRANSLATE_NOOP(
                "BIM_Classification",
                "Manages classification systems and apply classification to objects",
            ),
        }

    def IsActive(self):
        v = hasattr(FreeCADGui.getMainWindow().getActiveWindow(), "getSceneGraph")
        return v

    def Activated(self):

        # only raise the dialog if it is already open
        if getattr(self, "form", None):
            self.form.raise_()
            return

        import Draft
        from PySide import QtCore, QtGui
        from bimcommands import BimMaterial

        # init checks
        if not hasattr(self, "Classes"):
            self.Classes = {}
        self.isEditing = None
        current = None

        # load the form and set the tree model up
        self.form = FreeCADGui.PySideUic.loadUi(":/ui/dialogClassification.ui")
        self.form.setWindowIcon(QtGui.QIcon(":/icons/BIM_Classification.svg"))
        self.form.groupMode.setItemIcon(
            0, QtGui.QIcon(":/icons/Arch_SectionPlane_Tree.svg")
        )  # Alphabetical
        self.form.groupMode.setItemIcon(1, QtGui.QIcon(":/icons/IFC.svg"))  # Type
        self.form.groupMode.setItemIcon(2, QtGui.QIcon(":/icons/Arch_Material.svg"))  # Material
        self.form.groupMode.setItemIcon(3, QtGui.QIcon(":/icons/Document.svg"))  # Model structure

        # restore saved values
        self.form.onlyVisible.setChecked(PARAMS.GetInt("BimClassificationVisibleState", 0))
        self.form.checkPrefix.setChecked(PARAMS.GetInt("BimClassificationSystemNamePrefix", 1))
        w = PARAMS.GetInt("BimClassificationDialogWidth", 629)
        h = PARAMS.GetInt("BimClassificationDialogHeight", 516)
        self.form.resize(w, h)

        # add modified search box from bimmaterial
        searchBox = BimMaterial.MatLineEdit(self.form)
        searchBox.setPlaceholderText(translate("BIM", "Search..."))
        searchBox.setToolTip(translate("BIM", "Searches classes"))
        self.form.search = searchBox
        self.form.horizontalLayout_2.addWidget(searchBox)

        # set help line
        self.form.labelDownload.setText(
            self.form.labelDownload.text().replace(
                "%s", os.path.join(FreeCAD.getUserAppDataDir(), "BIM", "Classification")
            )
        )

        # hide materials list if we are editing a particular object
        if len(FreeCADGui.Selection.getSelection()) == 1:
            self.isEditing = FreeCADGui.Selection.getSelection()[0]
            pl = self.isEditing.PropertiesList
            if ("StandardCode" in pl) or ("IfcClass" in pl):
                self.form.groupMaterials.hide()
                self.form.buttonApply.hide()
                self.form.buttonRename.hide()
                self.form.setWindowTitle(translate("BIM", "Editing") + " " + self.isEditing.Label)
                if "IfcClass" in pl:
                    # load existing class if needed
                    from nativeifc import ifc_classification

                    ifc_classification.show_classification(self.isEditing)
                if "StandardCode" in pl:
                    current = self.isEditing.StandardCode
                elif "Classification" in self.isEditing.PropertiesList:
                    current = self.isEditing.Classification

        # fill materials list
        self.objectslist = {}
        self.matlist = {}
        self.labellist = {}
        for obj in FreeCAD.ActiveDocument.Objects:
            if "StandardCode" in obj.PropertiesList:
                if Draft.getType(obj) in ["Material", "MultiMaterial"]:
                    self.matlist[obj.Name] = obj.StandardCode
                else:
                    self.objectslist[obj.Name] = obj.StandardCode
                self.labellist[obj.Name] = obj.Label
            elif "Classification" in obj.PropertiesList:
                self.objectslist[obj.Name] = obj.Classification
                self.labellist[obj.Name] = obj.Label

        # fill objects list
        if not self.isEditing:
            self.updateObjects()

        # fill available classifications
        p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").GetString(
            "DefaultClassificationSystem", ""
        )
        presetdir = os.path.join(FreeCAD.getUserAppDataDir(), "BIM", "Classification")
        if os.path.isdir(presetdir):
            presets = []
            for f in os.listdir(presetdir):
                if f.lower().endswith(".xml") or f.lower().endswith(".ifc"):
                    n = os.path.splitext(f)[0]
                    if not n in presets:
                        presets.append(n)
                        self.form.comboSystem.addItem(n)
                        if n == p:
                            self.form.comboSystem.setCurrentIndex(self.form.comboSystem.count() - 1)

        # connect signals
        self.form.comboSystem.currentIndexChanged.connect(self.updateClasses)
        self.form.buttonApply.clicked.connect(self.apply)
        self.form.buttonRename.clicked.connect(self.rename)
        self.form.search.textEdited.connect(self.updateClasses)
        self.form.buttonBox.accepted.connect(self.accept)
        self.form.rejected.connect(self.reject)  # also triggered by self.form.buttonBox.rejected
        self.form.groupMode.currentIndexChanged.connect(self.updateObjects)
        self.form.treeClass.itemDoubleClicked.connect(self.apply)
        self.form.search.up.connect(self.onUpArrow)
        self.form.search.down.connect(self.onDownArrow)
        if hasattr(self.form.onlyVisible, "checkStateChanged"):  # Qt version >= 6.7.0
            self.form.onlyVisible.checkStateChanged.connect(self.onVisible)
            self.form.checkPrefix.checkStateChanged.connect(self.onPrefix)
        else:  # Qt version < 6.7.0
            self.form.onlyVisible.stateChanged.connect(self.onVisible)
            self.form.checkPrefix.stateChanged.connect(self.onPrefix)
        # center the dialog over FreeCAD window
        mw = FreeCADGui.getMainWindow()
        self.form.move(
            mw.frameGeometry().topLeft() + mw.rect().center() - self.form.rect().center()
        )

        self.updateClasses()

        # select current classification
        if current:
            system, classification = current.split(" ", 1)
            print("searching for", classification)
            if system in self.Classes:
                self.form.comboSystem.setCurrentText(system)
                res = self.form.treeClass.findItems(
                    classification, QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive, 0
                )
                if res:
                    self.form.treeClass.setCurrentItem(res[0])

        self.form.show()

        self.form.search.setFocus()

    def updateObjects(self, idx=None):
        # store current state of tree into self.objectslist before redrawing

        for row in range(self.form.treeObjects.topLevelItemCount()):
            child = self.form.treeObjects.topLevelItem(row)
            if child.toolTip(0):
                if child.toolTip(0) in self.objectslist:
                    self.objectslist[child.toolTip(0)] = child.text(1)
                elif child.toolTip(0) in self.matlist:
                    self.matlist[child.toolTip(0)] = child.text(1)
                self.labellist[child.toolTip(0)] = child.text(0)
            for childrow in range(child.childCount()):
                grandchild = child.child(childrow)
                if grandchild.toolTip(0):
                    if grandchild.toolTip(0) in self.objectslist:
                        self.objectslist[grandchild.toolTip(0)] = grandchild.text(1)
                    elif grandchild.toolTip(0) in self.matlist:
                        self.matlist[grandchild.toolTip(0)] = grandchild.text(1)
                    self.labellist[grandchild.toolTip(0)] = grandchild.text(0)

        self.form.treeObjects.clear()

        if self.form.groupMode.currentIndex() == 1:
            # group by type
            self.updateByType()
        elif self.form.groupMode.currentIndex() == 2:
            # group by material
            self.updateByMaterial()
        elif self.form.groupMode.currentIndex() == 3:
            # group by model structure
            self.updateByTree()
        else:
            # group alphabetically
            self.updateDefault()

        # resize columns - no resizeSection in pyside2
        # self.form.treeObjects.header().resizeSection(0,int(self.form.treeObjects.width()/2))
        # self.form.treeObjects.header().resizeSection(1,int(self.form.treeObjects.width()/2))

    def updateByType(self):
        from PySide import QtCore, QtGui
        import Draft

        groups = {}
        for name in self.objectslist.keys():
            obj = FreeCAD.ActiveDocument.getObject(name)
            if obj and hasattr(obj, "IfcType"):
                groups.setdefault(obj.IfcType, []).append(name)
            elif obj and hasattr(obj, "IfcRole"):
                groups.setdefault(obj.IfcRole, []).append(name)
            else:
                groups.setdefault("Undefined", []).append(name)
        groups["Materials"] = self.matlist.keys()
        d = self.objectslist.copy()
        d.update(self.matlist)

        for group in groups.keys():
            mit = QtGui.QTreeWidgetItem([group, ""])
            self.form.treeObjects.addTopLevelItem(mit)
            for name in groups[group]:
                obj = FreeCAD.ActiveDocument.getObject(name)
                if obj:
                    if (
                        (not self.form.onlyVisible.isChecked())
                        or obj.ViewObject.isVisible()
                        or (Draft.getType(obj) in ["Material", "MultiMaterial"])
                    ):
                        it = QtGui.QTreeWidgetItem([self.labellist[name], d[name]])
                        it.setIcon(0, self.getIcon(obj))
                        it.setToolTip(0, name)
                        mit.addChild(it)
            mit.sortChildren(0, QtCore.Qt.AscendingOrder)
        self.form.treeObjects.expandAll()
        # self.spanTopLevels()

    def updateByMaterial(self):
        from PySide import QtCore, QtGui

        groups = {}
        claimed = []
        for name in self.matlist.keys():
            mat = FreeCAD.ActiveDocument.getObject(name)
            if mat:
                children = [par.Name for par in mat.InList if par.Name in self.objectslist.keys()]
                groups[name] = children
                claimed.extend(children)
        groups["Undefined"] = [o for o in self.objectslist.keys() if not o in claimed]

        for group in groups.keys():
            matobj = FreeCAD.ActiveDocument.getObject(group)
            if matobj:
                mit = QtGui.QTreeWidgetItem([self.labellist[group], self.matlist[group]])
                mit.setIcon(0, self.getIcon(matobj))
                mit.setToolTip(0, group)
            else:
                mit = QtGui.QTreeWidgetItem(["Undefined", ""])
            self.form.treeObjects.addTopLevelItem(mit)
            for name in groups[group]:
                obj = FreeCAD.ActiveDocument.getObject(name)
                if obj:
                    if (not self.form.onlyVisible.isChecked()) or obj.ViewObject.isVisible():
                        it = QtGui.QTreeWidgetItem([self.labellist[name], self.objectslist[name]])
                        it.setIcon(0, self.getIcon(obj))
                        it.setToolTip(0, name)
                        mit.addChild(it)
            mit.sortChildren(0, QtCore.Qt.AscendingOrder)
        self.form.treeObjects.expandAll()
        # self.spanTopLevels()

    def updateByTree(self):
        from PySide import QtGui

        # order by hierarchy
        def istop(obj):
            for parent in obj.InList:
                if parent.Name in self.objectslist.keys():
                    return False
            return True

        rel = []
        deps = []
        for name in self.objectslist.keys():
            obj = FreeCAD.ActiveDocument.getObject(name)
            if obj:
                if istop(obj):
                    rel.append(obj)
                else:
                    deps.append(obj)
        pa = 1
        while deps:
            for obj in rel:
                for child in obj.OutList:
                    if child in deps:
                        rel.append(child)
                        deps.remove(child)
            pa += 1
            if pa == 10:  # max 10 hierarchy levels, okay? Let's keep civilised
                rel.extend(deps)
                break

        done = {}
        # materials first
        mit = QtGui.QTreeWidgetItem(["Materials", ""])
        self.form.treeObjects.addTopLevelItem(mit)
        for name, code in self.matlist.items():
            obj = FreeCAD.ActiveDocument.getObject(name)
            if obj:
                it = QtGui.QTreeWidgetItem([self.labellist[name], code])
                it.setIcon(0, self.getIcon(obj))
                it.setToolTip(0, name)
                mit.addChild(it)
        # objects next
        for obj in rel:
            code = self.objectslist[obj.Name]
            if (not self.form.onlyVisible.isChecked()) or obj.ViewObject.isVisible():
                it = QtGui.QTreeWidgetItem([self.labellist[obj.Name], code])
                it.setIcon(0, self.getIcon(obj))
                it.setToolTip(0, name)
                ok = False
                for par in obj.InListRecursive:
                    if par.Name in done:
                        if (not hasattr(par, "Hosts")) or (obj not in par.Hosts):
                            done[par.Name].addChild(it)
                            done[obj.Name] = it
                            ok = True
                            break
                if not ok:
                    self.form.treeObjects.addTopLevelItem(it)
                    done[obj.Name] = it
        self.form.treeObjects.expandAll()

    def updateDefault(self):
        from PySide import QtGui
        import Draft

        d = self.objectslist.copy()
        d.update(self.matlist)
        for name, code in d.items():
            obj = FreeCAD.ActiveDocument.getObject(name)
            if obj:
                if (
                    (not self.form.onlyVisible.isChecked())
                    or obj.ViewObject.isVisible()
                    or (Draft.getType(obj) in ["Material", "MultiMaterial"])
                ):
                    it = QtGui.QTreeWidgetItem([self.labellist[name], code])
                    it.setIcon(0, self.getIcon(obj))
                    it.setToolTip(0, name)
                    self.form.treeObjects.addTopLevelItem(it)
                    if obj in FreeCADGui.Selection.getSelection():
                        self.form.treeObjects.setCurrentItem(it)

    def updateClasses(self, search=""):
        from PySide import QtGui

        self.form.treeClass.clear()

        # save as default
        FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch").SetString(
            "DefaultClassificationSystem", self.form.comboSystem.currentText()
        )

        if isinstance(search, int):
            search = ""
        if self.form.search.text():
            search = self.form.search.text()
        if search:
            search = search.lower()

        system = self.form.comboSystem.currentText()
        if not system:
            return

        if not system in self.Classes:
            self.Classes[system] = self.build(system)
        if not self.Classes[system]:
            return

        for c in self.Classes[system]:
            it = None
            first = True
            if not c[1]:
                c[1] = ""
            if search:
                if (search in c[0].lower()) or (search in c[1].lower()):
                    it = QtGui.QTreeWidgetItem([c[0] + " " + c[1]])
                    it.setToolTip(0, c[1])
                    self.form.treeClass.addTopLevelItem(it)
            else:
                it = QtGui.QTreeWidgetItem([c[0] + " " + c[1]])
                it.setToolTip(0, c[1])
                self.form.treeClass.addTopLevelItem(it)
            if c[2]:
                self.addChildren(c[2], it, search)
            if it and first:
                # select first entry
                self.form.treeClass.setCurrentItem(it)
                first = False

    def addChildren(self, children, parent, search=""):
        from PySide import QtGui

        if children:
            for c in children:
                it = None
                if not c[1]:
                    c[1] = ""
                if search:
                    if (search in c[0].lower()) or (search in c[1].lower()):
                        it = QtGui.QTreeWidgetItem([c[0] + " " + c[1]])
                        it.setToolTip(0, c[1])
                        self.form.treeClass.addTopLevelItem(it)
                else:
                    it = QtGui.QTreeWidgetItem([c[0] + " " + c[1]])
                    it.setToolTip(0, c[1])
                    if parent:
                        parent.addChild(it)
                if c[2]:
                    self.addChildren(c[2], it, search)

    def build(self, system):
        # try to load the IFC first
        preset = os.path.join(FreeCAD.getUserAppDataDir(), "BIM", "Classification", system + ".ifc")
        if os.path.exists(preset):
            return self.build_ifc(system)
        else:
            preset = os.path.join(
                FreeCAD.getUserAppDataDir(), "BIM", "Classification", system + ".xml"
            )
            if os.path.exists(preset):
                return self.build_xml(system)
            else:
                FreeCAD.Console.PrintError("Unable to find classification file:" + system + "\n")
                return []

    def build_ifc(self, system):
        # builds from ifc instead of xml

        class Item:
            def __init__(self, parent=None):
                self.parent = parent
                self.ID = None
                self.Name = None
                self.children = []

        preset = os.path.join(FreeCAD.getUserAppDataDir(), "BIM", "Classification", system + ".ifc")
        if not os.path.exists(preset):
            return None
        import ifcopenshell

        f = ifcopenshell.open(preset)
        classes = f.by_type("IfcClassificationReference")
        rootclass = f.by_type("IfcClassification")
        if rootclass:
            rootclass = rootclass[0]
        else:
            return None
        root = Item()
        classdict = {rootclass.id(): root}
        for cl in classes:
            currentItem = Item()
            currentItem.Name = cl.Name
            currentItem.Description = cl.Description
            currentItem.ID = cl.Identification
            if cl.ReferencedSource:
                if cl.ReferencedSource.id() in classdict:
                    currentItem.parent = classdict[cl.ReferencedSource.id()]
                    classdict[cl.ReferencedSource.id()].children.append(currentItem)
            classdict[cl.id()] = currentItem
        return [self.listize(c) for c in root.children]

    def build_xml(self, system):
        class Item:
            def __init__(self, parent=None):
                self.parent = parent
                self.ID = None
                self.Name = None
                self.children = []

        preset = os.path.join(FreeCAD.getUserAppDataDir(), "BIM", "Classification", system + ".xml")
        if not os.path.exists(preset):
            return None
        import codecs
        import re

        d = Item()
        with codecs.open(preset, "r", "utf-8") as f:
            currentItem = d
            for l in f:
                if "<Item>" in l:
                    currentItem = Item(currentItem)
                    currentItem.parent.children.append(currentItem)
                if "</Item>" in l:
                    currentItem = currentItem.parent
                elif currentItem and re.findall(r"<ID>(.*?)</ID>", l):
                    currentItem.ID = re.findall(r"<ID>(.*?)</ID>", l)[0]
                elif currentItem and re.findall(r"<Name>(.*?)</Name>", l):
                    currentItem.Name = re.findall(r"<Name>(.*?)</Name>", l)[0]
                elif (
                    currentItem
                    and re.findall(r"<Description>(.*?)</Description>", l)
                    and not currentItem.Name
                ):
                    currentItem.Name = re.findall("<Description>(.*?)</Description>", l)[0]
        return [self.listize(c) for c in d.children]

    def listize(self, item):
        return [item.ID, item.Name, [self.listize(it) for it in item.children]]

    def apply(self, item=None, col=None):
        if self.form.treeObjects.selectedItems() and len(self.form.treeClass.selectedItems()) == 1:
            c = self.form.treeClass.selectedItems()[0].text(0)
            if self.form.checkPrefix.isChecked():
                c = self.form.comboSystem.currentText() + " " + c
            for m in self.form.treeObjects.selectedItems():
                if m.toolTip(0):
                    m.setText(1, c)

    def rename(self):
        if self.form.treeObjects.selectedItems() and len(self.form.treeClass.selectedItems()) == 1:
            c = self.form.treeClass.selectedItems()[0].toolTip(0)
            for m in self.form.treeObjects.selectedItems():
                if m.toolTip(0):
                    m.setText(0, c)

    def accept(self):
        if not self.isEditing:
            changed = False
            for row in range(self.form.treeObjects.topLevelItemCount()):
                child = self.form.treeObjects.topLevelItem(row)
                items = [child]
                items.extend([child.child(childrow) for childrow in range(child.childCount())])
                for item in items:
                    code = item.text(1)
                    label = item.text(0)
                    if item.toolTip(0):
                        obj = FreeCAD.ActiveDocument.getObject(item.toolTip(0))
                        if obj:
                            if hasattr(obj, "StandardCode"):
                                if code != obj.StandardCode:
                                    if not changed:
                                        FreeCAD.ActiveDocument.openTransaction(
                                            "Change standard codes"
                                        )
                                        changed = True
                                    obj.StandardCode = code
                            elif hasattr(obj, "IfcClass"):
                                if not "Classification" in obj.PropertiesList:
                                    obj.addProperty(
                                        "App::PropertyString", "Classification", "IFC", locked=True
                                    )
                                if code != obj.Classification:
                                    if not changed:
                                        FreeCAD.ActiveDocument.openTransaction(
                                            "Change standard codes"
                                        )
                                        changed = True
                                    obj.Classification = code
                            if label != obj.Label:
                                if not changed:
                                    FreeCAD.ActiveDocument.openTransaction("Change standard codes")
                                    changed = True
                                obj.Label = label
            if changed:
                FreeCAD.ActiveDocument.commitTransaction()
                FreeCAD.ActiveDocument.recompute()
        else:
            # Close the form if user has pressed Enter and did not
            # select anything
            if len(self.form.treeClass.selectedItems()) < 1:
                return self.reject()

            code = self.form.treeClass.selectedItems()[0].text(0)
            pl = self.isEditing.PropertiesList
            if ("StandardCode" in pl) or ("IfcClass" in pl):
                FreeCAD.ActiveDocument.openTransaction("Change standard codes")
                if self.form.checkPrefix.isChecked():
                    code = self.form.comboSystem.currentText() + " " + code
                if "StandardCode" in pl:
                    self.isEditing.StandardCode = code
                else:
                    if not "Classification" in self.isEditing.PropertiesList:
                        self.isEditing.addProperty(
                            "App::PropertyString", "Classification", "IFC", locked=True
                        )
                    self.isEditing.Classification = code
                if hasattr(self.isEditing.ViewObject, "Proxy") and hasattr(
                    self.isEditing.ViewObject.Proxy, "setTaskValue"
                ):
                    self.isEditing.ViewObject.Proxy.setTaskValue("FieldCode", code)
                FreeCAD.ActiveDocument.commitTransaction()
                FreeCAD.ActiveDocument.recompute()
        p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/BIM")
        p.SetInt("BimClassificationDialogWidth", self.form.width())
        p.SetInt("BimClassificationDialogHeight", self.form.height())
        return self.reject()

    def reject(self):
        self.form.hide()
        del self.form
        return True

    def onUpArrow(self):
        if self.form:
            i = self.form.treeClass.currentItem()
            if self.form.treeClass.itemAbove(i):
                self.form.treeClass.setCurrentItem(self.form.treeClass.itemAbove(i))

    def onDownArrow(self):
        if self.form:
            i = self.form.treeClass.currentItem()
            if self.form.treeClass.itemBelow(i):
                self.form.treeClass.setCurrentItem(self.form.treeClass.itemBelow(i))

    def onVisible(self, index):
        PARAMS.SetInt("BimClassificationVisibleState", getattr(index, "value", index))
        self.updateObjects()

    def onPrefix(self, index):
        PARAMS.SetInt("BimClassificationSystemNamePrefix", getattr(index, "value", index))

    def getIcon(self, obj):
        """returns a QIcon for an object"""

        from PySide import QtGui
        import Arch_rc

        if hasattr(obj.ViewObject, "Icon"):
            return obj.ViewObject.Icon
        elif hasattr(obj.ViewObject, "Proxy") and hasattr(obj.ViewObject.Proxy, "getIcon"):
            icon = obj.ViewObject.Proxy.getIcon()
            if icon.startswith("/*"):
                return QtGui.QIcon(QtGui.QPixmap(icon))
            else:
                return QtGui.QIcon(icon)
        else:
            return QtGui.QIcon(":/icons/Arch_Component.svg")


FreeCADGui.addCommand("BIM_Classification", BIM_Classification())
