Skip to content
Snippets Groups Projects
Commit a79f8920 authored by Andreas Bolin's avatar Andreas Bolin
Browse files

workspace dump

parent 6beade66
No related branches found
No related tags found
1 merge request!78Add scheduler GUI
Pipeline #73401 passed
......@@ -164,10 +164,11 @@ class GraphicsAxesItem(QGraphicsItemGroup):
if delta_width > 0:
for _ in range(delta_width):
self._append_x_tick()
self._width += 1
elif delta_width < 0:
for _ in range(abs(delta_width)):
self._pop_x_tick()
self._width = width
self._width -= 1
return self
......
......@@ -43,15 +43,16 @@ from graphics_timeline_item import GraphicsTimelineItem
sys.settrace
# class GraphicsGraphEvent(ABC):
class GraphicsGraphEvent(QGraphicsObject, QGraphicsItem):
class GraphicsGraphEvent(QGraphicsItemGroup, QObject):
# class GraphicsGraphEvent(QGraphicsObject):
"""Event filter and handlers for GraphicsGraphItem"""
_axes: GraphicsAxesItem
_current_pos: QPointF
_delta_time: int
component_selected = Signal(str)
schedule_time_changed = Signal()
@overload
def is_component_valid_pos(self, pos: float, end_time: int) -> bool: ...
......@@ -60,8 +61,12 @@ class GraphicsGraphEvent(QGraphicsObject, QGraphicsItem):
@overload
def set_schedule_time(self, delta_time: int) -> None: ...
def __init__(self):
super().__init__()
def __init__(self, parent: Optional[QGraphicsItem] = None):
QObject.__init__(self)
QGraphicsItemGroup.__init__(self, parent)
# QGraphicsObject.__init__(self)
# super().__init__(parent)
# super().__init__()
#################
#### Filters ####
......@@ -98,28 +103,27 @@ class GraphicsGraphEvent(QGraphicsObject, QGraphicsItem):
if isinstance(item, GraphicsComponentItem): # one component
switch = {
QEvent.FocusIn: self.comp_focusInEvent,
QEvent.GraphicsSceneContextMenu: self.comp_contextMenuEvent,
QEvent.GraphicsSceneDragEnter: self.comp_dragEnterEvent,
QEvent.GraphicsSceneDragMove: self.comp_dragMoveEvent,
QEvent.GraphicsSceneDragLeave: self.comp_dragLeaveEvent,
QEvent.GraphicsSceneDrop: self.comp_dropEvent,
QEvent.GraphicsSceneHoverEnter: self.comp_hoverEnterEvent,
QEvent.GraphicsSceneHoverMove: self.comp_hoverMoveEvent,
QEvent.GraphicsSceneHoverLeave: self.comp_hoverLeaveEvent,
# QEvent.FocusIn: self.comp_focusInEvent,
# QEvent.GraphicsSceneContextMenu: self.comp_contextMenuEvent,
# QEvent.GraphicsSceneDragEnter: self.comp_dragEnterEvent,
# QEvent.GraphicsSceneDragMove: self.comp_dragMoveEvent,
# QEvent.GraphicsSceneDragLeave: self.comp_dragLeaveEvent,
# QEvent.GraphicsSceneDrop: self.comp_dropEvent,
# QEvent.GraphicsSceneHoverEnter: self.comp_hoverEnterEvent,
# QEvent.GraphicsSceneHoverMove: self.comp_hoverMoveEvent,
# QEvent.GraphicsSceneHoverLeave: self.comp_hoverLeaveEvent,
QEvent.GraphicsSceneMouseMove: self.comp_mouseMoveEvent,
QEvent.GraphicsSceneMousePress: self.comp_mousePressEvent,
QEvent.GraphicsSceneMouseRelease: self.comp_mouseReleaseEvent,
QEvent.GraphicsSceneMouseDoubleClick: self.comp_mouseDoubleClickEvent,
QEvent.GraphicsSceneWheel: self.comp_wheelEvent
# QEvent.GraphicsSceneMouseDoubleClick: self.comp_mouseDoubleClickEvent,
# QEvent.GraphicsSceneWheel: self.comp_wheelEvent
}
handler = switch.get(event.type())
elif isinstance(item, GraphicsTimelineItem): # the timeline
print(f'{type(item).__name__} received {event.type()}')
switch = {
QEvent.GraphicsSceneHoverEnter: self.timeline_hoverEnterEvent,
QEvent.GraphicsSceneHoverLeave: self.timeline_hoverLeaveEvent,
# QEvent.GraphicsSceneHoverEnter: self.timeline_hoverEnterEvent,
# QEvent.GraphicsSceneHoverLeave: self.timeline_hoverLeaveEvent,
QEvent.GraphicsSceneMouseMove: self.timeline_mouseMoveEvent,
QEvent.GraphicsSceneMousePress: self.timeline_mousePressEvent,
QEvent.GraphicsSceneMouseRelease: self.timeline_mouseReleaseEvent,
......@@ -151,16 +155,9 @@ class GraphicsGraphEvent(QGraphicsObject, QGraphicsItem):
def comp_dragMoveEvent(self, event: QGraphicsSceneDragDropEvent) -> None: ...
def comp_dragLeaveEvent(self, event: QGraphicsSceneDragDropEvent) -> None: ...
def comp_dropEvent(self, event: QGraphicsSceneDragDropEvent) -> None: ...
def comp_hoverEnterEvent(self, event: QGraphicsSceneHoverEvent) -> None:
"""Changes the cursor to OpenHandCursor when hovering an object."""
self.setCursor(QCursor(Qt.OpenHandCursor))
def comp_hoverEnterEvent(self, event: QGraphicsSceneHoverEvent) -> None: ...
def comp_hoverMoveEvent(self, event: QGraphicsSceneHoverEvent) -> None: ...
def comp_hoverLeaveEvent(self, event: QGraphicsSceneHoverEvent) -> None:
"""Unsets the cursor to default cursor."""
self.unsetCursor()
def comp_hoverLeaveEvent(self, event: QGraphicsSceneHoverEvent) -> None: ...
def comp_mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None:
"""Set the position of the graphical element in the graphic scene,
......@@ -191,31 +188,23 @@ class GraphicsGraphEvent(QGraphicsObject, QGraphicsItem):
allows the item to receive future move, release and double-click events."""
item: GraphicsComponentItem = self.scene().mouseGrabberItem()
self.component_selected.emit(item.op_id)
# op = self.schedule.sfg.find_by_id(item.op_id)
# emit fill_info_table_component(op)
self._current_pos = item.mapToParent(event.pos())
self.setCursor(QCursor(Qt.ClosedHandCursor))
item.setCursor(QCursor(Qt.ClosedHandCursor))
event.accept()
def comp_mouseReleaseEvent(self, event: QGraphicsSceneMouseEvent) -> None:
"""Changes the cursor to OpenHandCursor when releasing an object."""
self.setCursor(QCursor(Qt.OpenHandCursor))
item: GraphicsComponentItem = self.scene().mouseGrabberItem()
item.setCursor(QCursor(Qt.OpenHandCursor))
def comp_mouseDoubleClickEvent(self, event: QGraphicsSceneMouseEvent) -> None: ...
def comp_wheelEvent(self, event: QGraphicsSceneWheelEvent) -> None: ...
###############################################
#### Event Handlers: GraphicsLineTem ####
###############################################
def timeline_hoverEnterEvent(self, event: QGraphicsSceneHoverEvent) -> None:
"""Changes the cursor to SizeHorCursor when hovering an object."""
self.setCursor(QCursor(Qt.SizeHorCursor))
def timeline_hoverLeaveEvent(self, event: QGraphicsSceneHoverEvent) -> None:
"""Unsets the cursor to default cursor."""
self.unsetCursor()
def timeline_mouseMoveEvent(self, event: QGraphicsSceneMouseEvent) -> None:
"""Set the position of the graphical element in the graphic scene,
translate coordinates of the cursor within the graphic element in the
......@@ -242,7 +231,6 @@ class GraphicsGraphEvent(QGraphicsObject, QGraphicsItem):
self._delta_time -= 1
item.set_text(self._delta_time)
def timeline_mousePressEvent(self, event: QGraphicsSceneMouseEvent) -> None:
"""Stores the current position in item's parent coordinates. 'event' will
by default be accepted, and this item is then the mouse grabber. This
......@@ -260,3 +248,5 @@ class GraphicsGraphEvent(QGraphicsObject, QGraphicsItem):
item.hide_label()
if self._delta_time != 0:
self.set_schedule_time(self._delta_time)
self.schedule_time_changed.emit()
......@@ -47,7 +47,7 @@ from graphics_axes_item import GraphicsAxesItem
from graphics_graph_event import GraphicsGraphEvent
class GraphicsGraphItem(QGraphicsItemGroup, GraphicsGraphEvent):
class GraphicsGraphItem(GraphicsGraphEvent, QGraphicsItemGroup):
"""A class to represent a graph in a QGraphicsScene. This class is a
subclass of QGraphicsItemGroup and contains the objects, axes from
GraphicsAxesItem, as well as components from GraphicsComponentItem. It
......@@ -63,8 +63,9 @@ class GraphicsGraphItem(QGraphicsItemGroup, GraphicsGraphEvent):
def __init__(self, schedule: Schedule, parent: Optional[QGraphicsItem] = None):
"""Constructs a GraphicsGraphItem. 'parent' is passed to QGraphicsItemGroup's constructor."""
super().__init__(parent)
self._schedule = deepcopy(schedule)
# super().__init__(parent)
super().__init__()
self._schedule = schedule
self._axes = None
self._components = []
self._components_height = 0.0
......
......@@ -102,19 +102,19 @@ def handle_exceptions(exc_type: Type[BaseException], exc_value: BaseException, e
logging.exception("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
def qt_message_handler(mode, context, message):
if mode == QtCore.QtInfoMsg:
mode = 'INFO'
elif mode == QtCore.QtWarningMsg:
mode = 'WARNING'
elif mode == QtCore.QtCriticalMsg:
mode = 'CRITICAL'
# elif mode == QtCore.QtErrorMsg:
# mode = 'ERROR'
elif mode == QtCore.QtFatalMsg:
mode = 'FATAL'
else:
mode = 'DEBUG'
print('qt_message_handler: line: %d, func: %s(), file: %s' % (
context.line, context.function, context.file))
print(' %s: %s\n' % (mode, message))
# def qt_message_handler(mode, context, message):
# if mode == QtCore.QtInfoMsg:
# mode = 'INFO'
# elif mode == QtCore.QtWarningMsg:
# mode = 'WARNING'
# elif mode == QtCore.QtCriticalMsg:
# mode = 'CRITICAL'
# # elif mode == QtCore.QtErrorMsg:
# # mode = 'ERROR'
# elif mode == QtCore.QtFatalMsg:
# mode = 'FATAL'
# else:
# mode = 'DEBUG'
# print('qt_message_handler: line: %d, func: %s(), file: %s' % (
# context.line, context.function, context.file))
# print(' %s: %s\n' % (mode, message))
......@@ -6,6 +6,7 @@ Contains the scheduler-gui MainWindow class for scheduling operations in an SFG.
Start main-window with start_gui().
"""
from copy import deepcopy
import os
import sys
from pathlib import Path
......@@ -118,6 +119,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
_debug_rects: QGraphicsItemGroup
_splitter_pos: int
_splitter_min: int
_schedule: Union[Schedule, None]
def __init__(self):
......@@ -127,17 +129,15 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self._open_file_dialog_opened = False
self._scale = 75
self._debug_rects = None
self._schedule = None
QIcon.setThemeName('breeze')
log.debug('themeName: \'{}\''.format(QIcon.themeName()))
log.debug('themeSearchPaths: {}'.format(QIcon.themeSearchPaths()))
self.setupUi(self)
# self._splitter_pos = 0
self._read_settings()
self._init_ui()
self._init_graphics()
# self._splitter_pos = self.splitter.sizes()[1]
def _init_ui(self) -> None:
......@@ -158,20 +158,8 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.closeEvent = self._close_event
# Setup info table
self.info_table.horizontalHeader().setDefaultAlignment(Qt.AlignLeft)
self.info_table.setHorizontalHeaderLabels(['Property','Value'])
# test = '#b085b2'
# self.info_table.setStyleSheet('alternate-background-color: lightGray;background-color: white;')
self.info_table.setStyleSheet('alternate-background-color: #fadefb;background-color: #ebebeb;')
self.info_table.setSpan(0, 0, 1, 2) # Span 'Schedule' over 2 columns
self.info_table.setSpan(1, 0, 1, 2) # Span 'Operator' over 2 columns
self.info_table.setItem(0, 0, QTableWidgetItem('Schedule'))
self.info_table.setItem(1, 0, QTableWidgetItem('Operator'))
self.info_table.item(0, 0).setBackground(Qt.gray)
self.info_table.item(1, 0).setBackground(Qt.gray)
# Init central-widget splitter
self._splitter_min = self.splitter.minimumSizeHint().height()
......@@ -183,15 +171,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def _init_graphics(self) -> None:
"""Initialize the QGraphics framework"""
self._scene = QGraphicsScene()
self._scene.addRect(0, 0, 0, 0) # dummy rect to be able to setPos graph
self._scene.addRect(0, 0, 0, 0) # dummy rect to be able to setPos() graph
self.view.setScene(self._scene)
self.view.scale(self._scale, self._scale)
GraphicsComponentItem._scale = self._scale
GraphicsAxesItem._scale = self._scale
self._scene.changed.connect(self.shrink_scene_to_min_size)
self._scene.sceneRectChanged.connect(self.shrink_scene_to_min_size)
@property
def schedule(self) -> Schedule:
return self._schedule
###############
......@@ -199,7 +189,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
###############
@Slot()
def actionTbtn(self) -> None:
self._graph.schedule.plot_schedule()
self.schedule.plot_schedule()
print(f'filtersChildEvents(): {self._graph.filtersChildEvents()}')
# self.printButtonPressed('callback_pushButton()')
......@@ -248,9 +238,9 @@ class MainWindow(QMainWindow, Ui_MainWindow):
ret_tuple = QInputDialog.getItem(self,
self.tr('Load object'),
self.tr('Found the following Schedule object(s) in file.)\n\n'
self.tr('Found the following Schedule object(s) in file.\n\n'
'Select an object to proceed:'),
schedule_obj_list.keys(),0,False)
schedule_obj_list.keys(), 0, False)
if not ret_tuple[1]: # User canceled the operation
log.debug('Load schedule operation: user canceled')
......@@ -263,12 +253,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
@Slot()
def close_schedule(self) -> None:
self._graph.removeSceneEventFilters(self._graph.event_items)
self._scene.removeItem(self._graph)
self.menu_close_schedule.setEnabled(False)
del self._graph
self._graph = None
self.clear_info_table()
if self._graph:
self._graph.component_selected.disconnect(self.info_table_update_component)
self._graph.schedule_time_changed.disconnect(self.info_table_update_schedule)
self._graph.removeSceneEventFilters(self._graph.event_items)
self._scene.removeItem(self._graph)
self.menu_close_schedule.setEnabled(False)
del self._graph
self._graph = None
del self._schedule
self._schedule = None
self.info_table_clear()
@Slot()
def save(self) -> None:
......@@ -319,15 +314,20 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self._splitter_pos = width
@Slot(str)
def fill_info_table_component(self, op_id: str) -> None:
def info_table_update_component(self, op_id: str) -> None:
"""Taked in an operator-id, first clears the 'Operator' part of the info
table and then fill in the table with new values from the operator
associated with 'op_id'."""
self.clear_info_table_component()
self._fill_info_table_component(op_id)
self.info_table_clear_component()
self._info_table_fill_component(op_id)
@Slot('QList<QRectF>')
def shrink_scene_to_min_size(self, region: List[QRectF]) -> None:
@Slot()
def info_table_update_schedule(self) -> None:
"""Updates the 'Schedule' part of the info table."""
self.info_table.item(1, 1).setText(str(self.schedule.schedule_time))
@Slot(QRectF)
def shrink_scene_to_min_size(self, rect: QRectF) -> None:
self._scene.setSceneRect(self._scene.itemsBoundingRect())
......@@ -379,16 +379,17 @@ class MainWindow(QMainWindow, Ui_MainWindow):
def open(self, schedule: Schedule) -> None:
"""Takes in an Schedule and creates a GraphicsGraphItem object."""
if self._graph:
print('Graph opened!')
self.close_schedule()
self._graph = GraphicsGraphItem(schedule)
self.close_schedule()
self._schedule = deepcopy(schedule)
self._graph = GraphicsGraphItem(self.schedule)
self._graph.setPos(1/self._scale, 1/self._scale)
self.menu_close_schedule.setEnabled(True)
self._scene.addItem(self._graph)
self._graph.installSceneEventFilters(self._graph.event_items)
self._graph.component_selected.connect(self.fill_info_table_component)
self.fill_info_table_schedule(self._graph.schedule)
self._graph.component_selected.connect(self.info_table_update_component)
self._graph.schedule_time_changed.connect(self.info_table_update_schedule)
self.info_table_fill_schedule(self.schedule)
self.update_statusbar(self.tr('Schedule loaded successfully'))
def update_statusbar(self, msg: str) -> None:
......@@ -427,7 +428,7 @@ class MainWindow(QMainWindow, Ui_MainWindow):
log.debug('Settings read from \'{}\'.'.format(s.fileName()))
def fill_info_table_schedule(self, schedule: Schedule) -> None:
def info_table_fill_schedule(self, schedule: Schedule) -> None:
"""Takes in a Schedule and fill in the 'Schedule' part of the info table
with values from 'schedule'"""
self.info_table.insertRow(1)
......@@ -440,10 +441,10 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.info_table.setItem(2, 1, QTableWidgetItem(str(schedule.cyclic)))
self.info_table.setItem(3, 1, QTableWidgetItem(str(schedule.resolution)))
def _fill_info_table_component(self, op_id: str) -> None:
def _info_table_fill_component(self, op_id: str) -> None:
"""Taked in an operator-id and fill in the 'Operator' part of the info
table with values from the operator associated with 'op_id'."""
op: GraphComponent = self._graph.schedule.sfg.find_by_id(op_id)
op: GraphComponent = self.schedule.sfg.find_by_id(op_id)
si = self.info_table.rowCount() # si = start index
if op.graph_id:
......@@ -457,29 +458,38 @@ class MainWindow(QMainWindow, Ui_MainWindow):
self.info_table.setItem(si, 1, QTableWidgetItem(str(op.name)))
si += 1
# params: dict = op.params
print('Params:')
pprint(op.params)
for key, value in op.params:
for key, value in op.params.items():
self.info_table.insertRow(si)
self.info_table.setItem(si, 0, QTableWidgetItem(key))
self.info_table.setItem(si, 1, QTableWidgetItem(str(value)))
si += 1
def clear_info_table(self) -> None:
def info_table_clear(self) -> None:
"""Clears the info table."""
self.clear_info_table_component()
if self.info_table.rowCount() > 2:
for _ in range(3):
self.info_table.removeRow(1)
self.info_table_clear_component()
self.info_table_clear_schedule()
def clear_info_table_component(self) -> None:
"""Clears only the component part of the info table, assuming that the table is filled."""
if self.info_table.rowCount() > 5:
for _ in range(self.info_table.rowCount() - 5):
self.info_table.removeRow(2)
def info_table_clear_schedule(self) -> None:
"""Clears the schedule part of the info table."""
row = self.info_table.findItems('Operator', Qt.MatchExactly)
if row:
row = row[0].row()
if row > 1:
for _ in range(3):
self.info_table.removeRow(1)
else:
log.error("'Operator' not found in info table. It may have been renamed.")
def info_table_clear_component(self) -> None:
"""Clears the component part of the info table."""
row = self.info_table.findItems('Operator', Qt.MatchExactly)
if row:
row = row[0].row()
for _ in range(self.info_table.rowCount() - row + 1):
self.info_table.removeRow(row + 1)
else:
log.error("'Operator' not found in info table. It may have been renamed.")
def start_gui():
......
......@@ -64,6 +64,9 @@
</property>
</widget>
<widget class="QTableWidget" name="info_table">
<property name="styleSheet">
<string notr="true">alternate-background-color: #fadefb;background-color: #ebebeb;</string>
</property>
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
......@@ -89,12 +92,98 @@
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>21</number>
<number>19</number>
</attribute>
<row/>
<row/>
<column/>
<column/>
<row>
<property name="text">
<string>1</string>
</property>
</row>
<row>
<property name="text">
<string>2</string>
</property>
</row>
<column>
<property name="text">
<string>Property</string>
</property>
<property name="textAlignment">
<set>AlignLeading|AlignVCenter</set>
</property>
</column>
<column>
<property name="text">
<string>Value</string>
</property>
<property name="textAlignment">
<set>AlignLeading|AlignVCenter</set>
</property>
</column>
<item row="0" column="0">
<property name="text">
<string>Schedule</string>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="background">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>160</red>
<green>160</green>
<blue>164</blue>
</color>
</brush>
</property>
<property name="foreground">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</property>
<property name="flags">
<set>ItemIsSelectable|ItemIsEditable|ItemIsDragEnabled|ItemIsDropEnabled|ItemIsUserCheckable</set>
</property>
</item>
<item row="1" column="0">
<property name="text">
<string>Operator</string>
</property>
<property name="font">
<font>
<weight>75</weight>
<bold>true</bold>
</font>
</property>
<property name="background">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>160</red>
<green>160</green>
<blue>164</blue>
</color>
</brush>
</property>
<property name="foreground">
<brush brushstyle="SolidPattern">
<color alpha="255">
<red>255</red>
<green>255</green>
<blue>255</blue>
</color>
</brush>
</property>
<property name="flags">
<set>ItemIsSelectable|ItemIsEditable|ItemIsDragEnabled|ItemIsDropEnabled|ItemIsUserCheckable</set>
</property>
</item>
</widget>
</widget>
</item>
......@@ -249,6 +338,10 @@
<property name="checkable">
<bool>true</bool>
</property>
<property name="icon">
<iconset theme="view-close">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Hide exit dialog</string>
</property>
......@@ -265,6 +358,10 @@
<property name="enabled">
<bool>false</bool>
</property>
<property name="icon">
<iconset theme="view-close">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>&amp;Close Schedule</string>
</property>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment