diff --git a/pyblish_lite/control.py b/pyblish_lite/control.py index c4df7eb..ff805fc 100644 --- a/pyblish_lite/control.py +++ b/pyblish_lite/control.py @@ -120,7 +120,6 @@ def _process(self, plugin, instance=None): """ self.processing["nextOrder"] = plugin.order - try: result = pyblish.plugin.process(plugin, self.context, instance) @@ -148,7 +147,9 @@ def _run(self, until=float("inf"), on_finished=lambda: None): """ def on_next(): - if self.current_pair == (None, None): + plugin, instance = self.current_pair + + if (plugin, instance) == (None, None): return util.defer(100, on_finished_) # The magic number 0.5 is the range between @@ -159,10 +160,17 @@ def on_next(): # # TODO(marcus): Make this less magical # - order = self.current_pair[0].order - if order > (until + 0.5): + if plugin.order > (until + 0.5): return util.defer(100, on_finished_) + # Support data["publish"] = False + if instance is not None: + if not instance.data.get("publish", True): + try: + self.current_pair = next(self.pair_generator) + except: + return util.defer(100, on_finished_) + self.about_to_process.emit(*self.current_pair) util.defer(10, on_process) diff --git a/pyblish_lite/model.py b/pyblish_lite/model.py index d819f60..02ea6ba 100644 --- a/pyblish_lite/model.py +++ b/pyblish_lite/model.py @@ -28,6 +28,8 @@ from .awesome import tags as awesome from .vendor.Qt import QtCore, __binding__ +from pyblish.logic import plugins_by_families + # GENERAL # The original object; Instance or Plugin @@ -162,6 +164,7 @@ def restore_checkstate(self): for uid, state in self.checkstate.items(): if uid == "{families}.{label}".format(**locals()): self.setData(index, state, IsChecked) + self.dataChanged.emit(index, index) break @@ -290,7 +293,7 @@ def setData(self, index, value, role): key = self.schema.get(role) if key is None: - return + return False setattr(item, key, value) @@ -299,6 +302,8 @@ def setData(self, index, value, role): else: self.dataChanged.emit(index, index, [role]) + return True + def update_with_result(self, result, action=False): item = result["plugin"] @@ -375,7 +380,7 @@ def setData(self, index, value, role): key = self.schema.get(role) if key is None: - return + return False item.data[key] = value @@ -384,6 +389,8 @@ def setData(self, index, value, role): else: self.dataChanged.emit(index, index, [role]) + return True + def update_with_result(self, result): item = result["instance"] @@ -455,7 +462,7 @@ def setData(self, index, value, role): key = self.schema.get(role) if key is None: - return + return False item[key] = value @@ -464,6 +471,8 @@ def setData(self, index, value, role): else: self.dataChanged.emit(index, index, [role]) + return True + def update_with_result(self, result): for record in result["records"]: self.append({ @@ -520,7 +529,7 @@ def __init__(self, source, parent=None): self.setSourceModel(source) self.excludes = dict() - self.includes = {'families': ['*']} + self.includes = {'families': []} def item(self, index): index = self.index(index, 0, QtCore.QModelIndex()) @@ -530,7 +539,7 @@ def item(self, index): def reset(self): self.beginResetModel() - self.includes = {'families': ['*']} + self.includes = {'families': []} self.endResetModel() def add_exclusion(self, role, value): @@ -597,7 +606,8 @@ def _add_rule(self, group, role, value): if role not in group: group[role] = list() - group[role].append(value) + if value not in group[role]: + group[role].append(value) self.invalidate() @@ -640,10 +650,8 @@ def filterAcceptsRow(self, source_row, source_parent): match = regex.indexIn(key) return False if match == -1 else True - # --- Check if any family assigned to the plugin is in allowed families - for role, values in self.includes.items(): - includes_list = [([x] if isinstance(x, (list, tuple)) else x) for x in getattr(item, role, None)] - return any(include in values for include in includes_list) + if not plugins_by_families([item], self.includes['families']): + return False for role, values in self.excludes.items(): data = getattr(item, role, None) diff --git a/pyblish_lite/version.py b/pyblish_lite/version.py index 1004c19..18ad251 100644 --- a/pyblish_lite/version.py +++ b/pyblish_lite/version.py @@ -1,7 +1,7 @@ VERSION_MAJOR = 0 VERSION_MINOR = 7 -VERSION_PATCH = 4 +VERSION_PATCH = 5 version_info = (VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH) diff --git a/pyblish_lite/view.py b/pyblish_lite/view.py index 2d560e7..207968b 100644 --- a/pyblish_lite/view.py +++ b/pyblish_lite/view.py @@ -1,4 +1,5 @@ from .vendor.Qt import QtCore, QtWidgets +from .model import IsChecked class Item(QtWidgets.QListView): @@ -59,6 +60,8 @@ def mousePressEvent(self, event): def mouseReleaseEvent(self, event): if event.button() == QtCore.Qt.LeftButton: indexes = self.selectionModel().selectedIndexes() + + # Allow drag-select across checkboxes. if len(indexes) <= 1 and event.pos().x() < 20: for index in indexes: self.toggled.emit(index, None) diff --git a/pyblish_lite/window.py b/pyblish_lite/window.py index 47c5806..cef1c28 100644 --- a/pyblish_lite/window.py +++ b/pyblish_lite/window.py @@ -357,11 +357,11 @@ def __init__(self, controller, parent=None): plugin_model = model.Plugin() terminal_model = model.Terminal() - filter_model = model.ProxyModel(plugin_model) + plugin_proxy_model = model.ProxyModel(plugin_model) artist_view.setModel(instance_model) left_view.setModel(instance_model) - right_view.setModel(filter_model) + right_view.setModel(plugin_proxy_model) terminal_view.setModel(terminal_model) instance_combo.setModel(instance_model) @@ -431,7 +431,7 @@ def __init__(self, controller, parent=None): "models": { "instances": instance_model, "plugins": plugin_model, - "filter": filter_model, + "pluginsProxy": plugin_proxy_model, "terminal": terminal_model, }, "terminal_toggles": { @@ -641,6 +641,8 @@ def on_item_toggled(self, index, state=None): # Emit signals if index.data(model.Type) == "instance": + self.update_proxy_models() + instance = self.data["models"]["instances"].items[index.row()] util.defer( 100, lambda: self.controller.emit_( @@ -739,7 +741,7 @@ def on_plugin_action_menu_requested(self, pos): return menu = QtWidgets.QMenu(self) - plugins_index = self.data["models"]["filter"].mapToSource(index) + plugins_index = self.data["models"]["pluginsProxy"].mapToSource(index) plugin = self.data["models"]["plugins"].items[plugins_index.row()] print("plugin is: %s" % plugin) @@ -774,6 +776,8 @@ def on_was_reset(self): models["instances"].restore_checkstate() models["plugins"].restore_checkstate() + self.update_proxy_models() + # Append placeholder comment from Context # This allows users to inject a comment from elsewhere, # or to perhaps provide a placeholder comment/template @@ -833,21 +837,35 @@ def on_was_processed(self, result): if instance.id not in models["instances"].ids: models["instances"].append(instance) + plugins_filter = self.data["models"]["pluginsProxy"] + family = instance.data["family"] if family: - plugins_filter = self.data["models"]["filter"] plugins_filter.add_inclusion(role="families", value=family) families = instance.data.get("families") if families: for f in families: - plugins_filter = self.data["models"]["filter"] plugins_filter.add_inclusion(role="families", value=f) models["plugins"].update_with_result(result) models["instances"].update_with_result(result) models["terminal"].update_with_result(result) + def update_proxy_models(self): + proxy = self.data["models"]["pluginsProxy"] + proxy.reset() + + # Filter based on remaining checked instances + for instance in self.data["models"]["instances"]: + if not instance.data(model.IsChecked): + continue + + for family in instance.data(model.Families): + proxy.add_inclusion(role="families", value=family) + + proxy.invalidate() + def on_was_acted(self, result): buttons = self.data["buttons"] buttons["reset"].show() diff --git a/tests/test_model.py b/tests/test_model.py index 5827f67..704f68f 100644 --- a/tests/test_model.py +++ b/tests/test_model.py @@ -1,9 +1,19 @@ import logging +# Vendor libraries +from nose.tools import ( + with_setup, +) + +import pyblish.api from pyblish_lite import model from pyblish_lite.vendor import six +def clean(): + pyblish.api.deregister_all_plugins() + + def test_label_nonstring(): """Logging things that aren't string is fine""" @@ -27,3 +37,47 @@ def test_label_nonstring(): for item in model_: assert isinstance(item.data(model.Label), six.text_type), ( "\"%s\" wasn't a string!" % item.data(model.Label)) + + +@with_setup(clean) +def test_proxy_hideinactive(): + """Plug-ins without active instances are hidden""" + + count = {"#": 0} + + class MyCollector(pyblish.api.ContextPlugin): + order = pyblish.api.CollectorOrder + + def process(self, context): + instance = context.create_instance("MyInstance") + instance.data["families"] = ["myFamily"] + count["#"] += 1 + + class OldValidator(pyblish.api.Validator): + """Old-style plug-in, not using InstancePlugin""" + + families = ["myFamily"] + order = 20 + + def process(self, instance): + count["#"] += 10 + + class NewValidator(pyblish.api.InstancePlugin): + families = ["myFamily"] + order = 20 + + def process(self, instance): + count["#"] += 100 + + pyblish.api.register_plugin(MyCollector) + pyblish.api.register_plugin(OldValidator) + pyblish.api.register_plugin(NewValidator) + + ctrl = control.Controller() + ctrl.reset() + + assert count["#"] == 1, count + + ctrl.publish() + + assert count["#"] == 111, count \ No newline at end of file