mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
[Automated] Merged develop into main
This commit is contained in:
commit
1ca4ca8520
16 changed files with 266 additions and 90 deletions
|
|
@ -39,7 +39,6 @@ class HostDirmap(object):
|
|||
self._project_settings = project_settings
|
||||
self._sync_module = sync_module # to limit reinit of Modules
|
||||
self._log = None
|
||||
self._mapping = None # cache mapping
|
||||
|
||||
@property
|
||||
def sync_module(self):
|
||||
|
|
@ -70,29 +69,28 @@ class HostDirmap(object):
|
|||
"""Run host dependent remapping from source_path to destination_path"""
|
||||
pass
|
||||
|
||||
def process_dirmap(self):
|
||||
def process_dirmap(self, mapping=None):
|
||||
# type: (dict) -> None
|
||||
"""Go through all paths in Settings and set them using `dirmap`.
|
||||
|
||||
If artists has Site Sync enabled, take dirmap mapping directly from
|
||||
Local Settings when artist is syncing workfile locally.
|
||||
|
||||
Args:
|
||||
project_settings (dict): Settings for current project.
|
||||
"""
|
||||
|
||||
if not self._mapping:
|
||||
self._mapping = self.get_mappings(self.project_settings)
|
||||
if not self._mapping:
|
||||
if not mapping:
|
||||
mapping = self.get_mappings()
|
||||
if not mapping:
|
||||
return
|
||||
|
||||
self.log.info("Processing directory mapping ...")
|
||||
self.on_enable_dirmap()
|
||||
self.log.info("mapping:: {}".format(self._mapping))
|
||||
|
||||
for k, sp in enumerate(self._mapping["source-path"]):
|
||||
dst = self._mapping["destination-path"][k]
|
||||
for k, sp in enumerate(mapping["source-path"]):
|
||||
dst = mapping["destination-path"][k]
|
||||
try:
|
||||
# add trailing slash if missing
|
||||
sp = os.path.join(sp, '')
|
||||
dst = os.path.join(dst, '')
|
||||
print("{} -> {}".format(sp, dst))
|
||||
self.dirmap_routine(sp, dst)
|
||||
except IndexError:
|
||||
|
|
@ -110,28 +108,24 @@ class HostDirmap(object):
|
|||
)
|
||||
continue
|
||||
|
||||
def get_mappings(self, project_settings):
|
||||
def get_mappings(self):
|
||||
"""Get translation from source-path to destination-path.
|
||||
|
||||
It checks if Site Sync is enabled and user chose to use local
|
||||
site, in that case configuration in Local Settings takes precedence
|
||||
"""
|
||||
|
||||
local_mapping = self._get_local_sync_dirmap(project_settings)
|
||||
dirmap_label = "{}-dirmap".format(self.host_name)
|
||||
if (
|
||||
not self.project_settings[self.host_name].get(dirmap_label)
|
||||
and not local_mapping
|
||||
):
|
||||
return {}
|
||||
mapping_settings = self.project_settings[self.host_name][dirmap_label]
|
||||
mapping_enabled = mapping_settings["enabled"] or bool(local_mapping)
|
||||
mapping_sett = self.project_settings[self.host_name].get(dirmap_label,
|
||||
{})
|
||||
local_mapping = self._get_local_sync_dirmap()
|
||||
mapping_enabled = mapping_sett.get("enabled") or bool(local_mapping)
|
||||
if not mapping_enabled:
|
||||
return {}
|
||||
|
||||
mapping = (
|
||||
local_mapping
|
||||
or mapping_settings["paths"]
|
||||
or mapping_sett["paths"]
|
||||
or {}
|
||||
)
|
||||
|
||||
|
|
@ -141,28 +135,27 @@ class HostDirmap(object):
|
|||
or not mapping.get("source-path")
|
||||
):
|
||||
return {}
|
||||
self.log.info("Processing directory mapping ...")
|
||||
self.log.info("mapping:: {}".format(mapping))
|
||||
return mapping
|
||||
|
||||
def _get_local_sync_dirmap(self, project_settings):
|
||||
def _get_local_sync_dirmap(self):
|
||||
"""
|
||||
Returns dirmap if synch to local project is enabled.
|
||||
|
||||
Only valid mapping is from roots of remote site to local site set
|
||||
in Local Settings.
|
||||
|
||||
Args:
|
||||
project_settings (dict)
|
||||
Returns:
|
||||
dict : { "source-path": [XXX], "destination-path": [YYYY]}
|
||||
"""
|
||||
project_name = os.getenv("AVALON_PROJECT")
|
||||
|
||||
mapping = {}
|
||||
|
||||
if not project_settings["global"]["sync_server"]["enabled"]:
|
||||
if (not self.sync_module.enabled or
|
||||
project_name not in self.sync_module.get_enabled_projects()):
|
||||
return mapping
|
||||
|
||||
project_name = os.getenv("AVALON_PROJECT")
|
||||
|
||||
active_site = self.sync_module.get_local_normalized_site(
|
||||
self.sync_module.get_active_site(project_name))
|
||||
remote_site = self.sync_module.get_local_normalized_site(
|
||||
|
|
@ -171,11 +164,7 @@ class HostDirmap(object):
|
|||
"active {} - remote {}".format(active_site, remote_site)
|
||||
)
|
||||
|
||||
if (
|
||||
active_site == "local"
|
||||
and project_name in self.sync_module.get_enabled_projects()
|
||||
and active_site != remote_site
|
||||
):
|
||||
if active_site == "local" and active_site != remote_site:
|
||||
sync_settings = self.sync_module.get_sync_project_setting(
|
||||
project_name,
|
||||
exclude_locals=False,
|
||||
|
|
@ -188,7 +177,15 @@ class HostDirmap(object):
|
|||
|
||||
self.log.debug("local overrides {}".format(active_overrides))
|
||||
self.log.debug("remote overrides {}".format(remote_overrides))
|
||||
|
||||
current_platform = platform.system().lower()
|
||||
remote_provider = self.sync_module.get_provider_for_site(
|
||||
project_name, remote_site
|
||||
)
|
||||
# dirmap has sense only with regular disk provider, in the workfile
|
||||
# wont be root on cloud or sftp provider
|
||||
if remote_provider != "local_drive":
|
||||
remote_site = "studio"
|
||||
for root_name, active_site_dir in active_overrides.items():
|
||||
remote_site_dir = (
|
||||
remote_overrides.get(root_name)
|
||||
|
|
|
|||
|
|
@ -3576,6 +3576,65 @@ def get_color_management_output_transform():
|
|||
return colorspace
|
||||
|
||||
|
||||
def image_info(file_path):
|
||||
# type: (str) -> dict
|
||||
"""Based on tha texture path, get its bit depth and format information.
|
||||
Take reference from makeTx.py in Arnold:
|
||||
ImageInfo(filename): Get Image Information for colorspace
|
||||
AiTextureGetFormat(filename): Get Texture Format
|
||||
AiTextureGetBitDepth(filename): Get Texture bit depth
|
||||
Args:
|
||||
file_path (str): Path to the texture file.
|
||||
Returns:
|
||||
dict: Dictionary with the information about the texture file.
|
||||
"""
|
||||
from arnold import (
|
||||
AiTextureGetBitDepth,
|
||||
AiTextureGetFormat
|
||||
)
|
||||
# Get Texture Information
|
||||
img_info = {'filename': file_path}
|
||||
if os.path.isfile(file_path):
|
||||
img_info['bit_depth'] = AiTextureGetBitDepth(file_path) # noqa
|
||||
img_info['format'] = AiTextureGetFormat(file_path) # noqa
|
||||
else:
|
||||
img_info['bit_depth'] = 8
|
||||
img_info['format'] = "unknown"
|
||||
return img_info
|
||||
|
||||
|
||||
def guess_colorspace(img_info):
|
||||
# type: (dict) -> str
|
||||
"""Guess the colorspace of the input image filename.
|
||||
Note:
|
||||
Reference from makeTx.py
|
||||
Args:
|
||||
img_info (dict): Image info generated by :func:`image_info`
|
||||
Returns:
|
||||
str: color space name use in the `--colorconvert`
|
||||
option of maketx.
|
||||
"""
|
||||
from arnold import (
|
||||
AiTextureInvalidate,
|
||||
# types
|
||||
AI_TYPE_BYTE,
|
||||
AI_TYPE_INT,
|
||||
AI_TYPE_UINT
|
||||
)
|
||||
try:
|
||||
if img_info['bit_depth'] <= 16:
|
||||
if img_info['format'] in (AI_TYPE_BYTE, AI_TYPE_INT, AI_TYPE_UINT): # noqa
|
||||
return 'sRGB'
|
||||
else:
|
||||
return 'linear'
|
||||
# now discard the image file as AiTextureGetFormat has loaded it
|
||||
AiTextureInvalidate(img_info['filename']) # noqa
|
||||
except ValueError:
|
||||
print(("[maketx] Error: Could not guess"
|
||||
"colorspace for {}").format(img_info["filename"]))
|
||||
return "linear"
|
||||
|
||||
|
||||
def len_flattened(components):
|
||||
"""Return the length of the list as if it was flattened.
|
||||
|
||||
|
|
|
|||
|
|
@ -336,7 +336,8 @@ class RenderSettings(object):
|
|||
)
|
||||
|
||||
# Set render file format to exr
|
||||
cmds.setAttr("{}.imageFormatStr".format(node), "exr", type="string")
|
||||
ext = vray_render_presets["image_format"]
|
||||
cmds.setAttr("{}.imageFormatStr".format(node), ext, type="string")
|
||||
|
||||
# animType
|
||||
cmds.setAttr("{}.animType".format(node), 1)
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import pyblish.api
|
|||
from openpype.lib import source_hash, run_subprocess
|
||||
from openpype.pipeline import legacy_io, publish
|
||||
from openpype.hosts.maya.api import lib
|
||||
from openpype.hosts.maya.api.lib import image_info, guess_colorspace
|
||||
|
||||
# Modes for transfer
|
||||
COPY = 1
|
||||
|
|
@ -367,16 +368,25 @@ class ExtractLook(publish.Extractor):
|
|||
for filepath in files_metadata:
|
||||
|
||||
linearize = False
|
||||
if do_maketx and files_metadata[filepath]["color_space"].lower() == "srgb": # noqa: E501
|
||||
linearize = True
|
||||
# set its file node to 'raw' as tx will be linearized
|
||||
files_metadata[filepath]["color_space"] = "Raw"
|
||||
# if OCIO color management enabled
|
||||
# it won't take the condition of the files_metadata
|
||||
|
||||
ocio_maya = cmds.colorManagementPrefs(q=True,
|
||||
cmConfigFileEnabled=True,
|
||||
cmEnabled=True)
|
||||
|
||||
if do_maketx and not ocio_maya:
|
||||
if files_metadata[filepath]["color_space"].lower() == "srgb": # noqa: E501
|
||||
linearize = True
|
||||
# set its file node to 'raw' as tx will be linearized
|
||||
files_metadata[filepath]["color_space"] = "Raw"
|
||||
|
||||
# if do_maketx:
|
||||
# color_space = "Raw"
|
||||
|
||||
source, mode, texture_hash = self._process_texture(
|
||||
filepath,
|
||||
resource,
|
||||
do_maketx,
|
||||
staging=staging_dir,
|
||||
linearize=linearize,
|
||||
|
|
@ -482,7 +492,8 @@ class ExtractLook(publish.Extractor):
|
|||
resources_dir, basename + ext
|
||||
)
|
||||
|
||||
def _process_texture(self, filepath, do_maketx, staging, linearize, force):
|
||||
def _process_texture(self, filepath, resource,
|
||||
do_maketx, staging, linearize, force):
|
||||
"""Process a single texture file on disk for publishing.
|
||||
This will:
|
||||
1. Check whether it's already published, if so it will do hardlink
|
||||
|
|
@ -524,10 +535,47 @@ class ExtractLook(publish.Extractor):
|
|||
texture_hash
|
||||
]
|
||||
if linearize:
|
||||
self.log.info("tx: converting sRGB -> linear")
|
||||
additional_args.extend(["--colorconvert", "sRGB", "linear"])
|
||||
if cmds.colorManagementPrefs(query=True, cmEnabled=True):
|
||||
render_colorspace = cmds.colorManagementPrefs(query=True,
|
||||
renderingSpaceName=True) # noqa
|
||||
config_path = cmds.colorManagementPrefs(query=True,
|
||||
configFilePath=True) # noqa
|
||||
if not os.path.exists(config_path):
|
||||
raise RuntimeError("No OCIO config path found!")
|
||||
|
||||
color_space_attr = resource["node"] + ".colorSpace"
|
||||
try:
|
||||
color_space = cmds.getAttr(color_space_attr)
|
||||
except ValueError:
|
||||
# node doesn't have color space attribute
|
||||
if cmds.loadPlugin("mtoa", quiet=True):
|
||||
img_info = image_info(filepath)
|
||||
color_space = guess_colorspace(img_info)
|
||||
else:
|
||||
color_space = "Raw"
|
||||
self.log.info("tx: converting {0} -> {1}".format(color_space, render_colorspace)) # noqa
|
||||
|
||||
additional_args.extend(["--colorconvert",
|
||||
color_space,
|
||||
render_colorspace])
|
||||
else:
|
||||
|
||||
if cmds.loadPlugin("mtoa", quiet=True):
|
||||
img_info = image_info(filepath)
|
||||
color_space = guess_colorspace(img_info)
|
||||
if color_space == "sRGB":
|
||||
self.log.info("tx: converting sRGB -> linear")
|
||||
additional_args.extend(["--colorconvert",
|
||||
"sRGB",
|
||||
"Raw"])
|
||||
else:
|
||||
self.log.info("tx: texture's colorspace "
|
||||
"is already linear")
|
||||
else:
|
||||
self.log.warning("cannot guess the colorspace"
|
||||
"color conversion won't be available!") # noqa
|
||||
|
||||
|
||||
config_path = get_ocio_config_path("nuke-default")
|
||||
additional_args.extend(["--colorconfig", config_path])
|
||||
# Ensure folder exists
|
||||
if not os.path.exists(os.path.dirname(converted)):
|
||||
|
|
|
|||
|
|
@ -0,0 +1,26 @@
|
|||
from maya import cmds
|
||||
|
||||
import pyblish.api
|
||||
from openpype.pipeline.publish import ValidateContentsOrder
|
||||
from openpype.pipeline import PublishValidationError
|
||||
|
||||
|
||||
class ValidateMayaColorSpace(pyblish.api.InstancePlugin):
|
||||
"""
|
||||
Check if the OCIO Color Management and maketx options
|
||||
enabled at the same time
|
||||
"""
|
||||
|
||||
order = ValidateContentsOrder
|
||||
families = ['look']
|
||||
hosts = ['maya']
|
||||
label = 'Color Management with maketx'
|
||||
|
||||
def process(self, instance):
|
||||
ocio_maya = cmds.colorManagementPrefs(q=True,
|
||||
cmConfigFileEnabled=True,
|
||||
cmEnabled=True)
|
||||
maketx = instance.data["maketx"]
|
||||
|
||||
if ocio_maya and maketx:
|
||||
raise PublishValidationError("Maya is color managed and maketx option is on. OpenPype doesn't support this combination yet.") # noqa
|
||||
|
|
@ -2861,10 +2861,10 @@ class NukeDirmap(HostDirmap):
|
|||
pass
|
||||
|
||||
def dirmap_routine(self, source_path, destination_path):
|
||||
log.debug("{}: {}->{}".format(self.file_name,
|
||||
source_path, destination_path))
|
||||
source_path = source_path.lower().replace(os.sep, '/')
|
||||
destination_path = destination_path.lower().replace(os.sep, '/')
|
||||
log.debug("Map: {} with: {}->{}".format(self.file_name,
|
||||
source_path, destination_path))
|
||||
if platform.system().lower() == "windows":
|
||||
self.file_name = self.file_name.lower().replace(
|
||||
source_path, destination_path)
|
||||
|
|
@ -2878,6 +2878,7 @@ class DirmapCache:
|
|||
_project_name = None
|
||||
_project_settings = None
|
||||
_sync_module = None
|
||||
_mapping = None
|
||||
|
||||
@classmethod
|
||||
def project_name(cls):
|
||||
|
|
@ -2897,6 +2898,36 @@ class DirmapCache:
|
|||
cls._sync_module = ModulesManager().modules_by_name["sync_server"]
|
||||
return cls._sync_module
|
||||
|
||||
@classmethod
|
||||
def mapping(cls):
|
||||
return cls._mapping
|
||||
|
||||
@classmethod
|
||||
def set_mapping(cls, mapping):
|
||||
cls._mapping = mapping
|
||||
|
||||
|
||||
def dirmap_file_name_filter(file_name):
|
||||
"""Nuke callback function with single full path argument.
|
||||
|
||||
Checks project settings for potential mapping from source to dest.
|
||||
"""
|
||||
|
||||
dirmap_processor = NukeDirmap(
|
||||
file_name,
|
||||
"nuke",
|
||||
DirmapCache.project_name(),
|
||||
DirmapCache.project_settings(),
|
||||
DirmapCache.sync_module(),
|
||||
)
|
||||
if not DirmapCache.mapping():
|
||||
DirmapCache.set_mapping(dirmap_processor.get_mappings())
|
||||
|
||||
dirmap_processor.process_dirmap(DirmapCache.mapping())
|
||||
if os.path.exists(dirmap_processor.file_name):
|
||||
return dirmap_processor.file_name
|
||||
return file_name
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def node_tempfile():
|
||||
|
|
@ -2942,25 +2973,6 @@ def duplicate_node(node):
|
|||
return dupli_node
|
||||
|
||||
|
||||
def dirmap_file_name_filter(file_name):
|
||||
"""Nuke callback function with single full path argument.
|
||||
|
||||
Checks project settings for potential mapping from source to dest.
|
||||
"""
|
||||
|
||||
dirmap_processor = NukeDirmap(
|
||||
file_name,
|
||||
"nuke",
|
||||
DirmapCache.project_name(),
|
||||
DirmapCache.project_settings(),
|
||||
DirmapCache.sync_module(),
|
||||
)
|
||||
dirmap_processor.process_dirmap()
|
||||
if os.path.exists(dirmap_processor.file_name):
|
||||
return dirmap_processor.file_name
|
||||
return file_name
|
||||
|
||||
|
||||
def get_group_io_nodes(nodes):
|
||||
"""Get the input and the output of a group of nodes."""
|
||||
|
||||
|
|
|
|||
|
|
@ -1472,13 +1472,15 @@ class SyncServerModule(OpenPypeModule, ITrayModule):
|
|||
|
||||
return sync_settings
|
||||
|
||||
def get_all_site_configs(self, project_name=None):
|
||||
def get_all_site_configs(self, project_name=None,
|
||||
local_editable_only=False):
|
||||
"""
|
||||
Returns (dict) with all sites configured system wide.
|
||||
|
||||
Args:
|
||||
project_name (str)(optional): if present, check if not disabled
|
||||
|
||||
local_editable_only (bool)(opt): if True return only Local
|
||||
Setting configurable (for LS UI)
|
||||
Returns:
|
||||
(dict): {'studio': {'provider':'local_drive'...},
|
||||
'MY_LOCAL': {'provider':....}}
|
||||
|
|
@ -1499,9 +1501,21 @@ class SyncServerModule(OpenPypeModule, ITrayModule):
|
|||
if site_settings:
|
||||
detail.update(site_settings)
|
||||
system_sites[site] = detail
|
||||
|
||||
system_sites.update(self._get_default_site_configs(sync_enabled,
|
||||
project_name))
|
||||
if local_editable_only:
|
||||
local_schema = SyncServerModule.get_local_settings_schema()
|
||||
editable_keys = {}
|
||||
for provider_code, editables in local_schema.items():
|
||||
editable_keys[provider_code] = ["enabled", "provider"]
|
||||
for editable_item in editables:
|
||||
editable_keys[provider_code].append(editable_item["key"])
|
||||
|
||||
for _, site in system_sites.items():
|
||||
provider = site["provider"]
|
||||
for site_config_key in list(site.keys()):
|
||||
if site_config_key not in editable_keys[provider]:
|
||||
site.pop(site_config_key, None)
|
||||
|
||||
return system_sites
|
||||
|
||||
|
|
|
|||
|
|
@ -330,6 +330,11 @@
|
|||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateMayaColorSpace": {
|
||||
"enabled": true,
|
||||
"optional": true,
|
||||
"active": true
|
||||
},
|
||||
"ValidateAttributes": {
|
||||
"enabled": false,
|
||||
"attributes": {}
|
||||
|
|
|
|||
|
|
@ -144,6 +144,10 @@
|
|||
{
|
||||
"key": "ValidateShadingEngine",
|
||||
"label": "Validate Look Shading Engine Naming"
|
||||
},
|
||||
{
|
||||
"key": "ValidateMayaColorSpace",
|
||||
"label": "ValidateMayaColorSpace"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -295,10 +295,10 @@ class SubsetWidget(QtWidgets.QWidget):
|
|||
self.model.set_grouping(state)
|
||||
|
||||
def _subset_changed(self, text):
|
||||
if hasattr(self.proxy, "setFilterRegularExpression"):
|
||||
self.proxy.setFilterRegularExpression(text)
|
||||
else:
|
||||
if hasattr(self.proxy, "setFilterRegExp"):
|
||||
self.proxy.setFilterRegExp(text)
|
||||
else:
|
||||
self.proxy.setFilterRegularExpression(text)
|
||||
self.view.expandAll()
|
||||
|
||||
def set_loading_state(self, loading, empty):
|
||||
|
|
|
|||
|
|
@ -482,10 +482,10 @@ class FilterProxyModel(QtCore.QSortFilterProxyModel):
|
|||
return True
|
||||
|
||||
# Filter by regex
|
||||
if hasattr(self, "filterRegularExpression"):
|
||||
regex = self.filterRegularExpression()
|
||||
else:
|
||||
if hasattr(self, "filterRegExp"):
|
||||
regex = self.filterRegExp()
|
||||
else:
|
||||
regex = self.filterRegularExpression()
|
||||
pattern = regex.pattern()
|
||||
if pattern:
|
||||
pattern = re.escape(pattern)
|
||||
|
|
|
|||
|
|
@ -160,10 +160,10 @@ class SceneInventoryWindow(QtWidgets.QDialog):
|
|||
self._model.set_hierarchy_view(enabled)
|
||||
|
||||
def _on_text_filter_change(self, text_filter):
|
||||
if hasattr(self._proxy, "setFilterRegularExpression"):
|
||||
self._proxy.setFilterRegularExpression(text_filter)
|
||||
else:
|
||||
if hasattr(self._proxy, "setFilterRegExp"):
|
||||
self._proxy.setFilterRegExp(text_filter)
|
||||
else:
|
||||
self._proxy.setFilterRegularExpression(text_filter)
|
||||
|
||||
def _on_outdated_state_change(self):
|
||||
self._proxy.set_filter_outdated(
|
||||
|
|
|
|||
|
|
@ -272,7 +272,7 @@ class SitesWidget(QtWidgets.QWidget):
|
|||
)
|
||||
|
||||
site_configs = sync_server_module.get_all_site_configs(
|
||||
self._project_name)
|
||||
self._project_name, local_editable_only=True)
|
||||
|
||||
roots_entity = (
|
||||
self.project_settings[PROJECT_ANATOMY_KEY][LOCAL_ROOTS_KEY]
|
||||
|
|
|
|||
|
|
@ -27,10 +27,10 @@ class RecursiveSortFilterProxyModel(QtCore.QSortFilterProxyModel):
|
|||
if not parent.isValid():
|
||||
return False
|
||||
|
||||
if hasattr(self, "filterRegularExpression"):
|
||||
regex = self.filterRegularExpression()
|
||||
else:
|
||||
if hasattr(self, "filterRegExp"):
|
||||
regex = self.filterRegExp()
|
||||
else:
|
||||
regex = self.filterRegularExpression()
|
||||
|
||||
pattern = regex.pattern()
|
||||
if pattern and regex.isValid():
|
||||
|
|
@ -111,10 +111,10 @@ class SearchEntitiesDialog(QtWidgets.QDialog):
|
|||
|
||||
def _on_filter_timer(self):
|
||||
text = self._filter_edit.text()
|
||||
if hasattr(self._proxy, "setFilterRegularExpression"):
|
||||
self._proxy.setFilterRegularExpression(text)
|
||||
else:
|
||||
if hasattr(self._proxy, "setFilterRegExp"):
|
||||
self._proxy.setFilterRegExp(text)
|
||||
else:
|
||||
self._proxy.setFilterRegularExpression(text)
|
||||
|
||||
# WARNING This expanding and resizing is relatively slow.
|
||||
self._view.expandAll()
|
||||
|
|
|
|||
|
|
@ -5,10 +5,10 @@ from qtpy import QtCore
|
|||
class RecursiveSortFilterProxyModel(QtCore.QSortFilterProxyModel):
|
||||
"""Filters to the regex if any of the children matches allow parent"""
|
||||
def filterAcceptsRow(self, row, parent):
|
||||
if hasattr(self, "filterRegularExpression"):
|
||||
regex = self.filterRegularExpression()
|
||||
else:
|
||||
if hasattr(self, "filterRegExp"):
|
||||
regex = self.filterRegExp()
|
||||
else:
|
||||
regex = self.filterRegularExpression()
|
||||
pattern = regex.pattern()
|
||||
if pattern:
|
||||
model = self.sourceModel()
|
||||
|
|
|
|||
|
|
@ -202,11 +202,20 @@ class RecursiveSortFilterProxyModel(QtCore.QSortFilterProxyModel):
|
|||
Use case: Filtering by string - parent won't be filtered if does not match
|
||||
the filter string but first checks if any children does.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(RecursiveSortFilterProxyModel, self).__init__(*args, **kwargs)
|
||||
recursive_enabled = False
|
||||
if hasattr(self, "setRecursiveFilteringEnabled"):
|
||||
self.setRecursiveFilteringEnabled(True)
|
||||
recursive_enabled = True
|
||||
self._recursive_enabled = recursive_enabled
|
||||
|
||||
def filterAcceptsRow(self, row, parent_index):
|
||||
if hasattr(self, "filterRegularExpression"):
|
||||
regex = self.filterRegularExpression()
|
||||
else:
|
||||
if hasattr(self, "filterRegExp"):
|
||||
regex = self.filterRegExp()
|
||||
else:
|
||||
regex = self.filterRegularExpression()
|
||||
|
||||
pattern = regex.pattern()
|
||||
if pattern:
|
||||
|
|
@ -219,8 +228,9 @@ class RecursiveSortFilterProxyModel(QtCore.QSortFilterProxyModel):
|
|||
|
||||
# Check current index itself
|
||||
value = model.data(source_index, self.filterRole())
|
||||
if re.search(pattern, value, re.IGNORECASE):
|
||||
return True
|
||||
matched = bool(re.search(pattern, value, re.IGNORECASE))
|
||||
if matched or self._recursive_enabled:
|
||||
return matched
|
||||
|
||||
rows = model.rowCount(source_index)
|
||||
for idx in range(rows):
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue