118 lines
3.2 KiB
Python
118 lines
3.2 KiB
Python
import re
|
|
|
|
from ngSkinTools2.api.python_compatibility import Object
|
|
from ngSkinTools2.signal import Signal
|
|
|
|
|
|
class InfluenceNameFilter(Object):
|
|
"""
|
|
simple helper object to match against filter strings;
|
|
accepts filter as a string, breaks it down into lowercase tokens, and
|
|
matches values in non-case sensitive way
|
|
|
|
e.g. filter "leg arm spines" matches "leg", "left_leg",
|
|
"R_arm", but does not match "spine"
|
|
|
|
in a special case of empty filter, returns true for isMatch
|
|
"""
|
|
|
|
def __init__(self):
|
|
self.matchers = []
|
|
self.changed = Signal("filter changed")
|
|
self.currentFilterString = ""
|
|
|
|
def set_filter_string(self, filter_string):
|
|
if self.currentFilterString == filter_string:
|
|
# avoid emitting change events if there's no change
|
|
return
|
|
self.currentFilterString = filter_string
|
|
|
|
def create_pattern(expression):
|
|
expression = "".join([char for char in expression if char.lower() in "abcdefghijklmnopqrstuvwxyz0123456789_*"])
|
|
expression = expression.replace("*", ".*")
|
|
return re.compile(expression, re.I)
|
|
|
|
self.matchers = [create_pattern(i.strip()) for i in filter_string.split() if i.strip() != '']
|
|
self.changed.emit()
|
|
return self
|
|
|
|
def short_name(self, name):
|
|
try:
|
|
return name[name.rindex("|") + 1 :]
|
|
except Exception as err:
|
|
return name
|
|
|
|
def is_match(self, value):
|
|
if len(self.matchers) == 0:
|
|
return True
|
|
|
|
value = self.short_name(str(value).lower())
|
|
for pattern in self.matchers:
|
|
if pattern.search(value) is not None:
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def short_name(name, min_len=0):
|
|
"""
|
|
|
|
:param str name:
|
|
:param int min_len:
|
|
"""
|
|
idx = name.rfind("|", None, len(name) - min_len - 1)
|
|
if idx < 0:
|
|
return name
|
|
return name[idx + 1 :]
|
|
|
|
|
|
class IndexedName(object):
|
|
def __init__(self, path):
|
|
self.path = path
|
|
self.name = short_name(path)
|
|
|
|
def extend_short_name(self):
|
|
self.name = short_name(self.path, len(self.name))
|
|
|
|
|
|
def extend_unique_names(items, from_item):
|
|
"""
|
|
|
|
:param int from_item:
|
|
:param list[IndexedName] items:
|
|
"""
|
|
|
|
if from_item >= len(items) - 1:
|
|
return
|
|
|
|
curr = items[from_item]
|
|
needs_more_iterations = True
|
|
while needs_more_iterations:
|
|
needs_more_iterations = False
|
|
curr_name = curr.name
|
|
|
|
for item in items[from_item + 1 :]:
|
|
if item.name == curr_name:
|
|
if not needs_more_iterations:
|
|
curr.extend_short_name()
|
|
item.extend_short_name()
|
|
needs_more_iterations = True
|
|
|
|
|
|
def unique_names(name_list):
|
|
"""
|
|
returns a list of shortened names without duplicates. e.g ["|a|b", "|a|b|c", "b|b"] will become ["a|b", "c", "b|b"]
|
|
:param name_list:
|
|
:return:
|
|
"""
|
|
|
|
# assign index to each name to later restore the original order
|
|
indexed_names = [IndexedName(i) for i in name_list]
|
|
|
|
sorted_by_reveresed_name = sorted(indexed_names, key=lambda x: x.path[::-1])
|
|
|
|
for i, _ in enumerate(sorted_by_reveresed_name):
|
|
extend_unique_names(sorted_by_reveresed_name, i)
|
|
|
|
return [i.name for i in indexed_names]
|