diff --git a/b_asic/scheduler-gui/graphics_axes_item.py b/b_asic/scheduler-gui/graphics_axes_item.py index 02b84900250f75751698671b51db0acb2d2a378e..445bdcf0112520d5d13cb094cf4197b049cf89f5 100644 --- a/b_asic/scheduler-gui/graphics_axes_item.py +++ b/b_asic/scheduler-gui/graphics_axes_item.py @@ -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 diff --git a/b_asic/scheduler-gui/graphics_graph_event.py b/b_asic/scheduler-gui/graphics_graph_event.py index f9b7b9a4e81dfcdc097c94737041930bc934b7ec..00aaa934a0cd626af0436bbd3884b0cf529bdd8e 100644 --- a/b_asic/scheduler-gui/graphics_graph_event.py +++ b/b_asic/scheduler-gui/graphics_graph_event.py @@ -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() + diff --git a/b_asic/scheduler-gui/graphics_graph_item.py b/b_asic/scheduler-gui/graphics_graph_item.py index 147cf984178f1353fcd8711a6f948f618dfba3ee..692c179d2d842886240a451f27ecf31783948429 100644 --- a/b_asic/scheduler-gui/graphics_graph_item.py +++ b/b_asic/scheduler-gui/graphics_graph_item.py @@ -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 diff --git a/b_asic/scheduler-gui/logger.py b/b_asic/scheduler-gui/logger.py index 2c40500bf357b2b6f0ba2a1a41b4be4b78831c63..bdbc06bbbba10fae924103b7ea2f91e4533a9ea3 100644 --- a/b_asic/scheduler-gui/logger.py +++ b/b_asic/scheduler-gui/logger.py @@ -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)) diff --git a/b_asic/scheduler-gui/main_window.py b/b_asic/scheduler-gui/main_window.py index df69b0d6db8e8550d53a9c5c63de18a2cdd04e72..b6d67de4abcdd28c8848eaa5594d212c1b8d37f6 100644 --- a/b_asic/scheduler-gui/main_window.py +++ b/b_asic/scheduler-gui/main_window.py @@ -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(): diff --git a/b_asic/scheduler-gui/main_window.ui b/b_asic/scheduler-gui/main_window.ui index c11f5929a380e2d77f2c5809b4ba510a35dc2412..ea181cbe7ad94a6c4cb71f09a297667189c849a1 100644 --- a/b_asic/scheduler-gui/main_window.ui +++ b/b_asic/scheduler-gui/main_window.ui @@ -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>&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>&Close Schedule</string> </property>