Files
IfcOpenShell/src/blenderbim/blenderbim/bim/module/search/ui.py
T
2023-07-29 20:46:07 +10:00

388 lines
16 KiB
Python

# BlenderBIM Add-on - OpenBIM Blender Add-on
# Copyright (C) 2020, 2021 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
from bpy.types import Panel
from blenderbim.bim.module.search.data import SearchData, ColourByPropertyData, SelectSimilarData
class BIM_PT_search(Panel):
bl_label = "Search"
bl_idname = "BIM_PT_search"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_grouping_and_filtering"
def draw(self, context):
if not SearchData.is_loaded:
SearchData.load()
props = context.scene.BIMSearchProperties
row = self.layout.row(align=True)
row.label(text=f"{len(SearchData.data['saved_searches'])} Saved Searches")
if SearchData.data["saved_searches"]:
row.operator("bim.load_search", text="", icon="IMPORT")
row.operator("bim.save_search", text="", icon="EXPORT")
row = self.layout.row(align=True)
row.operator("bim.add_filter_group", text="Add Search Group", icon="ADD")
for i, filter_group in enumerate(props.filter_groups):
box = self.layout.box()
row = box.row(align=True)
row.prop(props, "facet", text="")
op = row.operator("bim.add_filter", text="Add Filter", icon="ADD")
op.type = props.facet
op.index = i
for j, ifc_filter in enumerate(filter_group.filters):
if ifc_filter.type == "entity":
row = box.row(align=True)
row.prop(ifc_filter, "value", text="", icon="FILE_3D")
elif ifc_filter.type == "attribute":
row = box.row(align=True)
row.prop(ifc_filter, "name", text="", icon="COPY_ID")
row.prop(ifc_filter, "value", text="")
elif ifc_filter.type == "type":
row = box.row(align=True)
row.prop(ifc_filter, "value", text="", icon="FILE_VOLUME")
elif ifc_filter.type == "material":
row = box.row(align=True)
row.prop(ifc_filter, "value", text="", icon="MATERIAL")
elif ifc_filter.type == "property":
row = box.row(align=True)
row.prop(ifc_filter, "pset", text="", icon="PROPERTIES")
row.prop(ifc_filter, "name", text="")
row.prop(ifc_filter, "value", text="")
elif ifc_filter.type == "classification":
row = box.row(align=True)
row.prop(ifc_filter, "value", text="", icon="OUTLINER")
elif ifc_filter.type == "location":
row = box.row(align=True)
row.prop(ifc_filter, "name", text="", icon="PACKAGE")
elif ifc_filter.type == "instance":
row = box.row(align=True)
row.prop(ifc_filter, "value", text="", icon="GRIP")
op = row.operator("bim.remove_filter", text="", icon="X")
op.group_index = i
op.index = j
row = box.row()
row.operator("bim.remove_filter_group", icon="X").index = i
if len(props.filter_groups):
row = self.layout.row(align=True)
row.operator("bim.search", text="Search", icon="VIEWZOOM")
return # Temporary for now whilst searching is being upgraded.
row = self.layout.row()
row.prop(props, "should_use_regex")
row = self.layout.row()
row.prop(props, "should_ignorecase")
row = self.layout.row(align=True)
row.operator("bim.reset_object_colours", icon="BRUSH_DATA")
row = self.layout.row(align=True)
row.prop(props, "global_id", text="", icon="TRACKER")
row.operator("bim.select_global_id", text="", icon="VIEWZOOM").global_id = props.global_id
row = self.layout.row(align=True)
row.prop(props, "ifc_class", text="", icon="OBJECT_DATA")
row.operator("bim.select_ifc_class", text="", icon="VIEWZOOM").ifc_class = props.ifc_class
row.operator("bim.colour_by_class", text="", icon="BRUSH_DATA")
row = self.layout.row(align=True)
row.prop(props, "search_attribute_name", text="", icon="PROPERTIES")
row.prop(props, "search_attribute_value", text="")
op = row.operator("bim.select_attribute", text="", icon="VIEWZOOM")
op.attribute_name = props.search_attribute_name
op.attribute_value = props.search_attribute_value
op = row.operator("bim.colour_by_attribute", text="", icon="BRUSH_DATA")
op.attribute_name = props.search_attribute_name
row = self.layout.row(align=True)
row.prop(props, "search_pset_name", text="", icon="COPY_ID")
row.prop(props, "search_prop_name", text="")
row.prop(props, "search_pset_value", text="")
op = row.operator("bim.select_pset", text="", icon="VIEWZOOM")
op.pset_name = props.search_pset_name
op.prop_name = props.search_prop_name
op.pset_value = props.search_pset_value
op = row.operator("bim.colour_by_pset", text="", icon="BRUSH_DATA")
op.pset_name = props.search_pset_name
op.prop_name = props.search_prop_name
row = self.layout.row(align=True)
row.operator("bim.activate_ifc_class_filter", icon="FILTER")
row.operator("bim.activate_ifc_building_storey_filter", icon="FILTER")
class BIM_PT_colour_by_property(Panel):
bl_label = "Colour By Property"
bl_idname = "BIM_PT_colour_by_property"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_options = {"DEFAULT_CLOSED"}
bl_parent_id = "BIM_PT_tab_grouping_and_filtering"
def draw(self, context):
if not ColourByPropertyData.is_loaded:
ColourByPropertyData.load()
props = context.scene.BIMSearchProperties
row = self.layout.row(align=True)
row.label(text=f"{len(ColourByPropertyData.data['saved_colourschemes'])} Saved Colourschemes")
if ColourByPropertyData.data["saved_colourschemes"]:
row.operator("bim.load_colourscheme", text="", icon="IMPORT")
row.operator("bim.save_colourscheme", text="", icon="EXPORT")
row = self.layout.row()
row.prop(props, "colourscheme_query", text="Query")
row = self.layout.row(align=True)
row.operator("bim.colour_by_property", icon="BRUSH_DATA")
row.operator("bim.reset_object_colours")
if len(props.colourscheme):
self.layout.template_list("BIM_UL_colourscheme", "", props, "colourscheme", props, "active_colourscheme_index")
class BIM_PT_select_similar(Panel):
bl_label = "Select Similar"
bl_idname = "BIM_PT_select_similar"
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_options = {"DEFAULT_CLOSED"}
bl_parent_id = "BIM_PT_tab_grouping_and_filtering"
def draw(self, context):
if not SelectSimilarData.is_loaded:
SelectSimilarData.load()
props = context.scene.BIMSearchProperties
if SelectSimilarData.data["element_key"]:
row = self.layout.row(align=True)
row.prop(props, "element_key", text="")
row.operator("bim.select_similar", text="", icon="RESTRICT_SELECT_OFF")
else:
row = self.layout.row()
row.label(text=f"No Active Element")
class BIM_UL_colourscheme(bpy.types.UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname):
props = context.scene.BIMWorkScheduleProperties
if not item:
return
row = layout.row(align=True)
row.label(text=item.name)
row.prop(item, "colour", text="")
class BIM_UL_ifc_class_filter(bpy.types.UIList):
use_filter_linked: bpy.props.BoolProperty(name="Included", default=True, options=set(), description="Filter")
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
split = layout
split.use_property_split = True
split.use_property_decorate = False
split.prop(
item, "is_selected", text="", emboss=False, icon="CHECKBOX_HLT" if item.is_selected else "CHECKBOX_DEHLT"
)
split.prop(item, "name", text="", emboss=False, slider=True)
split = split.column()
split.scale_x = 0.5
split.label(text=str(item.total))
class BIM_UL_ifc_building_storey_filter(bpy.types.UIList):
use_filter_linked: bpy.props.BoolProperty(name="Included", default=True, options=set(), description="Filter")
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
split = layout
split.use_property_split = True
split.use_property_decorate = False
split.prop(
item, "is_selected", text="", emboss=False, icon="CHECKBOX_HLT" if item.is_selected else "CHECKBOX_DEHLT"
)
split.prop(item, "name", text="", emboss=False, slider=True)
split = split.column()
split.scale_x = 0.5
split.label(text=str(item.total))
class BIM_PT_IFCSelector(Panel):
bl_label = "Selector"
bl_idname = "BIM_PT_ifc_selector"
bl_options = {"DEFAULT_CLOSED"}
bl_space_type = "PROPERTIES"
bl_region_type = "WINDOW"
bl_context = "scene"
bl_parent_id = "BIM_PT_tab_sandbox"
def draw(self, context):
layout = self.layout
layout.operator("bim.ifc_selector")
# this doesn't inherit from Panel since it's just a class to abstract away UI code from the IfcSelector Operator
class IfcSelectorUI:
@classmethod
def draw(self, context, layout):
ifc_selector = context.scene.IfcSelectorProperties
row = layout.row()
row.context_pointer_set(name="bim_prop_group", data=ifc_selector)
op = row.operator("bim.edit_blender_collection", text="Add selection group")
op.option = "add"
op.collection = "groups"
layout.separator()
self.draw_query_group_ui(self, ifc_selector, layout)
if len(ifc_selector.groups) != 0:
row = layout.row(align=True)
row.prop(ifc_selector, "selector_query_syntax", text="Query Syntax")
row.prop(ifc_selector, "manual_override", text="")
select = row.operator("bim.filter_model_elements", text="", icon="RESTRICT_SELECT_OFF")
select.option = "select"
isolate = row.operator("bim.filter_model_elements", text="", icon="ZOOM_SELECTED")
isolate.option = "isolate"
hide = row.operator("bim.filter_model_elements", text="", icon="HIDE_ON")
hide.option = "hide"
unhide = row.operator("bim.filter_model_elements", text="", icon="HIDE_OFF")
unhide.option = "unhide"
row = layout.row(align=True)
row.alignment = "CENTER"
row.operator("bim.save_selector_query", text="Save Query")
op = row.operator("bim.open_query_library", text="Load Query")
row.operator("bim.add_to_ifc_group", text="Add to IFC Group")
row = layout.row(align=True)
row.operator("bim.show_scene_elements", text="Show All Elements", icon="HIDE_OFF")
def draw_query_group_ui(self, ifc_selector, layout):
for index, group in enumerate(ifc_selector.groups):
row = layout.row()
row.alignment = "CENTER"
row.label(text="or") if index != 0 else None
box = layout.box()
row = box.row(align=True)
row.alignment = "CENTER"
row.label(text=f"Group #{str(index+1)}")
row.context_pointer_set(name="bim_prop_group", data=group)
op = row.operator("bim.edit_blender_collection", text="Add query", icon="PLUS")
op.option = "add"
op.collection = "queries"
row.context_pointer_set(name="bim_prop_group", data=ifc_selector)
op = row.operator("bim.edit_blender_collection", text="Remove selection group")
op.option = "remove"
op.collection = "groups"
op.index = index
self.draw_query_ui(self, group, box)
def draw_query_ui(self, group, box):
for index, query in enumerate(group.queries):
row = box.row()
row.alignment = "LEFT"
row.prop(query, "and_or", text="") if index != 0 else None
if query.and_or == "or":
row = box.row()
row.alignment = "LEFT"
row.prop(query, "selector", text="")
if query.selector in ["IFC Class", "IfcSpatialElement", "IfcElementType"]:
row.label(text="Equals")
row.prop_search(query, "active_option", query, "options", text="")
row.prop_search(query, "active_sub_option", query, "sub_options", text="") if len(
query.sub_options
) != 0 else None
self.draw_filter_ui(self, box, query)
elif query.selector in ["GlobalId", "Attribute"]:
row.prop(query, "negation", text="")
row.prop(query, "comparison", text="")
row.prop(query, "value", text="")
row.context_pointer_set(name="bim_prop_group", data=group)
op = row.operator("bim.edit_blender_collection", icon="REMOVE", text="")
op.option = "remove"
op.collection = "queries"
op.index = index
row.context_pointer_set(name="bim_prop_group", data=query)
op = (
row.operator("bim.edit_blender_collection", text="Add filter")
if query.selector == "IFC Class"
else None
)
if op:
op.option = "add"
op.collection = "filters"
def draw_filter_ui(self, box, query):
for filter_index, f in enumerate(query.filters):
row = box.row()
row.alignment = "LEFT"
row.label(text="")
row.prop(f, "and_or", text="") if filter_index != 0 else None
if f.and_or == "or":
row = box.row()
row.alignment = "LEFT"
row.label(text="")
row.prop(f, "selector", text="")
if f.selector == "Attribute":
row.prop_search(f, "active_option", f, "options", text="", results_are_suggestions=True)
row.prop(
f,
"negation",
)
row.prop(f, "comparison", text="")
row.prop(f, "value", text="")
elif f.selector == "IfcPropertySet":
row.prop_search(f, "active_option", f, "options", text="")
row.prop_search(f, "active_sub_option", f, "sub_options", text="")
row.prop(f, "negation")
row.prop(f, "comparison", text="")
row.prop(f, "value", text="")
row.context_pointer_set(name="bim_prop_group", data=query)
op = row.operator("bim.edit_blender_collection", icon="REMOVE", text="")
op.option = "remove"
op.collection = "filters"
op.index = filter_index