UTF8 search support in usdviewq
authortylerm <tylerm@nvidia.com>
Wed, 27 Dec 2023 20:00:23 +0000 (12:00 -0800)
committertylerm <tylerm@nvidia.com>
Wed, 27 Dec 2023 20:00:23 +0000 (12:00 -0800)
pxr/usdImaging/usdviewq/appController.py
pxr/usdImaging/usdviewq/common.py

index ced1893ea6ea256b5a02eae658cb4f661814824f..1c1cb68cfdb7bc58ebc7018279a4f0867c75130a 100644 (file)
@@ -31,7 +31,7 @@ from __future__ import print_function
 from .qt import QtCore, QtGui, QtWidgets, QtActionWidgets
 
 # Stdlib components
-import re, sys, os, cProfile, pstats, traceback
+import re, sys, os, cProfile, pstats, traceback, unicodedata
 from itertools import groupby
 from time import time, sleep
 from collections import deque, OrderedDict
@@ -2203,6 +2203,9 @@ class AppController(QtCore.QObject):
 
     # Prim/Attribute search functionality =====================================
 
+    def _normalize_unicode(self, str: str, form = 'NFKC'):
+        return unicodedata.normalize(form, str) 
+
     def _isMatch(self, pattern, isRegex, prim, useDisplayName):
         """
         Determines if the given prim has a name that matches the
@@ -2229,11 +2232,13 @@ class AppController(QtCore.QObject):
         Returns:
             True if the pattern matches the specified prim content, False otherwise. 
         """
+
+        pattern = self._normalize_unicode(pattern)
         if isRegex:
             matchLambda = re.compile(pattern, re.IGNORECASE).search
         else:
-            pattern = pattern.lower()
-            matchLambda = lambda x: pattern in x.lower()
+            pattern = pattern.casefold()
+            matchLambda = lambda x: pattern in x.casefold()
 
         if useDisplayName:
             # typically we would check prim.HasAuthoredDisplayName()
@@ -2243,13 +2248,13 @@ class AppController(QtCore.QObject):
             # so we'd be paying twice the price for each prim
             # search, which on large scenes would be a big performance
             # hit, so we do it this way instead
-            displayName = prim.GetDisplayName()
+            displayName = self._normalize_unicode(prim.GetDisplayName())
             if displayName:
                 return matchLambda(displayName)
             else:
-                return matchLambda(prim.GetName())
+                return matchLambda(self._normalize_unicode(prim.GetName()))
         else:
-            return matchLambda(prim.GetName())
+            return matchLambda(self._normalize_unicode(prim.GetName()))
 
 
     def _findPrims(self, pattern, useRegex=True):
@@ -2374,13 +2379,15 @@ class AppController(QtCore.QObject):
                                 self._propertyLegendAnim)
 
     def _attrViewFindNext(self):
-        if (self._attrSearchString == self._ui.attrViewLineEdit.text() and
+        if (self._attrSearchString == self._normalize_unicode(self._ui.attrViewLineEdit.text()) and
             len(self._attrSearchResults) > 0 and
             self._lastPrimSearched == self._dataModel.selection.getFocusPrim()):
 
             # Go to the next result of the currently ongoing search
-            nextResult = self._attrSearchResults.popleft()
-            itemName = str(nextResult.text(PropertyViewIndex.NAME))
+            index = self._attrSearchResults.popleft()
+            nextResult = self._ui.propertyView.model().data(index)
+            item = self._ui.propertyView.itemFromIndex(index)
+            itemName = nextResult
 
             selectedProp = self._propertiesDict[itemName]
             if isinstance(selectedProp, CustomAttribute):
@@ -2389,9 +2396,9 @@ class AppController(QtCore.QObject):
             else:
                 self._dataModel.selection.setProp(selectedProp)
                 self._dataModel.selection.clearComputedProps()
-            self._ui.propertyView.scrollToItem(nextResult)
+            self._ui.propertyView.scrollToItem(item)
 
-            self._attrSearchResults.append(nextResult)
+            self._attrSearchResults.append(index)
             self._lastPrimSearched = self._dataModel.selection.getFocusPrim()
 
             self._ui.attributeValueEditor.populate(
@@ -2400,25 +2407,16 @@ class AppController(QtCore.QObject):
             self._updateLayerStackView(self._getSelectedObject())
         else:
             # Begin a new search
-            self._attrSearchString = self._ui.attrViewLineEdit.text()
-            attrSearchItems = self._ui.propertyView.findItems(
-                self._ui.attrViewLineEdit.text(),
-                QtCore.Qt.MatchRegExp,
-                PropertyViewIndex.NAME)
-
-            # Now just search for the string itself
-            otherSearch = self._ui.propertyView.findItems(
-                self._ui.attrViewLineEdit.text(),
-                QtCore.Qt.MatchContains,
-                PropertyViewIndex.NAME)
-
-            # Combine search results and sort by model index so that
-            # we iterate over results from top to bottom.
-            combinedItems = set(attrSearchItems + otherSearch)
+            self._attrSearchString = self._normalize_unicode(self._ui.attrViewLineEdit.text())
+            
+            search1 = deque(self._ui.propertyView.model().match(self._ui.propertyView.model().index(0, 1),
+                PropertyViewDataRoles.NORMALIZED_NAME, self._attrSearchString, -1, QtCore.Qt.MatchContains))
+            search2 = deque(self._ui.propertyView.model().match(self._ui.propertyView.model().index(0, 1),
+                PropertyViewDataRoles.NORMALIZED_NAME, self._attrSearchString, -1, QtCore.Qt.MatchRegExp))
+
+            combinedItems = set(search1 + search2)
             self._attrSearchResults = deque(
-                sorted(combinedItems, 
-                       key=lambda i: self._ui.propertyView.indexFromItem(
-                           i, PropertyViewIndex.NAME)))
+                sorted(combinedItems))
 
             self._lastPrimSearched = self._dataModel.selection.getFocusPrim()
             if (len(self._attrSearchResults) > 0):
@@ -4003,6 +4001,9 @@ class AppController(QtCore.QObject):
             treeWidget.topLevelItem(currRow).setData(PropertyViewIndex.TYPE,
                     QtCore.Qt.ItemDataRole.WhatsThisRole,
                     typeRole)
+            treeWidget.topLevelItem(currRow).setData(PropertyViewIndex.NAME,
+                PropertyViewDataRoles.NORMALIZED_NAME,
+                self._normalize_unicode(str(key)))
 
             currItem = treeWidget.topLevelItem(currRow)
 
@@ -4039,6 +4040,10 @@ class AppController(QtCore.QObject):
                     currItem.setFont(PropertyViewIndex.VALUE, valTextFont)
                     child = currItem.child(childRow)
 
+                    child.setData(PropertyViewIndex.NAME,
+                        PropertyViewDataRoles.NORMALIZED_NAME,
+                        self._normalize_unicode(str(t)))
+
                     if typeRole == PropertyViewDataRoles.RELATIONSHIP_WITH_TARGETS:
                         child.setIcon(PropertyViewIndex.TYPE, 
                                       PropertyViewIcons.TARGET())
index 257e1cfac14e015d5db1eba4cf44bb55f161b316..15734a87bdd8ec174bea652d9c9bd813799671dc 100644 (file)
@@ -145,6 +145,7 @@ class PropertyViewDataRoles(ConstantsGroup):
     TARGET = "Tgt"
     CONNECTION = "Conn"
     COMPOSED = "Cmp"
+    NORMALIZED_NAME = QtCore.Qt.UserRole + 1
 
 class RenderModes(ConstantsGroup):
     # Render modes