def set_window_size_and_position(window, window_key): """Adjust GTK Window's size, position and maximized state according to the corresponding values in the runtime_config file. The maximize method is triggered last to restore also the last stored size and position of the window. If the runtime_config does not exist, or the corresponding values are missing in the file, default values for the window size are used, and the mouse position is used to adjust the window's position. :param window: The GTK Window to be adjusted :param window_key: The window's key stored in the runtime config file """ size = global_runtime_config.get_config_value(window_key + '_WINDOW_SIZE') position = global_runtime_config.get_config_value(window_key + '_WINDOW_POS') maximized = global_runtime_config.get_config_value(window_key + '_WINDOW_MAXIMIZED') # un-maximize here on purpose otherwise resize and reposition fails if not maximized: window.unmaximize() if not size: size = constants.WINDOW_SIZE[window_key + '_WINDOW'] window.resize(*size) if position: position = (max(0, position[0]), max(0, position[1])) screen_width = gtk.gdk.screen_width() screen_height = gtk.gdk.screen_height() if position[0] < screen_width and position[1] < screen_height: window.move(*position) else: window.set_position(gtk.WIN_POS_MOUSE) if maximized: window.maximize() window.show()
def save_folder(query, default_name=None): """Shows a user dialog to save a folder/file A dialog is opened with the prompt `query`. The current path is set to the last path that was opened/created. The roots of all libraries is added to the list of shortcut folders. The file name can be folder or file. No existence check is performed. :param str query: Prompt asking the user for a specific path and a name in the entry widget :param str default_name: Default name of mounting point/library root key :return: Path handed by the user or `last_path`/`default_name` if no path was specified and None if directory does not exist (parent of name) :rtype: str """ from os.path import expanduser, dirname, join, exists, isdir from gi.repository import Gtk from rafcon.core.storage.storage import STATEMACHINE_FILE from rafcon.gui.singleton import main_window_controller from rafcon.gui.runtime_config import global_runtime_config last_path = global_runtime_config.get_config_value('LAST_PATH_OPEN_SAVE', "") if last_path and isdir(last_path) and not exists( join(last_path, STATEMACHINE_FILE)): pass elif last_path: last_path = dirname(last_path) else: last_path = expanduser('~') dialog = Gtk.FileChooserDialog(title=query, transient_for=None, action=Gtk.FileChooserAction.SAVE) dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK) # Allows confirming with Enter and double-click dialog.set_default_response(Gtk.ResponseType.OK) if main_window_controller: dialog.set_transient_for( main_window_controller.view.get_parent_widget()) dialog.set_current_folder(last_path) if default_name: dialog.set_current_name(default_name) dialog.set_show_hidden(False) # Add library roots to list of shortcut folders add_library_root_path_to_shortcut_folders_of_dialog(dialog) response = dialog.run() if response != Gtk.ResponseType.OK: dialog.destroy() return None path = dialog.get_filename() dialog.destroy() # check path existence if not exists(dirname(path)): return None return path
def prepare_destruction(self): """Saves current configuration of windows and panes to the runtime config file, before RAFCON is closed.""" plugins.run_hook("pre_destruction") logger.debug("Saving runtime config to {0}".format( global_runtime_config.config_file_path)) # store pane last positions for key, widget_name in constants.PANE_ID.items(): global_runtime_config.store_widget_properties( self.view[widget_name], key.replace('_POS', '')) # store hidden or undocked widget flags correctly -> make them independent for restoring for window_key in constants.UNDOCKABLE_WINDOW_KEYS: hidden = False if not global_runtime_config.get_config_value(window_key + "_WINDOW_UNDOCKED"): hidden = getattr(self, window_key.lower() + '_hidden') global_runtime_config.set_config_value(window_key + '_HIDDEN', hidden) global_runtime_config.save_configuration() # state-editor will relieve it's model => it won't observe the state machine manager any more self.get_controller('states_editor_ctrl').prepare_destruction( ) # avoid new state editor TODO tbd (deleted) rafcon.core.singleton.state_machine_manager.delete_all_state_machines() rafcon.core.singleton.library_manager.prepare_destruction() # Recursively destroys the main window self.destroy() from rafcon.gui.clipboard import global_clipboard global_clipboard.destroy() gui_singletons.main_window_controller = None
def get_stored_window_size(window_name): from rafcon.gui.runtime_config import global_runtime_config from rafcon.gui.utils import constants size = global_runtime_config.get_config_value(window_name.upper() + '_SIZE') if not size: size = constants.WINDOW_SIZE[window_name.upper()] return size
def create_folder(query, default_name=None, default_path=None): """Shows a user dialog for folder creation A dialog is opened with the prompt `query`. The current path is set to the last path that was opened/created. The roots of all libraries is added to the list of shortcut folders. :param str query: Prompt asking the user for a specific folder :param str default_name: Default name of the folder to be created :param str default_path: Path in which the folder is created if the user doesn't specify a path :return: Path created by the user or `default_path`\`default_name` if no path was specified or None if none of the paths is valid :rtype: str """ from os.path import expanduser, dirname, join, exists, isdir from rafcon.core.storage.storage import STATEMACHINE_FILE last_path = global_runtime_config.get_config_value('LAST_PATH_OPEN_SAVE', "") if last_path and isdir(last_path) and not exists( join(last_path, STATEMACHINE_FILE)): pass elif last_path: last_path = dirname(last_path) else: last_path = expanduser('~') dialog = gtk.FileChooserDialog(query, None, gtk.FILE_CHOOSER_ACTION_CREATE_FOLDER, (gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_SAVE, gtk.RESPONSE_OK)) # Allows confirming with Enter and double-click dialog.set_default_response(gtk.RESPONSE_OK) if main_window_controller: dialog.set_transient_for(main_window_controller.view.get_top_widget()) dialog.set_current_folder(last_path) if default_name: dialog.set_current_name(default_name) dialog.set_show_hidden(False) # Add library roots to list of shortcut folders add_library_root_path_to_shortcut_folders_of_dialog(dialog) response = dialog.run() if response != gtk.RESPONSE_OK: dialog.destroy() if default_path and default_name: default = os.path.join(default_path, default_name) if os.path.isdir(default): return default return None path = dialog.get_filename() dialog.destroy() if os.path.isdir(path): global_runtime_config.set_config_value('LAST_PATH_OPEN_SAVE', path) return path return None
def open_folder(query, default_path=None): """Shows a user dialog for folder selection A dialog is opened with the prompt `query`. The current path is set to the last path that was opened/created. The roots of all libraries is added to the list of shortcut folders. :param str query: Prompt asking the user for a specific folder :param str default_path: Path to use if user does not specify one :return: Path selected by the user or `default_path` if no path was specified or None if none of the paths is valid :rtype: str """ from gi.repository import Gtk from os.path import expanduser, pathsep, dirname, isdir from rafcon.gui.singleton import main_window_controller from rafcon.gui.runtime_config import global_runtime_config last_path = global_runtime_config.get_config_value('LAST_PATH_OPEN_SAVE', "") selected_filename = None if last_path and isdir(last_path): selected_filename = last_path.split(pathsep)[-1] last_path = dirname(last_path) else: last_path = expanduser('~') dialog = Gtk.FileChooserDialog(title=query, transient_for=None, action=Gtk.FileChooserAction.SELECT_FOLDER) dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK) # Allows confirming with Enter and double-click dialog.set_default_response(Gtk.ResponseType.OK) if main_window_controller: dialog.set_transient_for( main_window_controller.view.get_parent_widget()) dialog.set_current_folder(last_path) if selected_filename is not None: dialog.select_filename(selected_filename) dialog.set_show_hidden(False) # Add library roots to list of shortcut folders add_library_root_path_to_shortcut_folders_of_dialog(dialog) response = dialog.run() if response != Gtk.ResponseType.OK: dialog.destroy() if default_path and os.path.isdir(default_path): return default_path return None path = dialog.get_filename() dialog.destroy() if os.path.isdir(path): global_runtime_config.set_config_value('LAST_PATH_OPEN_SAVE', path) return path return None
def has_label(self): if self.has_outgoing_connection(): return False if not global_runtime_config.get_config_value( "SHOW_ABORTED_PREEMPTED", False) and self.outcome_id in [ -1, -2 ]: return False return True
def set_pane_position(self, config_id): """Adjusts the position of a GTK Pane to a value stored in the runtime config file. If there was no value stored, the pane's position is set to a default value. :param config_id: The pane identifier saved in the runtime config file """ default_pos = constants.DEFAULT_PANE_POS[config_id] position = global_runtime_config.get_config_value(config_id, default_pos) pane_id = constants.PANE_ID[config_id] self.view[pane_id].set_position(position)
def pane_position_check(self): """ Update right bar pane position if needed Checks calculates if the cursor is still visible and updates the pane position if it is close to not be seen. In case of an un-docked right-bar this method does nothing. :return: """ text_buffer = self.get_buffer() # not needed if the right side bar is un-docked from rafcon.gui.singleton import main_window_controller if main_window_controller is None or main_window_controller.view is None: return from rafcon.gui.runtime_config import global_runtime_config if global_runtime_config.get_config_value('RIGHT_BAR_WINDOW_UNDOCKED'): return # move the pane left if the cursor is to far right and the pane position is less then 440 from its max position button_container_min_width = self.button_container_min_width width_of_all = button_container_min_width + self.tab_width text_view_width = button_container_min_width - self.line_numbers_width min_line_string_length = float(button_container_min_width) / float( self.source_view_character_size) current_pane_pos = main_window_controller.view[ 'right_h_pane'].get_property('position') max_position = main_window_controller.view[ 'right_h_pane'].get_property('max_position') pane_rel_pos = main_window_controller.view[ 'right_h_pane'].get_property('max_position') - current_pane_pos if pane_rel_pos >= width_of_all + self.line_numbers_width: pass else: cursor_line_offset = text_buffer.get_iter_at_offset( text_buffer.props.cursor_position).get_line_offset() needed_rel_pos = text_view_width/min_line_string_length*cursor_line_offset \ + self.tab_width + self.line_numbers_width needed_rel_pos = min(width_of_all, needed_rel_pos) if pane_rel_pos >= needed_rel_pos: pass else: main_window_controller.view['right_h_pane'].set_property( 'position', max_position - needed_rel_pos) spacer_width = int(width_of_all + self.line_numbers_width - needed_rel_pos) self.spacer_frame.set_size_request(width=spacer_width, height=-1)
def prepare_destruction(self): """Saves current configuration of windows and panes to the runtime config file, before RAFCON is closed.""" plugins.run_hook("pre_destruction") logger.debug("Saving runtime config to {0}".format( global_runtime_config.config_file_path)) # store pane last positions for key, widget_name in constants.PANE_ID.items(): global_runtime_config.store_widget_properties( self.view[widget_name], key.replace('_POS', '')) # store hidden or undocked widget flags correctly -> make them independent for restoring for window_key in constants.UNDOCKABLE_WINDOW_KEYS: hidden = False if not global_runtime_config.get_config_value(window_key + "_WINDOW_UNDOCKED"): hidden = getattr(self, window_key.lower() + '_hidden') global_runtime_config.set_config_value(window_key + '_HIDDEN', hidden) global_runtime_config.save_configuration() # state-editor will relieve it's model => it won't observe the state machine manager any more self.get_controller('states_editor_ctrl').prepare_destruction( ) # avoid new state editor TODO tbd (deleted) rafcon.core.singleton.state_machine_manager.delete_all_state_machines() rafcon.core.singleton.library_manager.prepare_destruction() # gtkmvc installs a global glade custom handler that holds a reference to the last created View class, # preventing it from being destructed. By installing a dummy callback handler, after all views have been # created, the old handler is being removed and with it the reference, allowing all Views to be destructed. # Gtk TODO: check if necessary and search for replacement # try: # from gtk import glade # def dummy(*args, **kwargs): # pass # glade.set_custom_handler(dummy) # except ImportError: # pass # Recursively destroys the main window self.destroy() from rafcon.gui.clipboard import global_clipboard global_clipboard.destroy() gui_singletons.main_window_controller = None
def _update_recently_opened_state_machines(self): """Update the sub menu Open Recent in File menu Method clean's first all menu items of the sub menu 'recent open', then insert the user menu item to clean recent opened state machine paths and finally insert menu items for all elements in recent opened state machines list. """ if not self.registered_view: return for item in self.view.sub_menu_open_recently.get_children(): self.view.sub_menu_open_recently.remove(item) menu_item = gui_helper_label.create_menu_item( "remove invalid paths", constants.ICON_ERASE, global_runtime_config.clean_recently_opened_state_machines) self.view.sub_menu_open_recently.append(menu_item) self.view.sub_menu_open_recently.append(Gtk.SeparatorMenuItem()) for sm_path in global_runtime_config.get_config_value( "recently_opened_state_machines", []): # define label string root_state_name = gui_helper_state_machine.get_root_state_name_of_sm_file_system_path( sm_path) if root_state_name is None and not os.path.isdir(sm_path): root_state_name = 'NOT_ACCESSIBLE' label_string = "'{0}' in {1}".format( root_state_name, sm_path) if root_state_name is not None else sm_path # define icon of menu item is_in_libs = library_manager.is_os_path_within_library_root_paths( sm_path) button_image = constants.SIGN_LIB if is_in_libs else constants.BUTTON_OPEN # prepare state machine open call_back function sm_open_function = partial(self.on_open_activate, path=sm_path) # create and insert new menu item menu_item = gui_helper_label.create_menu_item( label_string, button_image, sm_open_function) self.view.sub_menu_open_recently.append(menu_item) self.view.sub_menu_open_recently.show_all()
def show_connection(self): return global_runtime_config.get_config_value("SHOW_TRANSITIONS", True)
def register_view(self, view): super(MainWindowController, self).register_view(view) self.register_actions(self.shortcut_manager) self.view.get_top_widget().connect("key-press-event", self._on_key_press) self.view.get_top_widget().connect("key-release-event", self._on_key_release) # using helper function to connect functions to GUI elements to be able to access the handler id later on self.connect_button_to_function( 'main_window', "delete_event", self.get_controller('menu_bar_controller').on_quit_activate) # connect left bar, right bar and console hide buttons' signals to their corresponding methods self.connect_button_to_function('left_bar_hide_button', "clicked", self.on_left_bar_hide_clicked) self.connect_button_to_function('right_bar_hide_button', "clicked", self.on_right_bar_hide_clicked) self.connect_button_to_function('console_hide_button', "clicked", self.on_console_hide_clicked) # Connect left bar, right bar and console return buttons' signals to their corresponding methods self.connect_button_to_function('left_bar_return_button', "clicked", self.on_left_bar_return_clicked) self.connect_button_to_function('right_bar_return_button', "clicked", self.on_right_bar_return_clicked) self.connect_button_to_function('console_return_button', "clicked", self.on_console_return_clicked) # Connect undock buttons signals for window_key in constants.UNDOCKABLE_WINDOW_KEYS: self.connect_button_to_function( 'undock_{}_button'.format(window_key.lower()), "clicked", partial(self.undock_sidebar, window_key)) # Connect collapse button for trees self.connect_button_to_function('collapse_tree_button', "clicked", self.on_collapse_button_clicked) # Connect Shortcut buttons' signals to their corresponding methods self.connect_button_to_function('button_start_shortcut', "toggled", self.on_button_start_shortcut_toggled) self.connect_button_to_function('button_stop_shortcut', "clicked", self.on_button_stop_shortcut_clicked) self.connect_button_to_function('button_pause_shortcut', "toggled", self.on_button_pause_shortcut_toggled) self.connect_button_to_function( 'button_start_from_shortcut', "clicked", self.on_button_start_from_shortcut_clicked) self.connect_button_to_function('button_run_to_shortcut', "clicked", self.on_button_run_to_shortcut_clicked) self.connect_button_to_function( 'button_step_mode_shortcut', "toggled", self.on_button_step_mode_shortcut_toggled) self.connect_button_to_function( 'button_step_in_shortcut', "clicked", self.on_button_step_in_shortcut_clicked) self.connect_button_to_function( 'button_step_over_shortcut', "clicked", self.on_button_step_over_shortcut_clicked) self.connect_button_to_function( 'button_step_out_shortcut', "clicked", self.on_button_step_out_shortcut_clicked) self.connect_button_to_function( 'button_step_backward_shortcut', "clicked", self.on_button_step_backward_shortcut_clicked) view['upper_notebook'].connect('switch-page', self.on_notebook_tab_switch, view['upper_notebook_title'], view.left_bar_window, 'upper') view['lower_notebook'].connect('switch-page', self.on_notebook_tab_switch, view['lower_notebook_title'], view.left_bar_window, 'lower') view.get_top_widget().connect("configure-event", self.update_widget_runtime_config, "MAIN_WINDOW") view.left_bar_window.get_top_widget().connect( "configure-event", self.update_widget_runtime_config, "LEFT_BAR_WINDOW") view.right_bar_window.get_top_widget().connect( "configure-event", self.update_widget_runtime_config, "RIGHT_BAR_WINDOW") view.console_window.get_top_widget().connect( "configure-event", self.update_widget_runtime_config, "CONSOLE_WINDOW") # save pane positions in the runtime config on every change view['top_level_h_pane'].connect("button-release-event", self.update_widget_runtime_config, "LEFT_BAR_DOCKED") view['right_h_pane'].connect("button-release-event", self.update_widget_runtime_config, "RIGHT_BAR_DOCKED") view['central_v_pane'].connect("button-release-event", self.update_widget_runtime_config, "CONSOLE_DOCKED") # hide not usable buttons self.view['step_buttons'].hide() # Initializing Main Window Size & Position # secure un maximize in initial condition to restore correct position and size view.get_top_widget().unmaximize() gui_helper_label.set_window_size_and_position(view.get_top_widget(), 'MAIN') wait_for_gui() # Initializing Pane positions for config_id in constants.PANE_ID: self.set_pane_position(config_id) # set the hidden status of all bars for window_key in constants.UNDOCKABLE_WINDOW_KEYS: if global_runtime_config.get_config_value(window_key + '_HIDDEN'): func = getattr(self, 'on_{}_hide_clicked'.format(window_key.lower())) func(None) # restore undock state of bar windows if gui_config.get_config_value("RESTORE_UNDOCKED_SIDEBARS"): for window_key in constants.UNDOCKABLE_WINDOW_KEYS: if global_runtime_config.get_config_value(window_key + "_WINDOW_UNDOCKED"): self.undock_sidebar(window_key) # secure maximized state if global_runtime_config.get_config_value("MAIN_WINDOW_MAXIMIZED"): wait_for_gui() view.get_top_widget().maximize() # check for auto backups if gui_config.get_config_value( 'AUTO_BACKUP_ENABLED') and gui_config.get_config_value( 'AUTO_RECOVERY_CHECK'): import rafcon.gui.models.auto_backup as auto_backup auto_backup.check_for_crashed_rafcon_instances() plugins.run_hook("main_window_setup", self) wait_for_gui() # Ensure that the next message is being printed (needed for LN manager to detect finished startup) level = logger.level logger.setLevel(logging.INFO) logger.info("Ready") logger.setLevel(level)
def test_pane_positions(gui): from rafcon.gui.runtime_config import global_runtime_config from rafcon.gui.utils import constants main_window_controller = gui.singletons.main_window_controller debug_sleep_time = 0.0 stored_pane_positions = {} for config_id, pan_id in constants.PANE_ID.items(): default_pos = constants.DEFAULT_PANE_POS[config_id] stored_pane_positions[ config_id] = global_runtime_config.get_config_value( config_id, default_pos) if stored_pane_positions[config_id] is None: import logging logging.warning("runtime_config-file has missing values?") return def test_bar(window, window_key): configure_handler_id = connect_window(gui, window, 'configure-event', notify_on_event) hide_handler_id = connect_window(gui, window, 'hide', notify_on_event) print("undocking...") time.sleep(debug_sleep_time) ready.clear() gui( main_window_controller.view["undock_{}_button".format( window_key.lower())].emit, "clicked") wait_for_event_notification(gui) print("docking...") time.sleep(debug_sleep_time) ready.clear() attribute_name_of_undocked_window_view = window_key.lower() + "_window" undocked_window_view = getattr(main_window_controller.view, attribute_name_of_undocked_window_view) redock_button = undocked_window_view['redock_button'] gui(redock_button.emit, "clicked") wait_for_event_notification(gui) time.sleep(debug_sleep_time) gui(window.disconnect, configure_handler_id) gui(window.disconnect, hide_handler_id) # Info: un- and redocking the left bar will change the right bar position; # thus, the equality check has to be done directly after un- and redocking the right bar print("=> test right_bar_window") test_bar(main_window_controller.view.right_bar_window.get_top_widget(), "RIGHT_BAR") gui(wait_for_gui) config_id = 'RIGHT_BAR_DOCKED_POS' pane_id = constants.PANE_ID['RIGHT_BAR_DOCKED_POS'] print("check pos of ", config_id, pane_id) assert_pos_equality(main_window_controller.view[pane_id].get_position(), stored_pane_positions[config_id], 10) print("=> test console_window") test_bar(main_window_controller.view.console_window.get_top_widget(), "CONSOLE") gui(wait_for_gui) config_id = 'CONSOLE_DOCKED_POS' pane_id = constants.PANE_ID['CONSOLE_DOCKED_POS'] print("check pos of ", config_id, pane_id) assert_pos_equality(main_window_controller.view[pane_id].get_position(), stored_pane_positions[config_id], 10) print("=> test left_bar_window") test_bar(main_window_controller.view.left_bar_window.get_top_widget(), "LEFT_BAR") gui(wait_for_gui) config_id = 'LEFT_BAR_DOCKED_POS' pane_id = constants.PANE_ID['LEFT_BAR_DOCKED_POS'] print("check pos of ", config_id, pane_id) assert_pos_equality(main_window_controller.view[pane_id].get_position(), stored_pane_positions[config_id], 10)
def show_data_port_label(self): return global_runtime_config.get_config_value("SHOW_DATA_FLOWS", True)
def test_bar(window, window_key): attribute_name_of_undocked_window_view = window_name = window_key.lower( ) + "_window" configure_handler_id = connect_window(gui, window, 'configure-event', notify_on_resize_event) hide_handler_id = connect_window(gui, window, 'hide', notify_on_event) logger.info("undocking...") time.sleep(debug_sleep_time) ready.clear() gui( main_window_controller.view["undock_{}_button".format( window_key.lower())].emit, "clicked") wait_for_event_notification(gui) assert window.get_property('visible') is True expected_size = get_stored_window_size(window_name) new_size = window.get_size() # print dir(window) if not bool(window.is_maximized()): assert_size_equality(new_size, expected_size, 90) else: maximized_parameter_name = window_key + "_WINDOW_MAXIMIZED" assert bool(window.is_maximized() ) and global_runtime_config.get_config_value( maximized_parameter_name) logger.info("resizing...") time.sleep(debug_sleep_time) ready.clear() target_size = (1400, 800) try: assert_size_equality(new_size, target_size, 90) # Change target size if it is similar to the current size target_size = (1600, 900) except AssertionError: pass logger.debug("target size: {}".format(target_size)) gui(window.resize, *target_size) wait_for_event_notification(gui) try: assert_size_equality(event_size, target_size, 90) except AssertionError: # For unknown reasons, there are two configure events and only the latter one if for the new window size ready.clear() wait_for_event_notification(gui) assert_size_equality(event_size, target_size, 90) logger.info("got additional configure-event") logger.info("docking...") undocked_window_view = getattr(main_window_controller.view, attribute_name_of_undocked_window_view) redock_button = undocked_window_view['redock_button'] time.sleep(debug_sleep_time) ready.clear() gui(redock_button.emit, "clicked") wait_for_event_notification(gui) assert window.get_property('visible') is False logger.info("undocking...") time.sleep(debug_sleep_time) ready.clear() show_handler_id = connect_window(gui, window, 'show', notify_on_event) gui( main_window_controller.view["undock_{}_button".format( window_key.lower())].emit, "clicked") wait_for_event_notification(gui) assert window.get_property('visible') is True assert_size_equality(window.get_size(), target_size, 90) logger.info("docking...") time.sleep(debug_sleep_time) ready.clear() gui(redock_button.emit, "clicked") wait_for_event_notification(gui) assert window.get_property('visible') is False gui(window.disconnect, configure_handler_id) gui(window.disconnect, show_handler_id) gui(window.disconnect, hide_handler_id)
def create_folder(query, default_name=None, default_path=None, current_folder=None): """Shows a user dialog for folder creation A dialog is opened with the prompt `query`. The current path is set to the last path that was opened/created. The roots of all libraries is added to the list of shortcut folders. :param str query: Prompt asking the user for a specific folder :param str default_name: Default name of the folder to be created :param str default_path: Path in which the folder is created if the user doesn't specify a path :param str current_folder: Current folder that the FileChooserDialog points to in the beginning :return: Path created by the user or `default_path`/`default_name` if no path was specified or None if none of the paths is valid :rtype: str """ from gi.repository import Gtk from os.path import expanduser, dirname, join, exists, isdir from rafcon.core.storage.storage import STATEMACHINE_FILE from rafcon.gui.singleton import main_window_controller from rafcon.gui.runtime_config import global_runtime_config last_path = global_runtime_config.get_config_value('LAST_PATH_OPEN_SAVE', "") if last_path and isdir(last_path) and not exists( join(last_path, STATEMACHINE_FILE)): pass elif last_path: last_path = dirname(last_path) else: last_path = expanduser('~') dialog = Gtk.FileChooserDialog(title=query, transient_for=None, action=Gtk.FileChooserAction.CREATE_FOLDER) dialog.add_buttons(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL, Gtk.STOCK_OPEN, Gtk.ResponseType.OK) # dialog.add_buttons(Gtk.ButtonsType.OK_CANCEL) # Allows confirming with Enter and double-click dialog.set_default_response(Gtk.ResponseType.OK) if main_window_controller: dialog.set_transient_for( main_window_controller.view.get_parent_widget()) dialog.set_current_folder(last_path) if current_folder: dialog.set_current_folder(current_folder) if default_name: dialog.set_current_name(default_name) dialog.set_show_hidden(False) # Add library roots to list of shortcut folders add_library_root_path_to_shortcut_folders_of_dialog(dialog) response = dialog.run() if response != Gtk.ResponseType.OK: dialog.destroy() if default_path and default_name: default = os.path.join(default_path, default_name) if os.path.isdir(default): return default return None path = dialog.get_filename() dialog.destroy() if os.path.isdir(path): global_runtime_config.set_config_value('LAST_PATH_OPEN_SAVE', path) return path return None
def check_pane_positions(): from rafcon.gui.singleton import main_window_controller from rafcon.gui.runtime_config import global_runtime_config from rafcon.gui.utils import constants debug_sleep_time = 0 stored_pane_positions = {} for config_id, pan_id in constants.PANE_ID.iteritems(): default_pos = constants.DEFAULT_PANE_POS[config_id] stored_pane_positions[ config_id] = global_runtime_config.get_config_value( config_id, default_pos) if stored_pane_positions[config_id] is None: import logging logging.warning("runtime_config-file has missing values?") return def test_bar(window, window_key): output_list = list() call_gui_callback(connect_window, window, 'configure-event', notify_on_event, output_list) configure_handler_id = output_list[0] output_list = list() call_gui_callback(connect_window, window, 'hide', notify_on_event, output_list) hide_handler_id = output_list[0] print "undocking..." time.sleep(debug_sleep_time) ready.clear() call_gui_callback( main_window_controller.view["undock_{}_button".format( window_key.lower())].emit, "clicked") wait_for_event_notification() print "docking..." time.sleep(debug_sleep_time) ready.clear() attribute_name_of_undocked_window_view = window_key.lower() + "_window" undocked_window_view = getattr(main_window_controller.view, attribute_name_of_undocked_window_view) redock_button = getattr(undocked_window_view, "top_tool_bar")['redock_button'] call_gui_callback(redock_button.emit, "clicked") wait_for_event_notification() window.disconnect(configure_handler_id) window.disconnect(hide_handler_id) print "=> test left_bar_window" test_bar(main_window_controller.view.left_bar_window.get_top_widget(), "LEFT_BAR") print "=> test right_bar_window" test_bar(main_window_controller.view.right_bar_window.get_top_widget(), "RIGHT_BAR") print "=> test console_window" test_bar(main_window_controller.view.console_window.get_top_widget(), "CONSOLE") testing_utils.wait_for_gui() print "check if pane positions are still like in runtime_config.yaml" for config_id, pane_id in constants.PANE_ID.iteritems(): print "check pos of ", config_id, pane_id assert main_window_controller.view[pane_id].get_position( ) == stored_pane_positions[config_id]
def draw_name(self, context, transparency, value): c = context.cairo port_height = self.port_size[1] label_position = self.side if not self.label_print_inside else self.side.opposite( ) position = self.pos show_additional_value = False if global_runtime_config.get_config_value( "SHOW_DATA_FLOW_VALUE_LABELS", True) and value is not None: show_additional_value = True parameters = { 'name': self.name, 'port_height': port_height, 'side': label_position, 'transparency': transparency, 'show_additional_value': show_additional_value } # add value to parameters only when value is shown on label if show_additional_value: parameters['value'] = value upper_left_corner = (position[0] + self._last_label_relative_pos[0], position[1] + self._last_label_relative_pos[1]) current_zoom = self.parent.canvas.get_first_view().get_zoom_factor() from_cache, image, zoom = self._label_image_cache.get_cached_image( self._last_label_size[0], self._last_label_size[1], current_zoom, parameters) # The parameters for drawing haven't changed, thus we can just copy the content from the last rendering result if from_cache and not context.draw_all: # print("draw port name from cache") self._label_image_cache.copy_image_to_context(c, upper_left_corner) # Parameters have changed or nothing in cache => redraw else: # print("draw port name") # First we have to do a "dry run", in order to determine the size of the new label c.move_to(position.x.value, position.y.value) extents = gap_draw_helper.draw_port_label( c, self, transparency, False, label_position, show_additional_value, value, only_extent_calculations=True) from rafcon.gui.mygaphas.utils.gap_helper import extend_extents extents = extend_extents(extents, factor=1.1) label_pos = extents[0], extents[1] relative_pos = label_pos[0] - position[0], label_pos[1] - position[ 1] label_size = extents[2] - extents[0], extents[3] - extents[1] # print(label_size[0], self.name, self.parent.model.state.name) # if label_size[0] < constants.MINIMUM_PORT_NAME_SIZE_FOR_DISPLAY and self.parent: # return self._last_label_relative_pos = relative_pos self._last_label_size = label_size # The size information is used to update the caching parameters and retrieve an image with the correct size self._label_image_cache.get_cached_image(label_size[0], label_size[1], current_zoom, parameters, clear=True) c = self._label_image_cache.get_context_for_image(current_zoom) c.move_to(-relative_pos[0], -relative_pos[1]) gap_draw_helper.draw_port_label(c, self, transparency, False, label_position, show_additional_value, value) # Copy image surface to current cairo context upper_left_corner = (position[0] + relative_pos[0], position[1] + relative_pos[1]) self._label_image_cache.copy_image_to_context(context.cairo, upper_left_corner, zoom=current_zoom) # draw_all means, the bounding box of the state is calculated # As we are using drawing operation, not supported by Gaphas, we manually need to update the bounding box if context.draw_all: from gaphas.geometry import Rectangle view = self.parent.canvas.get_first_view() abs_pos = view.get_matrix_i2v( self.parent).transform_point(*label_pos) abs_pos1 = view.get_matrix_i2v(self.parent).transform_point( extents[2], extents[3]) bounds = Rectangle(abs_pos[0], abs_pos[1], x1=abs_pos1[0], y1=abs_pos1[1]) context.cairo._update_bounds(bounds)
def register_view(self, view): """Called when the View was registered""" super(MenuBarController, self).register_view(view) data_flow_mode = global_runtime_config.get_config_value( "DATA_FLOW_MODE", False) view["data_flow_mode"].set_active(data_flow_mode) show_data_flows = global_runtime_config.get_config_value( "SHOW_DATA_FLOWS", True) view["show_data_flows"].set_active(show_data_flows) show_data_values = global_runtime_config.get_config_value( "SHOW_DATA_FLOW_VALUE_LABELS", True) view["show_data_values"].set_active(show_data_values) show_aborted_preempted = global_runtime_config.get_config_value( "SHOW_ABORTED_PREEMPTED", False) view["show_aborted_preempted"].set_active(show_aborted_preempted) view["expert_view"].hide() view["grid"].hide() # use dedicated function to connect the buttons to be able to access the handler id later on self.connect_button_to_function('new', 'activate', self.on_new_activate) self.connect_button_to_function('open', 'activate', self.on_open_activate) self.connect_button_to_function('save', 'activate', self.on_save_activate) self.connect_button_to_function('save_as', 'activate', self.on_save_as_activate) self.connect_button_to_function('save_as_copy', 'activate', self.on_save_as_copy_activate) self.connect_button_to_function('menu_preferences', 'activate', self.on_menu_preferences_activate) self.connect_button_to_function('refresh_all', 'activate', self.on_refresh_all_activate) self.connect_button_to_function('refresh_libraries', 'activate', self.on_refresh_libraries_activate) self.connect_button_to_function('bake_state_machine', 'activate', self.on_bake_state_machine_activate) self.connect_button_to_function('quit', 'activate', self.on_quit_activate) self.connect_button_to_function('cut', 'activate', self.on_cut_selection_activate) self.connect_button_to_function('copy', 'activate', self.on_copy_selection_activate) self.connect_button_to_function('paste', 'activate', self.on_paste_clipboard_activate) self.connect_button_to_function('delete', 'activate', self.on_delete_activate) self.connect_button_to_function('is_start_state', 'activate', self.on_toggle_is_start_state_active) self.connect_button_to_function('add', 'activate', self.on_add_state_activate) self.connect_button_to_function('group', 'activate', self.on_group_states_activate) self.connect_button_to_function('ungroup', 'activate', self.on_ungroup_state_activate) self.connect_button_to_function( 'substitute_state', 'activate', self.on_substitute_selected_state_activate) self.connect_button_to_function( 'save_state_as', 'activate', self.on_save_selected_state_as_activate) self.connect_button_to_function('undo', 'activate', self.on_undo_activate) self.connect_button_to_function('redo', 'activate', self.on_redo_activate) self.connect_button_to_function('grid', 'activate', self.on_grid_toggled) self.connect_button_to_function('data_flow_mode', 'toggled', self.on_data_flow_mode_toggled) self.connect_button_to_function('show_data_flows', 'toggled', self.on_show_data_flows_toggled) self.connect_button_to_function('show_data_values', 'toggled', self.on_show_data_values_toggled) self.connect_button_to_function('show_aborted_preempted', 'toggled', self.on_show_aborted_preempted_toggled) self.connect_button_to_function('expert_view', 'activate', self.on_expert_view_activate) self.connect_button_to_function('full_screen', 'toggled', self.on_full_screen_mode_toggled) self.connect_button_to_function('start', 'activate', self.on_start_activate) self.connect_button_to_function( 'start_from_selected', 'activate', self.on_start_from_selected_state_activate) self.connect_button_to_function('run_to_selected', 'activate', self.on_run_to_selected_state_activate) self.connect_button_to_function('pause', 'activate', self.on_pause_activate) self.connect_button_to_function('stop', 'activate', self.on_stop_activate) self.connect_button_to_function('step_mode', 'activate', self.on_step_mode_activate) self.connect_button_to_function('step_into', 'activate', self.on_step_into_activate) self.connect_button_to_function('step_over', 'activate', self.on_step_over_activate) self.connect_button_to_function('step_out', 'activate', self.on_step_out_activate) self.connect_button_to_function('backward_step', 'activate', self.on_backward_step_activate) self.connect_button_to_function('about', 'activate', self.on_about_activate) self.full_screen_window.connect( 'key_press_event', self.on_escape_key_press_event_leave_full_screen) self.view['menu_edit'].connect('select', self.check_edit_menu_items_status) self.registered_view = True self._update_recently_opened_state_machines() # do not move next line - here to show warning in GUI debug console self.create_logger_warning_if_shortcuts_are_overwritten_by_menu_bar()
def convert(config_path, source_path, target_path=None, gui_config_path=None): logger.info("RAFCON launcher") rafcon.gui.start.setup_l10n(logger) from rafcon.gui.controllers.main_window import MainWindowController from rafcon.gui.views.main_window import MainWindowView setup_environment() gui_config_path = gui_config_path or get_default_config_path() setup_config = {} setup_config["config_path"] = config_path setup_config["gui_config_path"] = gui_config_path setup_config["source_path"] = [source_path] if not target_path: setup_config["target_path"] = [source_path] else: setup_config["target_path"] = [target_path] global_config.load(path=setup_config['config_path']) global_gui_config.load(path=setup_config['gui_config_path']) global_runtime_config.load(path=setup_config['gui_config_path']) # Initialize library core_singletons.library_manager.initialize() # Create the GUI main_window_view = MainWindowView() if setup_config['source_path']: if len(setup_config['source_path']) > 1: logger.error("Only one state machine is supported yet") exit(-1) for path in setup_config['source_path']: try: state_machine = gui_helper_state_machine.open_state_machine( path) except Exception as e: logger.error("Could not load state machine {0}: {1}".format( path, e)) else: logger.error( "You need to specify exactly one state machine to be converted!") sm_manager_model = gui_singletons.state_machine_manager_model main_window_controller = MainWindowController(sm_manager_model, main_window_view) if not os.getenv("RAFCON_START_MINIMIZED", False): main_window = main_window_view.get_top_widget() size = global_runtime_config.get_config_value("WINDOW_SIZE", None) position = global_runtime_config.get_config_value("WINDOW_POS", None) if size: main_window.resize(size[0], size[1]) if position: position = (max(0, position[0]), max(0, position[1])) screen_width = Gdk.Screen.width() screen_height = Gdk.Screen.height() if position[0] < screen_width and position[1] < screen_height: main_window.move(position[0], position[1]) wait_for_gui() thread = threading.Thread(target=trigger_gui_signals, args=[ sm_manager_model, main_window_controller, setup_config, state_machine ]) thread.start() Gtk.main() logger.debug("Gtk main loop exited!") logger.debug("Conversion done")
def test_bar(window, window_key): attribute_name_of_undocked_window_view = window_name = window_key.lower( ) + "_window" output_list = list() call_gui_callback(connect_window, window, 'configure-event', notify_on_resize_event, output_list) configure_handler_id = output_list[0] output_list = list() call_gui_callback(connect_window, window, 'hide', notify_on_event, output_list) hide_handler_id = output_list[0] logger.info("undocking...") time.sleep(debug_sleep_time) ready.clear() call_gui_callback( main_window_controller.view["undock_{}_button".format( window_key.lower())].emit, "clicked") wait_for_event_notification() assert window.get_property('visible') is True expected_size = get_stored_window_size(window_name) new_size = window.get_size() if not bool(window.maximize_initially): assert_size_equality(new_size, expected_size) else: maximized_parameter_name = window_key + "_WINDOW_MAXIMIZED" assert bool(window.maximize_initially ) and global_runtime_config.get_config_value( maximized_parameter_name) logger.info("resizing...") time.sleep(debug_sleep_time) ready.clear() target_size = (800, 800) if new_size == target_size: target_size = (900, 900) logger.debug("target size: {}".format(target_size)) call_gui_callback(window.resize, *target_size) wait_for_event_notification() try: assert_size_equality(event_size, target_size) except AssertionError: # For unknown reasons, there are two configure events and only the latter one if for the new window size ready.clear() wait_for_event_notification() assert_size_equality(event_size, target_size) logger.info("got additional configure-event") logger.info("docking...") undocked_window_view = getattr(main_window_controller.view, attribute_name_of_undocked_window_view) redock_button = getattr(undocked_window_view, "top_tool_bar")['redock_button'] time.sleep(debug_sleep_time) ready.clear() call_gui_callback(redock_button.emit, "clicked") wait_for_event_notification() assert window.get_property('visible') is False logger.info("undocking...") time.sleep(debug_sleep_time) ready.clear() output_list = list() call_gui_callback(connect_window, window, 'show', notify_on_event, output_list) show_handler_id = output_list[0] call_gui_callback( main_window_controller.view["undock_{}_button".format( window_key.lower())].emit, "clicked") wait_for_event_notification() assert window.get_property('visible') is True assert_size_equality(window.get_size(), target_size) logger.info("docking...") time.sleep(debug_sleep_time) ready.clear() call_gui_callback(redock_button.emit, "clicked") wait_for_event_notification() assert window.get_property('visible') is False window.disconnect(configure_handler_id) window.disconnect(show_handler_id) window.disconnect(hide_handler_id)
def show_connection(self): return global_runtime_config.get_config_value("SHOW_DATA_FLOWS", True)