Commit d06600f0 authored by Maxime Perrotin's avatar Maxime Perrotin
Browse files

Text editor added for signallists on channels

parent 8e87ae7d
......@@ -24,6 +24,9 @@ from PySide.QtGui import QGraphicsPathItem, QPainterPath, QGraphicsItem, QPen,\
QPainter, QFont, QGraphicsTextItem, QColor, \
QFontMetrics
import ogParser
from TextInteraction import EditableText
LOG = logging.getLogger(__name__)
......@@ -234,30 +237,56 @@ class CommentConnection(Connection):
yield QPointF(go_to_point, self.end_point.y())
class Channel(Connection):
class SignalList(EditableText):
''' Simplified text editor for signal lists '''
def __init__(self, parent, text='', hyperlink = None):
''' Smaller font than normal text '''
super(SignalList, self).__init__(parent, text)
self.setFont(QFont('Ubuntu', pointSize=8))
def set_text_alignment(self):
''' Text justification - ignore '''
pass
def set_textbox_position(self):
''' Alignment vs parent - ignore, done by the parent '''
pass
def try_resize(self):
''' Resizing of the parent when size expands - ignore for now '''
pass
class Signalroute(Connection):
''' Subclass of Connection used to draw channels between processes '''
in_sig = out_sig = None
def __init__(self, process):
''' Set generic parameters from Connection class '''
super(Channel, self).__init__(process, process)
self.label_in = QGraphicsTextItem('[]', parent=self)
self.label_out = QGraphicsTextItem('[]', parent=self)
#self.label_in.setTextInteractionFlags(Qt.TextEditorInteraction)
#self.label_out.setTextInteractionFlags(Qt.TextEditorInteraction)
if not Channel.in_sig:
super(Signalroute, self).__init__(process, process)
self.parser = ogParser
# self.label_in = QGraphicsTextItem('[]', parent=self)
# self.label_out = QGraphicsTextItem('[]', parent=self)
self.completion_list = []
self.blackbold = ()
self.redbold = ()
self.label_in = SignalList(parent=self)
self.label_out = SignalList(parent=self)
if not Signalroute.in_sig:
# keep at class level as long as only one process is supported
# when copy-pasting a process the challel in/out signal lists
# are not parsed. Workaround is to keep the list "global"
# to allow a copy of both process and channel
# Needed for the image exporter, that copies the scene to a
# temporary one
Channel.in_sig = '[{}]'.format(',\n'.join(sig['name']
Signalroute.in_sig = '{}'.format(',\n'.join(sig['name']
for sig in process.input_signals))
Channel.out_sig = '[{}]'.format(',\n'.join(sig['name']
Signalroute.out_sig = '{}'.format(',\n'.join(sig['name']
for sig in process.output_signals))
font = QFont('Ubuntu', pointSize=8)
self.label_in.setPlainText('[{}]'.format(self.in_sig))
self.label_out.setPlainText('[{}]'.format(self.out_sig))
#font = QFont('Ubuntu', pointSize=8)
for each in (self.label_in, self.label_out):
each.setFont(font)
#each.setFont(font)
each.show()
self.process = process
self.reshape()
......@@ -284,10 +313,10 @@ class Channel(Connection):
def reshape(self):
''' Redefine shape function to add the text areas '''
super(Channel, self).reshape()
super(Signalroute, self).reshape()
self.label_in.setPlainText(self.in_sig)
self.label_out.setPlainText(self.out_sig)
#self.label_in.setPlainText('[{}]'.format(self.in_sig))
#self.label_out.setPlainText('[{}]'.format(self.out_sig))
width_in = self.label_in.boundingRect().width()
......@@ -296,6 +325,24 @@ class Channel(Connection):
self.label_out.setX(self.end_point.x() + 10)
self.label_out.setY(self.end_point.y() + 5)
def check_syntax(self, text):
''' Check the syntax of the IN and OUT signal lists '''
try:
_, syntax_errors, _, _, _ = self.parser.parseSingleElement(
'signalroute', text)
except (AssertionError, AttributeError) as err:
LOG.error('Checker failed:' + str(err))
else:
return syntax_errors
def update_completion_list(self, pr_text):
''' Called after text has been edited '''
print pr_text
def resize_item(self, new_rect):
''' Called after signallist text has been edited '''
pass
class Controlpoint(QGraphicsPathItem, object):
''' Class handling one edge control point (to change bezier curves) '''
......
......@@ -20,7 +20,7 @@ from collections import deque
from itertools import chain
from singledispatch import singledispatch
import genericSymbols, sdlSymbols
import genericSymbols, sdlSymbols, Connectors
LOG = logging.getLogger(__name__)
......@@ -330,3 +330,19 @@ def _start(symbol, recursive=True, **kwargs):
if recursive:
result.extend(recursive_aligned(symbol))
return result
@generate.register(Connectors.Signalroute)
def _channel(symbol, recursive=True, **kwargs):
''' Signalroute at block level '''
result = Indent()
result.append('SIGNALROUTE c')
if symbol.out_sig:
result.append('FROM {} TO ENV WITH {};'.format(unicode(symbol.process),
symbol.out_sig))
if symbol.in_sig:
result.append('FROM ENV TO {} WITH {};'.format(unicode(symbol.process),
symbol.in_sig))
return result
......@@ -151,10 +151,9 @@ class EditableText(QGraphicsTextItem, object):
(hlink=hyperlink, text=text.replace('\n', '<br>')))
else:
self.setPlainText(text)
self.setTextInteractionFlags(
Qt.TextEditorInteraction
| Qt.LinksAccessibleByMouse
| Qt.LinksAccessibleByKeyboard)
self.setTextInteractionFlags(Qt.TextEditorInteraction
| Qt.LinksAccessibleByMouse
| Qt.LinksAccessibleByKeyboard)
self.completer_has_focus = False
self.editing = False
self.try_resize()
......@@ -331,7 +330,11 @@ class EditableText(QGraphicsTextItem, object):
self.completer.resize(0, 0)
if not self.completer or not self.completer.isVisible():
# Trigger a select - side effect makes the toolbar update
self.parentItem().select(True)
try:
self.parentItem().select(True)
except AttributeError:
# Some parents may not be selectable (e.g. Signalroute)
pass
self.editing = False
text_cursor = self.textCursor()
if text_cursor.hasSelection():
......@@ -350,8 +353,12 @@ class EditableText(QGraphicsTextItem, object):
self.parentItem(), self.oldSize,
self.parentItem().boundingRect())
self.scene().undo_stack.push(undo_cmd)
self.parentItem().cam(self.parentItem().pos(),
self.parentItem().pos())
try:
self.parentItem().cam(self.parentItem().pos(),
self.parentItem().pos())
except AttributeError:
# Some parents may not have CAM function (e.g. Channel)
pass
undo_cmd = undoCommands.ReplaceText(self, self.oldText,
unicode(self))
......@@ -364,7 +371,11 @@ class EditableText(QGraphicsTextItem, object):
''' When user starts editing text, save previous state for Undo '''
super(EditableText, self).focusInEvent(event)
# Trigger a select - side effect makes the toolbar update
self.parentItem().select(True)
try:
self.parentItem().select(True)
except AttributeError:
# Some parents may not be selectable (e.g. Signalroute)
pass
# Update completer list of keywords
self.completer.set_completer_list()
# Clear selection otherwise the "Delete" key may delete other items
......
......@@ -329,8 +329,8 @@ def get_interfaces(ast, process_name):
raise TypeError('Process ' + process_name +
' is defined but not declared in a system')
# Find in and out signals names using the signalroutes
for signalroute in process_parent.signalroutes:
for route in signalroute['routes']:
for each in process_parent.signalroutes:
for route in each['routes']:
if route['source'] == process_name:
direction = 'out'
elif route['dest'] == process_name:
......@@ -2331,7 +2331,7 @@ def single_route(root):
return route
def channel_signalroute(root):
def signalroute(root, parent=None, context=None):
''' Channel/signalroute definition (connections) '''
# no AST entry for edges - a simple dict is sufficient
# (name, [route])
......@@ -2341,7 +2341,7 @@ def channel_signalroute(root):
edge['name'] = child.text
elif child.type == lexer.ROUTE:
edge['routes'].append(single_route(child))
return edge
return edge, [], []
def block_definition(root, parent):
......@@ -2371,7 +2371,7 @@ def block_definition(root, parent):
errors.extend(err)
warnings.extend(warn)
elif child.type == lexer.SIGNALROUTE:
sigroute = channel_signalroute(child)
sigroute, _, _ = signalroute(child)
block.signalroutes.append(sigroute)
else:
warnings.append('Unsupported block child type: ' +
......@@ -2406,7 +2406,7 @@ def system_definition(root, parent):
LOG.debug('Added procedure: ' + proc.inputString)
elif child.type == lexer.CHANNEL:
LOG.debug('channel declaration')
channel = channel_signalroute(child)
channel, _, _ = signalroute(child)
system.channels.append(channel)
elif child.type == lexer.BLOCK:
LOG.debug('block declaration')
......@@ -3915,7 +3915,8 @@ def parseSingleElement(elem='', string=''):
assert(elem in ('input_part', 'output', 'decision', 'alternative_part',
'terminator_statement', 'label', 'task', 'procedure_call', 'end',
'text_area', 'state', 'start', 'procedure', 'floating_label',
'connect_part', 'process_definition', 'proc_start', 'state_start'))
'connect_part', 'process_definition', 'proc_start', 'state_start',
'signalroute'))
# Create a dummy context, needed to place context data
if elem == 'proc_start':
elem = 'start'
......
......@@ -1851,7 +1851,8 @@ def init_logging(options):
Asn1scc,
Connectors,
Pr,
TextInteraction
TextInteraction,
Connectors
)
for module in modules:
module.LOG.addHandler(handler_console)
......
......@@ -29,7 +29,7 @@ from PySide.QtCore import Qt, QPoint, QRect, QRectF
from PySide.QtGui import(QPainterPath, QBrush, QColor, QRadialGradient, QPen)
from genericSymbols import HorizontalSymbol, VerticalSymbol, Comment
from Connectors import Connection, JoinConnection, Channel
from Connectors import Connection, JoinConnection, Signalroute
import ogParser
import ogAST
......@@ -695,7 +695,7 @@ class State(VerticalSymbol):
ast, _, _, _, terminators = self.parser.parseSingleElement('state',
pr_text)
return ast, terminators
def check_syntax(self, pr_text):
''' Redefinition of the check syntax function for the state '''
name = self.common_name if self.hasParent else 'state'
......@@ -741,8 +741,8 @@ class Process(HorizontalSymbol):
self.connection = self.connect_to_parent()
def connect_to_parent(self):
''' Redefinition: creates connection to env with a channel '''
return Channel(self)
''' Redefinition: creates connection to env with a signalroute '''
return Signalroute(self)
def set_shape(self, width, height):
''' Compute the polygon to fit in width, height '''
......
......@@ -72,14 +72,22 @@ class ResizeSymbol(QUndoCommand):
self.new_rect = new_rect
def undo(self):
self.symbol.resize_item(self.old_rect)
# Update grabber size
self.symbol.grabber.display()
try:
self.symbol.resize_item(self.old_rect)
# Update grabber size
self.symbol.grabber.display()
except AttributeError:
# Not all symbols can be resized
pass
def redo(self):
self.symbol.resize_item(self.new_rect)
# Update grabber size
self.symbol.grabber.display()
try:
self.symbol.resize_item(self.new_rect)
# Update grabber size
self.symbol.grabber.display()
except AttributeError:
# Not all symbols can be resized
pass
class InsertSymbol(QUndoCommand):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment