autonaming.py (7112B)
1 #Embedded file name: C:\BuildAgent\work\20d73f1b24eed06e\eve\release\V24.01\packages\carbonui\util\autonaming.py 2 import re 3 import weakref 4 import logging 5 log = logging.getLogger(__name__) 6 _click_registry = weakref.WeakValueDictionary() 7 AUTO_NAMING_ENABLED = True 8 GENERIC_NAMES = {'Container', 9 'container', 10 'Button', 11 'button', 12 'Frame', 13 'frame', 14 'Underlay', 15 'underlay'} 16 17 def register_clickable_element(ui_element, element_id): 18 if not element_id or not ui_element: 19 return 20 try: 21 prev = _click_registry.get(element_id) 22 if prev is not None and prev is not ui_element: 23 log.debug('autonaming: overwriting registry key %r: %s -> %s', element_id, prev.__class__.__name__, ui_element.__class__.__name__) 24 except Exception: 25 pass 26 27 _click_registry[element_id] = ui_element 28 29 30 def get_registered_element(element_id): 31 return _click_registry.get(element_id) 32 33 34 def _sanitize_name(name): 35 try: 36 name = re.sub('[^a-zA-Z0-9\\s]', '', str(name)) 37 words = name.split() 38 if not words: 39 return None 40 result = words[0].lower() 41 for word in words[1:]: 42 result += word.capitalize() 43 44 if result: 45 return result 46 return None 47 except Exception: 48 return None 49 50 51 def _find_parent_window(element): 52 try: 53 current = getattr(element, 'parent', None) 54 max_depth = 20 55 depth = 0 56 while current and depth < max_depth: 57 if hasattr(current, 'windowID') and current.windowID: 58 return current 59 class_name = current.__class__.__name__ 60 if 'Window' in class_name or 'Dialog' in class_name: 61 return current 62 current = getattr(current, 'parent', None) 63 depth += 1 64 65 return 66 except Exception: 67 return 68 69 70 def _get_semantic_role(ui_element, attributes): 71 try: 72 attributes = attributes or {} 73 label = attributes.get('label') or attributes.get('text', '') 74 if label: 75 label_lower = str(label).lower().strip() 76 role_map = {'submit': ['submit', 77 'ok', 78 'confirm', 79 'accept', 80 'apply'], 81 'cancel': ['cancel', 82 'close', 83 'dismiss', 84 'no'], 85 'next': ['next', 'continue', 'forward'], 86 'back': ['back', 'previous'], 87 'delete': ['delete', 'remove'], 88 'save': ['save'], 89 'edit': ['edit', 'modify']} 90 for role, keywords in role_map.items(): 91 if label_lower in keywords: 92 return role 93 94 sanitized = _sanitize_name(label) 95 if sanitized and len(sanitized) < 20 and sanitized not in GENERIC_NAMES: 96 return sanitized 97 icon_path = attributes.get('iconPath') or attributes.get('texturePath', '') 98 if icon_path: 99 icon_lower = str(icon_path).lower() 100 if 'close' in icon_lower: 101 return 'close' 102 if 'settings' in icon_lower or 'gear' in icon_lower: 103 return 'settings' 104 if 'help' in icon_lower or 'question' in icon_lower: 105 return 'help' 106 if 'search' in icon_lower: 107 return 'search' 108 func = attributes.get('func') or attributes.get('OnClick') 109 if func and hasattr(func, '__name__'): 110 func_name = func.__name__ 111 clean_name = func_name.replace('OnClick', '').replace('On', '').replace('_', '') 112 if clean_name and len(clean_name) < 20: 113 if clean_name: 114 return clean_name[0].lower() + clean_name[1:] 115 return None 116 return None 117 except Exception: 118 return None 119 120 121 def _try_register_unique_ui_name(ui_element): 122 if hasattr(ui_element, 'uniqueUiName') and ui_element.uniqueUiName: 123 register_clickable_element(ui_element, ui_element.uniqueUiName) 124 if hasattr(ui_element, 'elementId') and ui_element.elementId: 125 register_clickable_element(ui_element, ui_element.elementId) 126 return True 127 ui_element.elementId = ui_element.uniqueUiName 128 return True 129 return False 130 131 132 def _try_register_existing_element_id(ui_element): 133 if hasattr(ui_element, 'elementId') and ui_element.elementId: 134 register_clickable_element(ui_element, ui_element.elementId) 135 return True 136 return False 137 138 139 def _try_use_btnData_id(ui_element): 140 if hasattr(ui_element, 'btnData') and hasattr(ui_element.btnData, 'id'): 141 btn_id = ui_element.btnData.id 142 if btn_id: 143 generated_name = 'neocom.%s' % btn_id 144 ui_element.elementId = generated_name 145 register_clickable_element(ui_element, generated_name) 146 log.info('autonaming: generated neocom id %r (%s)', generated_name, ui_element.__class__.__name__) 147 return True 148 return False 149 150 151 def _try_use_attributes_name(ui_element, attributes, window): 152 element_name = attributes.get('name') 153 if element_name and element_name not in GENERIC_NAMES: 154 if window and hasattr(window, 'windowID'): 155 generated_name = '%s.%s' % (window.windowID, element_name) 156 else: 157 generated_name = element_name 158 ui_element.elementId = generated_name 159 register_clickable_element(ui_element, generated_name) 160 log.debug('autonaming: generated name id %r', generated_name) 161 return True 162 return False 163 164 165 def _try_use_window_and_role(ui_element, attributes, window): 166 role = _get_semantic_role(ui_element, attributes) 167 if window and role and hasattr(window, 'windowID'): 168 generated_name = '%s.%s' % (window.windowID, role) 169 ui_element.elementId = generated_name 170 register_clickable_element(ui_element, generated_name) 171 log.debug('autonaming: generated role id %r', generated_name) 172 return True 173 return False 174 175 176 def _try_use_role_only(ui_element, attributes): 177 role = _get_semantic_role(ui_element, attributes) 178 if role: 179 ui_element.elementId = role 180 register_clickable_element(ui_element, role) 181 log.debug('autonaming: generated fallback role id %r', role) 182 return True 183 return False 184 185 186 def apply_auto_naming(ui_element, attributes): 187 try: 188 if not AUTO_NAMING_ENABLED or not ui_element: 189 return 190 attributes = attributes or {} 191 if _try_register_unique_ui_name(ui_element): 192 return 193 if _try_register_existing_element_id(ui_element): 194 return 195 if _try_use_btnData_id(ui_element): 196 return 197 window = _find_parent_window(ui_element) 198 if _try_use_attributes_name(ui_element, attributes, window): 199 return 200 if _try_use_window_and_role(ui_element, attributes, window): 201 return 202 _try_use_role_only(ui_element, attributes) 203 except Exception as exc: 204 log.exception('Failed to apply auto naming: %s', exc)