Commit 533f4d8a authored by Maxime Perrotin's avatar Maxime Perrotin

Bugfixes with nested states

parent 1c5933ff
......@@ -15,12 +15,14 @@
This module is managing the Copy and Paste functions.
"""
import logging
from itertools import chain
import PySide
import ogAST
import sdlSymbols
import genericSymbols
import logging
import Renderer
import PySide
__all__ = ['copy', 'paste']
......@@ -120,6 +122,8 @@ def paste_floating_objects(scene):
states = [i for i in item_list if isinstance(i, ogAST.State)]
text_areas = (i for i in item_list if isinstance(i, ogAST.TextArea))
labels = (i for i in item_list if isinstance(i, ogAST.Floating_label))
procedures = (i for i in item_list if isinstance(i, ogAST.Procedure))
processes = (i for i in item_list if isinstance(i, ogAST.Process))
for state in states:
# First check if state has already been pasted
try:
......@@ -133,20 +137,16 @@ def paste_floating_objects(scene):
LOG.debug('PASTE STATE "' + state.inputString + '"')
symbols.append(new_item)
# Insert the new state at click coordinates
scene.addItem(new_item)
for text_area in text_areas:
LOG.debug('PASTE TEXT AREA')
new_item = Renderer.render(text_area, scene)
symbols.append(new_item)
for label in labels:
LOG.debug('PASTE LABEL')
new_item = Renderer.render(label, scene, states=states)
Renderer.add_to_scene(new_item, scene)
for each in chain(text_areas, labels, procedures, processes):
LOG.debug('PASTE TA/LAB/PROC')
new_item = Renderer.render(each, scene, states=states)
symbols.append(new_item)
if start:
start, = start
LOG.debug('PASTE START')
for item in scene.items():
if isinstance(item, sdlSymbols.Start) and item.isVisible():
for item in scene.visible_symb:
if isinstance(item, sdlSymbols.Start):
raise TypeError('Only one START symbol is possible')
new_item = Renderer.render(start, scene, states=states)
symbols.append(new_item)
......@@ -168,7 +168,7 @@ def paste_below_item(parent, scene):
# Check that item is compatible with parent
if (type(new_item).__name__ in parent.allowed_followers):
# Move the item from the clipboard to the scene
scene.addItem(new_item)
Renderer.add_to_scene(new_item, scene)
new_item.setPos(0, 0)
symbols.append(new_item)
else:
......
......@@ -27,7 +27,6 @@ from PySide.QtGui import QGraphicsPathItem, QPainterPath, QGraphicsItem, QPen,\
QPainter, QFont, QGraphicsTextItem, QColor, \
QFontMetrics
# pylint: disable=R0904
class Connection(QGraphicsPathItem, object):
''' Connection between two symbols (top-level class) '''
......@@ -67,17 +66,47 @@ class Connection(QGraphicsPathItem, object):
''' Compute connection intermediate points - redefine in subclasses '''
return self._middle_points
def arrow(self, path=None):
''' Compute the two points of an arrow head - vertical by default '''
endp = self.end_point
def simple_arrow(self, origin='head', path=None):
''' Compute the two points of an vertical arrow head '''
if origin == 'head':
endp = self.end_point
else:
endp = self.start_point
return (QPointF(endp.x() - 5, endp.y() - 5),
QPointF(endp.x() + 5, endp.y() - 5))
def draw_arrow_head(self, shape):
''' Generic function to draw any arrow head - don't redefine '''
arrowhead = self.arrow(shape)
def angle_arrow(self, path, origin='head'):
''' Compute the two points of the arrow head with the right angle '''
if origin == 'tail':
path = path.toReversed()
length = path.length()
percent = path.percentAtLength(length - 10.0)
src = path.pointAtPercent(percent)
#path.moveTo(path.pointAtPercent(1))
end_point = path.pointAtPercent(1)
#end_point = path.currentPosition()
line = QLineF(src, end_point)
angle = math.acos(line.dx() / (line.length() or 1))
if line.dy() >= 0:
angle = math.pi * 2 - angle
arrow_size = 10.0
arrow_p1 = end_point + QPointF(
math.sin(angle - math.pi/3) * arrow_size,
math.cos(angle - math.pi/3) * arrow_size)
arrow_p2 = end_point + QPointF(
math.sin(angle - math.pi + math.pi/3) * arrow_size,
math.cos(angle - math.pi + math.pi/3) * arrow_size)
return (arrow_p1, arrow_p2)
def draw_arrow_head(self, shape, origin='head', kind='simple'):
''' Generic function to draw a simple arrow '''
if kind == 'simple':
arrowhead = self.simple_arrow(path=shape)
else:
arrowhead = self.angle_arrow(shape, origin)
shape.lineTo(arrowhead[0])
shape.moveTo(self.end_point)
shape.moveTo(self.end_point if origin == 'head' else self.start_point)
shape.lineTo(arrowhead[1])
def __str__(self):
......@@ -94,7 +123,12 @@ class Connection(QGraphicsPathItem, object):
shape.lineTo(self.end_point)
# If required draw an arrow head (e.g. in SDL NEXTSTATE and JOIN)
if self.child.arrow_head:
self.draw_arrow_head(shape)
self.draw_arrow_head(shape, origin='head',
kind=self.child.arrow_head)
if self.child.arrow_tail:
shape.moveTo(shape.pointAtPercent(0))
self.draw_arrow_head(shape, origin='tail',
kind=self.child.arrow_head)
self.setPath(shape)
......@@ -203,21 +237,27 @@ class CommentConnection(Connection):
class Channel(Connection):
''' Subclass of Connection used to draw channels between processes '''
def __init__(self, elem1, elem2):
def __init__(self, process):
''' Set generic parameters from Connection class '''
super(Channel, self).__init__(elem1, elem2)
super(Channel, self).__init__(process, process)
self.text_label = None
self.elem1 = elem1
self.elem2 = elem2
self.process = process
def reshape(self):
''' Update the shape of the connection line '''
super(Channel, self).reshape()
@property
def start_point(self):
''' Compute connection origin - redefined function '''
parent_rect = self.process.boundingRect()
return QPointF(parent_rect.x(), parent_rect.height() / 2)
def paint(self, painter, option, widget):
''' Apply antialiasing '''
painter.setRenderHint(QPainter.Antialiasing, True)
super(Channel, self).paint(painter, option, widget)
@property
def end_point(self):
''' Compute connection end point - redefined function '''
# Arrow always bumps at the screen edge
view = self.scene().views()[0]
view_pos = view.mapToScene(
view.viewport().geometry()).boundingRect().topLeft()
scene_pos_x = self.mapFromScene(view_pos).x()
return QPointF(scene_pos_x, self.start_point.y())
class Controlpoint(QGraphicsPathItem, object):
......@@ -356,26 +396,7 @@ class Edge(Connection):
''' On a mouse click, display the control points '''
self.bezier_set_visible(True)
def arrow(self, path):
''' Compute the two points of the arrow head with the right angle '''
length = path.length()
percent = path.percentAtLength(length - 10.0)
src = path.pointAtPercent(percent)
end_point = path.currentPosition()
line = QLineF(src, end_point)
angle = math.acos(line.dx() / line.length())
if line.dy() >= 0:
angle = math.pi * 2 - angle
arrow_size = 10.0
arrow_p1 = end_point + QPointF(
math.sin(angle - math.pi/3) * arrow_size,
math.cos(angle - math.pi/3) * arrow_size)
arrow_p2 = end_point + QPointF(
math.sin(angle - math.pi + math.pi/3) * arrow_size,
math.cos(angle - math.pi + math.pi/3) * arrow_size)
return (arrow_p1, arrow_p2)
# pylint: disable=R0914
# pylint: disable=R0914
def reshape(self):
''' Update the shape of the edge (redefined function) '''
path = QPainterPath()
......@@ -394,7 +415,7 @@ class Edge(Connection):
path.lineTo(self.end_connection.center)
end_point = path.currentPosition()
arrowhead = self.arrow(path)
arrowhead = self.angle_arrow(path)
path.lineTo(arrowhead[0])
path.moveTo(end_point)
path.lineTo(arrowhead[1])
......
......@@ -54,15 +54,15 @@ def flatten(process):
''' Flatten the nested states:
Rename inner states, procedures, etc. and move them to process level
'''
def update_terminator(context, term):
def update_terminator(context, term, process):
'''Set next_id, identifying the next transition to run '''
if term.inputString.lower() in (st.statename.lower()
for st in context.composite_states):
if not term.via:
term.next_id = context.mapping \
term.next_id = process.mapping \
[term.inputString.lower() + '_START']
else:
term.next_id = context.mapping[term.inputString.lower()
term.next_id = process.mapping[term.inputString.lower()
+ '_'
+ term.entrypoint.lower()
+ '_START']
......@@ -118,6 +118,8 @@ def flatten(process):
# Go recursively in inner composite states
inner.statename = prefix + inner.statename
update_composite_state(inner, process)
propagate_inputs(inner, process.mapping[inner.statename]) # TESTME
del process.mapping[inner.statename]
for each in state.terminators:
# Give prefix to terminators
if each.label:
......@@ -125,7 +127,7 @@ def flatten(process):
if each.kind == 'next_state':
each.inputString = prefix + each.inputString
# Set next transition id
update_terminator(state, each)
update_terminator(context=state, term=each, process=process)
elif each.kind == 'join':
rename_everything(state.content,
each.inputString,
......@@ -158,7 +160,7 @@ def flatten(process):
for each in nested_state.composite_states:
# do the same recursively
propagate_inputs(each, nested_state.mapping[each.statename])
del nested_state.mapping[each.statename]
#del nested_state.mapping[each.statename]
for each in process.composite_states:
update_composite_state(each, process)
......@@ -168,7 +170,7 @@ def flatten(process):
# Update terminators at process level
for each in process.terminators:
if each.kind == 'next_state':
update_terminator(process, each)
update_terminator(process, each, process)
@singledispatch
......
......@@ -39,7 +39,15 @@ from singledispatch import singledispatch
LOG = logging.getLogger(__name__)
__all__ = ['render']
__all__ = ['render', 'add_to_scene']
def add_to_scene(item, scene):
''' Add item to a scene after verifying that the scene allows it '''
if type(item) in scene.allowed_symbols:
scene.addItem(item)
else:
raise TypeError('This symbol does not fit the current scene')
@singledispatch
def render(ast, scene, parent, states, terminators=None):
......@@ -62,7 +70,7 @@ def _block(ast, scene):
@render.register(ogAST.Process)
def _process(ast, scene):
def _process(ast, scene, **_):
''' Render a Process symbol (in a BLOCK diagram) '''
# Set autocompletion lists for input, output, state, types, variables:
try:
......@@ -82,7 +90,7 @@ def _process(ast, scene):
proc.inputString for proc in ast.procedures}
symbol = sdlSymbols.Process(ast, ast)
scene.addItem(symbol)
add_to_scene(symbol, scene)
return symbol
......@@ -149,7 +157,7 @@ def _state(ast, scene, states, terminators, parent=None):
raise TypeError('This state is a terminator')
new_state = sdlSymbols.State(parent=None, ast=ast)
if new_state not in scene.items():
scene.addItem(new_state)
add_to_scene(new_state, scene)
for exit in chain(ast.inputs, ast.connects):
render(exit, scene=scene, parent=new_state, states=states)
......@@ -164,7 +172,7 @@ def _procedure(ast, scene, parent=None, states=None):
''' Add a procedure symbol to the scene '''
_, _ = parent, states
proc_symbol = sdlSymbols.Procedure(ast, ast)
scene.addItem(proc_symbol)
add_to_scene(proc_symbol, scene)
return proc_symbol
......@@ -173,7 +181,7 @@ def _text_area(ast, scene, parent=None, states=None):
''' Render a text area from the AST '''
_, _ = parent, states
text = sdlSymbols.TextSymbol(ast)
scene.addItem(text)
add_to_scene(text, scene)
return text
......@@ -182,7 +190,7 @@ def _start(ast, scene, states, parent=None):
''' Add the start symbol to a scene '''
_ = parent
start_symbol = sdlSymbols.Start(ast)
scene.addItem(start_symbol)
add_to_scene(start_symbol, scene)
if ast.transition:
render(ast.transition, scene=scene, parent=start_symbol, states=states)
return start_symbol
......@@ -193,7 +201,7 @@ def _start(ast, scene, states, parent=None):
''' Add an editable start symbol to a scene (in composite states) '''
_ = parent
start_symbol = sdlSymbols.StateStart(ast)
scene.addItem(start_symbol)
add_to_scene(start_symbol, scene)
if ast.transition:
render(ast.transition,
scene=scene, parent=start_symbol, states=states)
......@@ -205,7 +213,7 @@ def _procedure_start(ast, scene, states, parent=None):
''' Add the procedure start symbol to a scene '''
_ = parent
start_symbol = sdlSymbols.ProcedureStart(ast)
scene.addItem(start_symbol)
add_to_scene(start_symbol, scene)
if ast.transition:
render(ast.transition, scene=scene, parent=start_symbol, states=states)
return start_symbol
......@@ -217,7 +225,7 @@ def _floating_label(ast, scene, states, parent=None):
_ = parent
lab = sdlSymbols.Label(parent=None, ast=ast)
if lab not in scene.items():
scene.addItem(lab)
add_to_scene(lab, scene)
lab.setPos(ast.pos_x, ast.pos_y)
if ast.transition:
render(ast.transition, scene=scene, parent=lab, states=states)
......@@ -334,7 +342,7 @@ def _input(ast, scene, parent, states):
# Note: PROVIDED clause is not supported
inp = sdlSymbols.Input(parent, ast=ast)
if inp not in scene.items():
scene.addItem(inp)
add_to_scene(inp, scene)
if not parent:
inp.setPos(ast.pos_x, ast.pos_y)
if ast.transition:
......@@ -349,7 +357,7 @@ def _connect(ast, scene, parent, states):
''' Add connect symbol from the AST to the scene '''
conn = sdlSymbols.Connect(parent, ast=ast)
if conn not in scene.items():
scene.addItem(conn)
add_to_scene(conn, scene)
if not parent:
conn.setPos(ast.pos_x, ast.pos_y)
if ast.transition:
......
......@@ -48,6 +48,7 @@
Contact: maxime.perrotin@esa.int
"""
__all__ = ['Symbol', 'VerticalSymbol', 'HorizontalSymbol', 'Comment']
import os
import sys
import logging
......@@ -434,7 +435,8 @@ class Symbol(QObject, QGraphicsPathItem, object):
# By default symbol size may expand when inner text exceeds border
auto_expand = True
# By default connections between symbols are lines, not arrows
arrow_head = False
arrow_head = None
arrow_tail = None
# Default mouse cursor
default_cursor = Qt.SizeAllCursor
# Decide if a symbol can be copy-pasted several times
......
This diff is collapsed.
icons/connect.png

1.76 KB | W: | H:

icons/connect.png

1.3 KB | W: | H:

icons/connect.png
icons/connect.png
icons/connect.png
icons/connect.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -15,7 +15,7 @@
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="connect.svg"
inkscape:export-filename="/home/maxime/taste/tool-src/misc/opengeode/icons/connect.png"
inkscape:export-filename="/home/maxime/taste/tool-src/trunk/misc/opengeode/icons/connect.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
......@@ -23,41 +23,16 @@
<marker
inkscape:stockid="Arrow2Mend"
orient="auto"
refY="0.0"
refX="0.0"
refY="0"
refX="0"
id="Arrow2Mend"
style="overflow:visible;">
<path
id="path3838"
style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(0.6) rotate(180) translate(0,0)" />
</marker>
<marker
inkscape:stockid="Arrow1Mstart"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow1Mstart"
style="overflow:visible">
<path
id="path3817"
d="M 0.0,0.0 L 5.0,-5.0 L -12.5,0.0 L 5.0,5.0 L 0.0,0.0 z "
style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt"
transform="scale(0.4) translate(10,0)" />
</marker>
<marker
inkscape:stockid="Arrow2Lend"
orient="auto"
refY="0.0"
refX="0.0"
id="Arrow2Lend"
style="overflow:visible;">
<path
id="path3832"
style="fill-rule:evenodd;stroke-width:0.62500000;stroke-linejoin:round;"
d="M 8.7185878,4.0337352 L -2.2072895,0.016013256 L 8.7185884,-4.0017078 C 6.9730900,-1.6296469 6.9831476,1.6157441 8.7185878,4.0337352 z "
transform="scale(1.1) rotate(180) translate(1,0)" />
inkscape:connector-curvature="0"
id="path3838"
style="fill-rule:evenodd;stroke-width:0.625;stroke-linejoin:round"
d="M 8.7185878,4.0337352 -2.2072895,0.01601326 8.7185884,-4.0017078 c -1.7454984,2.3720609 -1.7354408,5.6174519 -6e-7,8.035443 z"
transform="scale(-0.6,-0.6)" />
</marker>
</defs>
<sodipodi:namedview
......@@ -76,8 +51,8 @@
inkscape:document-units="px"
inkscape:window-width="894"
inkscape:window-height="688"
inkscape:window-x="960"
inkscape:window-y="134"
inkscape:window-x="2099"
inkscape:window-y="102"
inkscape:window-maximized="0" />
<metadata
id="metadata3026">
......@@ -87,7 +62,7 @@
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
......@@ -96,28 +71,25 @@
inkscape:label="Layer 1"
inkscape:groupmode="layer">
<rect
style="opacity:0.98999999;fill:#ffdab9;stroke:#000000;stroke-width:0.99311829;stroke-opacity:1"
style="opacity:0.98999999000000005;fill:#ffd5d5;stroke:#000000;stroke-width:1.7;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:6.8,1.7;stroke-dashoffset:0"
id="rect3029"
width="46.720268"
height="27.150137"
x="0.85415173"
y="0.56778735"
rx="10.993615"
ry="13.575068" />
<rect
style="opacity:0.98999999;fill:#ffdab9;stroke:#000000;stroke-width:0.79259622;stroke-opacity:1"
id="rect3029-8-1"
width="39.206127"
height="20.607506"
x="4.7540388"
y="3.6228223"
rx="9.2254829"
ry="10.303753" />
width="48.142857"
height="26.714285"
x="0.14285715"
y="0.71428573"
rx="4.6140742"
ry="13.357142"
inkscape:export-filename="/home/maxime/taste/tool-src/misc/opengeode/icons/state.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
<path
style="fill:none;stroke:#000000;stroke-width:1.23133481;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
d="M 24.271272,27.713533 24.436688,46.625446 24.171719,27.65284 24.436688,45.496976"
style="fill:none;stroke:#000000;stroke-width:1.55798042;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-end:url(#Arrow2Mend)"
d="m 25.224204,28.022382 0.269459,18.586312 -0.431628,-18.64596 0.431628,17.536919"
id="path3019"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc" />
sodipodi:nodetypes="cccc"
inkscape:export-filename="/home/maxime/taste/tool-src/trunk/misc/opengeode/icons/connect.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90" />
</g>
</svg>
icons/process.png

710 Bytes | W: | H:

icons/process.png

618 Bytes | W: | H:

icons/process.png
icons/process.png
icons/process.png
icons/process.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -16,8 +16,8 @@
id="svg3021"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="process.png"
inkscape:export-filename="/home/maxime/taste/tool-src/misc/opengeode/procedure.png"
sodipodi:docname="process.svg"
inkscape:export-filename="/home/maxime/taste/tool-src/trunk/misc/opengeode/icons/process.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90">
<defs
......@@ -83,7 +83,8 @@
y1="20.5"
x2="50.5"
y2="20.5"
gradientUnits="userSpaceOnUse" />
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.74554189,0,0,1.0053695,-54.924261,-0.68150343)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3810"
......@@ -92,7 +93,8 @@
y1="33"
x2="45.5"
y2="33"
gradientUnits="userSpaceOnUse" />
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.69337979,0,0,1,6.9512195,2)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3816"
......@@ -101,7 +103,8 @@
y1="8"
x2="45.5"
y2="8"
gradientUnits="userSpaceOnUse" />
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.70334383,0,0,1,6.6306893,1.7142857)" />
<linearGradient
inkscape:collect="always"
xlink:href="#linearGradient3788"
......@@ -110,7 +113,8 @@
y1="20.5"
x2="50.5"
y2="20.5"
gradientUnits="userSpaceOnUse" />
gradientUnits="userSpaceOnUse"
gradientTransform="matrix(0.70882367,0,0,1.0062188,6.4936939,1.7296578)" />
</defs>
<sodipodi:namedview
id="base"
......@@ -183,33 +187,23 @@
inkscape:export-xdpi="90"
inkscape:export-filename="/home/maxime/taste/tool-src/misc/opengeode/icons-src/procedure.png"
id="path18"
d="M 5,8 4e-7,13 l 0,15 5,5 M 45,8 l 5,5 0,15 -5,5"
d="m 10.037812,9.7794081 -3.5441178,5.0310939 0,15.093282 3.5441188,5.031094 M 38.39076,9.7794081 l 3.544118,5.0310939 0,15.093282 -3.544118,5.031094"
vector-effect="non-scaling-stroke"
inkscape:connector-curvature="0"
style="font-size:9px;font-style:normal;font-weight:400;fill:url(#linearGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:Sans Serif" />
style="font-size:9px;font-style:normal;font-weight:400;fill:url(#linearGradient3822);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:0.84453046;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:Sans Serif" />
<path
inkscape:connector-curvature="0"
id="path3008"
d="m 5,8 40,0 0,0"
style="font-size:9px;font-style:normal;font-weight:400;fill:url(#linearGradient3820);stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Sans Serif;fill-opacity:1" />
d="m 10.147409,9.7142857 28.133755,0 0,0"
style="font-size:9px;font-style:normal;font-weight:400;fill:url(#linearGradient3820);fill-opacity:1;stroke:#000000;stroke-width:0.83865595px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Sans Serif" />
<path
inkscape:connector-curvature="0"
id="path3010"
d="m 5,33 40,0"
style="font-size:9px;font-style:normal;font-weight:400;fill:url(#linearGradient3814);stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Sans Serif;fill-opacity:1" />
<path
style="font-size:9px;font-style:normal;font-weight:400;fill:url(#linearGradient3808);fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:1;stroke-linecap:square;stroke-linejoin:bevel;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;font-family:Sans Serif"
inkscape:connector-curvature="0"
vector-effect="non-scaling-stroke"
d="M 5,8 4e-7,13 l 0,15 5,5 M 45,8 l 5,5 0,15 -5,5"
id="path3796"
inkscape:export-filename="/home/maxime/taste/tool-src/misc/opengeode/icons-src/procedure.png"
inkscape:export-xdpi="90"
inkscape:export-ydpi="90"
sodipodi:nodetypes="cccccccc" />
d="m 10.418119,35 27.735192,0"
style="font-size:9px;font-style:normal;font-weight:400;fill:url(#linearGradient3814);fill-opacity:1;stroke:#000000;stroke-width:0.83269429px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Sans Serif" />
<path
style="opacity:0.98000003999999996;fill:#fffcc5;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.13795987000000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:12.38999944000000042"
d="m 4.9426766,32.246022 c -0.037606,-0.09821 -0.051711,-5.449944 -0.031343,-11.892734 l 0.037032,-11.7141649 19.9282354,0 19.928236,0 0.03666,11.8927339 0.03667,11.892735 -19.933558,0 c -15.8148019,0 -19.947687,-0.0369 -20.001934,-0.17857 z"
style="opacity:0.98000004;fill:#fffcc5;fill-opacity:1;fill-rule:evenodd;stroke:none"
d="m 10.073615,34.101019 c -0.02659,-0.09939 -0.03656,-5.515409 -0.02216,-12.035591 l 0.02618,-11.854877 14.08863,0 14.08863,0 0.02592,12.035591 0.02592,12.035592 -14.092393,0 c -11.180563,0 -14.102382,-0.03734 -14.140732,-0.180715 z"
id="path3824"
inkscape:connector-curvature="0" />
</g>
......
......@@ -665,8 +665,10 @@ class Procedure(object):
self.hyperlink = None
# Local variables dictionnary (see Process)
self.variables = {}
# Inherited variables from all levels above
self.timers = []
# Inherited variables and timers from all levels above
self.global_variables = {}
self.global_timers = []
# Formal parameters - list of dict:
# [{'name': str, 'direction': 'in'/'out', 'type': str}]
self.fpar = []
......@@ -710,9 +712,9 @@ class Process(object):
self.referenced = False
# variables: dictionnary: {variable1Name: (asn1SccType, default value)}
self.variables = {}
# global variables can be used to inherit variables
# global variables and timers can be used to inherit from a level above
self.global_variables = {}
self.global_timers = []
# Set default coordinates and width/height
self.pos_x = self.pos_y = 150
self.width = 150
......
......@@ -31,6 +31,7 @@ import os
import importlib
import logging
import traceback
from itertools import chain
import antlr3
import antlr3.tree
......@@ -327,7 +328,7 @@ def fix_special_operators(op_name, expr_list, context):
if not basic.kind.startswith('Integer'):
raise TypeError('SET_TIMER first parameter is not an integer')
timer = expr_list[1].inputString
for each in context.timers:
for each in chain(context.timers, context.global_timers):
if each.lower() == timer.lower():
break
else:
......@@ -641,7 +642,7 @@ def find_variable(var, context):
result = vartype
LOG.debug(str(var) + ' is defined')
return result
for timer in context.timers:
for timer in chain(context.timers, context.global_timers):
if var.lower() == timer.lower():
LOG.debug(str(var) + ' is defined')
return result
......@@ -1346,6 +1347,8 @@ def composite_state(root, parent=None, context=None):
try:
comp.global_variables = dict(context.variables)
comp.global_variables.update(context.global_variables)
comp.global_timers = list(context.timers)
comp.global_timers.extend(list(context.global_timers))
comp.input_signals = context.input_signals
comp.output_signals = context.output_signals
comp.procedures = context.procedures
......@@ -1430,6 +1433,8 @@ def procedure(root, parent=None, context=None):
try:
proc.global_variables = dict(context.variables)
proc.global_variables.update(context.global_variables)
proc.global_timers = list(context.timers)
proc.global_timers.extend(list(context.global_timers))
proc.input_signals = context.input_signals
proc.output_signals = context.output_signals
proc.procedures = context.procedures
......@@ -1685,6 +1690,7 @@ def block_definition(root, parent):
warnings.extend(warn)
elif child.type == lexer.PROCESS:
proc, err, warn = process_definition(child, parent=block)
block.processes.append(proc)
errors.extend(err)
warnings.extend(warn)
elif child.type == lexer.SIGNALROUTE:
......@@ -1741,7 +1747,6 @@ def process_definition(root, parent=None, context=None):
process = ogAST.Process()
process.filename = node_filename(root)
process.parent = parent
parent.processes.append(process)
coord = False
# Prepare the transition/state mapping
process.mapping = {name: [] for name in get_state_list(root)}
......@@ -1764,7 +1769,8 @@ def process_definition(root, parent=None, context=None):
if sig['direction'] == 'out'])
process.procedures.extend(procedures)
except AttributeError as err:
LOG.error('Discarding process ' + child.text + ' ' + str(err))
# No interface because process is defined standalone
LOG.debug('Discarding process ' + child.text + ' ' + str(err))
except TypeError as error:
LOG.debug(str(error))
errors.append(str(error))
......@@ -1849,7 +1855,7 @@ def input_part(root, parent, context):
sig_param_type = inp_sig.get('type')
break
else:
for timer in context.timers:
for timer in chain(context.timers, context.global_timers):
if timer.lower() == inputname.text.lower():
i.inputlist.append(timer.lower())
break
......@@ -2841,6 +2847,7 @@ def pr_file(root):
# process definition at root level (must be referenced in a system)
LOG.debug('found PROCESS')
process, err, warn = process_definition(child, parent=ast)
ast.processes.append(process)
process.dataview = ast.dataview
process.asn1Modules = ast.asn1Modules
errors.extend(err)
......
......@@ -135,7 +135,11 @@ ACTIONS = {
'statechart': [],
'state': [StateStart, State, Input, Connect, Task, Decision,
DecisionAnswer, Output, ProcedureCall, TextSymbol, Comment,
Label, Join, ProcedureStop, Procedure]
Label, Join, ProcedureStop, Procedure],
'clipboard': [Start, State, Input, Connect, Task, Decision, DecisionAnswer,
Output, ProcedureCall, TextSymbol, Comment, Label,
Join, Procedure, Process, StateStart, ProcedureStop],
'lander': []
}