Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
TASTE
OpenGEODE
Commits
a21c962a
Commit
a21c962a
authored
Apr 07, 2014
by
Maxime Perrotin
Browse files
Support for composite states
parent
1522826f
Changes
16
Expand all
Hide whitespace changes
Inline
Side-by-side
AdaGenerator.py
View file @
a21c962a
...
...
@@ -136,7 +136,7 @@ def _process(process):
else
:
term
.
next_id
=
context
.
mapping
[
term
.
inputString
.
lower
()
+
'_'
+
term
.
via
.
lower
()
+
term
.
entrypoint
.
lower
()
+
'_START'
]
def
update_composite_state
(
state
,
process
):
...
...
@@ -163,20 +163,39 @@ def _process(process):
if
each
.
kind
==
'next_state'
:
each
.
inputString
=
state
.
statename
+
'_'
+
each
.
inputString
update_terminator
(
state
,
each
,
process
)
def
propagate_inputs
(
nested_state
,
inputlist
):
''' Nested states: Inputs at level N but be handled at level N-1
that is, all inputs of a composite states (the ones that allow
to exit the composite state from the outer scope) must be
processed by each of the substates.
'''
for
_
,
val
in
nested_state
.
mapping
.
viewitems
():
try
:
val
.
extend
(
inputlist
)
except
AttributeError
:
pass
for
each
in
nested_state
.
composite_states
:
# do the same recursively
propagate_inputs
(
each
,
nested_state
.
mapping
[
nested
.
statename
])
del
nested_state
.
mapping
[
nested
.
statename
]
for
each
in
process
.
composite_states
:
update_composite_state
(
each
,
process
)
propagate_inputs
(
each
,
process
.
mapping
[
each
.
statename
])
del
process
.
mapping
[
each
.
statename
]
# Update terminators at process level
for
each
in
process
.
terminators
:
if
each
.
kind
==
'next_state'
:
update_terminator
(
process
,
each
,
process
)
# Add the process states list to the process-level variables
states_decl
=
'type states is ('
states_decl
+=
', '
.
join
(
process
.
mapping
.
iterkeys
())
+
');'
states_decl
+=
', '
.
join
(
name
for
name
in
process
.
mapping
.
iterkeys
()
if
not
name
.
endswith
(
'START'
))
+
');'
process_level_decl
.
append
(
states_decl
)
process_level_decl
.
append
(
'state : states
:= START
;'
)
process_level_decl
.
append
(
'state : states;'
)
# Add function allowing to trace current state as a string
process_level_decl
.
append
(
'function get_state return String;'
)
...
...
Renderer.py
View file @
a21c962a
...
...
@@ -34,6 +34,7 @@ import ogAST
import
sdlSymbols
import
genericSymbols
import
logging
from
itertools
import
chain
from
singledispatch
import
singledispatch
LOG
=
logging
.
getLogger
(
__name__
)
...
...
@@ -130,8 +131,8 @@ def _state(ast, scene, states, terminators, parent=None):
if
new_state
not
in
scene
.
items
():
scene
.
addItem
(
new_state
)
for
inp
in
ast
.
inputs
:
render
(
inp
,
scene
=
scene
,
parent
=
new_state
,
states
=
states
)
for
exit
in
cha
in
(
ast
.
inputs
,
ast
.
connects
)
:
render
(
exit
,
scene
=
scene
,
parent
=
new_state
,
states
=
states
)
new_state
.
nested_scene
=
ast
.
composite
or
ogAST
.
CompositeState
()
...
...
@@ -328,3 +329,19 @@ def _input(ast, scene, parent, states):
parent
=
inp
,
states
=
states
)
return
inp
@
render
.
register
(
ogAST
.
Connect
)
def
_input
(
ast
,
scene
,
parent
,
states
):
''' Add connect symbol from the AST to the scene '''
# Note: PROVIDED clause is not supported
conn
=
sdlSymbols
.
Connect
(
parent
,
ast
=
ast
)
if
conn
not
in
scene
.
items
():
scene
.
addItem
(
inp
)
if
not
parent
:
conn
.
setPos
(
ast
.
pos_x
,
ast
.
pos_y
)
if
ast
.
transition
:
render
(
ast
.
transition
,
scene
=
scene
,
parent
=
conn
,
states
=
states
)
return
conn
Statechart.py
View file @
a21c962a
...
...
@@ -60,6 +60,8 @@ class Record(genericSymbols.HorizontalSymbol, object):
property_box
=
QtGui
.
QGraphicsTextItem
(
self
)
property_box
.
setPos
(
5
,
30
)
property_box
.
setPlainText
(
node
[
'properties'
])
# Text in statecharts is read-only:
self
.
text
.
setTextInteractionFlags
(
QtCore
.
Qt
.
TextBrowserInteraction
)
def
set_shape
(
self
,
width
,
height
):
''' Define the polygon shape from width and height '''
...
...
genericSymbols.py
View file @
a21c962a
...
...
@@ -286,6 +286,9 @@ class EditableText(QGraphicsTextItem, object):
Slot connected to the autocompletion popup,
invoked when selection is made
'''
if
not
(
self
.
textInteractionFlags
()
&
Qt
.
TextEditable
):
self
.
completer
.
hide
()
return
text_cursor
=
self
.
textCursor
()
# Go back to the previously saved cursor position
text_cursor
.
setPosition
(
self
.
cursor_position
)
...
...
@@ -537,6 +540,8 @@ class Symbol(QObject, QGraphicsPathItem, object):
_unique_followers
=
[]
# unique : e.g. comment symbol
_insertable_followers
=
[]
# no limit to insert below current symbol
_terminal_followers
=
[]
# cannot be inserted between two symbols
# By default a symbol is resizeable
resizeable
=
True
# By default symbol size may expand when inner text exceeds border
auto_expand
=
True
# By default connections between symbols are lines, not arrows
...
...
@@ -561,8 +566,8 @@ class Symbol(QObject, QGraphicsPathItem, object):
redbold
=
()
# Specify if the symbol can be drawn with anti-aliasing
_antialiasing
=
True
# Specify if the symbol
text can be edited
editable
=
True
# Specify if the symbol
has a text area
has_text_area
=
True
def
__init__
(
self
,
parent
=
None
):
'''
...
...
@@ -615,6 +620,13 @@ class Symbol(QObject, QGraphicsPathItem, object):
position
=
Property
(
QPointF
,
_pos
,
_set_pos
)
def
is_composite
(
self
):
''' Return True if nested scene has something in it '''
try
:
return
any
(
item
.
isVisible
()
for
item
in
self
.
nested_scene
.
items
())
except
AttributeError
:
return
False
@
property
def
allowed_followers
(
self
):
'''
...
...
@@ -714,7 +726,7 @@ class Symbol(QObject, QGraphicsPathItem, object):
_
,
syntax_errors
,
___
,
____
,
_____
=
(
self
.
parser
.
parseSingleElement
(
self
.
common_name
,
repr
(
self
)))
except
AssertionError
:
except
(
AssertionError
,
AttributeError
)
:
LOG
.
error
(
'Checker failed - no parser for this construct?'
)
else
:
try
:
...
...
@@ -885,6 +897,8 @@ class Symbol(QObject, QGraphicsPathItem, object):
def
resize_item
(
self
,
rect
):
''' resize item, e.g. when editing text - move children accordingly '''
if
not
self
.
resizeable
:
return
pos
=
self
.
pos
()
delta_x
=
(
self
.
boundingRect
().
width
()
-
rect
.
width
())
/
2.0
delta_y
=
self
.
boundingRect
().
height
()
-
rect
.
height
()
...
...
@@ -1170,7 +1184,7 @@ class Comment(Symbol, object):
Redefinition of the Resize function
(Comment symbol only resizes in one direction)
'''
if
self
.
grabber
.
resize_mode
.
endswith
(
'left'
):
if
not
self
.
resizeable
or
self
.
grabber
.
resize_mode
.
endswith
(
'left'
):
return
self
.
set_shape
(
rect
.
width
(),
rect
.
height
())
self
.
update_connections
()
...
...
@@ -1298,6 +1312,9 @@ class Cornergrabber(QGraphicsPolygonItem, object):
# Parent item may have changed its cursor (e.g. when inserting
# items). In that case, don't override the cursor for that area
cursor
=
self
.
parent
.
cursor
()
elif
not
self
.
parent
.
resizeable
:
cursor
=
self
.
parent
.
default_cursor
self
.
resize_mode
=
''
# Left side
elif
0.0
<=
pos
.
x
()
<=
10.0
:
# Top-left corner: disabled
...
...
@@ -1311,7 +1328,6 @@ class Cornergrabber(QGraphicsPolygonItem, object):
self
.
resize_mode
=
'left'
# Middle of item
elif
5.0
<
pos
.
x
()
<
self
.
boundingRect
().
width
()
-
10.0
and
(
# pos.y() <= 10.0 or
pos
.
y
()
>
self
.
boundingRect
().
height
()
-
10.0
):
cursor
=
Qt
.
SizeVerCursor
self
.
resize_mode
=
'bottom'
...
...
@@ -1344,7 +1360,7 @@ class HorizontalSymbol(Symbol, object):
super
(
HorizontalSymbol
,
self
).
__init__
(
parent
)
self
.
minDistanceToSymbolAbove
=
20
self
.
connection
=
None
if
self
.
editable
:
if
self
.
has_text_area
:
self
.
text
=
EditableText
(
parent
=
self
,
text
=
text
,
hyperlink
=
hyperlink
)
if
parent
:
...
...
@@ -1412,7 +1428,8 @@ class HorizontalSymbol(Symbol, object):
''' Return all the items's sibling symbols '''
try
:
return
(
item
for
item
in
self
.
parent
.
childItems
()
if
item
is
not
self
and
type
(
item
)
is
type
(
self
))
if
item
is
not
self
and
(
isinstance
(
self
,
type
(
item
))
or
isinstance
(
item
,
type
(
self
))))
# is type(self))
except
:
return
()
...
...
@@ -1508,7 +1525,7 @@ class VerticalSymbol(Symbol, object):
x
=
None
,
y
=
None
,
hyperlink
=
None
):
super
(
VerticalSymbol
,
self
).
__init__
(
parent
)
self
.
connection
=
None
if
self
.
editable
:
if
self
.
has_text_area
:
self
.
text
=
EditableText
(
parent
=
self
,
text
=
text
,
hyperlink
=
hyperlink
)
...
...
icons.py
View file @
a21c962a
This diff is collapsed.
Click to expand it.
icons/connect.png
0 → 100644
View file @
a21c962a
1.76 KB
icons/connect.svg
0 → 100644
View file @
a21c962a
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc=
"http://purl.org/dc/elements/1.1/"
xmlns:cc=
"http://creativecommons.org/ns#"
xmlns:rdf=
"http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg=
"http://www.w3.org/2000/svg"
xmlns=
"http://www.w3.org/2000/svg"
xmlns:sodipodi=
"http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape=
"http://www.inkscape.org/namespaces/inkscape"
width=
"48px"
height=
"48px"
id=
"svg3021"
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-xdpi=
"90"
inkscape:export-ydpi=
"90"
>
<defs
id=
"defs3023"
>
<marker
inkscape:stockid=
"Arrow2Mend"
orient=
"auto"
refY=
"0.0"
refX=
"0.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)"
/>
</marker>
</defs>
<sodipodi:namedview
id=
"base"
pagecolor=
"#ffffff"
bordercolor=
"#666666"
borderopacity=
"1.0"
inkscape:pageopacity=
"0.0"
inkscape:pageshadow=
"2"
inkscape:zoom=
"7"
inkscape:cx=
"24"
inkscape:cy=
"24"
inkscape:current-layer=
"layer1"
showgrid=
"true"
inkscape:grid-bbox=
"true"
inkscape:document-units=
"px"
inkscape:window-width=
"894"
inkscape:window-height=
"688"
inkscape:window-x=
"960"
inkscape:window-y=
"134"
inkscape:window-maximized=
"0"
/>
<metadata
id=
"metadata3026"
>
<rdf:RDF>
<cc:Work
rdf:about=
""
>
<dc:format>
image/svg+xml
</dc:format>
<dc:type
rdf:resource=
"http://purl.org/dc/dcmitype/StillImage"
/>
<dc:title
/>
</cc:Work>
</rdf:RDF>
</metadata>
<g
id=
"layer1"
inkscape:label=
"Layer 1"
inkscape:groupmode=
"layer"
>
<rect
style=
"opacity:0.98999999;fill:#ffdab9;stroke:#000000;stroke-width:0.99311829;stroke-opacity:1"
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"
/>
<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"
id=
"path3019"
inkscape:connector-curvature=
"0"
sodipodi:nodetypes=
"cccc"
/>
</g>
</svg>
ogAST.py
View file @
a21c962a
...
...
@@ -391,7 +391,10 @@ class Terminator(object):
# Return expression
self
.
return_expr
=
None
# via clause, used for entering nested state with an entry point
# 'via' is the string for the renderer (e.g. "via foo")
self
.
via
=
None
# 'entrypoint' is the string of the entry point (e.g. "foo")
self
.
entrypoint
=
None
# some transitions can be chained, when entering/leaving nested states
self
.
next_id
=
-
1
...
...
@@ -508,6 +511,21 @@ class Input(object):
l
=
self
.
line
,
c
=
self
.
charPositionInLine
)
class
Connect
(
Input
):
''' AST Entry for the CONNECT part (transition below a nested state) '''
def
__init__
(
self
):
''' Only one difference with INPUT: the connect_list attribute '''
super
(
Connect
,
self
).
__init__
()
# List of strings
self
.
connect_list
=
[]
self
.
width
=
1
def
__repr__
(
self
):
''' Debug output for a CONNECT symbol '''
return
'CONNECT {exp} ({l},{c})'
.
format
(
exp
=
self
.
inputString
,
l
=
self
.
line
,
c
=
self
.
charPositionInLine
)
class
Start
(
object
):
''' AST Entry for the START symbol '''
def
__init__
(
self
):
...
...
@@ -578,6 +596,8 @@ class State(object):
self
.
height
=
35
# list of type Input
self
.
inputs
=
[]
# list of type Connect (connection below a nested state)
self
.
connects
=
[]
# optional comment symbol
self
.
comment
=
None
# optional hyperlink
...
...
ogParser.py
View file @
a21c962a
...
...
@@ -1777,7 +1777,6 @@ def process_definition(root, parent=None):
errors
.
extend
(
err
)
warnings
.
extend
(
warn
)
process
.
composite_states
.
append
(
comp
)
warnings
.
append
(
'Composite state detected but not supported yet'
)
elif
child
.
type
==
lexer
.
REFERENCED
:
process
.
referenced
=
True
else
:
...
...
@@ -1788,8 +1787,7 @@ def process_definition(root, parent=None):
def
input_part
(
root
,
parent
,
context
):
''' Parse an INPUT - set of TASTE provided interfaces '''
i
=
ogAST
.
Input
()
warnings
=
[]
errors
=
[]
warnings
,
errors
=
[],
[]
coord
=
False
# Keep track of the number of terminator statements follow the input
# useful if we want to render graphs from the SDL model
...
...
@@ -1946,7 +1944,8 @@ def state(root, parent, context):
'be followed by a connect statement'
.
format
(
state_def
.
statelist
[
0
]))
else
:
err
,
warn
=
connect_part
(
child
,
state_def
,
context
)
conn_part
,
err
,
warn
=
connect_part
(
child
,
state_def
,
context
)
state_def
.
connects
.
append
(
conn_part
)
warnings
.
extend
(
warn
)
errors
.
extend
(
err
)
elif
child
.
type
==
lexer
.
COMMENT
:
...
...
@@ -1976,31 +1975,59 @@ def state(root, parent, context):
def
connect_part
(
root
,
parent
,
context
):
''' Connection of a nested state exit point with a transition '''
''' Connection of a nested state exit point with a transition
Very similar to INPUT '''
errors
,
warnings
=
[],
[]
connect_list
=
[]
coord
=
False
conn
=
ogAST
.
Connect
()
statename
=
parent
.
statelist
[
0
].
lower
()
id_token
=
[]
# Keep track of the number of terminator statements follow the input
# useful if we want to render graphs from the SDL model
terms
=
len
(
context
.
terminators
)
# Retrieve composite state
nested
,
=
(
comp
for
comp
in
context
.
composite_states
if
comp
.
statename
==
statename
)
for
child
in
root
.
getChildren
():
if
child
.
type
==
lexer
.
ID
:
connect_list
.
append
(
child
.
toString
().
lower
())
if
child
.
type
==
lexer
.
CIF
:
# Get symbol coordinates
conn
.
pos_x
,
conn
.
pos_y
,
conn
.
width
,
conn
.
height
=
cif
(
child
)
coord
=
True
elif
child
.
type
==
lexer
.
ID
:
id_token
.
append
(
child
)
conn
.
connect_list
.
append
(
child
.
toString
().
lower
())
elif
child
.
type
==
lexer
.
ASTERISK
:
connect_list
=
nested
.
state_exitpoints
id_token
.
append
(
child
)
conn
.
connect_list
=
nested
.
state_exitpoints
elif
child
.
type
==
lexer
.
TRANSITION
:
trans
,
err
,
warn
=
transition
(
child
,
parent
,
context
=
context
)
trans
,
err
,
warn
=
transition
(
child
,
parent
=
conn
,
context
=
context
)
errors
.
extend
(
err
)
warnings
.
extend
(
warn
)
context
.
transitions
.
append
(
trans
)
trans_id
=
len
(
context
.
transitions
)
-
1
conn
.
transition_id
=
trans_id
conn
.
transition
=
trans
elif
child
.
type
==
lexer
.
HYPERLINK
:
conn
.
hyperlink
=
child
.
getChild
(
0
).
toString
()[
1
:
-
1
]
elif
child
.
type
==
lexer
.
COMMENT
:
conn
.
comment
,
_
,
___
=
end
(
child
)
else
:
warnings
.
append
(
'Unsupported CONNECT PART child type: '
+
str
(
child
.
type
))
if
not
connect_list
:
connect_list
.
append
(
''
)
for
exitp
in
connect_list
:
sdl92Parser
.
tokenNames
[
child
.
type
])
if
not
conn
.
connect_list
:
conn
.
connect_list
.
append
(
''
)
if
not
id_token
:
conn
.
inputString
=
''
conn
.
line
=
root
.
getLine
()
conn
.
charPositionInLine
=
root
.
getCharPositionInLine
()
else
:
conn
.
line
=
id_token
[
0
].
getLine
()
conn
.
charPositionInLine
=
id_token
[
0
].
getCharPositionInLine
()
conn
.
inputString
=
token_stream
(
id_token
[
0
]).
toString
(
id_token
[
0
].
getTokenStartIndex
(),
id_token
[
-
1
].
getTokenStopIndex
())
for
exitp
in
conn
.
connect_list
:
if
exitp
!=
''
and
not
exitp
in
nested
.
state_exitpoints
:
errors
.
append
(
'Exit point {ep} not defined in state {st}'
.
format
(
ep
=
exitp
,
st
=
statename
))
...
...
@@ -2013,7 +2040,13 @@ def connect_part(root, parent, context):
for
each
in
terminators
:
# Set transition ID, referencing process.transitions
each
.
next_id
=
trans_id
return
errors
,
warnings
# Set list of terminators
conn
.
terminators
=
list
(
context
.
terminators
[
terms
:])
# Report errors with symbol coordinates
if
coord
:
errors
=
[[
e
,
[
conn
.
pos_x
,
conn
.
pos_y
]]
for
e
in
errors
]
warnings
=
[[
w
,
[
conn
.
pos_x
,
conn
.
pos_y
]]
for
w
in
warnings
]
return
conn
,
errors
,
warnings
def
cif
(
root
):
...
...
@@ -2303,38 +2336,41 @@ def decision(root, parent, context):
def
nextstate
(
root
,
context
):
''' Parse a NEXTSTATE [VIA State_Entry_Point] '''
next_state_id
,
via
=
''
,
None
next_state_id
,
via
,
entrypoint
=
''
,
None
,
None
for
child
in
root
.
getChildren
():
if
child
.
type
==
lexer
.
ID
:
next_state_id
=
child
.
text
.
lower
()
next_state_id
=
child
.
text
elif
child
.
type
==
lexer
.
DASH
:
next_state_id
=
'-'
elif
child
.
type
==
lexer
.
VIA
:
if
next_state_id
.
strip
()
!=
'-'
:
via
=
child
.
getChild
(
0
).
text
.
lower
()
via
=
get_input_string
(
root
).
replace
(
'NEXTSTATE'
,
''
,
1
).
strip
()
entrypoint
=
child
.
getChild
(
0
).
text
try
:
composite
,
=
(
comp
for
comp
in
context
.
composite_states
if
comp
.
statename
==
next_state_id
)
if
comp
.
statename
.
lower
()
==
next_state_id
.
lower
())
except
ValueError
:
raise
TypeError
(
'State {} is not a composite state'
.
format
(
next_state_id
))
else
:
if
via
not
in
composite
.
state_entrypoints
:
if
entrypoint
.
lower
()
not
in
composite
.
state_entrypoints
:
raise
TypeError
(
'State {s} has no "{p}" entrypoint'
.
format
(
s
=
next_state_id
,
p
=
via
))
.
format
(
s
=
next_state_id
,
p
=
entrypoint
))
for
each
in
composite
.
content
.
named_start
:
if
each
.
inputString
==
via
+
'_START'
:
if
each
.
inputString
==
entrypoint
.
lower
()
+
'_START'
:
break
else
:
raise
TypeError
(
'Entrypoint {p} in state {s} is '
'declared but not defined'
.
format
(
s
=
next_state_id
,
p
=
via
))
(
s
=
next_state_id
,
p
=
entrypoint
))
else
:
raise
TypeError
(
'"History" NEXTSTATE'
' cannot have a "via" clause'
)
else
:
raise
TypeError
(
'NEXTSTATE undefined construct'
)
return
next_state_id
,
via
return
next_state_id
,
via
,
entrypoint
def
terminator_statement
(
root
,
parent
,
context
):
...
...
@@ -2357,7 +2393,7 @@ def terminator_statement(root, parent, context):
elif
term
.
type
==
lexer
.
NEXTSTATE
:
t
.
kind
=
'next_state'
try
:
t
.
inputString
,
t
.
via
=
nextstate
(
term
,
context
)
t
.
inputString
,
t
.
via
,
t
.
entrypoint
=
nextstate
(
term
,
context
)
except
TypeError
as
err
:
errors
.
append
(
str
(
err
))
t
.
line
=
term
.
getChild
(
0
).
getLine
()
...
...
@@ -2839,7 +2875,7 @@ def parseSingleElement(elem='', string=''):
'terminator_statement'
,
'label'
,
'task'
,
'procedure_call'
,
'end'
,
'text_area'
,
'state'
,
'start'
,
'procedure'
,
'floating_label'
,
'connect_part'
))
LOG
.
debug
(
'Parsing string: '
+
string
)
LOG
.
debug
(
'Parsing string: '
+
string
+
'with elem '
+
elem
)
parser
=
parser_init
(
string
=
string
)
parser_ptr
=
getattr
(
parser
,
elem
)
assert
(
parser_ptr
is
not
None
)
...
...
opengeode.py
View file @
a21c962a
...
...
@@ -24,6 +24,8 @@ import re
import
code
import
pprint
from
functools
import
partial
from
collections
import
deque
from
itertools
import
chain
# Added to please py2exe - NOQA makes flake8 ignore the following lines:
# pylint: disable=W0611
...
...
@@ -50,10 +52,11 @@ from PySide.QtCore import Qt, QSize, QFile, QIODevice, QRectF, QTimer
from
PySide.QtUiTools
import
QUiLoader
from
PySide
import
QtSvg
from
genericSymbols
import
Symbol
,
Comment
,
EditableText
,
Cornergrabber
from
genericSymbols
import
(
Symbol
,
Comment
,
EditableText
,
Cornergrabber
,
Connection
)
from
sdlSymbols
import
(
Input
,
Output
,
Decision
,
DecisionAnswer
,
Task
,
ProcedureCall
,
TextSymbol
,
State
,
Start
,
Join
,
Label
,
Procedure
,
ProcedureStart
,
ProcedureStop
,
StateStart
)
ProcedureStart
,
ProcedureStop
,
StateStart
,
Connect
)
# Icons and png files generated from the resource file:
import
icons
# NOQA
...
...
@@ -122,14 +125,15 @@ G_SYMBOLS = set()
# Lookup table used to configure the context-dependent toolbars
ACTIONS
=
{
'process'
:
[
Start
,
State
,
Input
,
Task
,
Decision
,
DecisionAnswer
,
'process'
:
[
Start
,
State
,
Input
,
Connect
,
Task
,
Decision
,
DecisionAnswer
,
Output
,
ProcedureCall
,
TextSymbol
,
Comment
,
Label
,
Join
,
Procedure
],
'procedure'
:
[
ProcedureStart
,
Task
,
Decision
,
DecisionAnswer
,
Output
,
ProcedureCall
,
TextSymbol
,
Comment
,
Label
,
Join
,
ProcedureStop
],
'statechart'
:
[],
'state'
:
[
StateStart
,
State
,
Input
,
Task
,
Decision
,
DecisionAnswer
,
Output
,
'state'
:
[
StateStart
,
State
,
Input
,
Connect
,
Task
,
Decision
,
DecisionAnswer
,
Output
,
ProcedureCall
,
TextSymbol
,
Comment
,
Label
,
Join
,
ProcedureStop
]
}
...
...
@@ -231,9 +235,9 @@ class Sdl_toolbar(QtGui.QToolBar, object):
# Check for singletons (e.g. START symbol)
try
:
for
item
in
scene
.
items
()
:
for
item
in
scene
.
visible_symb
:
try
:
if
item
.
is_singleton
and
item
.
isVisible
():
if
item
.
is_singleton
:
#
and item.isVisible():
self
.
actions
[
item
.
__class__
.
__name__
].
setEnabled
(
False
)
except
(
AttributeError
,
KeyError
)
as
error
:
...
...
@@ -289,10 +293,63 @@ class SDL_Scene(QtGui.QGraphicsScene, object):
# Selection rectangle when user clicks on the scene and moves mouse
self
.
select_rect
=
None
@
property
def
visible_symb
(
self
):
''' Return the visible items of a scene '''