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

app/proc: Load real procedures and upgrade viz #58

Merged
merged 8 commits into from
Oct 6, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions application/application.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import os
import sys

from PySide2.QtGui import QGuiApplication, QIcon
from PySide2.QtGui import QIcon
from PySide2.QtQml import QQmlApplicationEngine, qmlRegisterType
from PySide2.QtWidgets import QApplication

import topside as top
from .visualization_area import VisualizationArea
Expand All @@ -26,7 +27,7 @@ class Application:
def __init__(self, argv):
self.procedures_bridge = ProceduresBridge()

self.app = QGuiApplication(argv)
self.app = QApplication(argv)

# ALL custom built QQuickItems have to be registed as QML objects in this way:
qmlRegisterType(VisualizationArea, 'VisualizationArea', 1, 0, 'VisualizationArea')
Expand Down
100 changes: 61 additions & 39 deletions application/procedures_bridge.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from PySide2.QtCore import Qt, Slot, Signal, Property, \
QObject, QAbstractListModel, QModelIndex
from PySide2.QtWidgets import QFileDialog

import topside as top


# TODO(jacob): Delete this test code and load a real engine and procedure
# TODO(jacob): Delete this test code and load a real engine

class MockPlumbingEngine:
def __init__(self):
Expand All @@ -20,41 +21,35 @@ def current_pressures(self):
return {}


def build_test_procedure_suite():
open_action_1 = top.StateChangeAction('c1', 'open')
open_action_2 = top.StateChangeAction('c2', 'open')
close_action_1 = top.StateChangeAction('c1', 'closed')
close_action_2 = top.StateChangeAction('c2', 'closed')
class ProcedureConditionWrapper(QObject):
satisfied_changed_signal = Signal(name='satisfiedChanged')

# Add miscellaneous action
misc_action = top.MiscAction('Approach the tower')
def __init__(self, condition, transition, parent=None):
QObject.__init__(self, parent=parent)
self._condition = condition
self._transition = transition

s1 = top.ProcedureStep('s1', open_action_1, [(
top.Immediate(), top.Transition('p1', 's2'))], 'PRIMARY')
s2 = top.ProcedureStep('s2', open_action_2, [(
top.Immediate(), top.Transition('p2', 's3'))], 'CONTROL')
# TODO(jacob): Make sure this actually updates properly once we're
# managing a real plumbing engine and stepping in time.
@Property(bool, notify=satisfied_changed_signal)
def satisfied(self):
return self._condition.satisfied()

# The step contain misc action
s5 = top.ProcedureStep('s5', misc_action, [(
top.Immediate(), top.Transition('p2', 's3'))], 'MISCELLANEOUS ACTION')
@Property(str, constant=True)
def condition(self):
return str(self._condition)

p1 = top.Procedure('p1', [s1, s2, s5])

s3 = top.ProcedureStep('s3', close_action_1, [(
top.Immediate(), top.Transition('p2', 's4'))], 'OPS')
s4 = top.ProcedureStep('s4', close_action_2, [(
top.Immediate(), top.Transition('p1', 's1'))], 'SECONDARY')

p2 = top.Procedure('p2', [s3, s4])

return top.ProcedureSuite([p1, p2], 'p1')
@Property(str, constant=True)
def transition(self):
return str(self._transition)


class ProcedureStepsModel(QAbstractListModel):
PersonRoleIdx = Qt.UserRole + 1
StepRoleIdx = Qt.UserRole + 2
ActionRoleIdx = Qt.UserRole + 1
OperatorRoleIdx = Qt.UserRole + 2
ConditionsRoleIdx = Qt.UserRole + 3

def __init__(self, procedure, parent=None):
def __init__(self, procedure=None, parent=None):
QAbstractListModel.__init__(self, parent)
self.procedure = procedure

Expand All @@ -66,6 +61,8 @@ def change_procedure(self, new_procedure):
# Qt accessible methods

def rowCount(self, parent=QModelIndex()):
if self.procedure is None:
return 0
return len(self.procedure.steps)

def roleNames(self):
Expand All @@ -75,24 +72,31 @@ def roleNames(self):
# error ('expected hash, got dict'). See below:
# https://bugreports.qt.io/browse/PYSIDE-703
return {
ProcedureStepsModel.PersonRoleIdx: b'person',
ProcedureStepsModel.StepRoleIdx: b'step'
ProcedureStepsModel.ActionRoleIdx: b'action',
ProcedureStepsModel.OperatorRoleIdx: b'operator',
ProcedureStepsModel.ConditionsRoleIdx: b'conditions'
}

def data(self, index, role):
if self.procedure is None:
return None

try:
step = self.procedure.step_list[index.row()]
except IndexError:
return 'Invalid Index'
if role == ProcedureStepsModel.PersonRoleIdx:
return step.operator
elif role == ProcedureStepsModel.StepRoleIdx:

if role == ProcedureStepsModel.ActionRoleIdx:
action = step.action
# Check if misc action or not
if type(action) == top.StateChangeAction:
return f'Set {action.component} to {action.state}'
elif type(action) == top.MiscAction:
return f'{action.action_type}'
elif role == ProcedureStepsModel.OperatorRoleIdx:
return step.operator
elif role == ProcedureStepsModel.ConditionsRoleIdx:
return [ProcedureConditionWrapper(cond, trans, self) for cond, trans in step.conditions]

return None


Expand All @@ -104,15 +108,20 @@ def __init__(self):
QObject.__init__(self)

plumb = MockPlumbingEngine()
suite = build_test_procedure_suite()

self._procedures_engine = top.ProceduresEngine(plumb, suite)
self._procedure_steps = ProcedureStepsModel(self._procedures_engine.current_procedure())
self._procedures_engine = top.ProceduresEngine(plumb)
self._procedure_steps = ProcedureStepsModel()
self._refresh_procedure_view()

def _refresh_procedure_view(self):
proc = self._procedures_engine.current_procedure()
displayed_proc = self._procedure_steps.procedure

if self._procedure_steps.procedure.procedure_id != proc.procedure_id:
if proc is None:
self._procedure_steps.change_procedure(None)
return

if displayed_proc != proc:
self._procedure_steps.change_procedure(proc)

idx = proc.index_of(self._procedures_engine.current_step.step_id)
Expand All @@ -122,6 +131,17 @@ def _refresh_procedure_view(self):
def steps(self):
return self._procedure_steps

@Slot()
def loadProcedureSuite(self):
# TODO(jacob): Make this menu remember the last file opened
filepath, _ = QFileDialog.getOpenFileName(self.parent(), 'Load ProcLang file')
if filepath != '':
with open(filepath) as f:
proclang = f.read()
suite = top.proclang.parse(proclang)
self._procedures_engine.load_suite(suite)
self._refresh_procedure_view()

@Slot()
def playBackwards(self):
pass
Expand All @@ -140,7 +160,9 @@ def pause(self):

@Slot()
def stop(self):
pass
# TODO(jacob): Should this reset the plumbing engine as well?
self._procedures_engine.reset()
self._refresh_procedure_view()

@Slot()
def stepForward(self):
Expand Down
Loading