Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Opt-in PySide2 via Qt5.py #354

Merged
merged 13 commits into from
Feb 9, 2020
3 changes: 1 addition & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,7 @@ MAINTAINER marcus@abstractfactory.io
RUN apt-get update && apt-get install -y \
build-essential \
git \
python3-pyqt5 \
python3-pyqt5.qtquick \
python3-pyqt5* \
python3-pip \
python3-nose && \
pip3 install \
Expand Down
32 changes: 14 additions & 18 deletions pyblish_qml/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,9 @@
import traceback
import threading

# Dependencies
from PyQt5 import QtCore, QtGui, QtQuick, QtTest

# Local libraries
from . import util, compat, control, settings, ipc
from .vendor.Qt5 import QtCore, QtGui, QtQuick

MODULE_DIR = os.path.dirname(__file__)
QML_IMPORT_DIR = os.path.join(MODULE_DIR, "qml")
Expand Down Expand Up @@ -64,17 +62,17 @@ class Application(QtGui.QGuiApplication):

"""

shown = QtCore.pyqtSignal(QtCore.QVariant)
hidden = QtCore.pyqtSignal()
quitted = QtCore.pyqtSignal()
published = QtCore.pyqtSignal()
validated = QtCore.pyqtSignal()
shown = QtCore.Signal("QVariant")
hidden = QtCore.Signal()
quitted = QtCore.Signal()
published = QtCore.Signal()
validated = QtCore.Signal()

targeted = QtCore.pyqtSignal(QtCore.QVariant)
targeted = QtCore.Signal("QVariant")

risen = QtCore.pyqtSignal()
inFocused = QtCore.pyqtSignal()
outFocused = QtCore.pyqtSignal()
risen = QtCore.Signal()
inFocused = QtCore.Signal()
outFocused = QtCore.Signal()

def __init__(self, source, targets=[]):
super(Application, self).__init__(sys.argv)
Expand All @@ -88,7 +86,7 @@ def __init__(self, source, targets=[]):
engine.addImportPath(QML_IMPORT_DIR)

host = ipc.client.Proxy()
controller = control.Controller(host, targets=targets)
controller = control.Controller(host, targets=targets, parent=window)
controller.finished.connect(lambda: window.alert(0))

context = engine.rootContext()
Expand Down Expand Up @@ -176,11 +174,7 @@ def show(self, client_settings=None):
for state in ["ready", "finished"]):
util.timer("ready")

ready = QtTest.QSignalSpy(self.controller.ready)

count = len(ready)
ready.wait(1000)
if len(ready) != count + 1:
if not self.controller.is_ready():
print("Warning: Could not enter ready state")

util.timer_end("ready", "Awaited statemachine for %.2f ms")
Expand Down Expand Up @@ -214,12 +208,14 @@ def inFocus(self):
previous_flags = self.window.flags()
self.window.setFlags(previous_flags |
QtCore.Qt.WindowStaysOnTopHint)
self.window.setFlags(previous_flags)

def outFocus(self):
"""Remove GUI on-top flag"""
previous_flags = self.window.flags()
self.window.setFlags(previous_flags ^
QtCore.Qt.WindowStaysOnTopHint)
self.window.setFlags(previous_flags)

def publish(self):
"""Fire up the publish sequence"""
Expand Down
104 changes: 57 additions & 47 deletions pyblish_qml/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,52 +4,52 @@
import collections

# Dependencies
from PyQt5 import QtCore
import pyblish.logic

# Local libraries
from . import util, models, version, settings
from .vendor.Qt5 import QtCore

qtproperty = util.pyqtConstantProperty
qtproperty = util.qtConstantProperty


class Controller(QtCore.QObject):
"""Communicate with QML"""

# PyQt Signals
info = QtCore.pyqtSignal(str, arguments=["message"])
error = QtCore.pyqtSignal(str, arguments=["message"])
# Signals
info = QtCore.Signal(str, arguments=["message"])
error = QtCore.Signal(str, arguments=["message"])

show = QtCore.pyqtSignal()
hide = QtCore.pyqtSignal()
show = QtCore.Signal()
hide = QtCore.Signal()

firstRun = QtCore.pyqtSignal()
firstRun = QtCore.Signal()

collecting = QtCore.pyqtSignal()
validating = QtCore.pyqtSignal()
extracting = QtCore.pyqtSignal()
integrating = QtCore.pyqtSignal()
collecting = QtCore.Signal()
validating = QtCore.Signal()
extracting = QtCore.Signal()
integrating = QtCore.Signal()

repairing = QtCore.pyqtSignal()
stopping = QtCore.pyqtSignal()
saving = QtCore.pyqtSignal()
initialising = QtCore.pyqtSignal()
acting = QtCore.pyqtSignal()
acted = QtCore.pyqtSignal()
repairing = QtCore.Signal()
stopping = QtCore.Signal()
saving = QtCore.Signal()
initialising = QtCore.Signal()
acting = QtCore.Signal()
acted = QtCore.Signal()

# A plug-in/instance pair is about to be processed
about_to_process = QtCore.pyqtSignal(object, object)
about_to_process = QtCore.Signal(object, object)

changed = QtCore.pyqtSignal()
changed = QtCore.Signal()

ready = QtCore.pyqtSignal()
saved = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
initialised = QtCore.pyqtSignal()
commented = QtCore.pyqtSignal()
commenting = QtCore.pyqtSignal(str, arguments=["comment"])
ready = QtCore.Signal()
saved = QtCore.Signal()
finished = QtCore.Signal()
initialised = QtCore.Signal()
commented = QtCore.Signal()
commenting = QtCore.Signal(str, arguments=["comment"])

state_changed = QtCore.pyqtSignal(str, arguments=["state"])
state_changed = QtCore.Signal(str, arguments=["state"])

# Statically expose these members to the QML run-time.
itemModel = qtproperty(lambda self: self.data["models"]["item"])
Expand Down Expand Up @@ -107,6 +107,7 @@ def __init__(self, host, parent=None, targets=[]):
},
"state": {
"is_running": False,
"readyCount": 0,
"current": None,
"all": list(),

Expand All @@ -125,6 +126,7 @@ def __init__(self, host, parent=None, targets=[]):
self.info.connect(self.on_info)
self.error.connect(self.on_error)
self.finished.connect(self.on_finished)
self.ready.connect(self.on_ready)
self.show.connect(self.on_show)

# NOTE: Listeners to this signal are run in the main thread
Expand Down Expand Up @@ -291,28 +293,28 @@ def setup_statemachine(self):
machine.start()
return machine

@QtCore.pyqtSlot(result=str)
@QtCore.Slot(result=str)
def comment(self):
"""Return first line of comment"""
return self.data["comment"]

@QtCore.pyqtProperty(str, notify=state_changed)
@QtCore.Property(str, notify=state_changed)
def state(self):
return self.data["state"]["current"]

@QtCore.pyqtProperty(bool, notify=commented)
@QtCore.Property(bool, notify=commented)
def hasComment(self):
return True if self.data["comment"] else False

@QtCore.pyqtProperty(bool, constant=True)
@QtCore.Property(bool, constant=True)
def commentEnabled(self):
return "comment" in self.host.cached_context.data

@property
def states(self):
return self.data["state"]["all"]

@QtCore.pyqtSlot(result=float)
@QtCore.Slot(result=float)
def time(self):
return time.time()

Expand Down Expand Up @@ -377,7 +379,7 @@ def iterator(self, plugins, context):

yield result

@QtCore.pyqtSlot(int, result=QtCore.QVariant)
@QtCore.Slot(int, result="QVariant")
def getPluginActions(self, index):
"""Return actions from plug-in at `index`

Expand Down Expand Up @@ -439,7 +441,7 @@ def getPluginActions(self, index):

return remaining_actions

@QtCore.pyqtSlot(str)
@QtCore.Slot(str)
def runPluginAction(self, action):
if "acting" in self.states:
return self.error.emit("Busy")
Expand Down Expand Up @@ -491,7 +493,7 @@ def on_finished(result):

util.defer(run, callback=on_finished)

@QtCore.pyqtSlot(int)
@QtCore.Slot(int)
def toggleInstance(self, index):
models = self.data["models"]
proxies = self.data["proxies"]
Expand All @@ -506,7 +508,7 @@ def toggleInstance(self, index):
else:
self.error.emit("Cannot toggle")

@QtCore.pyqtSlot(bool, str)
@QtCore.Slot(bool, str)
def toggleSection(self, checkState, sectionLabel):
model = self.data["models"]["item"]

Expand Down Expand Up @@ -535,7 +537,7 @@ def toggleSection(self, checkState, sectionLabel):
if item.isToggled != checkState and item.optional:
self.__toggle_item(model, model.items.index(item))

@QtCore.pyqtSlot(bool, str)
@QtCore.Slot(bool, str)
def hideSection(self, hideState, sectionLabel):
model = self.data["models"]["item"]

Expand All @@ -549,7 +551,7 @@ def hideSection(self, hideState, sectionLabel):
if item.itemType == "section" and item.name == sectionLabel:
self.__hide_item(model, model.items.index(item), hideState)

@QtCore.pyqtSlot(int, result=QtCore.QVariant)
@QtCore.Slot(int, result="QVariant")
def pluginData(self, index):
models = self.data["models"]
proxies = self.data["proxies"]
Expand All @@ -559,7 +561,7 @@ def pluginData(self, index):
source_index = source_qindex.row()
return self.__item_data(models["item"], source_index)

@QtCore.pyqtSlot(int, result=QtCore.QVariant)
@QtCore.Slot(int, result="QVariant")
def instanceData(self, index):
models = self.data["models"]
proxies = self.data["proxies"]
Expand All @@ -569,7 +571,7 @@ def instanceData(self, index):
source_index = source_qindex.row()
return self.__item_data(models["item"], source_index)

@QtCore.pyqtSlot(int)
@QtCore.Slot(int)
def togglePlugin(self, index):
models = self.data["models"]
proxies = self.data["proxies"]
Expand All @@ -584,7 +586,7 @@ def togglePlugin(self, index):
else:
self.error.emit("Cannot toggle")

@QtCore.pyqtSlot(str, str, str, str)
@QtCore.Slot(str, str, str, str)
def exclude(self, target, operation, role, value):
"""Exclude a `role` of `value` at `target`

Expand All @@ -609,7 +611,7 @@ def exclude(self, target, operation, role, value):
else:
raise TypeError("operation must be either `add` or `remove`")

@QtCore.pyqtSlot()
@QtCore.Slot()
def save(self):
# Deprecated
return
Expand Down Expand Up @@ -664,6 +666,11 @@ def comment_sync(self, comment):
self.host.update(key="comment", value=comment)
self.host.emit("commented", comment=comment)

def is_ready(self):
count = self.data["state"]["readyCount"]
util.wait(self.ready, 1000)
return self.data["state"]["readyCount"] == count + 1

# Event handlers

def on_commenting(self, comment):
Expand Down Expand Up @@ -712,6 +719,9 @@ def on_state_changed(self, state):
s.name for s in self.machine.configuration()
)

def on_ready(self):
self.data["state"]["readyCount"] += 1

def on_finished(self):
self.data["models"]["item"].reset_status()

Expand All @@ -733,12 +743,12 @@ def on_info(self, message):

# Slots

@QtCore.pyqtSlot()
@QtCore.Slot()
def stop(self):
self.data["state"]["is_running"] = False
self.stopping.emit()

@QtCore.pyqtSlot()
@QtCore.Slot()
def reset(self):
"""Request that host re-discovers plug-ins and re-processes selectors

Expand Down Expand Up @@ -885,7 +895,7 @@ def on_reset():

util.defer(self.host.reset, callback=on_reset)

@QtCore.pyqtSlot()
@QtCore.Slot()
def publish(self):
"""Start asynchonous publishing

Expand Down Expand Up @@ -942,7 +952,7 @@ def on_finished():

util.defer(get_data, callback=on_data_received)

@QtCore.pyqtSlot()
@QtCore.Slot()
def validate(self):
"""Start asynchonous validation

Expand Down Expand Up @@ -1102,7 +1112,7 @@ def on_finished(message=None):
iterator = self.iterator(plugins, context)
util.defer(lambda: next(iterator), callback=on_next)

@QtCore.pyqtSlot(int)
@QtCore.Slot(int)
def repairPlugin(self, index):
"""

Expand Down
Loading