Update BBIM tester module UI to be compatible with new IfcTester upgrades

This commit is contained in:
Dion Moult
2023-09-01 16:47:55 +10:00
parent 283961fc72
commit 2ea3704d96
5 changed files with 89 additions and 52 deletions
@@ -0,0 +1,45 @@
# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2023 Dion Moult <dion@thinkmoult.com>
#
# This file is part of BlenderBIM Add-on.
#
# BlenderBIM Add-on is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# BlenderBIM Add-on 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 General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
import bpy
import blenderbim.tool as tool
def refresh():
TesterData.is_loaded = False
class TesterData:
data = {}
is_loaded = False
@classmethod
def load(cls):
cls.data = {"has_report": cls.has_report(), "specification": cls.specification()}
cls.is_loaded = True
@classmethod
def has_report(cls):
return tool.Tester.report
@classmethod
def specification(cls):
if not tool.Tester.report:
return {}
props = bpy.context.scene.IfcTesterProperties
return tool.Tester.report[props.active_specification_index]
@@ -21,15 +21,16 @@ import bpy
import time
import tempfile
import webbrowser
import json
import ifctester
import ifctester.ids
import ifctester.reporter
import ifcopenshell
import blenderbim.tool as tool
import blenderbim.bim.handler
from blenderbim.bim.module.tester.data import TesterData
class ExecuteIfcTester(bpy.types.Operator):
class ExecuteIfcTester(bpy.types.Operator, tool.Ifc.Operator):
bl_idname = "bim.execute_ifc_tester"
bl_label = "Execute IfcTester"
@@ -54,28 +55,27 @@ class ExecuteIfcTester(bpy.types.Operator):
print("Finished loading:", time.time() - start)
start = time.time()
specs.validate(ifc)
print("Finished validating:", time.time() - start)
start = time.time()
if props.generate_html_report:
engine = ifctester.reporter.Html(specs)
engine.report()
engine.report()
engine.to_file(output)
webbrowser.open("file://" + output)
report = None
report = ifctester.reporter.Json(specs).report()['specifications']
report = ifctester.reporter.Json(specs).report()["specifications"]
if report:
props.has_report = True
props.report = json.dumps(report)
tool.Tester.report = report
props.specifications.clear()
c=0
for spec in report:
new_spec = props.specifications.add()
new_spec.name = spec['name']
new_spec.status = spec['status']
new_spec.name = spec["name"]
new_spec.status = spec["status"]
blenderbim.bim.handler.refresh_ui_data()
return {"FINISHED"}
@@ -118,23 +118,24 @@ class SelectRequirement(bpy.types.Operator):
bl_label = "Select Specification"
bl_options = {"REGISTER", "UNDO"}
spec_index: bpy.props.IntProperty()
req_index: bpy.props.IntProperty()
req_index: bpy.props.IntProperty()
def execute(self, context):
props = context.scene.IfcTesterProperties
report = json.loads(props.report)
report = tool.Tester.report
props.old_index = self.spec_index
failed_entities = report[self.spec_index]['requirements'] [self.req_index]['failed_entities']
failed_entities = report[self.spec_index]["requirements"][self.req_index]["failed_entities"]
props.n_entities = len(failed_entities)
props.has_entities = True if props.n_entities > 0 else False
props.failed_entities.clear()
for e in failed_entities:
new_entity = props.failed_entities.add()
new_entity.element = e['element']
new_entity.reason = e['reason']
new_entity = props.failed_entities.add()
new_entity.element = e["element"]
new_entity.reason = e["reason"]
return {"FINISHED"}
class SelectEntity(bpy.types.Operator):
bl_idname = "bim.select_entity"
bl_label = "Select Entity"
@@ -142,13 +143,14 @@ class SelectEntity(bpy.types.Operator):
ifc_id: bpy.props.IntProperty()
def execute(self, context):
bpy.ops.object.select_all(action='DESELECT')
bpy.ops.object.select_all(action="DESELECT")
for obj in context.scene.objects:
if obj.BIMObjectProperties.ifc_definition_id == self.ifc_id:
obj.select_set(True)
bpy.context.view_layer.objects.active = obj
return {"FINISHED"}
class ExportBcf(bpy.types.Operator):
bl_idname = "bim.export_bcf"
bl_label = "Export BCF"
@@ -168,7 +170,6 @@ class ExportBcf(bpy.types.Operator):
bcf_reporter.report()
bcf_reporter.to_file(output)
print("Finished exporting!")
self.report({"INFO"}, 'Finished exporting!')
self.report({"INFO"}, "Finished exporting!")
return {"FINISHED"}
@@ -16,6 +16,7 @@
# You should have received a copy of the GNU General Public License
# along with BlenderBIM Add-on. If not, see <http://www.gnu.org/licenses/>.
from blenderbim.bim.module.tester.data import TesterData
from blenderbim.bim.prop import StrProperty
from bpy.types import PropertyGroup
from bpy.props import (
@@ -34,8 +35,8 @@ def purge():
pass
def get_failure_entities():
return
def update_active_specification_index(self, context):
TesterData.load()
class Specification(PropertyGroup):
@@ -53,13 +54,10 @@ class IfcTesterProperties(PropertyGroup):
ifc_file: StringProperty(default="", name="IFC File")
should_load_from_memory: BoolProperty(default=False, name="Load from Memory")
generate_html_report: BoolProperty(default=False, name="Generate HTML report")
active_specification_index: IntProperty(name="Active Specification Index")
active_requirement_index: IntProperty(name="Active Requirement Index")
active_specification_index: IntProperty(name="Active Specification Index", update=update_active_specification_index)
old_index: IntProperty(name="", default=0)
active_failed_entity_index: IntProperty(name="Active Failed Entity Index")
report: StringProperty(default="", name="JSON report")
specifications: CollectionProperty(name="Specifications", type=Specification)
failed_entities: CollectionProperty(name="FailedEntities", type=FailedEntities)
has_report: BoolProperty(default=False, name="")
has_entities: BoolProperty(default=False, name="")
n_entities: IntProperty(name="", default=0)
@@ -18,7 +18,7 @@
import blenderbim.tool as tool
from bpy.types import Panel, UIList
import json
from blenderbim.bim.module.tester.data import TesterData
class BIM_PT_tester(Panel):
@@ -31,6 +31,9 @@ class BIM_PT_tester(Panel):
bl_parent_id = "BIM_PT_tab_quality_control"
def draw(self, context):
if not TesterData.is_loaded:
TesterData.load()
self.layout.use_property_split = True
props = context.scene.IfcTesterProperties
@@ -53,7 +56,7 @@ class BIM_PT_tester(Panel):
row = self.layout.row()
row.operator("bim.execute_ifc_tester")
if props.has_report:
if TesterData.data["has_report"]:
self.layout.template_list(
"BIM_UL_tester_specifications",
"",
@@ -69,33 +72,26 @@ class BIM_PT_tester(Panel):
def draw_editable_ui(self, context):
props = context.scene.IfcTesterProperties
i = props.active_specification_index
dic_report = json.loads(props.report)
specification = TesterData.data["specification"]
total_successes = dic_report[i]["total_successes"]
total = dic_report[i]["total"]
percentage = dic_report[i]["percentage"]
n_requirements = len(dic_report[i]["requirements"])
n_requirements = len(specification["requirements"])
row = self.layout.row()
row.label(text=f"Passed: {total_successes}/{total} ({percentage}%)")
row.label(
text=f'Passed: {specification["total_checks_pass"]}/{specification["total_checks"]} ({specification["percent_checks_pass"]}%)'
)
row = self.layout.row()
row.label(text=f"Requirements ({n_requirements}):")
c = 0
box = self.layout.box()
for req in dic_report[i]["requirements"]:
for i, requirement in enumerate(specification["requirements"]):
row = box.row(align=True)
row.label(text=f" {c+1}. {req['description']}")
if req["status"]:
row.label(text="PASS", icon="CHECKMARK")
else:
row.label(text="FAIL", icon="CANCEL")
row.label(text=requirement["description"], icon="CHECKMARK" if requirement["status"] else "CANCEL")
if not requirement["status"]:
op = row.operator("bim.select_requirement", text="", icon="LONGDISPLAY")
op.spec_index = i
op.req_index = c
c += 1
op.spec_index = props.active_specification_index
op.req_index = i
if props.old_index == i and props.n_entities > 0:
if props.old_index == props.active_specification_index and props.n_entities > 0:
row = self.layout.row()
row.label(text=f"Failed entities [{props.n_entities}]:")
self.layout.template_list(
@@ -112,11 +108,7 @@ class BIM_UL_tester_specifications(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
if item:
row = layout.row(align=True)
row.label(text=item.name, icon="WORDWRAP_ON")
if item.status:
row.label(text="PASS")
else:
row.label(text="FAIL")
row.label(text=item.name, icon="CHECKMARK" if item.status else "CANCEL")
class BIM_UL_tester_failed_entities(UIList):
@@ -51,6 +51,7 @@ from blenderbim.tool.structural import Structural
from blenderbim.tool.style import Style
from blenderbim.tool.surveyor import Surveyor
from blenderbim.tool.system import System
from blenderbim.tool.tester import Tester
from blenderbim.tool.type import Type
from blenderbim.tool.unit import Unit
from blenderbim.tool.search import Search