summaryrefslogtreecommitdiff
path: root/grc/gui/Application.py
diff options
context:
space:
mode:
Diffstat (limited to 'grc/gui/Application.py')
-rw-r--r--grc/gui/Application.py281
1 files changed, 178 insertions, 103 deletions
diff --git a/grc/gui/Application.py b/grc/gui/Application.py
index 9e89009dc9..c1456c3a8d 100644
--- a/grc/gui/Application.py
+++ b/grc/gui/Application.py
@@ -24,9 +24,9 @@ import os
import subprocess
import logging
-from gi.repository import Gtk, GObject
+from gi.repository import Gtk, Gio, GLib, GObject
-from . import Dialogs, Actions, Executor, FileDialogs, Utils
+from . import Dialogs, Actions, Executor, FileDialogs, Utils, Bars
from .MainWindow import MainWindow
from .ParserErrorsDialog import ParserErrorsDialog
from .PropsDialog import PropsDialog
@@ -56,54 +56,58 @@ class Application(Gtk.Application):
"""
self.clipboard = None
self.dialog = None
- for action in Actions.get_all_actions(): action.connect('activate', self._handle_action)
- #setup the main window
+
+ # Setup the main window
self.platform = platform
self.config = platform.config
- log.debug("__init__()")
-
- #initialize
+ log.debug("Application()")
+ # Connect all actions to _handle_action
+ for x in Actions.get_actions():
+ Actions.connect(x, handler=self._handle_action)
+ Actions.actions[x].enable()
+ if x.startswith("app."):
+ self.add_action(Actions.actions[x])
+ # Setup the shortcut keys
+ # These are the globally defined shortcuts
+ keypress = Actions.actions[x].keypresses
+ if keypress:
+ self.set_accels_for_action(x, keypress)
+
+ # Initialize
self.init_file_paths = [os.path.abspath(file_path) for file_path in file_paths]
self.init = False
def do_startup(self):
Gtk.Application.do_startup(self)
- log.debug("do_startup()")
+ log.debug("Application.do_startup()")
+
+ # Setup the menu
+ log.debug("Creating menu")
+ '''
+ self.menu = Bars.Menu()
+ self.set_menu()
+ if self.prefers_app_menu():
+ self.set_app_menu(self.menu)
+ else:
+ self.set_menubar(self.menu)
+ '''
def do_activate(self):
Gtk.Application.do_activate(self)
- log.debug("do_activate()")
+ log.debug("Application.do_activate()")
- self.main_window = MainWindow(self, self.platform, self._handle_action)
+ self.main_window = MainWindow(self, self.platform)
self.main_window.connect('delete-event', self._quit)
- self.main_window.connect('key-press-event', self._handle_key_press)
self.get_focus_flag = self.main_window.get_focus_flag
+
#setup the messages
Messages.register_messenger(self.main_window.add_console_line)
Messages.send_init(self.platform)
+ log.debug("Calling Actions.APPLICATION_INITIALIZE")
Actions.APPLICATION_INITIALIZE()
- def _handle_key_press(self, widget, event):
- """
- Handle key presses from the keyboard and translate key combinations into actions.
- This key press handler is called prior to the gtk key press handler.
- This handler bypasses built in accelerator key handling when in focus because
- * some keys are ignored by the accelerators like the direction keys,
- * some keys are not registered to any accelerators but are still used.
- When not in focus, gtk and the accelerators handle the the key press.
-
- Returns:
- false to let gtk handle the key action
- """
- # prevent key event stealing while the search box is active
- # .has_focus() only in newer versions 2.17+?
- # .is_focus() seems to work, but exactly the same
- if self.main_window.btwin.search_entry.has_focus():
- return False
- return Actions.handle_key_press(event)
-
def _quit(self, window, event):
"""
Handle the delete event from the main window.
@@ -117,7 +121,7 @@ class Application(Gtk.Application):
return True
def _handle_action(self, action, *args):
- #print action
+ log.debug("_handle_action({0}, {1})".format(action, args))
main = self.main_window
page = main.current_page
flow_graph = page.flow_graph if page else None
@@ -130,6 +134,7 @@ class Application(Gtk.Application):
# Initialize/Quit
##################################################
if action == Actions.APPLICATION_INITIALIZE:
+ log.debug("APPLICATION_INITIALIZE")
file_path_to_show = self.config.file_open()
for file_path in (self.init_file_paths or self.config.get_open_files()):
if os.path.exists(file_path):
@@ -139,35 +144,84 @@ class Application(Gtk.Application):
main.btwin.search_entry.hide()
- # Disable all actions, then re-enable a few
- for action in Actions.get_all_actions():
- action.set_sensitive(False) # set all actions disabled
+ """
+ Only disable certain actions on startup. Each of these actions are
+ conditionally enabled in _handle_action, so disable them first.
+ - FLOW_GRAPH_UNDO/REDO are set in gui/StateCache.py
+ - XML_PARSER_ERRORS_DISPLAY is set in RELOAD_BLOCKS
+
+ TODO: These 4 should probably be included, but they are not currently
+ enabled anywhere else:
+ - PORT_CONTROLLER_DEC, PORT_CONTROLLER_INC
+ - BLOCK_INC_TYPE, BLOCK_DEC_TYPE
+
+ TODO: These should be handled better. They are set in
+ update_exec_stop(), but not anywhere else
+ - FLOW_GRAPH_GEN, FLOW_GRAPH_EXEC, FLOW_GRAPH_KILL
+ """
+ for action in (
+ Actions.ERRORS_WINDOW_DISPLAY,
+ Actions.ELEMENT_DELETE,
+ Actions.BLOCK_PARAM_MODIFY,
+ Actions.BLOCK_ROTATE_CCW,
+ Actions.BLOCK_ROTATE_CW,
+ Actions.BLOCK_VALIGN_TOP,
+ Actions.BLOCK_VALIGN_MIDDLE,
+ Actions.BLOCK_VALIGN_BOTTOM,
+ Actions.BLOCK_HALIGN_LEFT,
+ Actions.BLOCK_HALIGN_CENTER,
+ Actions.BLOCK_HALIGN_RIGHT,
+ Actions.BLOCK_CUT,
+ Actions.BLOCK_COPY,
+ Actions.BLOCK_PASTE,
+ Actions.BLOCK_ENABLE,
+ Actions.BLOCK_DISABLE,
+ Actions.BLOCK_BYPASS,
+ Actions.BLOCK_CREATE_HIER,
+ Actions.OPEN_HIER,
+ Actions.BUSSIFY_SOURCES,
+ Actions.BUSSIFY_SINKS,
+ Actions.FLOW_GRAPH_SAVE,
+ Actions.FLOW_GRAPH_UNDO,
+ Actions.FLOW_GRAPH_REDO,
+ Actions.XML_PARSER_ERRORS_DISPLAY
+ ):
+ action.disable()
+
+ # Load preferences
for action in (
- Actions.APPLICATION_QUIT, Actions.FLOW_GRAPH_NEW,
- Actions.FLOW_GRAPH_OPEN, Actions.FLOW_GRAPH_SAVE_AS,
- Actions.FLOW_GRAPH_DUPLICATE, Actions.FLOW_GRAPH_SAVE_A_COPY,
- Actions.FLOW_GRAPH_CLOSE, Actions.ABOUT_WINDOW_DISPLAY,
- Actions.FLOW_GRAPH_SCREEN_CAPTURE, Actions.HELP_WINDOW_DISPLAY,
- Actions.TYPES_WINDOW_DISPLAY, Actions.TOGGLE_BLOCKS_WINDOW,
- Actions.TOGGLE_CONSOLE_WINDOW, Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
- Actions.TOOLS_RUN_FDESIGN, Actions.TOGGLE_SCROLL_LOCK,
- Actions.CLEAR_CONSOLE, Actions.SAVE_CONSOLE,
- Actions.TOGGLE_AUTO_HIDE_PORT_LABELS, Actions.TOGGLE_SNAP_TO_GRID,
+ Actions.TOGGLE_BLOCKS_WINDOW,
+ Actions.TOGGLE_CONSOLE_WINDOW,
+ Actions.TOGGLE_HIDE_DISABLED_BLOCKS,
+ Actions.TOGGLE_SCROLL_LOCK,
+ Actions.TOGGLE_AUTO_HIDE_PORT_LABELS,
+ Actions.TOGGLE_SNAP_TO_GRID,
Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB,
Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY,
- Actions.FLOW_GRAPH_OPEN_QSS_THEME,
Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR,
Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR,
Actions.TOGGLE_HIDE_VARIABLES,
- Actions.SELECT_ALL,
):
- action.set_sensitive(True)
+ action.set_enabled(True)
if hasattr(action, 'load_from_preferences'):
action.load_from_preferences()
+
+ # Hide the panels *IF* it's saved in preferences
+ main.update_panel_visibility(main.BLOCKS, Actions.TOGGLE_BLOCKS_WINDOW.get_active())
+ main.update_panel_visibility(main.CONSOLE, Actions.TOGGLE_CONSOLE_WINDOW.get_active())
+ main.update_panel_visibility(main.VARIABLES, Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR.get_active())
+
if ParseXML.xml_failures:
Messages.send_xml_errors_if_any(ParseXML.xml_failures)
- Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(True)
+ Actions.XML_PARSER_ERRORS_DISPLAY.set_enabled(True)
+
+ # Force an update on the current page to match loaded preferences.
+ # In the future, change the __init__ order to load preferences first
+ page = main.current_page
+ if page:
+ page.flow_graph.update()
+
self.init = True
elif action == Actions.APPLICATION_QUIT:
if main.close_pages():
@@ -400,12 +454,17 @@ class Application(Gtk.Application):
elif action == Actions.ERRORS_WINDOW_DISPLAY:
Dialogs.ErrorsDialog(main, flow_graph).run_and_destroy()
elif action == Actions.TOGGLE_CONSOLE_WINDOW:
+ action.set_active(not action.get_active())
main.update_panel_visibility(main.CONSOLE, action.get_active())
action.save_to_preferences()
elif action == Actions.TOGGLE_BLOCKS_WINDOW:
+ # This would be better matched to a Gio.PropertyAction, but to do
+ # this, actions would have to be defined in the window not globally
+ action.set_active(not action.get_active())
main.update_panel_visibility(main.BLOCKS, action.get_active())
action.save_to_preferences()
elif action == Actions.TOGGLE_SCROLL_LOCK:
+ action.set_active(not action.get_active())
active = action.get_active()
main.console.text_display.scroll_lock = active
if active:
@@ -418,41 +477,53 @@ class Application(Gtk.Application):
if file_path is not None:
main.console.text_display.save(file_path)
elif action == Actions.TOGGLE_HIDE_DISABLED_BLOCKS:
+ action.set_active(not action.get_active())
Actions.NOTHING_SELECT()
elif action == Actions.TOGGLE_AUTO_HIDE_PORT_LABELS:
+ action.set_active(not action.get_active())
action.save_to_preferences()
for page in main.get_pages():
page.flow_graph.create_shapes()
elif action in (Actions.TOGGLE_SNAP_TO_GRID,
Actions.TOGGLE_SHOW_BLOCK_COMMENTS,
Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB):
+ action.set_active(not action.get_active())
action.save_to_preferences()
elif action == Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY:
+ action.set_active(not action.get_active())
action.save_to_preferences()
for page in main.get_pages():
flow_graph_update(page.flow_graph)
elif action == Actions.TOGGLE_HIDE_VARIABLES:
- # Call the variable editor TOGGLE in case it needs to be showing
- Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR()
+ action.set_active(not action.get_active())
+ active = action.get_active()
+ # Either way, triggering this should simply trigger the variable editor
+ # to be visible.
+ varedit = Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR
+ if active:
+ log.debug("Variables are hidden. Forcing the variable panel to be visible.")
+ varedit.disable()
+ else:
+ varedit.enable()
+ # Just force it to show.
+ varedit.set_active(True)
+ main.update_panel_visibility(main.VARIABLES)
Actions.NOTHING_SELECT()
action.save_to_preferences()
+ varedit.save_to_preferences()
+ flow_graph_update()
elif action == Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR:
- # See if the variables are hidden
- if Actions.TOGGLE_HIDE_VARIABLES.get_active():
- # Force this to be shown
- main.update_panel_visibility(main.VARIABLES, True)
- action.set_active(True)
- action.set_sensitive(False)
- else:
- if action.get_sensitive():
- main.update_panel_visibility(main.VARIABLES, action.get_active())
- else: # This is occurring after variables are un-hidden
- # Leave it enabled
- action.set_sensitive(True)
- action.set_active(True)
- # Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR.set_sensitive(action.get_active())
+ # TODO: There may be issues at startup since these aren't triggered
+ # the same was as Gtk.Actions when loading preferences.
+ action.set_active(not action.get_active())
+ # Just assume this was triggered because it was enabled.
+ main.update_panel_visibility(main.VARIABLES, action.get_active())
+ action.save_to_preferences()
+
+ # Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR.set_enabled(action.get_active())
action.save_to_preferences()
elif action == Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR:
+ action.set_active(not action.get_active())
if self.init:
Dialogs.MessageDialogWrapper(
main, Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE,
@@ -463,7 +534,7 @@ class Application(Gtk.Application):
# Param Modifications
##################################################
elif action == Actions.BLOCK_PARAM_MODIFY:
- selected_block = action.args[0] if action.args else flow_graph.selected_block
+ selected_block = args[0] if args[0] else flow_graph.selected_block
if selected_block:
self.dialog = PropsDialog(self.main_window, selected_block)
response = Gtk.ResponseType.APPLY
@@ -520,17 +591,17 @@ class Application(Gtk.Application):
elif action == Actions.FLOW_GRAPH_NEW:
main.new_page()
if args:
- flow_graph = main.get_flow_graph()
+ flow_graph = main.current_page.flow_graph
flow_graph._options_block.get_param('generate_options').set_value(args[0])
flow_graph_update(flow_graph)
elif action == Actions.FLOW_GRAPH_OPEN:
- file_paths = args if args else FileDialogs.OpenFlowGraph(main, page.file_path).run()
+ file_paths = args[0] if args[0] else FileDialogs.OpenFlowGraph(main, page.file_path).run()
if file_paths: # Open a new page for each file, show only the first
for i,file_path in enumerate(file_paths):
main.new_page(file_path, show=(i==0))
self.config.add_recent_file(file_path)
main.tool_bar.refresh_submenus()
- main.menu_bar.refresh_submenus()
+ #main.menu_bar.refresh_submenus()
elif action == Actions.FLOW_GRAPH_OPEN_QSS_THEME:
file_paths = FileDialogs.OpenQSS(main, self.platform.config.install_prefix +
'/share/gnuradio/themes/').run()
@@ -558,33 +629,37 @@ class Application(Gtk.Application):
Actions.FLOW_GRAPH_SAVE()
self.config.add_recent_file(file_path)
main.tool_bar.refresh_submenus()
- main.menu_bar.refresh_submenus()
- elif action == Actions.FLOW_GRAPH_SAVE_A_COPY:
+ #TODO
+ #main.menu_bar.refresh_submenus()
+ elif action == Actions.FLOW_GRAPH_SAVE_COPY:
try:
- if not page.get_file_path():
+ if not page.file_path:
+ # Make sure the current flowgraph has been saved
Actions.FLOW_GRAPH_SAVE_AS()
else:
- dup_file_path = page.get_file_path()
+ dup_file_path = page.file_path
dup_file_name = '.'.join(dup_file_path.split('.')[:-1]) + "_copy" # Assuming .grc extension at the end of file_path
dup_file_path_temp = dup_file_name+'.grc'
count = 1
while os.path.exists(dup_file_path_temp):
dup_file_path_temp = dup_file_name+'('+str(count)+').grc'
count += 1
- dup_file_path_user = SaveFlowGraphFileDialog(dup_file_path_temp).run()
+ dup_file_path_user = FileDialogs.SaveFlowGraph(main, dup_file_path_temp).run()
if dup_file_path_user is not None:
ParseXML.to_file(flow_graph.export_data(), dup_file_path_user)
Messages.send('Saved Copy to: "' + dup_file_path_user + '"\n')
except IOError:
Messages.send_fail_save("Can not create a copy of the flowgraph\n")
elif action == Actions.FLOW_GRAPH_DUPLICATE:
- flow_graph = main.get_flow_graph()
+ previous = flow_graph
+ # Create a new page
main.new_page()
- curr_page = main.get_page()
- new_flow_graph = main.get_flow_graph()
- new_flow_graph.import_data(flow_graph.export_data())
+ page = main.current_page
+ new_flow_graph = page.flow_graph
+ # Import the old data and mark the current as not saved
+ new_flow_graph.import_data(previous.export_data())
flow_graph_update(new_flow_graph)
- curr_page.set_saved(False)
+ page.saved = False
elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE:
file_path, background_transparent = FileDialogs.SaveScreenShot(main, page.file_path).run()
if file_path is not None:
@@ -634,7 +709,7 @@ class Application(Gtk.Application):
elif action == Actions.RELOAD_BLOCKS:
self.platform.build_block_library()
main.btwin.repopulate()
- Actions.XML_PARSER_ERRORS_DISPLAY.set_sensitive(bool(
+ Actions.XML_PARSER_ERRORS_DISPLAY.set_enabled(bool(
ParseXML.xml_failures))
Messages.send_xml_errors_if_any(ParseXML.xml_failures)
# Force a redraw of the graph, by getting the current state and re-importing it
@@ -667,7 +742,7 @@ class Application(Gtk.Application):
shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
else:
- print('!!! Action "%s" not handled !!!' % action)
+ log.warning('!!! Action "%s" not handled !!!' % action)
##################################################
# Global Actions for all States
##################################################
@@ -678,19 +753,19 @@ class Application(Gtk.Application):
selected_block = selected_blocks[0] if selected_blocks else None
#update general buttons
- Actions.ERRORS_WINDOW_DISPLAY.set_sensitive(not flow_graph.is_valid())
- Actions.ELEMENT_DELETE.set_sensitive(bool(flow_graph.selected_elements))
- Actions.BLOCK_PARAM_MODIFY.set_sensitive(bool(selected_block))
- Actions.BLOCK_ROTATE_CCW.set_sensitive(bool(selected_blocks))
- Actions.BLOCK_ROTATE_CW.set_sensitive(bool(selected_blocks))
+ Actions.ERRORS_WINDOW_DISPLAY.set_enabled(not flow_graph.is_valid())
+ Actions.ELEMENT_DELETE.set_enabled(bool(flow_graph.selected_elements))
+ Actions.BLOCK_PARAM_MODIFY.set_enabled(bool(selected_block))
+ Actions.BLOCK_ROTATE_CCW.set_enabled(bool(selected_blocks))
+ Actions.BLOCK_ROTATE_CW.set_enabled(bool(selected_blocks))
#update alignment options
for act in Actions.BLOCK_ALIGNMENTS:
if act:
- act.set_sensitive(len(selected_blocks) > 1)
+ act.set_enabled(len(selected_blocks) > 1)
#update cut/copy/paste
- Actions.BLOCK_CUT.set_sensitive(bool(selected_blocks))
- Actions.BLOCK_COPY.set_sensitive(bool(selected_blocks))
- Actions.BLOCK_PASTE.set_sensitive(bool(self.clipboard))
+ Actions.BLOCK_CUT.set_enabled(bool(selected_blocks))
+ Actions.BLOCK_COPY.set_enabled(bool(selected_blocks))
+ Actions.BLOCK_PASTE.set_enabled(bool(self.clipboard))
#update enable/disable/bypass
can_enable = any(block.state != 'enabled'
for block in selected_blocks)
@@ -700,26 +775,26 @@ class Application(Gtk.Application):
all(block.can_bypass() for block in selected_blocks) and
any(not block.get_bypassed() for block in selected_blocks)
)
- Actions.BLOCK_ENABLE.set_sensitive(can_enable)
- Actions.BLOCK_DISABLE.set_sensitive(can_disable)
- Actions.BLOCK_BYPASS.set_sensitive(can_bypass_all)
+ Actions.BLOCK_ENABLE.set_enabled(can_enable)
+ Actions.BLOCK_DISABLE.set_enabled(can_disable)
+ Actions.BLOCK_BYPASS.set_enabled(can_bypass_all)
- Actions.BLOCK_CREATE_HIER.set_sensitive(bool(selected_blocks))
- Actions.OPEN_HIER.set_sensitive(bool(selected_blocks))
- Actions.BUSSIFY_SOURCES.set_sensitive(bool(selected_blocks))
- Actions.BUSSIFY_SINKS.set_sensitive(bool(selected_blocks))
- Actions.RELOAD_BLOCKS.set_sensitive(True)
- Actions.FIND_BLOCKS.set_sensitive(True)
+ Actions.BLOCK_CREATE_HIER.set_enabled(bool(selected_blocks))
+ Actions.OPEN_HIER.set_enabled(bool(selected_blocks))
+ Actions.BUSSIFY_SOURCES.set_enabled(bool(selected_blocks))
+ Actions.BUSSIFY_SINKS.set_enabled(bool(selected_blocks))
+ Actions.RELOAD_BLOCKS.enable()
+ Actions.FIND_BLOCKS.enable()
self.update_exec_stop()
- Actions.FLOW_GRAPH_SAVE.set_sensitive(not page.saved)
+ Actions.FLOW_GRAPH_SAVE.set_enabled(not page.saved)
main.update()
flow_graph.update_selected()
page.drawing_area.queue_draw()
- return True # action was handled
+ return True # Action was handled
def update_exec_stop(self):
"""
@@ -728,6 +803,6 @@ class Application(Gtk.Application):
"""
page = self.main_window.current_page
sensitive = page.flow_graph.is_valid() and not page.process
- Actions.FLOW_GRAPH_GEN.set_sensitive(sensitive)
- Actions.FLOW_GRAPH_EXEC.set_sensitive(sensitive)
- Actions.FLOW_GRAPH_KILL.set_sensitive(page.process is not None)
+ Actions.FLOW_GRAPH_GEN.set_enabled(sensitive)
+ Actions.FLOW_GRAPH_EXEC.set_enabled(sensitive)
+ Actions.FLOW_GRAPH_KILL.set_enabled(page.process is not None)