@@ -79,12 +79,23 @@ class SelectGlobalId(Operator):
7979
8080 def execute (self , context ):
8181 ifc_file = tool .Ifc .get ()
82- props = context .scene .BIMSearchProperties
83- global_id = self .global_id or props .global_id
84- entity = ifc_file .by_guid (global_id )
82+ global_id = self .global_id .strip ()
83+
84+ if not global_id :
85+ self .report ({"ERROR" }, "Set Global ID for search." )
86+ return {"CANCELLED" }
87+
88+ try :
89+ entity = ifc_file .by_guid (global_id )
90+ except RuntimeError :
91+ self .report ({"ERROR" }, f"No IFC entity found with guid '{ global_id } '." )
92+ return {"CANCELLED" }
93+
8594 obj = tool .Ifc .get_object (entity )
8695 if not obj :
87- self .report ({"ERROR" }, "No object found" )
96+ self .report ({"ERROR" }, f"No Blender object found with guid '{ global_id } '." )
97+ return {"CANCELLED" }
98+
8899 obj .select_set (True )
89100 bpy .context .view_layer .objects .active = obj
90101 return {"FINISHED" }
@@ -99,13 +110,29 @@ class SelectIfcClass(Operator):
99110 ifc_class : StringProperty ()
100111
101112 def execute (self , context ):
113+ ifc_class = self .ifc_class
114+
115+ if not ifc_class :
116+ self .report ({"ERROR" }, "Set IFC Class for search." )
117+ return {"CANCELLED" }
118+
119+ sch = tool .Ifc .schema ()
120+ try :
121+ sch .declaration_by_name (ifc_class )
122+ except RuntimeError :
123+ self .report ({"ERROR" }, f"IFC Class '{ ifc_class } ' is not found in schema { sch .name ()} ." )
124+ return {"CANCELLED" }
125+
102126 self .file = IfcStore .get_file ()
127+ n_objects = 0
103128 for obj in context .visible_objects :
104129 if not obj .BIMObjectProperties .ifc_definition_id or obj .is_library_indirect :
105130 continue
106131 element = self .file .by_id (obj .BIMObjectProperties .ifc_definition_id )
107- if does_keyword_exist (self . ifc_class , element .is_a (), context ):
132+ if does_keyword_exist (ifc_class , element .is_a (), context ):
108133 obj .select_set (True )
134+ n_objects += 1
135+ self .report ({"INFO" }, f"{ n_objects } objects selected." )
109136 return {"FINISHED" }
110137
111138
@@ -116,11 +143,21 @@ class SelectAttribute(Operator):
116143 bl_label = "Select Attribute"
117144 bl_options = {"REGISTER" , "UNDO" }
118145
146+ @classmethod
147+ def poll (cls , context ):
148+ props = context .scene .BIMSearchProperties
149+ attribute_name = props .search_attribute_name .strip ()
150+ if attribute_name :
151+ return True
152+ cls .poll_message_set ("Set Attribute Name for search." )
153+ return False
154+
119155 def execute (self , context ):
120156 self .file = IfcStore .get_file ()
121157 props = context .scene .BIMSearchProperties
122- pattern = props .search_attribute_value
158+ attribute_value = props .search_attribute_value
123159 attribute_name = props .search_attribute_name
160+ n_objects = 0
124161 for obj in context .visible_objects :
125162 if not obj .BIMObjectProperties .ifc_definition_id :
126163 continue
@@ -130,8 +167,10 @@ def execute(self, context):
130167 value = next ((v for k , v in data .items () if k .lower () == attribute_name .lower ()), None )
131168 else :
132169 value = getattr (element , attribute_name , None )
133- if does_keyword_exist (pattern , value , context ):
170+ if does_keyword_exist (attribute_value , value , context ):
134171 obj .select_set (True )
172+ n_objects += 1
173+ self .report ({"INFO" }, f"{ n_objects } objects selected." )
135174 return {"FINISHED" }
136175
137176
@@ -142,12 +181,26 @@ class SelectPset(Operator):
142181 bl_label = "Select Pset"
143182 bl_options = {"REGISTER" , "UNDO" }
144183
184+ @classmethod
185+ def poll (cls , context ):
186+ props = context .scene .BIMSearchProperties
187+ pset_name = props .search_pset_name .strip ()
188+ prop_name = props .search_prop_name .strip ()
189+ if not pset_name :
190+ cls .poll_message_set ("Set PSet name for search." )
191+ return False
192+ if not prop_name :
193+ cls .poll_message_set ("Set Property name for search." )
194+ return False
195+ return True
196+
145197 def execute (self , context ):
146198 self .file = IfcStore .get_file ()
147199 props = context .scene .BIMSearchProperties
148200 search_pset_name = props .search_pset_name
149201 search_prop_name = props .search_prop_name
150202 pattern = props .search_pset_value
203+ n_objects = 0
151204 for obj in context .visible_objects :
152205 if not obj .BIMObjectProperties .ifc_definition_id :
153206 continue
@@ -166,6 +219,8 @@ def execute(self, context):
166219 value = props .get (search_prop_name , None )
167220 if does_keyword_exist (pattern , value , context ):
168221 obj .select_set (True )
222+ n_objects += 1
223+ self .report ({"INFO" }, f"{ n_objects } objects selected." )
169224 return {"FINISHED" }
170225
171226
@@ -176,6 +231,10 @@ class ColourByAttribute(Operator):
176231 bl_label = "Colour by Attribute"
177232 bl_options = {"REGISTER" , "UNDO" }
178233
234+ @classmethod
235+ def poll (cls , context ):
236+ return SelectAttribute .poll (context )
237+
179238 def execute (self , context ):
180239 IfcStore .begin_transaction (self )
181240 self .store_state (context )
@@ -227,6 +286,10 @@ class ColourByPset(Operator):
227286 bl_label = "Colour by Pset"
228287 bl_options = {"REGISTER" , "UNDO" }
229288
289+ @classmethod
290+ def poll (cls , context ):
291+ return SelectPset .poll (context )
292+
230293 def execute (self , context ):
231294 IfcStore .begin_transaction (self )
232295 self .store_state (context )
@@ -364,6 +427,13 @@ class ActivateIfcClassFilter(Operator):
364427 bl_idname = "bim.activate_ifc_class_filter"
365428 bl_label = "Filter by Class"
366429
430+ @classmethod
431+ def poll (cls , context ):
432+ if not context .selected_objects :
433+ cls .poll_message_set ("Select objects to filter." )
434+ return False
435+ return True
436+
367437 def invoke (self , context , event ):
368438 props = bpy .context .scene .BIMSearchProperties
369439 props .filter_classes .clear ()
@@ -410,6 +480,13 @@ class ActivateIfcBuildingStoreyFilter(Operator):
410480 bl_idname = "bim.activate_ifc_building_storey_filter"
411481 bl_label = "Filter by Building Storey"
412482
483+ @classmethod
484+ def poll (cls , context ):
485+ if not context .selected_objects :
486+ cls .poll_message_set ("Select objects to filter." )
487+ return False
488+ return True
489+
413490 def invoke (self , context , event ):
414491 props = bpy .context .scene .BIMSearchProperties
415492 props .filter_building_storeys .clear ()
@@ -475,14 +552,18 @@ class FilterModelElements(Operator):
475552
476553 def execute (self , context ):
477554 selection_props = context .scene .IfcSelectorProperties
478- selection = selection_props .selector_query_syntax if selection_props .manual_override else self .add_groups (selection_props )
555+ selection = (
556+ selection_props .selector_query_syntax
557+ if selection_props .manual_override
558+ else self .add_groups (selection_props )
559+ )
479560 selection_props .selector_query_syntax = selection
480561 r = core .search (tool .Search , tool .Spatial , query = selection , action = self .option )
481562 if isinstance (r , str ):
482563 self .report ({"WARNING" }, r )
483564 return {"FINISHED" }
484565
485- def add_groups (self , selector :str ) -> str :
566+ def add_groups (self , selector : str ) -> str :
486567 selection = ""
487568 for group_index , group in enumerate (selector .groups ):
488569 if group_index != 0 :
@@ -517,7 +598,6 @@ def add_queries(self, selection: str, group: str) -> str:
517598
518599 def add_filters (self , selection : str , query : str ) -> str :
519600 for f_index , f in enumerate (query .filters ):
520-
521601 if f_index != 0 :
522602 selection += " & " if f .and_or == "and" else " | "
523603 selection += f".{ query .active_option } "
@@ -535,12 +615,13 @@ def add_filters(self, selection: str, query: str) -> str:
535615 selection += f'{ f .active_option .split (": " )[1 ]} .{ f .active_sub_option .split (": " )[1 ]} { "!" if f .negation else "" } { f .comparison } { value } '
536616 elif f .selector == "Attribute" :
537617 # we're using the prop_search functionality in blender which returns the index of the option. Sometimes the user can override this and enter a value that doesn't exist in the list. In this case there is no index and we need to handle it. @vulevukusej
538- pattern = re .compile (r' ^[0-9]+:' )
618+ pattern = re .compile (r" ^[0-9]+:" )
539619 match = pattern .search (f .active_option )
540620 selection += f'{ f .active_option .split (": " )[1 ] if match else f .active_option } { "!" if f .negation else "" } { f .comparison } { value } '
541621 selection += "]"
542622 return selection
543623
624+
544625# This needs to be moved into ui code, I know ;) - vulevukusej
545626class IfcSelector (Operator ):
546627 """Select elements in model with IFC Selector"""
0 commit comments