From 12f75e476dcb0b2c5e2a976d9b65e8a3b38ac5e3 Mon Sep 17 00:00:00 2001 From: p4vv37 Date: Tue, 17 Jan 2017 19:03:56 +0100 Subject: [PATCH 1/6] Hides plugins without checked instances now Also: simplified families matching, based on pyblish-bese elements --- pyblish_lite/model.py | 12 ++++++------ pyblish_lite/window.py | 21 +++++++++++++++++++-- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/pyblish_lite/model.py b/pyblish_lite/model.py index d819f60..9f1b188 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 @@ -520,7 +522,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 +532,7 @@ def item(self, index): def reset(self): self.beginResetModel() - self.includes = {'families': ['*']} + self.includes = {'families': []} self.endResetModel() def add_exclusion(self, role, value): @@ -640,10 +642,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/window.py b/pyblish_lite/window.py index 8900b8e..9746fb0 100644 --- a/pyblish_lite/window.py +++ b/pyblish_lite/window.py @@ -640,6 +640,23 @@ def on_item_toggled(self, index, state=None): # Emit signals if index.data(model.Type) == "instance": + + instances = [index.data(model.Data) for index in self.data["models"]["instances"] + if index.data(model.IsChecked)] + + plugins_filter = self.data["models"]["filter"] + plugins_filter.reset() + + for instance in instances: + family = instance["family"] + if family: + plugins_filter.add_inclusion(role="families", value=family) + + families = instance.get("families") + if families: + for f in families: + plugins_filter.add_inclusion(role="families", value=f) + util.defer( 100, lambda: self.controller.emit_( signal="instanceToggled", @@ -833,15 +850,15 @@ def on_was_processed(self, result): if instance.id not in models["instances"].ids: models["instances"].append(instance) + plugins_filter = self.data["models"]["filter"] + 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) From ff002f40a6dcb2638bceda373b8b16933fa02aa0 Mon Sep 17 00:00:00 2001 From: p4vv37 Date: Mon, 23 Jan 2017 10:41:51 +0100 Subject: [PATCH 2/6] Version up --- pyblish_lite/version.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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) From 49057170985b6d524d9564163a5de6009513ca89 Mon Sep 17 00:00:00 2001 From: "michal.krupa" Date: Thu, 2 Feb 2017 17:32:12 +0100 Subject: [PATCH 3/6] Fixed bug with current_pair processed even if instance disabled --- pyblish_lite/control.py | 8 +++++++- pyblish_lite/model.py | 7 ++++++- pyblish_lite/view.py | 10 ++++++++-- pyblish_lite/window.py | 20 ++++++++++++++++++++ 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/pyblish_lite/control.py b/pyblish_lite/control.py index c4df7eb..26000c3 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) @@ -159,6 +158,13 @@ def on_next(): # # TODO(marcus): Make this less magical # + if self.current_pair[1] is not None: + if self.current_pair[1].data.get("publish", True) is False: + try: + self.current_pair = next(self.pair_generator) + except: + return util.defer(100, on_finished_) + order = self.current_pair[0].order if order > (until + 0.5): return util.defer(100, on_finished_) diff --git a/pyblish_lite/model.py b/pyblish_lite/model.py index 9f1b188..216d754 100644 --- a/pyblish_lite/model.py +++ b/pyblish_lite/model.py @@ -164,6 +164,10 @@ def restore_checkstate(self): for uid, state in self.checkstate.items(): if uid == "{families}.{label}".format(**locals()): self.setData(index, state, IsChecked) + try: + self.dataChanged.emit(index, index) + except: + self.dataChanged.emit(index, index, []) break @@ -599,7 +603,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() diff --git a/pyblish_lite/view.py b/pyblish_lite/view.py index 2d560e7..317569d 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,9 +60,14 @@ def mousePressEvent(self, event): def mouseReleaseEvent(self, event): if event.button() == QtCore.Qt.LeftButton: indexes = self.selectionModel().selectedIndexes() - if len(indexes) <= 1 and event.pos().x() < 20: + + if len(indexes) >= 1 and event.pos().x() < 20: + checked = indexes[0].model().data(indexes[0], IsChecked) + for index in indexes: - self.toggled.emit(index, None) + current_item_checked = index.model().data(index, IsChecked) + if checked == current_item_checked: + self.toggled.emit(index, None) return super(Item, self).mouseReleaseEvent(event) diff --git a/pyblish_lite/window.py b/pyblish_lite/window.py index 32216d3..f3b5579 100644 --- a/pyblish_lite/window.py +++ b/pyblish_lite/window.py @@ -792,6 +792,8 @@ def on_was_reset(self): models["instances"].restore_checkstate() models["plugins"].restore_checkstate() + self.on_after_reset_filter() + # Append placeholder comment from Context # This allows users to inject a comment from elsewhere, # or to perhaps provide a placeholder comment/template @@ -866,6 +868,24 @@ def on_was_processed(self, result): models["instances"].update_with_result(result) models["terminal"].update_with_result(result) + def on_after_reset_filter(self): + plugins_filter = self.data["models"]["filter"] + plugins_filter.reset() + for instance in self.controller.context: + if instance.data.get("publish", True) is False: + continue + + family = instance.data["family"] + if family: + plugins_filter.add_inclusion(role="families", value=family) + + families = instance.data.get("families") + + if families: + for f in families: + plugins_filter.add_inclusion(role="families", value=f) + plugins_filter.invalidate() + def on_was_acted(self, result): buttons = self.data["buttons"] buttons["reset"].show() From 71057948cf16a20e76e615251f6af614575dbfa2 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Sun, 22 Jan 2017 17:16:14 +0000 Subject: [PATCH 4/6] Add test for proxy model --- tests/test_model.py | 54 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) 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 From 52db0de8d0b471760f613e329a088d5d86014279 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Sat, 11 Mar 2017 18:19:37 +0000 Subject: [PATCH 5/6] Relative import, restore release event Without a relative import, Lite would only run with a CWD inside of the repository itself. About the release event, see note. --- pyblish_lite/view.py | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/pyblish_lite/view.py b/pyblish_lite/view.py index 317569d..207968b 100644 --- a/pyblish_lite/view.py +++ b/pyblish_lite/view.py @@ -1,5 +1,5 @@ from .vendor.Qt import QtCore, QtWidgets -from model import IsChecked +from .model import IsChecked class Item(QtWidgets.QListView): @@ -61,13 +61,10 @@ def mouseReleaseEvent(self, event): if event.button() == QtCore.Qt.LeftButton: indexes = self.selectionModel().selectedIndexes() - if len(indexes) >= 1 and event.pos().x() < 20: - checked = indexes[0].model().data(indexes[0], IsChecked) - + # Allow drag-select across checkboxes. + if len(indexes) <= 1 and event.pos().x() < 20: for index in indexes: - current_item_checked = index.model().data(index, IsChecked) - if checked == current_item_checked: - self.toggled.emit(index, None) + self.toggled.emit(index, None) return super(Item, self).mouseReleaseEvent(event) From 875d8b17e8eeee575c4bafae7944492e1c8107c5 Mon Sep 17 00:00:00 2001 From: Marcus Ottosson Date: Sat, 11 Mar 2017 18:20:20 +0000 Subject: [PATCH 6/6] Reduce and refactor --- pyblish_lite/control.py | 16 +++++++------ pyblish_lite/model.py | 17 +++++++------ pyblish_lite/window.py | 53 +++++++++++++---------------------------- 3 files changed, 36 insertions(+), 50 deletions(-) diff --git a/pyblish_lite/control.py b/pyblish_lite/control.py index 26000c3..ff805fc 100644 --- a/pyblish_lite/control.py +++ b/pyblish_lite/control.py @@ -147,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 @@ -158,17 +160,17 @@ def on_next(): # # TODO(marcus): Make this less magical # - if self.current_pair[1] is not None: - if self.current_pair[1].data.get("publish", True) is False: + 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_) - order = self.current_pair[0].order - if order > (until + 0.5): - 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 216d754..02ea6ba 100644 --- a/pyblish_lite/model.py +++ b/pyblish_lite/model.py @@ -164,10 +164,7 @@ def restore_checkstate(self): for uid, state in self.checkstate.items(): if uid == "{families}.{label}".format(**locals()): self.setData(index, state, IsChecked) - try: - self.dataChanged.emit(index, index) - except: - self.dataChanged.emit(index, index, []) + self.dataChanged.emit(index, index) break @@ -296,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) @@ -305,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"] @@ -381,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 @@ -390,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"] @@ -461,7 +462,7 @@ def setData(self, index, value, role): key = self.schema.get(role) if key is None: - return + return False item[key] = value @@ -470,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({ diff --git a/pyblish_lite/window.py b/pyblish_lite/window.py index f3b5579..fb44cb6 100644 --- a/pyblish_lite/window.py +++ b/pyblish_lite/window.py @@ -356,11 +356,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) @@ -430,7 +430,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": { @@ -640,22 +640,7 @@ def on_item_toggled(self, index, state=None): # Emit signals if index.data(model.Type) == "instance": - - instances = [index.data(model.Data) for index in self.data["models"]["instances"] - if index.data(model.IsChecked)] - - plugins_filter = self.data["models"]["filter"] - plugins_filter.reset() - - for instance in instances: - family = instance["family"] - if family: - plugins_filter.add_inclusion(role="families", value=family) - - families = instance.get("families") - if families: - for f in families: - plugins_filter.add_inclusion(role="families", value=f) + self.update_proxy_models() instance = self.data["models"]["instances"].items[index.row()] util.defer( @@ -755,7 +740,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) @@ -792,7 +777,7 @@ def on_was_reset(self): models["instances"].restore_checkstate() models["plugins"].restore_checkstate() - self.on_after_reset_filter() + self.update_proxy_models() # Append placeholder comment from Context # This allows users to inject a comment from elsewhere, @@ -853,7 +838,7 @@ def on_was_processed(self, result): if instance.id not in models["instances"].ids: models["instances"].append(instance) - plugins_filter = self.data["models"]["filter"] + plugins_filter = self.data["models"]["pluginsProxy"] family = instance.data["family"] if family: @@ -868,23 +853,19 @@ def on_was_processed(self, result): models["instances"].update_with_result(result) models["terminal"].update_with_result(result) - def on_after_reset_filter(self): - plugins_filter = self.data["models"]["filter"] - plugins_filter.reset() - for instance in self.controller.context: - if instance.data.get("publish", True) is False: - continue + def update_proxy_models(self): + proxy = self.data["models"]["pluginsProxy"] + proxy.reset() - family = instance.data["family"] - if family: - plugins_filter.add_inclusion(role="families", value=family) + # Filter based on remaining checked instances + for instance in self.data["models"]["instances"]: + if not instance.data(model.IsChecked): + continue - families = instance.data.get("families") + for family in instance.data(model.Families): + proxy.add_inclusion(role="families", value=family) - if families: - for f in families: - plugins_filter.add_inclusion(role="families", value=f) - plugins_filter.invalidate() + proxy.invalidate() def on_was_acted(self, result): buttons = self.data["buttons"]