From e66cfa31ff52b95a9c3df27c8a1f3b02bef6db3d Mon Sep 17 00:00:00 2001 From: Seth Hitefield <sdhitefield@gmail.com> Date: Mon, 11 Apr 2016 22:09:16 -0400 Subject: grc: Main window opens with pygobject and gtk3. Still throws tons of errors. --- grc/gui/Bars.py | 63 ++++++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 30 deletions(-) (limited to 'grc/gui/Bars.py') diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index a4819b973c..2d0709309c 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -17,9 +17,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -import pygtk -pygtk.require('2.0') -import gtk +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk +from gi.repository import GObject from . import Actions @@ -62,7 +63,7 @@ TOOLBAR_LIST = ( # The list of actions and categories for the menu bar. MENU_BAR_LIST = ( - (gtk.Action('File', '_File', None, None), [ + (Gtk.Action(name='File', label='_File'), [ 'flow_graph_new', Actions.FLOW_GRAPH_OPEN, 'flow_graph_recent', @@ -75,7 +76,7 @@ MENU_BAR_LIST = ( Actions.FLOW_GRAPH_CLOSE, Actions.APPLICATION_QUIT, ]), - (gtk.Action('Edit', '_Edit', None, None), [ + (Gtk.Action(name='Edit', label='_Edit'), [ Actions.FLOW_GRAPH_UNDO, Actions.FLOW_GRAPH_REDO, None, @@ -95,7 +96,7 @@ MENU_BAR_LIST = ( None, Actions.BLOCK_PARAM_MODIFY, ]), - (gtk.Action('View', '_View', None, None), [ + (Gtk.Action(name='View', label='_View'), [ Actions.TOGGLE_BLOCKS_WINDOW, None, Actions.TOGGLE_CONSOLE_WINDOW, @@ -117,12 +118,12 @@ MENU_BAR_LIST = ( Actions.ERRORS_WINDOW_DISPLAY, Actions.FIND_BLOCKS, ]), - (gtk.Action('Run', '_Run', None, None), [ + (Gtk.Action(name='Run', label='_Run'), [ Actions.FLOW_GRAPH_GEN, Actions.FLOW_GRAPH_EXEC, Actions.FLOW_GRAPH_KILL, ]), - (gtk.Action('Tools', '_Tools', None, None), [ + (Gtk.Action(name='Tools', label='_Tools'), [ Actions.TOOLS_RUN_FDESIGN, Actions.FLOW_GRAPH_OPEN_QSS_THEME, None, @@ -130,7 +131,7 @@ MENU_BAR_LIST = ( None, Actions.TOOLS_MORE_TO_COME, ]), - (gtk.Action('Help', '_Help', None, None), [ + (Gtk.Action(name='Help', label='_Help'), [ Actions.HELP_WINDOW_DISPLAY, Actions.TYPES_WINDOW_DISPLAY, Actions.XML_PARSER_ERRORS_DISPLAY, @@ -152,7 +153,7 @@ CONTEXT_MENU_LIST = [ Actions.BLOCK_DISABLE, Actions.BLOCK_BYPASS, None, - (gtk.Action('More', '_More', None, None), [ + (Gtk.Action(name='More', label='_More'), [ Actions.BLOCK_CREATE_HIER, Actions.OPEN_HIER, None, @@ -189,13 +190,13 @@ class SubMenuCreator(object): def _fill_flow_graph_new_submenu(self, action): """Sub menu to create flow-graph with pre-set generate mode""" - menu = gtk.Menu() + menu = Gtk.Menu() for key, name, default in self.generate_modes: if default: item = Actions.FLOW_GRAPH_NEW.create_menu_item() item.set_label(name) else: - item = gtk.MenuItem(name, use_underline=False) + item = Gtk.MenuItem(name=name, use_underline=False) item.connect('activate', self.callback_adaptor, (action, key)) menu.append(item) menu.show_all() @@ -204,11 +205,11 @@ class SubMenuCreator(object): def _fill_flow_graph_recent_submenu(self, action): """menu showing recent flow-graphs""" import Preferences - menu = gtk.Menu() + menu = Gtk.Menu() recent_files = Preferences.get_recent_files() if len(recent_files) > 0: for i, file_name in enumerate(recent_files): - item = gtk.MenuItem("%d. %s" % (i+1, file_name), use_underline=False) + item = Gtk.MenuItem(name="%d. %s" % (i+1, file_name), use_underline=False) item.connect('activate', self.callback_adaptor, (action, file_name)) menu.append(item) @@ -217,7 +218,7 @@ class SubMenuCreator(object): return None -class Toolbar(gtk.Toolbar, SubMenuCreator): +class Toolbar(Gtk.Toolbar, SubMenuCreator): """The gtk toolbar with actions added from the toolbar list.""" def __init__(self, generate_modes, action_handler_callback): @@ -226,23 +227,25 @@ class Toolbar(gtk.Toolbar, SubMenuCreator): Look up the action for each name in the action list and add it to the toolbar. """ - gtk.Toolbar.__init__(self) - self.set_style(gtk.TOOLBAR_ICONS) + GObject.GObject.__init__(self) + self.set_style(Gtk.ToolbarStyle.ICONS) SubMenuCreator.__init__(self, generate_modes, action_handler_callback) for action in TOOLBAR_LIST: if isinstance(action, tuple) and isinstance(action[1], str): # create a button with a sub-menu - action[0].set_tool_item_type(gtk.MenuToolButton) + # TODO: Fix later + #action[0].set_tool_item_type(Gtk.MenuToolButton) item = action[0].create_tool_item() - self.create_submenu(action, item) - self.refresh_submenus() + #self.create_submenu(action, item) + #self.refresh_submenus() elif action is None: - item = gtk.SeparatorToolItem() + item = Gtk.SeparatorToolItem() else: - action.set_tool_item_type(gtk.ToolButton) + #TODO: Fix later + #action.set_tool_item_type(Gtk.ToolButton) item = action.create_tool_item() # this reset of the tooltip property is required # (after creating the tool item) for the tooltip to show @@ -255,14 +258,14 @@ class MenuHelperMixin(object): def _fill_menu(self, actions, menu=None): """Create a menu from list of actions""" - menu = menu or gtk.Menu() + menu = menu or Gtk.Menu() for item in actions: if isinstance(item, tuple): menu_item = self._make_sub_menu(*item) elif isinstance(item, str): menu_item = getattr(self, 'create_' + item)() elif item is None: - menu_item = gtk.SeparatorMenuItem() + menu_item = Gtk.SeparatorMenuItem() else: menu_item = item.create_menu_item() menu.append(menu_item) @@ -276,7 +279,7 @@ class MenuHelperMixin(object): return main -class MenuBar(gtk.MenuBar, MenuHelperMixin, SubMenuCreator): +class MenuBar(Gtk.MenuBar, MenuHelperMixin, SubMenuCreator): """The gtk menu bar with actions added from the menu bar list.""" def __init__(self, generate_modes, action_handler_callback): @@ -286,13 +289,13 @@ class MenuBar(gtk.MenuBar, MenuHelperMixin, SubMenuCreator): Look up the action for each name in the action list and add it to the submenu. Add the submenu to the menu bar. """ - gtk.MenuBar.__init__(self) + GObject.GObject.__init__(self) SubMenuCreator.__init__(self, generate_modes, action_handler_callback) for main_action, actions in MENU_BAR_LIST: self.append(self._make_sub_menu(main_action, actions)) def create_flow_graph_new(self): - main = gtk.ImageMenuItem(gtk.STOCK_NEW) + main = Gtk.ImageMenuItem(Gtk.STOCK_NEW) main.set_label(Actions.FLOW_GRAPH_NEW.get_label()) func = self._fill_flow_graph_new_submenu self.submenus.append((Actions.FLOW_GRAPH_NEW, func, main)) @@ -300,7 +303,7 @@ class MenuBar(gtk.MenuBar, MenuHelperMixin, SubMenuCreator): return main def create_flow_graph_recent(self): - main = gtk.ImageMenuItem(gtk.STOCK_OPEN) + main = Gtk.ImageMenuItem(Gtk.STOCK_OPEN) main.set_label(Actions.FLOW_GRAPH_OPEN_RECENT.get_label()) func = self._fill_flow_graph_recent_submenu self.submenus.append((Actions.FLOW_GRAPH_OPEN, func, main)) @@ -310,9 +313,9 @@ class MenuBar(gtk.MenuBar, MenuHelperMixin, SubMenuCreator): return main -class ContextMenu(gtk.Menu, MenuHelperMixin): +class ContextMenu(Gtk.Menu, MenuHelperMixin): """The gtk menu with actions added from the context menu list.""" def __init__(self): - gtk.Menu.__init__(self) + GObject.GObject.__init__(self) self._fill_menu(CONTEXT_MENU_LIST, self) -- cgit v1.2.3 From 5352dfd80fd238256da7bbd5efd15c154f3f5a14 Mon Sep 17 00:00:00 2001 From: Sebastian Koslowski <koslowski@kit.edu> Date: Mon, 18 Apr 2016 18:11:52 +0200 Subject: gtk3: add flowgraph draw code and other gtk3 fixes (WIP) --- grc/core/Platform.py | 7 ++-- grc/gui/ActionHandler.py | 9 ++--- grc/gui/Actions.py | 21 ++++++----- grc/gui/Bars.py | 4 +- grc/gui/Block.py | 91 ++++++++++++++++++++++++--------------------- grc/gui/Colors.py | 25 +++++++------ grc/gui/Connection.py | 29 +++++++-------- grc/gui/DrawingArea.py | 57 ++++++---------------------- grc/gui/Element.py | 26 +++++++------ grc/gui/FlowGraph.py | 29 ++++++++------- grc/gui/MainWindow.py | 28 ++++++-------- grc/gui/NotebookPage.py | 16 ++++---- grc/gui/Port.py | 63 +++++++++++++------------------ grc/gui/VariableEditor.py | 95 ++++++++++++++++++++++++----------------------- 14 files changed, 230 insertions(+), 270 deletions(-) (limited to 'grc/gui/Bars.py') diff --git a/grc/core/Platform.py b/grc/core/Platform.py index dfb60ee6a5..82d91ddb72 100644 --- a/grc/core/Platform.py +++ b/grc/core/Platform.py @@ -219,10 +219,9 @@ class Platform(Element): color = n.find('color') or '' try: - import gi # ugly but handy - from gi.repository import Gdk - Gdk.color_parse(color) - except (ValueError, ImportError): + chars_per_color = 2 if len(color) > 4 else 1 + tuple(int(color[o:o + 2], 16) / 255.0 for o in range(1, 3 * chars_per_color, chars_per_color)) + except ValueError: if color: # no color is okay, default set in GUI print >> sys.stderr, 'Warning: Can\'t parse color code "{}" for domain "{}" '.format(color, key) color = None diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 96f7080c40..e25fa19030 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -84,9 +84,8 @@ class ActionHandler: # 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.flags() & Gtk.HAS_FOCUS: + if self.main_window.btwin.search_entry.has_focus(): return False - if not self.get_focus_flag(): return False return Actions.handle_key_press(event) def _quit(self, window, event): @@ -447,9 +446,9 @@ class ActionHandler: action.save_to_preferences() elif action == Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR: if self.init: - md = gtk.MessageDialog(main, - gtk.DIALOG_DESTROY_WITH_PARENT, gtk.MESSAGE_INFO, - gtk.BUTTONS_CLOSE, "Moving the variable editor requires a restart of GRC.") + md = Gtk.MessageDialog(main, + Gtk.DIALOG_DESTROY_WITH_PARENT, Gtk.MESSAGE_INFO, + Gtk.BUTTONS_CLOSE, "Moving the variable editor requires a restart of GRC.") md.run() md.destroy() action.save_to_preferences() diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index b2745c995a..d0e114293f 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -27,6 +27,7 @@ import Preferences NO_MODS_MASK = 0 + ######################################################################## # Actions API ######################################################################## @@ -48,7 +49,7 @@ def handle_key_press(event): """ _used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for keyval, mod_mask in _actions_keypress_dict], NO_MODS_MASK) # extract the key value and the consumed modifiers - keyval, egroup, level, consumed = _keymap.translate_keyboard_state( + _unused, keyval, egroup, level, consumed = _keymap.translate_keyboard_state( event.hardware_keycode, event.get_state(), event.group) # get the modifier mask and ignore irrelevant modifiers mod_mask = event.get_state() & ~consumed & _used_mods_mask @@ -261,32 +262,32 @@ BLOCK_ROTATE_CW = Action( BLOCK_VALIGN_TOP = Action( label='Vertical Align Top', tooltip='Align tops of selected blocks', - keypresses=(gtk.keysyms.t, gtk.gdk.SHIFT_MASK), + keypresses=(Gdk.KEY_t, Gdk.ModifierType.SHIFT_MASK), ) BLOCK_VALIGN_MIDDLE = Action( label='Vertical Align Middle', tooltip='Align centers of selected blocks vertically', - keypresses=(gtk.keysyms.m, gtk.gdk.SHIFT_MASK), + keypresses=(Gdk.KEY_m, Gdk.ModifierType.SHIFT_MASK), ) BLOCK_VALIGN_BOTTOM = Action( label='Vertical Align Bottom', tooltip='Align bottoms of selected blocks', - keypresses=(gtk.keysyms.b, gtk.gdk.SHIFT_MASK), + keypresses=(Gdk.KEY_b, Gdk.ModifierType.SHIFT_MASK), ) BLOCK_HALIGN_LEFT = Action( label='Horizontal Align Left', tooltip='Align left edges of blocks selected blocks', - keypresses=(gtk.keysyms.l, gtk.gdk.SHIFT_MASK), + keypresses=(Gdk.KEY_l, Gdk.ModifierType.SHIFT_MASK), ) BLOCK_HALIGN_CENTER = Action( label='Horizontal Align Center', tooltip='Align centers of selected blocks horizontally', - keypresses=(gtk.keysyms.c, gtk.gdk.SHIFT_MASK), + keypresses=(Gdk.KEY_c, Gdk.ModifierType.SHIFT_MASK), ) BLOCK_HALIGN_RIGHT = Action( label='Horizontal Align Right', tooltip='Align right edges of selected blocks', - keypresses=(gtk.keysyms.r, gtk.gdk.SHIFT_MASK), + keypresses=(Gdk.KEY_r, Gdk.ModifierType.SHIFT_MASK), ) BLOCK_ALIGNMENTS = [ BLOCK_VALIGN_TOP, @@ -341,9 +342,9 @@ TOGGLE_HIDE_VARIABLES = ToggleAction( TOGGLE_FLOW_GRAPH_VAR_EDITOR = ToggleAction( label='Show _Variable Editor', tooltip='Show the variable editor. Modify variables and imports in this flow graph', - stock_id=gtk.STOCK_EDIT, + stock_id=Gtk.STOCK_EDIT, default=True, - keypresses=(gtk.keysyms.e, gtk.gdk.CONTROL_MASK), + keypresses=(Gdk.KEY_e, Gdk.ModifierType.CONTROL_MASK), preference_name='variable_editor_visable', ) TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR = ToggleAction( @@ -407,7 +408,7 @@ ERRORS_WINDOW_DISPLAY = Action( TOGGLE_CONSOLE_WINDOW = ToggleAction( label='Show _Console Panel', tooltip='Toggle visibility of the console', - keypresses=(Gdk.KEY_c, Gdk.ModifierType.CONTROL_MASK), + keypresses=(Gdk.KEY_r, Gdk.ModifierType.CONTROL_MASK), preference_name='console_window_visible' ) TOGGLE_BLOCKS_WINDOW = ToggleAction( diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index 2d0709309c..c8631aa298 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -61,6 +61,7 @@ TOOLBAR_LIST = ( Actions.OPEN_HIER, ) + # The list of actions and categories for the menu bar. MENU_BAR_LIST = ( (Gtk.Action(name='File', label='_File'), [ @@ -88,7 +89,7 @@ MENU_BAR_LIST = ( None, Actions.BLOCK_ROTATE_CCW, Actions.BLOCK_ROTATE_CW, - (gtk.Action('Align', '_Align', None, None), Actions.BLOCK_ALIGNMENTS), + (Gtk.Action('Align', '_Align', None, None), Actions.BLOCK_ALIGNMENTS), None, Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, @@ -140,6 +141,7 @@ MENU_BAR_LIST = ( ]), ) + # The list of actions for the context menu. CONTEXT_MENU_LIST = [ Actions.BLOCK_CUT, diff --git a/grc/gui/Block.py b/grc/gui/Block.py index 64c9e022b5..d16c9d01c6 100644 --- a/grc/gui/Block.py +++ b/grc/gui/Block.py @@ -17,10 +17,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +import math import gi gi.require_version('Gtk', '3.0') -from gi.repository import Gtk -from gi.repository import Pango +gi.require_version('PangoCairo', '1.0') +from gi.repository import Gtk, Pango, PangoCairo from . import Actions, Colors, Utils @@ -89,7 +90,9 @@ class Block(Element, _Block): )) Element.__init__(self) self._comment_pixmap = None + self._bg_color = Colors.BLOCK_ENABLED_COLOR self.has_busses = [False, False] # source, sink + self.layouts = [] def get_coordinate(self): """ @@ -196,14 +199,14 @@ class Block(Element, _Block): def create_labels(self): """Create the labels for the signal block.""" Element.create_labels(self) - self._bg_color = self.is_dummy_block and Colors.MISSING_BLOCK_BACKGROUND_COLOR or \ - self.get_bypassed() and Colors.BLOCK_BYPASSED_COLOR or \ - self.get_enabled() and Colors.BLOCK_ENABLED_COLOR or Colors.BLOCK_DISABLED_COLOR - - layouts = list() + self._bg_color = Colors.MISSING_BLOCK_BACKGROUND_COLOR if self.is_dummy_block else \ + Colors.BLOCK_BYPASSED_COLOR if self.get_bypassed() else \ + Colors.BLOCK_ENABLED_COLOR if self.get_enabled() else \ + Colors.BLOCK_DISABLED_COLOR + del self.layouts[:] #create the main layout layout = Gtk.DrawingArea().create_pango_layout('') - layouts.append(layout) + self.layouts.append(layout) layout.set_markup(Utils.parse_template(BLOCK_MARKUP_TMPL, block=self, font=BLOCK_FONT)) self.label_width, self.label_height = layout.get_pixel_size() #display the params @@ -217,30 +220,11 @@ class Block(Element, _Block): layout = Gtk.DrawingArea().create_pango_layout('') layout.set_spacing(LABEL_SEPARATION*Pango.SCALE) layout.set_markup('\n'.join(markups)) - layouts.append(layout) + self.layouts.append(layout) w, h = layout.get_pixel_size() self.label_width = max(w, self.label_width) self.label_height += h + LABEL_SEPARATION - width = self.label_width - height = self.label_height - #setup the pixmap - pixmap = self.get_parent().new_pixmap(width, height) - gc = pixmap.new_gc() - gc.set_foreground(self._bg_color) - pixmap.draw_rectangle(gc, True, 0, 0, width, height) - #draw the layouts - h_off = 0 - for i,layout in enumerate(layouts): - w,h = layout.get_pixel_size() - if i == 0: w_off = (width-w)/2 - else: w_off = 0 - pixmap.draw_layout(gc, w_off, h_off, layout) - h_off = h + h_off + LABEL_SEPARATION - #create vertical and horizontal pixmaps - self.horizontal_label = pixmap - if self.is_vertical(): - self.vertical_label = self.get_parent().new_pixmap(height, width) - Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label) + #calculate width and height needed W = self.label_width + 2 * BLOCK_LABEL_PADDING @@ -301,29 +285,50 @@ class Block(Element, _Block): else: self._comment_pixmap = None - def draw(self, gc, window): + def draw(self, widget, cr): """ Draw the signal block with label and inputs/outputs. - - Args: - gc: the graphics context - window: the gtk window to draw on """ # draw ports for port in self.get_ports_gui(): - port.draw(gc, window) + port.draw(widget, cr) # draw main block - x, y = self.get_coordinate() - Element.draw( - self, gc, window, bg_color=self._bg_color, - border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or - self.is_dummy_block and Colors.MISSING_BLOCK_BORDER_COLOR or Colors.BORDER_COLOR, + border_color = ( + Colors.HIGHLIGHT_COLOR if self.is_highlighted() else + Colors.MISSING_BLOCK_BORDER_COLOR if self.is_dummy_block else + Colors.BORDER_COLOR ) - #draw label image + Element.draw(self, widget, cr, border_color, self._bg_color) + x, y = self.get_coordinate() + # create the image surface + width = self.label_width + height = self.label_height + cr.set_source_rgb(*self._bg_color) + cr.save() if self.is_horizontal(): - window.draw_drawable(gc, self.horizontal_label, 0, 0, x+BLOCK_LABEL_PADDING, y+(self.H-self.label_height)/2, -1, -1) + cr.translate(x + BLOCK_LABEL_PADDING, y + (self.H - self.label_height) / 2) elif self.is_vertical(): - window.draw_drawable(gc, self.vertical_label, 0, 0, x+(self.H-self.label_height)/2, y+BLOCK_LABEL_PADDING, -1, -1) + cr.translate(x + (self.H - self.label_height) / 2, y + BLOCK_LABEL_PADDING) + cr.rotate(-90 * math.pi / 180.) + cr.translate(-width, 0) + + # cr.rectangle(0, 0, width, height) + # cr.fill() + + # draw the layouts + h_off = 0 + for i, layout in enumerate(self.layouts): + w, h = layout.get_pixel_size() + if i == 0: + w_off = (width - w) / 2 + else: + w_off = 0 + cr.translate(w_off, h_off) + PangoCairo.update_layout(cr, layout) + PangoCairo.show_layout(cr, layout) + cr.translate(-w_off, -h_off) + h_off = h + h_off + LABEL_SEPARATION + cr.restore() def what_is_selected(self, coor, coor_m=None): """ diff --git a/grc/gui/Colors.py b/grc/gui/Colors.py index 2c5c73017e..686b378c38 100644 --- a/grc/gui/Colors.py +++ b/grc/gui/Colors.py @@ -16,26 +16,30 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ + try: import gi gi.require_version('Gtk', '3.0') - from gi.repository import Gtk from gi.repository import Gdk + # Not gtk3? + #COLORMAP = Gdk.colormap_get_system() #create all of the colors + #def get_color(color_code): return _COLORMAP.alloc_color(color_code, True, True) + def get_color(color_code): - color = Gdk.RGBA() - color.parse(color_code) - return color + chars_per_color = 2 if len(color_code) > 4 else 1 + offsets = range(1, 3 * chars_per_color + 1, chars_per_color) + return tuple(int(color_code[o:o + 2], 16) / 255.0 for o in offsets) HIGHLIGHT_COLOR = get_color('#00FFFF') BORDER_COLOR = get_color('#444444') # Missing blocks stuff MISSING_BLOCK_BACKGROUND_COLOR = get_color('#FFF2F2') - MISSING_BLOCK_BORDER_COLOR = get_color('red') + MISSING_BLOCK_BORDER_COLOR = get_color('#FF0000') # Param entry boxes - PARAM_ENTRY_TEXT_COLOR = get_color('black') + PARAM_ENTRY_TEXT_COLOR = get_color('#000000') ENTRYENUM_CUSTOM_COLOR = get_color('#EEEEEE') # Flow graph color constants @@ -49,12 +53,9 @@ try: BLOCK_BYPASSED_COLOR = get_color('#F4FF81') # Connection color constants - CONNECTION_ENABLED_COLOR = get_color('black') + CONNECTION_ENABLED_COLOR = get_color('#000000') CONNECTION_DISABLED_COLOR = get_color('#BBBBBB') - CONNECTION_ERROR_COLOR = get_color('red') + CONNECTION_ERROR_COLOR = get_color('#FF0000') except Exception as e: - print 'Unable to import Colors' - - -DEFAULT_DOMAIN_COLOR_CODE = '#777777' + print 'Unable to import Colors', e diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py index 356a55d83b..46414c94c8 100644 --- a/grc/gui/Connection.py +++ b/grc/gui/Connection.py @@ -91,10 +91,10 @@ class Connection(Element, _Connection): ] source_domain = self.get_source().get_domain() sink_domain = self.get_sink().get_domain() - self.line_attributes[0] = 2 if source_domain != sink_domain else 0 - self.line_attributes[1] = Gdk.LINE_DOUBLE_DASH \ - if not source_domain == sink_domain == GR_MESSAGE_DOMAIN \ - else Gdk.LINE_ON_OFF_DASH + # self.line_attributes[0] = 2 if source_domain != sink_domain else 0 + # self.line_attributes[1] = Gdk.LINE_DOUBLE_DASH \ + # if not source_domain == sink_domain == GR_MESSAGE_DOMAIN \ + # else Gdk.LINE_ON_OFF_DASH get_domain_color = lambda d: Colors.get_color(( self.get_parent().get_parent().domains.get(d, {}) ).get('color') or Colors.DEFAULT_DOMAIN_COLOR_CODE) @@ -147,13 +147,9 @@ class Connection(Element, _Connection): self.add_line((x1, y1), points[0]) self.add_line((x2, y2), points[0]) - def draw(self, gc, window): + def draw(self, widget, cr): """ Draw the connection. - - Args: - gc: the graphics context - window: the gtk window to draw on """ sink = self.get_sink() source = self.get_source() @@ -175,11 +171,12 @@ class Connection(Element, _Connection): Colors.CONNECTION_DISABLED_COLOR if not self.get_enabled() else color ) - Element.draw(self, gc, window, mod_color(self._color), mod_color(self._bg_color)) + Element.draw(self, widget, cr, mod_color(self._color), mod_color(self._bg_color)) # draw arrow on sink port - try: - gc.set_foreground(mod_color(self._arrow_color)) - gc.set_line_attributes(0, Gdk.LINE_SOLID, Gdk.CAP_BUTT, Gdk.JOIN_MITER) - window.draw_polygon(gc, True, self._arrow) - except: - pass + cr.set_source_rgb(*self._arrow_color) + # TODO: gc.set_line_attributes(0, Gdk.LINE_SOLID, Gdk.CAP_BUTT, Gdk.JOIN_MITER) + cr.move_to(*self._arrow[0]) + cr.line_to(*self._arrow[1]) + cr.line_to(*self._arrow[2]) + cr.close_path() + cr.fill() diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py index f91fb2a3de..2bce21fa6d 100644 --- a/grc/gui/DrawingArea.py +++ b/grc/gui/DrawingArea.py @@ -48,8 +48,7 @@ class DrawingArea(Gtk.DrawingArea): GObject.GObject.__init__(self) self.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT) self.connect('realize', self._handle_window_realize) - self.connect('configure-event', self._handle_window_configure) - self.connect('expose-event', self._handle_window_expose) + self.connect('draw', self.draw) self.connect('motion-notify-event', self._handle_mouse_motion) self.connect('button-press-event', self._handle_mouse_button_press) self.connect('button-release-event', self._handle_mouse_button_release) @@ -59,35 +58,22 @@ class DrawingArea(Gtk.DrawingArea): Gdk.EventMask.POINTER_MOTION_MASK | \ Gdk.EventMask.BUTTON_RELEASE_MASK | \ Gdk.EventMask.LEAVE_NOTIFY_MASK | \ - Gdk.EventMask.ENTER_NOTIFY_MASK | \ - Gdk.EventMask.FOCUS_CHANGE_MASK + Gdk.EventMask.ENTER_NOTIFY_MASK #| \ + #Gdk.EventMask.FOCUS_CHANGE_MASK ) #setup drag and drop - self.drag_dest_set(Gtk.DestDefaults.ALL, DND_TARGETS, Gdk.DragAction.COPY) + self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY) self.connect('drag-data-received', self._handle_drag_data_received) + self.drag_dest_set_target_list(None) + self.drag_dest_add_text_targets() #setup the focus flag self._focus_flag = False self.get_focus_flag = lambda: self._focus_flag def _handle_notify_event(widget, event, focus_flag): self._focus_flag = focus_flag self.connect('leave-notify-event', _handle_notify_event, False) self.connect('enter-notify-event', _handle_notify_event, True) - self.set_flags(Gtk.CAN_FOCUS) # self.set_can_focus(True) - self.connect('focus-out-event', self._handle_focus_lost_event) - - def new_pixmap(self, width, height): - return Gdk.Pixmap(self.window, width, height, -1) - - def get_screenshot(self, transparent_bg=False): - pixmap = self._pixmap - W, H = pixmap.get_size() - pixbuf = GdkPixbuf.Pixbuf(GdkPixbuf.Colorspace.RGB, 0, 8, W, H) - pixbuf.fill(0xFF + Colors.FLOWGRAPH_BACKGROUND_COLOR.pixel << 8) - pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, W-1, H-1) - if transparent_bg: - bgc = Colors.FLOWGRAPH_BACKGROUND_COLOR - pixbuf = pixbuf.add_alpha(True, bgc.red, bgc.green, bgc.blue) - return pixbuf - +# self.set_flags(Gtk.CAN_FOCUS) # self.set_can_focus(True) +# self.connect('focus-out-event', self._handle_focus_lost_event) ########################################################################## ## Handlers @@ -96,7 +82,7 @@ class DrawingArea(Gtk.DrawingArea): """ Handle a drag and drop by adding a block at the given coordinate. """ - self._flow_graph.add_new_block(selection_data.data, (x, y)) + self._flow_graph.add_new_block(selection_data.get_text(), (x, y)) def _handle_mouse_scroll(self, widget, event): if event.get_state() & Gdk.ModifierType.SHIFT_MASK: @@ -113,7 +99,7 @@ class DrawingArea(Gtk.DrawingArea): self.ctrl_mask = event.get_state() & Gdk.ModifierType.CONTROL_MASK self.mod1_mask = event.get_state() & Gdk.ModifierType.MOD1_MASK if event.button == 1: self._flow_graph.handle_mouse_selector_press( - double_click=(event.type == Gdk._2BUTTON_PRESS), + double_click=(event.type == Gdk.EventType._2BUTTON_PRESS), coordinate=(event.x, event.y), ) if event.button == 3: self._flow_graph.handle_mouse_context_press( @@ -148,27 +134,8 @@ class DrawingArea(Gtk.DrawingArea): """ self._flow_graph.update() - def _handle_window_configure(self, widget, event): - """ - Called when the window is resized. - Create a new pixmap for background buffer. - """ - self._pixmap = self.new_pixmap(*self.get_size_request()) - - def _handle_window_expose(self, widget, event): - """ - Called when window is exposed, or queue_draw is called. - Double buffering: draw to pixmap, then draw pixmap to window. - """ - gc = self.window.new_gc() - self._flow_graph.draw(gc, self._pixmap) - self.window.draw_drawable(gc, self._pixmap, 0, 0, 0, 0, -1, -1) - # draw a light grey line on the bottom and right end of the canvas. - # this is useful when the theme uses the same panel bg color as the canvas - W, H = self._pixmap.get_size() - gc.set_foreground(Colors.FLOWGRAPH_EDGE_COLOR) - self.window.draw_line(gc, 0, H-1, W, H-1) - self.window.draw_line(gc, W-1, 0, W-1, H) + def draw(self, widget, cr): + self._flow_graph.draw(widget, cr) def _handle_focus_lost_event(self, widget, event): # don't clear selection while context menu is active diff --git a/grc/gui/Element.py b/grc/gui/Element.py index 3f6017def7..30c0f5dba7 100644 --- a/grc/gui/Element.py +++ b/grc/gui/Element.py @@ -90,29 +90,33 @@ class Element(object): self.clear() for child in self.get_children(): child.create_shapes() - def draw(self, gc, window, border_color, bg_color): + def draw(self, widget, cr, border_color, bg_color): """ Draw in the given window. Args: - gc: the graphics context - window: the gtk window to draw on + widget: + cr: border_color: the color for lines and rectangle borders bg_color: the color for the inside of the rectangle """ X, Y = self.get_coordinate() - gc.set_line_attributes(*self.line_attributes) + # TODO: gc.set_line_attributes(*self.line_attributes) for (rX, rY), (W, H) in self._areas_list: aX = X + rX aY = Y + rY - gc.set_foreground(bg_color) - window.draw_rectangle(gc, True, aX, aY, W, H) - gc.set_foreground(border_color) - window.draw_rectangle(gc, False, aX, aY, W, H) + cr.set_source_rgb(*bg_color) + cr.rectangle(aX, aY, W, H) + cr.fill() + cr.set_source_rgb(*border_color) + cr.rectangle(aX, aY, W, H) + cr.stroke() + for (x1, y1), (x2, y2) in self._lines_list: - gc.set_foreground(border_color) - gc.set_background(bg_color) - window.draw_line(gc, X+x1, Y+y1, X+x2, Y+y2) + cr.set_source_rgb(*border_color) + cr.move_to(X + x1, Y + y1) + cr.line_to(X + x2, Y + y2) + cr.stroke() def rotate(self, rotation): """ diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index f7af93fe8e..c3ea6770c1 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -397,23 +397,21 @@ class FlowGraph(Element, _Flowgraph): changed = True return changed - def draw(self, gc, window): + def draw(self, widget, cr): """ Draw the background and grid if enabled. - Draw all of the elements in this flow graph onto the pixmap. - Draw the pixmap to the drawable window of this flow graph. """ - W,H = self.get_size() - #draw the background - gc.set_foreground(Colors.FLOWGRAPH_BACKGROUND_COLOR) - window.draw_rectangle(gc, True, 0, 0, W, H) + cr.set_source_rgb(*Colors.FLOWGRAPH_BACKGROUND_COLOR) + cr.rectangle(0, 0, *self.get_size()) + cr.fill() # draw comments first if Actions.TOGGLE_SHOW_BLOCK_COMMENTS.get_active(): for block in self.blocks: if block.get_enabled(): - block.draw_comment(gc, window) + # block.draw_comment(widget, cr) + pass #draw multi select rectangle if self.mouse_pressed and (not self.get_selected_elements() or self.get_ctrl_mask()): #coordinates @@ -423,10 +421,13 @@ class FlowGraph(Element, _Flowgraph): x, y = int(min(x1, x2)), int(min(y1, y2)) w, h = int(abs(x1 - x2)), int(abs(y1 - y2)) #draw - gc.set_foreground(Colors.HIGHLIGHT_COLOR) - window.draw_rectangle(gc, True, x, y, w, h) - gc.set_foreground(Colors.BORDER_COLOR) - window.draw_rectangle(gc, False, x, y, w, h) + cr.set_source_rgb(*Colors.HIGHLIGHT_COLOR) + cr.rectangle(x, y, w, h) + cr.fill() + cr.set_source_rgb(*Colors.BORDER_COLOR) + cr.rectangle(x, y, w, h) + cr.stroke() + #draw blocks on top of connections hide_disabled_blocks = Actions.TOGGLE_HIDE_DISABLED_BLOCKS.get_active() hide_variables = Actions.TOGGLE_HIDE_VARIABLES.get_active() @@ -437,10 +438,10 @@ class FlowGraph(Element, _Flowgraph): continue # skip hidden disabled blocks and connections if hide_variables and (element.is_variable or element.is_import): continue # skip hidden disabled blocks and connections - element.draw(gc, window) + element.draw(widget, cr) #draw selected blocks on top of selected connections for selected_element in self.get_selected_connections() + self.get_selected_blocks(): - selected_element.draw(gc, window) + selected_element.draw(widget, cr) def update_selected(self): """ diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py index 649b8b29c5..95a5c89867 100644 --- a/grc/gui/MainWindow.py +++ b/grc/gui/MainWindow.py @@ -36,6 +36,7 @@ from .NotebookPage import NotebookPage from ..core import Messages + MAIN_WINDOW_TITLE_TMPL = """\ #if not $saved *#slurp @@ -104,8 +105,8 @@ class MainWindow(Gtk.Window): vbox.pack_start(self.tool_bar, False, False, 0) # Main parent container for the different panels - self.container = Gtk.HPaned() - vbox.pack_start(self.container) + self.main = Gtk.HPaned() #(orientation=Gtk.Orientation.HORIZONTAL) + vbox.pack_start(self.main, True, True, 0) # Create the notebook self.notebook = Gtk.Notebook() @@ -127,9 +128,9 @@ class MainWindow(Gtk.Window): self.vars = VariableEditor(platform, self.get_flow_graph) # Figure out which place to put the variable editor - self.left = Gtk.VPaned() - self.right = Gtk.VPaned() - self.left_subpanel = Gtk.HPaned() + self.left = Gtk.VPaned() #orientation=Gtk.Orientation.VERTICAL) + self.right = Gtk.VPaned() #orientation=Gtk.Orientation.VERTICAL) + self.left_subpanel = Gtk.HPaned() #orientation=Gtk.Orientation.HORIZONTAL) self.variable_panel_sidebar = Preferences.variable_editor_sidebar() if self.variable_panel_sidebar: @@ -147,12 +148,12 @@ class MainWindow(Gtk.Window): # Create the right panel self.right.pack1(self.btwin) - self.container.pack1(self.left) - self.container.pack2(self.right, False) + self.main.pack1(self.left) + self.main.pack2(self.right, False) # Load preferences and show the main window self.resize(*Preferences.main_window_size()) - self.container.set_position(Preferences.blocks_window_position()) + self.main.set_position(Preferences.blocks_window_position()) self.left.set_position(Preferences.console_window_position()) if self.variable_panel_sidebar: self.right.set_position(Preferences.variable_editor_position(sidebar=True)) @@ -276,9 +277,7 @@ class MainWindow(Gtk.Window): return #add this page to the notebook self.notebook.append_page(page, page.get_tab()) - try: self.notebook.set_tab_reorderable(page, True) - except: pass #gtk too old - self.notebook.set_tab_label_packing(page, False, False, Gtk.PACK_START) + self.notebook.set_tab_reorderable(page, True) #only show if blank or manual if not file_path or show: self._set_page(page) @@ -303,7 +302,7 @@ class MainWindow(Gtk.Window): Preferences.file_open(open_file) Preferences.main_window_size(self.get_size()) Preferences.console_window_position(self.left.get_position()) - Preferences.blocks_window_position(self.container.get_position()) + Preferences.blocks_window_position(self.main.get_position()) if self.variable_panel_sidebar: Preferences.variable_editor_position(self.right.get_position(), sidebar=True) else: @@ -405,14 +404,11 @@ class MainWindow(Gtk.Window): Returns: the selected flow graph """ - return None - # TODO: Issues with flowgraphs - #return self.get_page().get_flow_graph() + return self.get_page().get_flow_graph() def get_focus_flag(self): """ Get the focus flag from the current page. - Returns: the focus flag """ diff --git a/grc/gui/NotebookPage.py b/grc/gui/NotebookPage.py index 3f49cd0223..9a76897fe6 100644 --- a/grc/gui/NotebookPage.py +++ b/grc/gui/NotebookPage.py @@ -54,7 +54,7 @@ class NotebookPage(Gtk.HBox): GObject.GObject.__init__(self) self.show() #tab box to hold label and close button - self.tab = Gtk.HBox(False, 0) + self.tab = Gtk.HBox(homogeneous=False, spacing=0) #setup tab label self.label = Gtk.Label() self.tab.pack_start(self.label, False, False, 0) @@ -62,7 +62,7 @@ class NotebookPage(Gtk.HBox): image = Gtk.Image() image.set_from_stock('gtk-close', Gtk.IconSize.MENU) #setup image box - image_box = Gtk.HBox(False, 0) + image_box = Gtk.HBox(homogeneous=False, spacing=0) image_box.pack_start(image, True, False, 0) #setup the button button = Gtk.Button() @@ -79,20 +79,18 @@ class NotebookPage(Gtk.HBox): self.scrolled_window.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT) self.scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.scrolled_window.connect('key-press-event', self._handle_scroll_window_key_press) - #self.drawing_area = DrawingArea(self.get_flow_graph()) - #self.scrolled_window.add_with_viewport(self.get_drawing_area()) + self.drawing_area = DrawingArea(self.get_flow_graph()) + self.scrolled_window.add_with_viewport(self.drawing_area) self.pack_start(self.scrolled_window, True, True, 0) #inject drawing area into flow graph - #self.get_flow_graph().drawing_area = self.get_drawing_area() + self.get_flow_graph().drawing_area = self.drawing_area self.show_all() - def get_drawing_area(self): return self.drawing_area - def _handle_scroll_window_key_press(self, widget, event): """forward Ctrl-PgUp/Down to NotebookPage (switch fg instead of horiz. scroll""" is_ctrl_pg = ( - event.state & gtk.gdk.CONTROL_MASK and - event.keyval in (gtk.keysyms.Page_Up, gtk.keysyms.Page_Down) + event.state & Gdk.ModifierType.CONTROL_MASK and + event.keyval in (Gdk.KEY_Page_Up, Gdk.KEY_Page_Down) ) if is_ctrl_pg: return self.get_parent().event(event) diff --git a/grc/gui/Port.py b/grc/gui/Port.py index 02cef5d04b..eb15f6c788 100644 --- a/grc/gui/Port.py +++ b/grc/gui/Port.py @@ -17,9 +17,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +import math import gi gi.require_version('Gtk', '3.0') -from gi.repository import Gtk +from gi.repository import Gtk, PangoCairo from . import Actions, Colors, Utils from .Constants import ( @@ -45,15 +46,19 @@ class Port(_Port, Element): """ _Port.__init__(self, block, n, dir) Element.__init__(self) - self.W = self.H = self.w = self.h = 0 + self.W = self.w = self.h = 0 + self.H = 20 # todo: fix self._connector_coordinate = (0, 0) self._connector_length = 0 self._hovering = True self._force_label_unhidden = False + self.layout = Gtk.DrawingArea().create_pango_layout('') + self._bg_color = Colors.get_color(self.get_color()) def create_shapes(self): """Create new areas and labels for the port.""" Element.create_shapes(self) + self._bg_color = Colors.get_color(self.get_color()) if self.get_hide(): return # this port is hidden, no need to create shapes if self.get_domain() == GR_MESSAGE_DOMAIN: @@ -112,50 +117,34 @@ class Port(_Port, Element): def create_labels(self): """Create the labels for the socket.""" - Element.create_labels(self) - self._bg_color = Colors.get_color(self.get_color()) - # create the layout - layout = Gtk.DrawingArea().create_pango_layout('') - layout.set_markup(Utils.parse_template(PORT_MARKUP_TMPL, port=self, font=PORT_FONT)) - self.w, self.h = layout.get_pixel_size() - self.W = 2 * PORT_LABEL_PADDING + self.w - self.H = 2 * PORT_LABEL_PADDING + self.h * ( - 3 if self.get_type() == 'bus' else 1) - self.H += self.H % 2 - # create the pixmap - pixmap = self.get_parent().get_parent().new_pixmap(self.w, self.h) - gc = pixmap.new_gc() - gc.set_foreground(self._bg_color) - pixmap.draw_rectangle(gc, True, 0, 0, self.w, self.h) - pixmap.draw_layout(gc, 0, 0, layout) - # create vertical and horizontal pixmaps - self.horizontal_label = pixmap - if self.is_vertical(): - self.vertical_label = self.get_parent().get_parent().new_pixmap(self.h, self.w) - Utils.rotate_pixmap(gc, self.horizontal_label, self.vertical_label) - - def draw(self, gc, window): + self.layout.set_markup(Utils.parse_template(PORT_MARKUP_TMPL, port=self, font=PORT_FONT)) + + def draw(self, widget, cr): """ Draw the socket with a label. - - Args: - gc: the graphics context - window: the gtk window to draw on """ - Element.draw( - self, gc, window, bg_color=self._bg_color, - border_color=self.is_highlighted() and Colors.HIGHLIGHT_COLOR or - self.get_parent().is_dummy_block and Colors.MISSING_BLOCK_BORDER_COLOR or - Colors.BORDER_COLOR, + border_color = ( + Colors.HIGHLIGHT_COLOR if self.is_highlighted() else + Colors.MISSING_BLOCK_BORDER_COLOR if self.get_parent().is_dummy_block else + Colors.BORDER_COLOR ) + Element.draw(self, widget, cr, border_color, self._bg_color) + if not self._areas_list or self._label_hidden(): return # this port is either hidden (no areas) or folded (no label) X, Y = self.get_coordinate() - (x, y), (w, h) = self._areas_list[0] # use the first area's sizes to place the labels + (x, y), _ = self._areas_list[0] + cr.set_source_rgb(*self._bg_color) + cr.save() if self.is_horizontal(): - window.draw_drawable(gc, self.horizontal_label, 0, 0, x+X+(self.W-self.w)/2, y+Y+(self.H-self.h)/2, -1, -1) + cr.translate(x + X + (self.W - self.w) / 2, y + Y + (self.H - self.h) / 2) elif self.is_vertical(): - window.draw_drawable(gc, self.vertical_label, 0, 0, x+X+(self.H-self.h)/2, y+Y+(self.W-self.w)/2, -1, -1) + cr.translate(x + X + (self.H - self.h) / 2, y + Y + (self.W - self.w) / 2) + cr.rotate(-90 * math.pi / 180.) + cr.translate(-self.w, 0) + PangoCairo.update_layout(cr, self.layout) + PangoCairo.show_layout(cr, self.layout) + cr.restore() def get_connector_coordinate(self): """ diff --git a/grc/gui/VariableEditor.py b/grc/gui/VariableEditor.py index 7721f3bda6..8729762928 100644 --- a/grc/gui/VariableEditor.py +++ b/grc/gui/VariableEditor.py @@ -1,5 +1,5 @@ """ -Copyright 2015 Free Software Foundation, Inc. +Copyright 2015, 2016 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -19,10 +19,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from operator import attrgetter -import pygtk -pygtk.require('2.0') -import gtk -import gobject +import gi +gi.require_version('Gtk', '3.0') +from gi.repository import Gtk +from gi.repository import Gdk +from gi.repository import GObject from . import Actions from . import Preferences @@ -32,34 +33,34 @@ BLOCK_INDEX = 0 ID_INDEX = 1 -class VariableEditorContextMenu(gtk.Menu): +class VariableEditorContextMenu(Gtk.Menu): """ A simple context menu for our variable editor """ def __init__(self, var_edit): - gtk.Menu.__init__(self) + Gtk.Menu.__init__(self) - self.imports = gtk.MenuItem("Add _Import") + self.imports = Gtk.MenuItem("Add _Import") self.imports.connect('activate', var_edit.handle_action, var_edit.ADD_IMPORT) self.add(self.imports) - self.variables = gtk.MenuItem("Add _Variable") + self.variables = Gtk.MenuItem("Add _Variable") self.variables.connect('activate', var_edit.handle_action, var_edit.ADD_VARIABLE) self.add(self.variables) - self.add(gtk.SeparatorMenuItem()) + self.add(Gtk.SeparatorMenuItem()) - self.enable = gtk.MenuItem("_Enable") + self.enable = Gtk.MenuItem("_Enable") self.enable.connect('activate', var_edit.handle_action, var_edit.ENABLE_BLOCK) - self.disable = gtk.MenuItem("_Disable") + self.disable = Gtk.MenuItem("_Disable") self.disable.connect('activate', var_edit.handle_action, var_edit.DISABLE_BLOCK) self.add(self.enable) self.add(self.disable) - self.add(gtk.SeparatorMenuItem()) + self.add(Gtk.SeparatorMenuItem()) - self.delete = gtk.MenuItem("_Delete") + self.delete = Gtk.MenuItem("_Delete") self.delete.connect('activate', var_edit.handle_action, var_edit.DELETE_BLOCK) self.add(self.delete) - self.add(gtk.SeparatorMenuItem()) + self.add(Gtk.SeparatorMenuItem()) - self.properties = gtk.MenuItem("_Properties...") + self.properties = Gtk.MenuItem("_Properties...") self.properties.connect('activate', var_edit.handle_action, var_edit.OPEN_PROPERTIES) self.add(self.properties) self.show_all() @@ -71,7 +72,7 @@ class VariableEditorContextMenu(gtk.Menu): self.disable.set_sensitive(selected and enabled) -class VariableEditor(gtk.VBox): +class VariableEditor(Gtk.VBox): # Actions that are handled by the editor ADD_IMPORT = 0 @@ -83,7 +84,7 @@ class VariableEditor(gtk.VBox): DISABLE_BLOCK = 6 def __init__(self, platform, get_flow_graph): - gtk.VBox.__init__(self) + Gtk.VBox.__init__(self) self.platform = platform self.get_flow_graph = get_flow_graph self._block = None @@ -91,14 +92,14 @@ class VariableEditor(gtk.VBox): # Only use the model to store the block reference and name. # Generate everything else dynamically - self.treestore = gtk.TreeStore(gobject.TYPE_PYOBJECT, # Block reference - gobject.TYPE_STRING) # Category and block name - self.treeview = gtk.TreeView(self.treestore) + self.treestore = Gtk.TreeStore(GObject.TYPE_PYOBJECT, # Block reference + GObject.TYPE_STRING) # Category and block name + self.treeview = Gtk.TreeView(self.treestore) self.treeview.set_enable_search(False) self.treeview.set_search_column(-1) #self.treeview.set_enable_search(True) #self.treeview.set_search_column(ID_INDEX) - self.treeview.get_selection().set_mode('single') + self.treeview.get_selection().set_mode(Gtk.SelectionMode.SINGLE) self.treeview.set_headers_visible(True) self.treeview.connect('button-press-event', self._handle_mouse_button_press) self.treeview.connect('button-release-event', self._handle_mouse_button_release) @@ -106,67 +107,67 @@ class VariableEditor(gtk.VBox): self.treeview.connect('key-press-event', self._handle_key_button_press) # Block Name or Category - self.id_cell = gtk.CellRendererText() + self.id_cell = Gtk.CellRendererText() self.id_cell.connect('edited', self._handle_name_edited_cb) - id_column = gtk.TreeViewColumn("Id", self.id_cell, text=ID_INDEX) + id_column = Gtk.TreeViewColumn("Id", self.id_cell, text=ID_INDEX) id_column.set_name("id") id_column.set_resizable(True) id_column.set_max_width(300) id_column.set_min_width(80) id_column.set_fixed_width(100) - id_column.set_sizing(gtk.TREE_VIEW_COLUMN_FIXED) + id_column.set_sizing(Gtk.TreeViewColumnSizing.FIXED) id_column.set_cell_data_func(self.id_cell, self.set_properties) self.id_column = id_column self.treeview.append_column(id_column) - self.treestore.set_sort_column_id(ID_INDEX, gtk.SORT_ASCENDING) + self.treestore.set_sort_column_id(ID_INDEX, Gtk.SortType.ASCENDING) # For forcing resize self._col_width = 0 # Block Value - self.value_cell = gtk.CellRendererText() + self.value_cell = Gtk.CellRendererText() self.value_cell.connect('edited', self._handle_value_edited_cb) - value_column = gtk.TreeViewColumn("Value", self.value_cell) + value_column = Gtk.TreeViewColumn("Value", self.value_cell) value_column.set_name("value") value_column.set_resizable(False) value_column.set_expand(True) value_column.set_min_width(100) - value_column.set_sizing(gtk.TREE_VIEW_COLUMN_AUTOSIZE) + value_column.set_sizing(Gtk.TreeViewColumnSizing.AUTOSIZE) value_column.set_cell_data_func(self.value_cell, self.set_value) self.value_column = value_column self.treeview.append_column(value_column) # Block Actions (Add, Remove) - self.action_cell = gtk.CellRendererPixbuf() + self.action_cell = Gtk.CellRendererPixbuf() value_column.pack_start(self.action_cell, False) value_column.set_cell_data_func(self.action_cell, self.set_icon) # Make the scrolled window to hold the tree view - scrolled_window = gtk.ScrolledWindow() - scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) + scrolled_window = Gtk.ScrolledWindow() + scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) scrolled_window.add_with_viewport(self.treeview) scrolled_window.set_size_request(DEFAULT_BLOCKS_WINDOW_WIDTH, -1) - self.pack_start(scrolled_window) + self.pack_start(scrolled_window, True, True, 0) # Context menus self._context_menu = VariableEditorContextMenu(self) self._confirm_delete = Preferences.variable_editor_confirm_delete() # Sets cell contents - def set_icon(self, col, cell, model, iter): + def set_icon(self, col, cell, model, iter, data): block = model.get_value(iter, BLOCK_INDEX) if block: - pb = self.treeview.render_icon(gtk.STOCK_CLOSE, gtk.ICON_SIZE_MENU, None) + pb = self.treeview.render_icon(Gtk.STOCK_CLOSE, 16, None) else: - pb = self.treeview.render_icon(gtk.STOCK_ADD, gtk.ICON_SIZE_MENU, None) + pb = self.treeview.render_icon(Gtk.STOCK_ADD, 16, None) cell.set_property('pixbuf', pb) - def set_value(self, col, cell, model, iter): + def set_value(self, col, cell, model, iter, data): sp = cell.set_property block = model.get_value(iter, BLOCK_INDEX) # Set the default properties for this column first. # Some set in set_properties() may be overridden (editable for advanced variable blocks) - self.set_properties(col, cell, model, iter) + self.set_properties(col, cell, model, iter, data) # Set defaults value = None @@ -198,7 +199,7 @@ class VariableEditor(gtk.VBox): # Always set the text value. sp('text', value) - def set_properties(self, col, cell, model, iter): + def set_properties(self, col, cell, model, iter, data): sp = cell.set_property block = model.get_value(iter, BLOCK_INDEX) # Set defaults @@ -268,13 +269,13 @@ class VariableEditor(gtk.VBox): elif key == self.DELETE_CONFIRM: if self._confirm_delete: # Create a context menu to confirm the delete operation - confirmation_menu = gtk.Menu() + confirmation_menu = Gtk.Menu() block_id = self._block.get_param('id').get_value().replace("_", "__") - confirm = gtk.MenuItem("Delete {}".format(block_id)) + confirm = Gtk.MenuItem("Delete {}".format(block_id)) confirm.connect('activate', self.handle_action, self.DELETE_BLOCK) confirmation_menu.add(confirm) confirmation_menu.show_all() - confirmation_menu.popup(None, None, None, event.button, event.time) + confirmation_menu.popup(None, None, None, None, event.button, event.time) else: self.handle_action(None, self.DELETE_BLOCK, None) elif key == self.ENABLE_BLOCK: @@ -302,12 +303,12 @@ class VariableEditor(gtk.VBox): if event.button == 1 and col.get_name() == "value": # Make sure this has a block (not the import/variable rows) - if self._block and event.type == gtk.gdk._2BUTTON_PRESS: + if self._block and event.type == Gdk.EventType._2BUTTON_PRESS: # Open the advanced dialog if it is a gui variable if self._block.get_key() not in ("variable", "import"): self.handle_action(None, self.OPEN_PROPERTIES, event=event) return True - if event.type == gtk.gdk.BUTTON_PRESS: + if event.type == Gdk.EventType.BUTTON_PRESS: # User is adding/removing blocks # Make sure this is the action cell (Add/Remove Icons) if path[2] > col.cell_get_position(self.action_cell)[0]: @@ -320,15 +321,15 @@ class VariableEditor(gtk.VBox): else: self.handle_action(None, self.DELETE_CONFIRM, event=event) return True - elif event.button == 3 and event.type == gtk.gdk.BUTTON_PRESS: + elif event.button == 3 and event.type == Gdk.EventType.BUTTON_PRESS: if self._block: self._context_menu.update_sensitive(True, enabled=self._block.get_enabled()) else: self._context_menu.update_sensitive(False) - self._context_menu.popup(None, None, None, event.button, event.time) + self._context_menu.popup(None, None, None, None, event.button, event.time) # Null handler. Stops the treeview from handling double click events. - if event.type == gtk.gdk._2BUTTON_PRESS: + if event.type == Gdk.EventType._2BUTTON_PRESS: return True return False -- cgit v1.2.3 From 94c4606edd30dc8b1278580782f2809b69f04641 Mon Sep 17 00:00:00 2001 From: Sebastian Koslowski <koslowski@kit.edu> Date: Fri, 3 Jun 2016 10:02:36 +0200 Subject: grc: py3k compat using python-modernize --- grc/checks.py | 1 + grc/core/Block.py | 33 +++++++++-------- grc/core/Config.py | 1 + grc/core/Connection.py | 8 +++-- grc/core/Constants.py | 10 ++++-- grc/core/Element.py | 6 ++-- grc/core/FlowGraph.py | 57 +++++++++++++++-------------- grc/core/Messages.py | 3 +- grc/core/Param.py | 69 ++++++++++++++++++------------------ grc/core/ParseXML.py | 21 +++++++---- grc/core/Platform.py | 34 ++++++++++-------- grc/core/Port.py | 41 +++++++++++---------- grc/core/generator/FlowGraphProxy.py | 16 +++++---- grc/core/generator/Generator.py | 30 +++++++++------- grc/core/generator/__init__.py | 3 +- grc/core/utils/__init__.py | 10 +++--- grc/core/utils/complexity.py | 13 +++---- grc/core/utils/epy_block_io.py | 11 ++++-- grc/core/utils/expr_utils.py | 21 ++++++----- grc/core/utils/extract_docs.py | 28 ++++++++------- grc/core/utils/odict.py | 2 ++ grc/gui/ActionHandler.py | 8 +++-- grc/gui/Actions.py | 14 +++++--- grc/gui/Bars.py | 3 +- grc/gui/Block.py | 3 +- grc/gui/BlockTreeWindow.py | 14 +++++--- grc/gui/Colors.py | 1 + grc/gui/Config.py | 7 ++-- grc/gui/Connection.py | 16 ++++----- grc/gui/Constants.py | 1 + grc/gui/Dialogs.py | 1 + grc/gui/DrawingArea.py | 1 + grc/gui/Element.py | 6 ++-- grc/gui/Executor.py | 1 + grc/gui/FileDialogs.py | 9 ++--- grc/gui/FlowGraph.py | 14 +++++--- grc/gui/MainWindow.py | 6 ++-- grc/gui/NotebookPage.py | 1 + grc/gui/Param.py | 1 + grc/gui/ParamWidgets.py | 1 + grc/gui/ParserErrorsDialog.py | 8 +++-- grc/gui/Platform.py | 4 ++- grc/gui/Port.py | 8 ++--- grc/gui/Preferences.py | 21 ++++++----- grc/gui/PropsDialog.py | 6 ++-- grc/gui/StateCache.py | 5 +-- grc/gui/Utils.py | 8 +++-- grc/gui/VariableEditor.py | 6 ++-- grc/gui/external_editor.py | 6 ++-- grc/main.py | 1 + 50 files changed, 356 insertions(+), 243 deletions(-) (limited to 'grc/gui/Bars.py') diff --git a/grc/checks.py b/grc/checks.py index 66c114d723..40a0b2b270 100755 --- a/grc/checks.py +++ b/grc/checks.py @@ -15,6 +15,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +from __future__ import absolute_import import os import warnings diff --git a/grc/core/Block.py b/grc/core/Block.py index aafc5db6f1..062598e9d1 100644 --- a/grc/core/Block.py +++ b/grc/core/Block.py @@ -17,9 +17,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import + import collections import itertools +from six.moves import map, range + from Cheetah.Template import Template from .utils import epy_block_io, odict @@ -70,7 +74,7 @@ class Block(Element): self._flags += BLOCK_FLAG_THROTTLE self._doc = (n.find('doc') or '').strip('\n').replace('\\\n', '') - self._imports = map(lambda i: i.strip(), n.findall('import')) + self._imports = [i.strip() for i in n.findall('import')] self._make = n.find('make') self._var_make = n.find('var_make') self._var_value = n.find('var_value') or '$value' @@ -250,7 +254,7 @@ class Block(Element): self.back_ofthe_bus(ports) # Renumber non-message/message ports domain_specific_port_index = collections.defaultdict(int) - for port in filter(lambda p: p.get_key().isdigit(), ports): + for port in [p for p in ports if p.get_key().isdigit()]: domain = port.get_domain() port._key = str(domain_specific_port_index[domain]) domain_specific_port_index[domain] += 1 @@ -275,7 +279,8 @@ class Block(Element): """ if raw: return self._imports - return filter(lambda i: i, sum(map(lambda i: self.resolve_dependencies(i).split('\n'), self._imports), [])) + return [i for i in sum([self.resolve_dependencies(i).split('\n') + for i in self._imports], []) if i] def get_make(self, raw=False): if raw: @@ -300,7 +305,7 @@ class Block(Element): if 'self.' in callback: return callback return 'self.{}.{}'.format(self.get_id(), callback) - return map(make_callback, self._callbacks) + return [make_callback(c) for c in self._callbacks] def is_virtual_sink(self): return self.get_key() == 'virtual_sink' @@ -622,10 +627,10 @@ class Block(Element): """ changed = False type_param = None - for param in filter(lambda p: p.is_enum(), self.get_params()): + for param in [p for p in self.get_params() if p.is_enum()]: children = self.get_ports() + self.get_params() # Priority to the type controller - if param.get_key() in ' '.join(map(lambda p: p._type, children)): type_param = param + if param.get_key() in ' '.join([p._type for p in children]): type_param = param # Use param if type param is unset if not type_param: type_param = param @@ -681,10 +686,10 @@ class Block(Element): """ n = odict() n['key'] = self.get_key() - n['param'] = map(lambda p: p.export_data(), sorted(self.get_params(), key=str)) - if 'bus' in map(lambda a: a.get_type(), self.get_sinks()): + n['param'] = [p.export_data() for p in sorted(self.get_params(), key=str)] + if 'bus' in [a.get_type() for a in self.get_sinks()]: n['bus_sink'] = str(1) - if 'bus' in map(lambda a: a.get_type(), self.get_sources()): + if 'bus' in [a.get_type() for a in self.get_sources()]: n['bus_source'] = str(1) return n @@ -773,12 +778,12 @@ class Block(Element): get_p_gui = self.get_sinks_gui bus_structure = self.get_bus_structure('sink') - struct = [range(len(get_p()))] - if True in map(lambda a: isinstance(a.get_nports(), int), get_p()): + struct = [list(range(len(get_p())))] + if True in [isinstance(a.get_nports(), int) for a in get_p()]: structlet = [] last = 0 for j in [i.get_nports() for i in get_p() if isinstance(i.get_nports(), int)]: - structlet.extend(map(lambda a: a+last, range(j))) + structlet.extend([a+last for a in range(j)]) last = structlet[-1] + 1 struct = [structlet] if bus_structure: @@ -802,7 +807,7 @@ class Block(Element): for connect in elt.get_connections(): self.get_parent().remove_element(connect) - if ('bus' not in map(lambda a: a.get_type(), get_p())) and len(get_p()) > 0: + if ('bus' not in [a.get_type() for a in get_p()]) and len(get_p()) > 0: struct = self.form_bus_structure(direc) self.current_bus_structure[direc] = struct if get_p()[0].get_nports(): @@ -813,7 +818,7 @@ class Block(Element): n = odict(n) port = self.get_parent().get_parent().Port(block=self, n=n, dir=direc) get_p().append(port) - elif 'bus' in map(lambda a: a.get_type(), get_p()): + elif 'bus' in [a.get_type() for a in get_p()]: for elt in get_p_gui(): get_p().remove(elt) self.current_bus_structure[direc] = '' diff --git a/grc/core/Config.py b/grc/core/Config.py index ac38d9978c..400d5d365f 100644 --- a/grc/core/Config.py +++ b/grc/core/Config.py @@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import import os from os.path import expanduser, normpath, expandvars, exists diff --git a/grc/core/Connection.py b/grc/core/Connection.py index 3aa32ef183..ddc6c0256f 100644 --- a/grc/core/Connection.py +++ b/grc/core/Connection.py @@ -17,6 +17,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import + +from six.moves import range + from . import Constants from .Element import Element from .utils import odict @@ -51,8 +55,8 @@ class Connection(Element): raise ValueError('Connection could not isolate source') if not sink: raise ValueError('Connection could not isolate sink') - busses = len(filter(lambda a: a.get_type() == 'bus', [source, sink])) % 2 - if not busses == 0: + + if (source.get_type() == 'bus') != (sink.get_type() == 'bus'): raise ValueError('busses must get with busses') if not len(source.get_associated_ports()) == len(sink.get_associated_ports()): diff --git a/grc/core/Constants.py b/grc/core/Constants.py index 4f278bb22d..8a99f8b256 100644 --- a/grc/core/Constants.py +++ b/grc/core/Constants.py @@ -17,10 +17,14 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import + import os -import numpy import stat +import numpy +import six + # Data files DATA_DIR = os.path.dirname(__file__) FLOW_GRAPH_DTD = os.path.join(DATA_DIR, 'flow_graph.dtd') @@ -63,7 +67,7 @@ HIER_BLOCK_FILE_MODE = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP VECTOR_TYPES = (tuple, list, set, numpy.ndarray) COMPLEX_TYPES = [complex, numpy.complex, numpy.complex64, numpy.complex128] REAL_TYPES = [float, numpy.float, numpy.float32, numpy.float64] -INT_TYPES = [int, long, numpy.int, numpy.int8, numpy.int16, numpy.int32, numpy.uint64, +INT_TYPES = [int, numpy.int, numpy.int8, numpy.int16, numpy.int32, numpy.uint64, numpy.uint, numpy.uint8, numpy.uint16, numpy.uint32, numpy.uint64] # Cast to tuple for isinstance, concat subtypes COMPLEX_TYPES = tuple(COMPLEX_TYPES + REAL_TYPES + INT_TYPES) @@ -129,6 +133,6 @@ for name, key, sizeof, color in CORE_TYPES: TYPE_TO_COLOR[key] = color TYPE_TO_SIZEOF[key] = sizeof -for key, (sizeof, color) in ALIAS_TYPES.iteritems(): +for key, (sizeof, color) in six.iteritems(ALIAS_TYPES): TYPE_TO_COLOR[key] = color TYPE_TO_SIZEOF[key] = sizeof diff --git a/grc/core/Element.py b/grc/core/Element.py index 67c36e12b4..e697d293fb 100644 --- a/grc/core/Element.py +++ b/grc/core/Element.py @@ -22,7 +22,7 @@ class Element(object): def __init__(self, parent=None): self._parent = parent - self._error_messages = list() + self._error_messages = [] ################################################## # Element Validation API @@ -64,7 +64,9 @@ class Element(object): a list of error message strings """ error_messages = list(self._error_messages) # Make a copy - for child in filter(lambda c: c.get_enabled() and not c.get_bypassed(), self.get_children()): + for child in self.get_children(): + if not child.get_enabled() or child.get_bypassed(): + continue for msg in child.get_error_messages(): error_messages.append("{}:\n\t{}".format(child, msg.replace("\n", "\n\t"))) return error_messages diff --git a/grc/core/FlowGraph.py b/grc/core/FlowGraph.py index 949eecaa71..9edd4f24d8 100644 --- a/grc/core/FlowGraph.py +++ b/grc/core/FlowGraph.py @@ -15,12 +15,15 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +from __future__ import absolute_import, print_function + import imp import time -from itertools import ifilter, chain +import re +from itertools import chain from operator import methodcaller, attrgetter -import re +from six.moves import filter from . import Messages from .Constants import FLOW_GRAPH_FILE_FORMAT_VERSION @@ -87,7 +90,7 @@ class FlowGraph(Element): Returns: a sorted list of variable blocks in order of dependency (indep -> dep) """ - variables = filter(attrgetter('is_variable'), self.iter_enabled_blocks()) + variables = list(filter(attrgetter('is_variable'), self.iter_enabled_blocks())) return expr_utils.sort_objects(variables, methodcaller('get_id'), methodcaller('get_var_make')) def get_parameters(self): @@ -97,15 +100,14 @@ class FlowGraph(Element): Returns: a list of parameterized variables """ - parameters = filter(lambda b: _parameter_matcher.match(b.get_key()), self.iter_enabled_blocks()) + parameters = [b for b in self.iter_enabled_blocks() if _parameter_matcher.match(b.get_key())] return parameters def get_monitors(self): """ Get a list of all ControlPort monitors """ - monitors = filter(lambda b: _monitors_searcher.search(b.get_key()), - self.iter_enabled_blocks()) + monitors = [b for b in self.iter_enabled_blocks() if _monitors_searcher.search(b.get_key())] return monitors def get_python_modules(self): @@ -115,7 +117,7 @@ class FlowGraph(Element): yield block.get_id(), block.get_param('source_code').get_value() def get_bussink(self): - bussink = filter(lambda b: _bussink_searcher.search(b.get_key()), self.get_enabled_blocks()) + bussink = [b for b in self.get_enabled_blocks() if _bussink_searcher.search(b.get_key())] for i in bussink: for j in i.get_params(): @@ -124,7 +126,7 @@ class FlowGraph(Element): return False def get_bussrc(self): - bussrc = filter(lambda b: _bussrc_searcher.search(b.get_key()), self.get_enabled_blocks()) + bussrc = [b for b in self.get_enabled_blocks() if _bussrc_searcher.search(b.get_key())] for i in bussrc: for j in i.get_params(): @@ -133,18 +135,18 @@ class FlowGraph(Element): return False def get_bus_structure_sink(self): - bussink = filter(lambda b: _bus_struct_sink_searcher.search(b.get_key()), self.get_enabled_blocks()) + bussink = [b for b in self.get_enabled_blocks() if _bus_struct_sink_searcher.search(b.get_key())] return bussink def get_bus_structure_src(self): - bussrc = filter(lambda b: _bus_struct_src_searcher.search(b.get_key()), self.get_enabled_blocks()) + bussrc = [b for b in self.get_enabled_blocks() if _bus_struct_src_searcher.search(b.get_key())] return bussrc def iter_enabled_blocks(self): """ Get an iterator of all blocks that are enabled and not bypassed. """ - return ifilter(methodcaller('get_enabled'), self.blocks) + return filter(methodcaller('get_enabled'), self.blocks) def get_enabled_blocks(self): """ @@ -162,7 +164,7 @@ class FlowGraph(Element): Returns: a list of blocks """ - return filter(methodcaller('get_bypassed'), self.blocks) + return list(filter(methodcaller('get_bypassed'), self.blocks)) def get_enabled_connections(self): """ @@ -171,7 +173,7 @@ class FlowGraph(Element): Returns: a list of connections """ - return filter(methodcaller('get_enabled'), self.connections) + return list(filter(methodcaller('get_enabled'), self.connections)) def get_option(self, key): """ @@ -206,7 +208,7 @@ class FlowGraph(Element): options_block_count = self.blocks.count(self._options_block) if not options_block_count: self.blocks.append(self._options_block) - for i in range(options_block_count-1): + for _ in range(options_block_count-1): self.blocks.remove(self._options_block) return self.blocks + self.connections @@ -229,14 +231,14 @@ class FlowGraph(Element): # Load imports for expr in self.get_imports(): try: - exec expr in namespace + exec(expr, namespace) except: pass for id, expr in self.get_python_modules(): try: module = imp.new_module(id) - exec expr in module.__dict__ + exec(expr, module.__dict__) namespace[id] = module except: pass @@ -333,15 +335,15 @@ class FlowGraph(Element): if element in self.blocks: # Remove block, remove all involved connections for port in element.get_ports(): - map(self.remove_element, port.get_connections()) + for connection in port.get_connections(): + self.remove_element(connection) self.blocks.remove(element) elif element in self.connections: if element.is_bus(): - cons_list = [] - for i in map(lambda a: a.get_connections(), element.get_source().get_associated_ports()): - cons_list.extend(i) - map(self.remove_element, cons_list) + for port in element.get_source().get_associated_ports(): + for connection in port.get_connections(): + self.remove_element(connection) self.connections.remove(element) ############################################## @@ -484,21 +486,19 @@ class FlowGraph(Element): get_p_gui = block.get_sinks_gui bus_structure = block.form_bus_structure('sink') - if 'bus' in map(lambda a: a.get_type(), get_p_gui()): + if 'bus' in [a.get_type() for a in get_p_gui()]: if len(get_p_gui()) > len(bus_structure): - times = range(len(bus_structure), len(get_p_gui())) + times = list(range(len(bus_structure), len(get_p_gui()))) for i in times: for connect in get_p_gui()[-1].get_connections(): block.get_parent().remove_element(connect) get_p().remove(get_p_gui()[-1]) elif len(get_p_gui()) < len(bus_structure): n = {'name': 'bus', 'type': 'bus'} - if True in map( - lambda a: isinstance(a.get_nports(), int), - get_p()): + if any(isinstance(a.get_nports(), int) for a in get_p()): n['nports'] = str(1) - times = range(len(get_p_gui()), len(bus_structure)) + times = list(range(len(get_p_gui()), len(bus_structure))) for i in times: n['key'] = str(len(get_p())) @@ -507,8 +507,7 @@ class FlowGraph(Element): block=block, n=n, dir=direc) get_p().append(port) - if 'bus' in map(lambda a: a.get_type(), - block.get_sources_gui()): + if 'bus' in [a.get_type() for a in block.get_sources_gui()]: for i in range(len(block.get_sources_gui())): if len(block.get_sources_gui()[ i].get_connections()) > 0: diff --git a/grc/core/Messages.py b/grc/core/Messages.py index 8daa12c33f..596b6197d8 100644 --- a/grc/core/Messages.py +++ b/grc/core/Messages.py @@ -16,9 +16,10 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +from __future__ import absolute_import + import traceback import sys -import os # A list of functions that can receive a message. MESSENGERS_LIST = list() diff --git a/grc/core/Param.py b/grc/core/Param.py index 73d54b6aff..45f0187d27 100644 --- a/grc/core/Param.py +++ b/grc/core/Param.py @@ -17,20 +17,20 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import + import ast import weakref import re +from six.moves import builtins, filter, map, range, zip + from . import Constants -from .Constants import VECTOR_TYPES, COMPLEX_TYPES, REAL_TYPES, INT_TYPES from .Element import Element from .utils import odict # Blacklist certain ids, its not complete, but should help -import __builtin__ - - -ID_BLACKLIST = ['self', 'options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 'forms', 'firdes'] + dir(__builtin__) +ID_BLACKLIST = ['self', 'options', 'gr', 'blks2', 'wxgui', 'wx', 'math', 'forms', 'firdes'] + dir(builtins) try: from gnuradio import gr ID_BLACKLIST.extend(attr for attr in dir(gr.top_block()) if not attr.startswith('_')) @@ -64,7 +64,7 @@ def num_to_str(num): return template.format(value / factor, symbol.strip()) return template.format(value, '') - if isinstance(num, COMPLEX_TYPES): + if isinstance(num, Constants.COMPLEX_TYPES): num = complex(num) # Cast to python complex if num == 0: return '0' @@ -112,13 +112,13 @@ class Option(Element): # Access Opts ############################################## def get_opt_keys(self): - return self._opts.keys() + return list(self._opts.keys()) def get_opt(self, key): return self._opts[key] def get_opts(self): - return self._opts.values() + return list(self._opts.values()) class TemplateArg(object): @@ -176,7 +176,8 @@ class Param(Element): # Create the Option objects from the n data self._options = list() self._evaluated = None - for option in map(lambda o: Option(param=self, n=o), n.findall('option')): + for o_n in n.findall('option'): + option = Option(param=self, n=o_n) key = option.get_key() # Test against repeated keys if key in self.get_option_keys(): @@ -257,9 +258,9 @@ class Param(Element): t = self.get_type() if isinstance(e, bool): return str(e) - elif isinstance(e, COMPLEX_TYPES): + elif isinstance(e, Constants.COMPLEX_TYPES): dt_str = num_to_str(e) - elif isinstance(e, VECTOR_TYPES): + elif isinstance(e, Constants.VECTOR_TYPES): # Vector types if len(e) > 8: # Large vectors use code @@ -310,13 +311,10 @@ class Param(Element): if self.get_key() == 'id' and not _show_id_matcher.match(self.get_parent().get_key()): return 'part' # Hide port controllers for type and nports - if self.get_key() in ' '.join(map(lambda p: ' '.join([p._type, p._nports]), - self.get_parent().get_ports())): + if self.get_key() in ' '.join([' '.join([p._type, p._nports]) for p in self.get_parent().get_ports()]): return 'part' # Hide port controllers for vlen, when == 1 - if self.get_key() in ' '.join(map( - lambda p: p._vlen, self.get_parent().get_ports()) - ): + if self.get_key() in ' '.join(p._vlen for p in self.get_parent().get_ports()): try: if int(self.get_evaluated()) == 1: return 'part' @@ -339,7 +337,7 @@ class Param(Element): self._evaluated = None try: self._evaluated = self.evaluate() - except Exception, e: + except Exception as e: self.add_error_message(str(e)) def get_evaluated(self): @@ -372,21 +370,21 @@ class Param(Element): # Raise exception if python cannot evaluate this value try: e = self.get_parent().get_parent().evaluate(v) - except Exception, e: + except Exception as e: raise Exception('Value "{}" cannot be evaluated:\n{}'.format(v, e)) # Raise an exception if the data is invalid if t == 'raw': return e elif t == 'complex': - if not isinstance(e, COMPLEX_TYPES): + if not isinstance(e, Constants.COMPLEX_TYPES): raise Exception('Expression "{}" is invalid for type complex.'.format(str(e))) return e elif t == 'real' or t == 'float': - if not isinstance(e, REAL_TYPES): + if not isinstance(e, Constants.REAL_TYPES): raise Exception('Expression "{}" is invalid for type float.'.format(str(e))) return e elif t == 'int': - if not isinstance(e, INT_TYPES): + if not isinstance(e, Constants.INT_TYPES): raise Exception('Expression "{}" is invalid for type integer.'.format(str(e))) return e elif t == 'hex': @@ -407,28 +405,28 @@ class Param(Element): # Raise exception if python cannot evaluate this value try: e = self.get_parent().get_parent().evaluate(v) - except Exception, e: + except Exception as e: raise Exception('Value "{}" cannot be evaluated:\n{}'.format(v, e)) # Raise an exception if the data is invalid if t == 'complex_vector': - if not isinstance(e, VECTOR_TYPES): + if not isinstance(e, Constants.VECTOR_TYPES): self._lisitify_flag = True e = [e] - if not all([isinstance(ei, COMPLEX_TYPES) for ei in e]): + if not all([isinstance(ei, Constants.COMPLEX_TYPES) for ei in e]): raise Exception('Expression "{}" is invalid for type complex vector.'.format(str(e))) return e elif t == 'real_vector' or t == 'float_vector': - if not isinstance(e, VECTOR_TYPES): + if not isinstance(e, Constants.VECTOR_TYPES): self._lisitify_flag = True e = [e] - if not all([isinstance(ei, REAL_TYPES) for ei in e]): + if not all([isinstance(ei, Constants.REAL_TYPES) for ei in e]): raise Exception('Expression "{}" is invalid for type float vector.'.format(str(e))) return e elif t == 'int_vector': - if not isinstance(e, VECTOR_TYPES): + if not isinstance(e, Constants.VECTOR_TYPES): self._lisitify_flag = True e = [e] - if not all([isinstance(ei, INT_TYPES) for ei in e]): + if not all([isinstance(ei, Constants.INT_TYPES) for ei in e]): raise Exception('Expression "{}" is invalid for type integer vector.'.format(str(e))) return e ######################### @@ -545,7 +543,7 @@ class Param(Element): for c in range(col_span): self._hostage_cells.append((my_parent, (row+r, col+c))) # Avoid collisions - params = filter(lambda p: p is not self, self.get_all_params('grid_pos')) + params = [p for p in self.get_all_params('grid_pos') if p is not self] for param in params: for parent, cell in param._hostage_cells: if (parent, cell) in self._hostage_cells: @@ -560,7 +558,7 @@ class Param(Element): return '' # Get a list of all notebooks - notebook_blocks = filter(lambda b: b.get_key() == 'notebook', self.get_parent().get_parent().get_enabled_blocks()) + notebook_blocks = [b for b in self.get_parent().get_parent().get_enabled_blocks() if b.get_key() == 'notebook'] # Check for notebook param syntax try: notebook_id, page_index = map(str.strip, v.split(',')) @@ -568,7 +566,7 @@ class Param(Element): raise Exception('Bad notebook page format.') # Check that the notebook id is valid try: - notebook_block = filter(lambda b: b.get_id() == notebook_id, notebook_blocks)[0] + notebook_block = [b for b in notebook_blocks if b.get_id() == notebook_id][0] except: raise Exception('Notebook id "{}" is not an existing notebook id.'.format(notebook_id)) @@ -584,12 +582,12 @@ class Param(Element): # New namespace n = dict() try: - exec v in n + exec(v, n) except ImportError: raise Exception('Import "{}" failed.'.format(v)) except Exception: raise Exception('Bad import syntax: "{}".'.format(v)) - return filter(lambda k: str(k) != '__builtins__', n.keys()) + return [k for k in list(n.keys()) if str(k) != '__builtins__'] ######################### else: @@ -635,7 +633,10 @@ class Param(Element): Returns: a list of params """ - return sum([filter(lambda p: p.get_type() == type, block.get_params()) for block in self.get_parent().get_parent().get_enabled_blocks()], []) + params = [] + for block in self.get_parent().get_parent().get_enabled_blocks(): + params.extend(p for p in block.get_params() if p.get_type() == type) + return params def is_enum(self): return self._type == 'enum' diff --git a/grc/core/ParseXML.py b/grc/core/ParseXML.py index c9f6541ee7..d1306fcab4 100644 --- a/grc/core/ParseXML.py +++ b/grc/core/ParseXML.py @@ -17,8 +17,13 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import + from lxml import etree +import six +from six.moves import map + from .utils import odict xml_failures = {} @@ -80,7 +85,9 @@ def from_file(xml_file): # Get the embedded instructions and build a dictionary item nested_data['_instructions'] = {} xml_instructions = xml.xpath('/processing-instruction()') - for inst in filter(lambda i: i.target == 'grc', xml_instructions): + for inst in xml_instructions: + if inst.target != 'grc': + continue nested_data['_instructions'] = odict(inst.attrib) return nested_data @@ -100,13 +107,13 @@ def _from_file(xml): return odict({tag: xml.text or ''}) # store empty tags (text is None) as empty string nested_data = odict() for elem in xml: - key, value = _from_file(elem).items()[0] + key, value = list(_from_file(elem).items())[0] if key in nested_data: nested_data[key].append(value) else: nested_data[key] = [value] # Delistify if the length of values is 1 - for key, values in nested_data.iteritems(): + for key, values in six.iteritems(nested_data): if len(values) == 1: nested_data[key] = values[0] @@ -127,7 +134,7 @@ def to_file(nested_data, xml_file): if instructions: xml_data += etree.tostring(etree.ProcessingInstruction( 'grc', ' '.join( - "{0}='{1}'".format(*item) for item in instructions.iteritems()) + "{0}='{1}'".format(*item) for item in six.iteritems(instructions)) ), xml_declaration=True, pretty_print=True, encoding='utf-8') xml_data += etree.tostring(_to_file(nested_data)[0], pretty_print=True, encoding='utf-8') @@ -146,14 +153,14 @@ def _to_file(nested_data): the xml tree filled with child nodes """ nodes = list() - for key, values in nested_data.iteritems(): + for key, values in six.iteritems(nested_data): # Listify the values if not a list if not isinstance(values, (list, set, tuple)): values = [values] for value in values: node = etree.Element(key) - if isinstance(value, (str, unicode)): - node.text = unicode(value) + if isinstance(value, (str, six.text_type)): + node.text = six.text_type(value) else: node.extend(_to_file(value)) nodes.append(node) diff --git a/grc/core/Platform.py b/grc/core/Platform.py index 02a625bbf4..25f415639a 100644 --- a/grc/core/Platform.py +++ b/grc/core/Platform.py @@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import +from __future__ import print_function import os import sys @@ -32,6 +34,9 @@ from .Port import Port from .Param import Param from .utils import odict, extract_docs +import six +from six.moves import map +from six.moves import range class Platform(Element): @@ -156,7 +161,7 @@ class Platform(Element): # print >> sys.stderr, 'Warning: Block validation failed:\n\t%s\n\tIgnoring: %s' % (e, xml_file) pass except Exception as e: - print >> sys.stderr, 'Warning: XML parsing failed:\n\t%r\n\tIgnoring: %s' % (e, xml_file) + print('Warning: XML parsing failed:\n\t%r\n\tIgnoring: %s' % (e, xml_file), file=sys.stderr) self._docstring_extractor.finish() # self._docstring_extractor.wait() @@ -168,7 +173,7 @@ class Platform(Element): yield block_path elif os.path.isdir(block_path): for dirpath, dirnames, filenames in os.walk(block_path): - for filename in sorted(filter(lambda f: f.endswith('.xml'), filenames)): + for filename in sorted(f for f in filenames if f.endswith('.xml')): yield os.path.join(dirpath, filename) def load_block_xml(self, xml_file): @@ -181,7 +186,7 @@ class Platform(Element): block = self.Block(self._flow_graph, n) key = block.get_key() if key in self.blocks: - print >> sys.stderr, 'Warning: Block with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file) + print('Warning: Block with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file), file=sys.stderr) else: # Store the block self.blocks[key] = block self._blocks_n[key] = n @@ -205,13 +210,13 @@ class Platform(Element): key = n.find('key') if not key: - print >> sys.stderr, 'Warning: Domain with emtpy key.\n\tIgnoring: {}'.format(xml_file) + print('Warning: Domain with emtpy key.\n\tIgnoring: {}'.format(xml_file), file=sys.stderr) return if key in self.domains: # test against repeated keys - print >> sys.stderr, 'Warning: Domain with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file) + print('Warning: Domain with key "{}" already exists.\n\tIgnoring: {}'.format(key, xml_file), file=sys.stderr) return - #to_bool = lambda s, d: d if s is None else s.lower() not in ('false', 'off', '0', '') + # to_bool = lambda s, d: d if s is None else s.lower() not in ('false', 'off', '0', '') def to_bool(s, d): if s is not None: return s.lower() not in ('false', 'off', '0', '') @@ -223,7 +228,7 @@ class Platform(Element): tuple(int(color[o:o + 2], 16) / 255.0 for o in range(1, 3 * chars_per_color, chars_per_color)) except ValueError: if color: # no color is okay, default set in GUI - print >> sys.stderr, 'Warning: Can\'t parse color code "{}" for domain "{}" '.format(color, key) + print('Warning: Can\'t parse color code "{}" for domain "{}" '.format(color, key), file=sys.stderr) color = None self.domains[key] = dict( @@ -235,9 +240,9 @@ class Platform(Element): for connection_n in n.findall('connection'): key = (connection_n.find('source_domain'), connection_n.find('sink_domain')) if not all(key): - print >> sys.stderr, 'Warning: Empty domain key(s) in connection template.\n\t{}'.format(xml_file) + print('Warning: Empty domain key(s) in connection template.\n\t{}'.format(xml_file), file=sys.stderr) elif key in self.connection_templates: - print >> sys.stderr, 'Warning: Connection template "{}" already exists.\n\t{}'.format(key, xml_file) + print('Warning: Connection template "{}" already exists.\n\t{}'.format(key, xml_file), file=sys.stderr) else: self.connection_templates[key] = connection_n.find('make') or '' @@ -256,11 +261,12 @@ class Platform(Element): parent = (parent or []) + [cat_n.find('name')] block_tree.add_block(parent) # Recursive call to load sub categories - map(lambda c: load_category(c, parent), cat_n.findall('cat')) + for cat in cat_n.findall('cat'): + load_category(cat, parent) # Add blocks in this category for block_key in cat_n.findall('block'): if block_key not in self.blocks: - print >> sys.stderr, 'Warning: Block key "{}" not found when loading category tree.'.format(block_key) + print('Warning: Block key "{}" not found when loading category tree.'.format(block_key), file=sys.stderr) continue block = self.blocks[block_key] # If it exists, the block's category shall not be overridden by the xml tree @@ -272,7 +278,7 @@ class Platform(Element): load_category(category_tree_n) # Add blocks to block tree - for block in self.blocks.itervalues(): + for block in six.itervalues(self.blocks): # Blocks with empty categories are hidden if not block.get_category(): continue @@ -280,7 +286,7 @@ class Platform(Element): def _save_docstring_extraction_result(self, key, docstrings): docs = {} - for match, docstring in docstrings.iteritems(): + for match, docstring in six.iteritems(docstrings): if not docstring or match.endswith('_sptr'): continue docstring = docstring.replace('\n\n', '\n').strip() @@ -312,7 +318,7 @@ class Platform(Element): return self.FlowGraph(platform=self) def get_blocks(self): - return self.blocks.values() + return list(self.blocks.values()) def get_new_block(self, flow_graph, key): return self.Block(flow_graph, n=self._blocks_n[key]) diff --git a/grc/core/Port.py b/grc/core/Port.py index 6a8f484082..a24262da6b 100644 --- a/grc/core/Port.py +++ b/grc/core/Port.py @@ -17,7 +17,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from .Constants import DEFAULT_DOMAIN, GR_STREAM_DOMAIN, GR_MESSAGE_DOMAIN +from __future__ import absolute_import + +from six.moves import filter + from .Element import Element from . import Constants @@ -47,13 +50,13 @@ def _get_source_from_virtual_source_port(vsp, traversed=[]): try: return _get_source_from_virtual_source_port( _get_source_from_virtual_sink_port( - filter( # Get all virtual sinks with a matching stream id + list(filter( # Get all virtual sinks with a matching stream id lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(), - filter( # Get all enabled blocks that are also virtual sinks + list(filter( # Get all enabled blocks that are also virtual sinks lambda b: b.is_virtual_sink(), vsp.get_parent().get_parent().get_enabled_blocks(), - ), - )[0].get_sinks()[0] + )), + ))[0].get_sinks()[0] ), traversed + [vsp], ) except: @@ -87,10 +90,10 @@ def _get_sink_from_virtual_sink_port(vsp, traversed=[]): _get_sink_from_virtual_source_port( filter( # Get all virtual source with a matching stream id lambda vs: vs.get_param('stream_id').get_value() == vsp.get_parent().get_param('stream_id').get_value(), - filter( # Get all enabled blocks that are also virtual sinks + list(filter( # Get all enabled blocks that are also virtual sinks lambda b: b.is_virtual_source(), vsp.get_parent().get_parent().get_enabled_blocks(), - ), + )), )[0].get_sources()[0] ), traversed + [vsp], ) @@ -113,10 +116,10 @@ class Port(Element): """ self._n = n if n['type'] == 'message': - n['domain'] = GR_MESSAGE_DOMAIN + n['domain'] = Constants.GR_MESSAGE_DOMAIN if 'domain' not in n: - n['domain'] = DEFAULT_DOMAIN - elif n['domain'] == GR_MESSAGE_DOMAIN: + n['domain'] = Constants.DEFAULT_DOMAIN + elif n['domain'] == Constants.GR_MESSAGE_DOMAIN: n['key'] = n['name'] n['type'] = 'message' # For port color if n['type'] == 'msg': @@ -147,7 +150,7 @@ class Port(Element): return 'Sink - {}({})'.format(self.get_name(), self.get_key()) def get_types(self): - return Constants.TYPE_TO_SIZEOF.keys() + return list(Constants.TYPE_TO_SIZEOF.keys()) def is_type_empty(self): return not self._n['type'] @@ -189,11 +192,11 @@ class Port(Element): # Update domain if was deduced from (dynamic) port type type_ = self.get_type() - if self._domain == GR_STREAM_DOMAIN and type_ == "message": - self._domain = GR_MESSAGE_DOMAIN + if self._domain == Constants.GR_STREAM_DOMAIN and type_ == "message": + self._domain = Constants.GR_MESSAGE_DOMAIN self._key = self._name - if self._domain == GR_MESSAGE_DOMAIN and type_ != "message": - self._domain = GR_STREAM_DOMAIN + if self._domain == Constants.GR_MESSAGE_DOMAIN and type_ != "message": + self._domain = Constants.GR_STREAM_DOMAIN self._key = '0' # Is rectified in rewrite() def resolve_virtual_source(self): @@ -341,7 +344,7 @@ class Port(Element): def get_name(self): number = '' if self.get_type() == 'bus': - busses = filter(lambda a: a._dir == self._dir, self.get_parent().get_ports_gui()) + busses = [a for a in self.get_parent().get_ports_gui() if a._dir == self._dir] number = str(busses.index(self)) + '#' + str(len(self.get_associated_ports())) return self._name + number @@ -373,7 +376,7 @@ class Port(Element): a list of connection objects """ connections = self.get_parent().get_parent().connections - connections = filter(lambda c: c.get_source() is self or c.get_sink() is self, connections) + connections = [c for c in connections if c.get_source() is self or c.get_sink() is self] return connections def get_enabled_connections(self): @@ -383,7 +386,7 @@ class Port(Element): Returns: a list of connection objects """ - return filter(lambda c: c.get_enabled(), self.get_connections()) + return [c for c in self.get_connections() if c.get_enabled()] def get_associated_ports(self): if not self.get_type() == 'bus': @@ -400,5 +403,5 @@ class Port(Element): if bus_structure: busses = [i for i in get_ports() if i.get_type() == 'bus'] bus_index = busses.index(self) - ports = filter(lambda a: ports.index(a) in bus_structure[bus_index], ports) + ports = [a for a in ports if ports.index(a) in bus_structure[bus_index]] return ports diff --git a/grc/core/generator/FlowGraphProxy.py b/grc/core/generator/FlowGraphProxy.py index 3723005576..c673c5b005 100644 --- a/grc/core/generator/FlowGraphProxy.py +++ b/grc/core/generator/FlowGraphProxy.py @@ -16,6 +16,10 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +from __future__ import absolute_import +from six.moves import range + + class FlowGraphProxy(object): def __init__(self, fg): @@ -34,7 +38,7 @@ class FlowGraphProxy(object): Returns: a list of dicts with: type, label, vlen, size, optional """ - return filter(lambda p: p['type'] != "message", self.get_hier_block_io(direction)) + return [p for p in self.get_hier_block_io(direction) if p['type'] != "message"] def get_hier_block_message_io(self, direction): """ @@ -46,7 +50,7 @@ class FlowGraphProxy(object): Returns: a list of dicts with: type, label, vlen, size, optional """ - return filter(lambda p: p['type'] == "message", self.get_hier_block_io(direction)) + return [p for p in self.get_hier_block_io(direction) if p['type'] == "message"] def get_hier_block_io(self, direction): """ @@ -71,7 +75,7 @@ class FlowGraphProxy(object): } num_ports = pad.get_param('num_streams').get_evaluated() if num_ports > 1: - for i in xrange(num_ports): + for i in range(num_ports): clone = master.copy() clone['label'] += str(i) ports.append(clone) @@ -86,7 +90,7 @@ class FlowGraphProxy(object): Returns: a list of pad source blocks in this flow graph """ - pads = filter(lambda b: b.get_key() == 'pad_source', self.get_enabled_blocks()) + pads = [b for b in self.get_enabled_blocks() if b.get_key() == 'pad_source'] return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id())) def get_pad_sinks(self): @@ -96,7 +100,7 @@ class FlowGraphProxy(object): Returns: a list of pad sink blocks in this flow graph """ - pads = filter(lambda b: b.get_key() == 'pad_sink', self.get_enabled_blocks()) + pads = [b for b in self.get_enabled_blocks() if b.get_key() == 'pad_sink'] return sorted(pads, lambda x, y: cmp(x.get_id(), y.get_id())) def get_pad_port_global_key(self, port): @@ -123,4 +127,4 @@ class FlowGraphProxy(object): # assuming we have either only sources or sinks if not is_message_pad: key_offset += len(pad.get_ports()) - return -1 \ No newline at end of file + return -1 diff --git a/grc/core/generator/Generator.py b/grc/core/generator/Generator.py index 0d0ca6f55f..c9b065372d 100644 --- a/grc/core/generator/Generator.py +++ b/grc/core/generator/Generator.py @@ -16,9 +16,11 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +from __future__ import absolute_import import codecs import os import tempfile +import operator from Cheetah.Template import Template @@ -85,14 +87,15 @@ class TopBlockGenerator(object): def write(self): """generate output and write it to files""" # Do throttle warning - throttling_blocks = filter(lambda b: b.throtteling(), self._flow_graph.get_enabled_blocks()) + throttling_blocks = [b for b in self._flow_graph.get_enabled_blocks() + if b.throtteling()] if not throttling_blocks and not self._generate_options.startswith('hb'): Messages.send_warning("This flow graph may not have flow control: " "no audio or RF hardware blocks found. " "Add a Misc->Throttle block to your flow " "graph to avoid CPU congestion.") if len(throttling_blocks) > 1: - keys = set(map(lambda b: b.get_key(), throttling_blocks)) + keys = set([b.get_key() for b in throttling_blocks]) if len(keys) > 1 and 'blocks_throttle' in keys: Messages.send_warning("This flow graph contains a throttle " "block and another rate limiting block, " @@ -139,15 +142,15 @@ class TopBlockGenerator(object): return code blocks = expr_utils.sort_objects( - filter(lambda b: b.get_enabled() and not b.get_bypassed(), fg.blocks), - lambda b: b.get_id(), _get_block_sort_text + [b for b in fg.blocks if b.get_enabled() and not b.get_bypassed()], + operator.methodcaller('get_id'), _get_block_sort_text ) deprecated_block_keys = set(block.get_name() for block in blocks if block.is_deprecated) for key in deprecated_block_keys: Messages.send_warning("The block {!r} is deprecated.".format(key)) # List of regular blocks (all blocks minus the special ones) - blocks = filter(lambda b: b not in (imports + parameters), blocks) + blocks = [b for b in blocks if b not in imports and b not in parameters] for block in blocks: key = block.get_key() @@ -162,10 +165,10 @@ class TopBlockGenerator(object): # Filter out virtual sink connections def cf(c): return not (c.is_bus() or c.is_msg() or c.get_sink().get_parent().is_virtual_sink()) - connections = filter(cf, fg.get_enabled_connections()) + connections = [con for con in fg.get_enabled_connections() if cf(con)] # Get the virtual blocks and resolve their connections - virtual = filter(lambda c: c.get_source().get_parent().is_virtual_source(), connections) + virtual = [c for c in connections if c.get_source().get_parent().is_virtual_source()] for connection in virtual: source = connection.get_source().resolve_virtual_source() sink = connection.get_sink() @@ -183,7 +186,7 @@ class TopBlockGenerator(object): for block in bypassed_blocks: # Get the upstream connection (off of the sink ports) # Use *connections* not get_connections() - source_connection = filter(lambda c: c.get_sink() == block.get_sinks()[0], connections) + source_connection = [c for c in connections if c.get_sink() == block.get_sinks()[0]] # The source connection should never have more than one element. assert (len(source_connection) == 1) @@ -191,7 +194,7 @@ class TopBlockGenerator(object): source_port = source_connection[0].get_source() # Loop through all the downstream connections - for sink in filter(lambda c: c.get_source() == block.get_sources()[0], connections): + for sink in (c for c in connections if c.get_source() == block.get_sources()[0]): if not sink.get_enabled(): # Ignore disabled connections continue @@ -210,7 +213,8 @@ class TopBlockGenerator(object): )) connection_templates = fg.get_parent().connection_templates - msgs = filter(lambda c: c.is_msg(), fg.get_enabled_connections()) + msgs = [c for c in fg.get_enabled_connections() if c.is_msg()] + # List of variable names var_ids = [var.get_id() for var in parameters + variables] # Prepend self. @@ -222,7 +226,7 @@ class TopBlockGenerator(object): ] # Map var id to callbacks var_id2cbs = dict([ - (var_id, filter(lambda c: expr_utils.get_variable_dependencies(c, [var_id]), callbacks)) + (var_id, [c for c in callbacks if expr_utils.get_variable_dependencies(c, [var_id])]) for var_id in var_ids ]) # Load the namespace @@ -290,8 +294,8 @@ class HierBlockGenerator(TopBlockGenerator): parameters = self._flow_graph.get_parameters() def var_or_value(name): - if name in map(lambda p: p.get_id(), parameters): - return "$"+name + if name in (p.get_id() for p in parameters): + return "$" + name return name # Build the nested data diff --git a/grc/core/generator/__init__.py b/grc/core/generator/__init__.py index f44b94a85d..98f410c8d4 100644 --- a/grc/core/generator/__init__.py +++ b/grc/core/generator/__init__.py @@ -15,4 +15,5 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -from Generator import Generator +from __future__ import absolute_import +from .Generator import Generator diff --git a/grc/core/utils/__init__.py b/grc/core/utils/__init__.py index 6b23da2723..0d84f7131d 100644 --- a/grc/core/utils/__init__.py +++ b/grc/core/utils/__init__.py @@ -15,8 +15,10 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -import expr_utils -import epy_block_io -import extract_docs +from __future__ import absolute_import -from odict import odict +from . import expr_utils +from . import epy_block_io +from . import extract_docs + +from .odict import odict diff --git a/grc/core/utils/complexity.py b/grc/core/utils/complexity.py index baa8040db4..d72db9b3dd 100644 --- a/grc/core/utils/complexity.py +++ b/grc/core/utils/complexity.py @@ -8,8 +8,8 @@ def calculate_flowgraph_complexity(flowgraph): continue # Don't worry about optional sinks? - sink_list = filter(lambda c: not c.get_optional(), block.get_sinks()) - source_list = filter(lambda c: not c.get_optional(), block.get_sources()) + sink_list = [c for c in block.get_sinks() if not c.get_optional()] + source_list = [c for c in block.get_sources() if not c.get_optional()] sinks = float(len(sink_list)) sources = float(len(source_list)) base = max(min(sinks, sources), 1) @@ -22,14 +22,15 @@ def calculate_flowgraph_complexity(flowgraph): multi = 1 # Connection ratio multiplier - sink_multi = max(float(sum(map(lambda c: len(c.get_connections()), sink_list)) / max(sinks, 1.0)), 1.0) - source_multi = max(float(sum(map(lambda c: len(c.get_connections()), source_list)) / max(sources, 1.0)), 1.0) - dbal = dbal + (base * multi * sink_multi * source_multi) + sink_multi = max(float(sum(len(c.get_connections()) for c in sink_list) / max(sinks, 1.0)), 1.0) + source_multi = max(float(sum(len(c.get_connections()) for c in source_list) / max(sources, 1.0)), 1.0) + dbal += base * multi * sink_multi * source_multi blocks = float(len(flowgraph.blocks)) connections = float(len(flowgraph.connections)) elements = blocks + connections - disabled_connections = len(filter(lambda c: not c.get_enabled(), flowgraph.connections)) + disabled_connections = sum(not c.get_enabled() for c in flowgraph.connections) + variables = elements - blocks - connections enabled = float(len(flowgraph.get_enabled_blocks())) diff --git a/grc/core/utils/epy_block_io.py b/grc/core/utils/epy_block_io.py index 76b50051db..7a2006a833 100644 --- a/grc/core/utils/epy_block_io.py +++ b/grc/core/utils/epy_block_io.py @@ -1,7 +1,12 @@ +from __future__ import absolute_import + import inspect import collections +import six +from six.moves import zip + TYPE_MAP = { 'complex64': 'complex', 'complex': 'complex', @@ -31,10 +36,10 @@ def _ports(sigs, msgs): def _find_block_class(source_code, cls): ns = {} try: - exec source_code in ns + exec(source_code, ns) except Exception as e: raise ValueError("Can't interpret source code: " + str(e)) - for var in ns.itervalues(): + for var in six.itervalues(ns): if inspect.isclass(var) and issubclass(var, cls): return var raise ValueError('No python block class found in code') @@ -52,7 +57,7 @@ def extract(cls): spec = inspect.getargspec(cls.__init__) init_args = spec.args[1:] - defaults = map(repr, spec.defaults or ()) + defaults = [repr(arg) for arg in (spec.defaults or ())] doc = cls.__doc__ or cls.__init__.__doc__ or '' cls_name = cls.__name__ diff --git a/grc/core/utils/expr_utils.py b/grc/core/utils/expr_utils.py index 66911757d6..0577f06a75 100644 --- a/grc/core/utils/expr_utils.py +++ b/grc/core/utils/expr_utils.py @@ -17,7 +17,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import, print_function + import string + +import six + VAR_CHARS = string.letters + string.digits + '_' @@ -50,7 +55,7 @@ class graph(object): self._graph[src_node_key].remove(dest_node_key) def get_nodes(self): - return self._graph.keys() + return list(self._graph.keys()) def get_edges(self, node_key): return self._graph[node_key] @@ -85,7 +90,7 @@ def expr_split(expr): toks.append(char) tok = '' toks.append(tok) - return filter(lambda t: t, toks) + return [t for t in toks if t] def expr_replace(expr, replace_dict): @@ -101,7 +106,7 @@ def expr_replace(expr, replace_dict): """ expr_splits = expr_split(expr) for i, es in enumerate(expr_splits): - if es in replace_dict.keys(): + if es in list(replace_dict.keys()): expr_splits[i] = replace_dict[es] return ''.join(expr_splits) @@ -118,7 +123,7 @@ def get_variable_dependencies(expr, vars): a subset of vars used in the expression """ expr_toks = expr_split(expr) - return set(filter(lambda v: v in expr_toks, vars)) + return set(v for v in vars if v in expr_toks) def get_graph(exprs): @@ -131,12 +136,12 @@ def get_graph(exprs): Returns: a graph of variable deps """ - vars = exprs.keys() + vars = list(exprs.keys()) # Get dependencies for each expression, load into graph var_graph = graph() for var in vars: var_graph.add_node(var) - for var, expr in exprs.iteritems(): + for var, expr in six.iteritems(exprs): for dep in get_variable_dependencies(expr, vars): if dep != var: var_graph.add_edge(dep, var) @@ -159,7 +164,7 @@ def sort_variables(exprs): # Determine dependency order while var_graph.get_nodes(): # Get a list of nodes with no edges - indep_vars = filter(lambda var: not var_graph.get_edges(var), var_graph.get_nodes()) + indep_vars = [var for var in var_graph.get_nodes() if not var_graph.get_edges(var)] if not indep_vars: raise Exception('circular dependency caught in sort_variables') # Add the indep vars to the end of the list @@ -193,4 +198,4 @@ def sort_objects(objects, get_id, get_expr): if __name__ == '__main__': for i in sort_variables({'x': '1', 'y': 'x+1', 'a': 'x+y', 'b': 'y+1', 'c': 'a+b+x+y'}): - print i + print(i) diff --git a/grc/core/utils/extract_docs.py b/grc/core/utils/extract_docs.py index a6e0bc971e..cff8a81099 100644 --- a/grc/core/utils/extract_docs.py +++ b/grc/core/utils/extract_docs.py @@ -17,15 +17,19 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import, print_function + import sys import re import subprocess import threading import json -import Queue import random import itertools +import six +from six.moves import queue, filter, range + ############################################################################### # The docstring extraction @@ -124,7 +128,7 @@ class SubprocessLoader(object): self.callback_query_result = callback_query_result self.callback_finished = callback_finished or (lambda: None) - self._queue = Queue.Queue() + self._queue = queue.Queue() self._thread = None self._worker = None self._shutdown = threading.Event() @@ -157,14 +161,14 @@ class SubprocessLoader(object): cmd, args = self._last_cmd if cmd == 'query': msg += " (crashed while loading {0!r})".format(args[0]) - print >> sys.stderr, msg + print(msg, file=sys.stderr) continue # restart else: break # normal termination, return finally: self._worker.terminate() else: - print >> sys.stderr, "Warning: docstring loader crashed too often" + print("Warning: docstring loader crashed too often", file=sys.stderr) self._thread = None self._worker = None self.callback_finished() @@ -203,9 +207,9 @@ class SubprocessLoader(object): key, docs = args self.callback_query_result(key, docs) elif cmd == 'error': - print args + print(args) else: - print >> sys.stderr, "Unknown response:", cmd, args + print("Unknown response:", cmd, args, file=sys.stderr) def query(self, key, imports=None, make=None): """ Request docstring extraction for a certain key """ @@ -270,12 +274,12 @@ if __name__ == '__worker__': elif __name__ == '__main__': def callback(key, docs): - print key - for match, doc in docs.iteritems(): - print '-->', match - print doc.strip() - print - print + print(key) + for match, doc in six.iteritems(docs): + print('-->', match) + print(doc.strip()) + print() + print() r = SubprocessLoader(callback) diff --git a/grc/core/utils/odict.py b/grc/core/utils/odict.py index 20970e947c..38f898a97f 100644 --- a/grc/core/utils/odict.py +++ b/grc/core/utils/odict.py @@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import + from UserDict import DictMixin diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index 492bf8de9c..9c3e9246d5 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -18,6 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import, print_function + import os import subprocess @@ -114,7 +116,7 @@ class ActionHandler: ################################################## if action == Actions.APPLICATION_INITIALIZE: if not self.init_file_paths: - self.init_file_paths = filter(os.path.exists, Preferences.get_open_files()) + self.init_file_paths = list(filter(os.path.exists, Preferences.get_open_files())) if not self.init_file_paths: self.init_file_paths = [''] for file_path in self.init_file_paths: if file_path: main.new_page(file_path) #load pages from file paths @@ -603,7 +605,7 @@ class ActionHandler: try: page.process.kill() except: - print "could not kill process: %d" % page.process.pid + print("could not kill process: %d" % page.process.pid) elif action == Actions.PAGE_CHANGE: # pass and run the global actions pass elif action == Actions.RELOAD_BLOCKS: @@ -645,7 +647,7 @@ class ActionHandler: shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) else: - print '!!! Action "%s" not handled !!!' % action + print('!!! Action "%s" not handled !!!' % action) ################################################## # Global Actions for all States ################################################## diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index d0e114293f..3a51e80918 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -17,13 +17,17 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import + +import six + import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk from gi.repository import Gdk from gi.repository import GObject -import Preferences +from . import Preferences NO_MODS_MASK = 0 @@ -47,7 +51,6 @@ def handle_key_press(event): Returns: true if handled """ - _used_mods_mask = reduce(lambda x, y: x | y, [mod_mask for keyval, mod_mask in _actions_keypress_dict], NO_MODS_MASK) # extract the key value and the consumed modifiers _unused, keyval, egroup, level, consumed = _keymap.translate_keyboard_state( event.hardware_keycode, event.get_state(), event.group) @@ -80,13 +83,16 @@ class _ActionBase(object): Register actions and keypresses with this module. """ def __init__(self, label, keypresses): + global _used_mods_mask + _all_actions_list.append(self) for i in range(len(keypresses)/2): keyval, mod_mask = keypresses[i*2:(i+1)*2] # register this keypress - if _actions_keypress_dict.has_key((keyval, mod_mask)): + if (keyval, mod_mask) in _actions_keypress_dict: raise KeyError('keyval/mod_mask pair already registered "%s"' % str((keyval, mod_mask))) _actions_keypress_dict[(keyval, mod_mask)] = self + _used_mods_mask |= mod_mask # set the accelerator group, and accelerator path # register the key name and mod mask with the accelerator path if label is None: @@ -102,7 +108,7 @@ class _ActionBase(object): The string representation should be the name of the action id. Try to find the action id for this action by searching this module. """ - for name, value in globals().iteritems(): + for name, value in six.iteritems(globals()): if value == self: return name return self.get_name() diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index c8631aa298..0c18836c4e 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk @@ -206,7 +207,7 @@ class SubMenuCreator(object): def _fill_flow_graph_recent_submenu(self, action): """menu showing recent flow-graphs""" - import Preferences + from . import Preferences menu = Gtk.Menu() recent_files = Preferences.get_recent_files() if len(recent_files) > 0: diff --git a/grc/gui/Block.py b/grc/gui/Block.py index 1b90cf69a0..a6c31cd473 100644 --- a/grc/gui/Block.py +++ b/grc/gui/Block.py @@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import import math import gi gi.require_version('Gtk', '3.0') @@ -150,7 +151,7 @@ class Block(Element, _Block): W = self.label_width + 2 * BLOCK_LABEL_PADDING def get_min_height_for_ports(): - visible_ports = filter(lambda p: not p.get_hide(), ports) + visible_ports = [p for p in ports if not p.get_hide()] min_height = 2*PORT_BORDER_SEPARATION + len(visible_ports) * PORT_SEPARATION if visible_ports: min_height -= ports[0].H diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py index 829ddfed68..26086f58e9 100644 --- a/grc/gui/BlockTreeWindow.py +++ b/grc/gui/BlockTreeWindow.py @@ -17,6 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import +import six + import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk @@ -33,7 +36,7 @@ def _format_doc(doc): docs = [] if doc.get(''): docs += doc.pop('').splitlines() + [''] - for block_name, docstring in doc.iteritems(): + for block_name, docstring in six.iteritems(doc): docs.append('--- {0} ---'.format(block_name)) docs += docstring.splitlines() docs.append('') @@ -142,8 +145,9 @@ class BlockTreeWindow(Gtk.VBox): if categories is None: categories = self._categories - if isinstance(category, (str, unicode)): category = category.split('/') - category = tuple(filter(lambda x: x, category)) # tuple is hashable + if isinstance(category, (str, six.text_type)): + category = category.split('/') + category = tuple(x for x in category if x) # tuple is hashable # add category and all sub categories for i, cat_name in enumerate(category): sub_category = category[:i+1] @@ -210,8 +214,8 @@ class BlockTreeWindow(Gtk.VBox): self.treeview.set_model(self.treestore) self.treeview.collapse_all() else: - matching_blocks = filter(lambda b: key in b.get_key().lower() or key in b.get_name().lower(), - self.platform.blocks.values()) + matching_blocks = [b for b in list(self.platform.blocks.values()) + if key in b.get_key().lower() or key in b.get_name().lower()] self.treestore_search.clear() self._categories_search = {tuple(): None} diff --git a/grc/gui/Colors.py b/grc/gui/Colors.py index a03a7bcade..b2ed55b711 100644 --- a/grc/gui/Colors.py +++ b/grc/gui/Colors.py @@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import def get_color(color_code): diff --git a/grc/gui/Config.py b/grc/gui/Config.py index 9b0c5d4afe..b6556ad724 100644 --- a/grc/gui/Config.py +++ b/grc/gui/Config.py @@ -17,8 +17,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import, print_function + import sys import os + from ..core.Config import Config as _Config from . import Constants @@ -57,7 +60,7 @@ class Config(_Config): raise Exception() return value except: - print >> sys.stderr, "Error: invalid 'canvas_default_size' setting." + print("Error: invalid 'canvas_default_size' setting.", file=sys.stderr) return Constants.DEFAULT_CANVAS_SIZE_DEFAULT @property @@ -69,6 +72,6 @@ class Config(_Config): raise Exception() except: font_size = Constants.DEFAULT_FONT_SIZE - print >> sys.stderr, "Error: invalid 'canvas_font_size' setting." + print("Error: invalid 'canvas_font_size' setting.", file=sys.stderr) return font_size diff --git a/grc/gui/Connection.py b/grc/gui/Connection.py index 46414c94c8..8953ca0183 100644 --- a/grc/gui/Connection.py +++ b/grc/gui/Connection.py @@ -17,16 +17,14 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -import gi -gi.require_version('Gtk', '3.0') -from gi.repository import Gtk -from gi.repository import Gdk +from __future__ import absolute_import +from six.moves import map -import Colors -import Utils -from Constants import CONNECTOR_ARROW_BASE, CONNECTOR_ARROW_HEIGHT -from Element import Element +from . import Colors +from . import Utils +from .Constants import CONNECTOR_ARROW_BASE, CONNECTOR_ARROW_HEIGHT +from .Element import Element from ..core.Constants import GR_MESSAGE_DOMAIN from ..core.Connection import Connection as _Connection @@ -130,7 +128,7 @@ class Connection(Element, _Connection): #points[0][0] -> source connector should not be in the direction of source if Utils.get_angle_from_coordinates(points[0][0], (x1, y1)) == source.get_connector_direction(): points.reverse() #create 3-line connector - p1, p2 = map(int, points[0][0]), map(int, points[0][1]) + p1, p2 = list(map(int, points[0][0])), list(map(int, points[0][1])) self.add_line((x1, y1), p1) self.add_line(p1, p2) self.add_line((x2, y2), p2) diff --git a/grc/gui/Constants.py b/grc/gui/Constants.py index 55739a7c03..8bb15acc09 100644 --- a/grc/gui/Constants.py +++ b/grc/gui/Constants.py @@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py index 953373ee24..8f0f60d764 100644 --- a/grc/gui/Dialogs.py +++ b/grc/gui/Dialogs.py @@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py index d1e0e78634..33c669c99f 100644 --- a/grc/gui/DrawingArea.py +++ b/grc/gui/DrawingArea.py @@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import from gi.repository import Gtk, Gdk, GObject diff --git a/grc/gui/Element.py b/grc/gui/Element.py index 30c0f5dba7..4e88df375f 100644 --- a/grc/gui/Element.py +++ b/grc/gui/Element.py @@ -17,10 +17,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from Constants import LINE_SELECT_SENSITIVITY -from Constants import POSSIBLE_ROTATIONS +from __future__ import absolute_import +from .Constants import LINE_SELECT_SENSITIVITY +from .Constants import POSSIBLE_ROTATIONS import gi +from six.moves import zip gi.require_version('Gtk', '3.0') from gi.repository import Gtk from gi.repository import Gdk diff --git a/grc/gui/Executor.py b/grc/gui/Executor.py index 13a1cfd942..a8c67986e5 100644 --- a/grc/gui/Executor.py +++ b/grc/gui/Executor.py @@ -15,6 +15,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +from __future__ import absolute_import import os import threading import shlex diff --git a/grc/gui/FileDialogs.py b/grc/gui/FileDialogs.py index 63d4a397a8..3ee715dac6 100644 --- a/grc/gui/FileDialogs.py +++ b/grc/gui/FileDialogs.py @@ -17,18 +17,19 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk from gi.repository import GObject -from Dialogs import MessageDialogHelper -from Constants import \ +from .Dialogs import MessageDialogHelper +from .Constants import \ DEFAULT_FILE_PATH, IMAGE_FILE_EXTENSION, TEXT_FILE_EXTENSION, \ NEW_FLOGRAPH_TITLE -import Preferences +from . import Preferences from os import path -import Utils +from . import Utils ################################################## # Constants diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py index 802c54f7a7..50e146b4db 100644 --- a/grc/gui/FlowGraph.py +++ b/grc/gui/FlowGraph.py @@ -17,16 +17,20 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import + import functools import random from distutils.spawn import find_executable from itertools import chain, count from operator import methodcaller +import six +from six.moves import filter + from gi.repository import GObject -from . import Actions, Colors, Constants, Utils, Bars, Dialogs -from .Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE +from . import Actions, Colors, Utils, Bars, Dialogs from .Element import Element from .external_editor import ExternalEditor @@ -179,10 +183,10 @@ class FlowGraph(Element, _Flowgraph): x_min = min(x, x_min) y_min = min(y, y_min) #get connections between selected blocks - connections = filter( + connections = list(filter( lambda c: c.get_source().get_parent() in blocks and c.get_sink().get_parent() in blocks, self.connections, - ) + )) clipboard = ( (x_min, y_min), [block.export_data() for block in blocks], @@ -222,7 +226,7 @@ class FlowGraph(Element, _Flowgraph): block.get_param('_io_cache').set_value(params.pop('_io_cache')) block.get_param('_source_code').set_value(params.pop('_source_code')) block.rewrite() # this creates the other params - for param_key, param_value in params.iteritems(): + for param_key, param_value in six.iteritems(params): #setup id parameter if param_key == 'id': old_id2block[param_value] = block diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py index ce16074c81..3236768969 100644 --- a/grc/gui/MainWindow.py +++ b/grc/gui/MainWindow.py @@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import + import os import gi @@ -270,7 +272,7 @@ class MainWindow(Gtk.Window): Returns: true if all closed """ - open_files = filter(lambda file: file, self._get_files()) #filter blank files + open_files = [file for file in self._get_files() if file] #filter blank files open_file = self.current_page.file_path #close each page for page in sorted(self.get_pages(), key=lambda p: p.saved): @@ -416,7 +418,7 @@ class MainWindow(Gtk.Window): Returns: list of file paths """ - return map(lambda page: page.file_path, self.get_pages()) + return [page.file_path for page in self.get_pages()] def get_pages(self): """ diff --git a/grc/gui/NotebookPage.py b/grc/gui/NotebookPage.py index bcfb4d87fe..757dcbc0f8 100644 --- a/grc/gui/NotebookPage.py +++ b/grc/gui/NotebookPage.py @@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import import os from gi.repository import Gtk, Gdk, GObject diff --git a/grc/gui/Param.py b/grc/gui/Param.py index 0f88015256..137c5e057b 100644 --- a/grc/gui/Param.py +++ b/grc/gui/Param.py @@ -15,6 +15,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +from __future__ import absolute_import from . import Utils, Constants from . import ParamWidgets diff --git a/grc/gui/ParamWidgets.py b/grc/gui/ParamWidgets.py index 2fd6ccd1dc..e0979e19f3 100644 --- a/grc/gui/ParamWidgets.py +++ b/grc/gui/ParamWidgets.py @@ -15,6 +15,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +from __future__ import absolute_import import os from gi.repository import Gtk, Gdk diff --git a/grc/gui/ParserErrorsDialog.py b/grc/gui/ParserErrorsDialog.py index f49e6923e5..28cc8ece0c 100644 --- a/grc/gui/ParserErrorsDialog.py +++ b/grc/gui/ParserErrorsDialog.py @@ -17,12 +17,16 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import + +import six + import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk from gi.repository import GObject -from Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT +from .Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT class ParserErrorsDialog(Gtk.Dialog): @@ -72,7 +76,7 @@ class ParserErrorsDialog(Gtk.Dialog): """set up data model""" self.tree_store.clear() self._error_logs = error_logs - for filename, errors in error_logs.iteritems(): + for filename, errors in six.iteritems(error_logs): parent = self.tree_store.append(None, [str(filename)]) try: with open(filename, 'r') as fp: diff --git a/grc/gui/Platform.py b/grc/gui/Platform.py index 500df1cce4..997e96ab59 100644 --- a/grc/gui/Platform.py +++ b/grc/gui/Platform.py @@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import, print_function + import os import sys @@ -58,7 +60,7 @@ class Platform(Element, _Platform): import shutil shutil.move(old_gui_prefs_file, gui_prefs_file) except Exception as e: - print >> sys.stderr, e + print(e, file=sys.stderr) ############################################## # Constructors diff --git a/grc/gui/Port.py b/grc/gui/Port.py index fb1cd678cd..0fa35573c1 100644 --- a/grc/gui/Port.py +++ b/grc/gui/Port.py @@ -17,6 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import import math import gi gi.require_version('Gtk', '3.0') @@ -68,7 +69,7 @@ class Port(_Port, Element): #get all sibling ports ports = self.get_parent().get_sources_gui() \ if self.is_source else self.get_parent().get_sinks_gui() - ports = filter(lambda p: not p.get_hide(), ports) + ports = [p for p in ports if not p.get_hide()] #get the max width self.W = max([port.W for port in ports] + [PORT_MIN_WIDTH]) W = self.W if not self._label_hidden() else PORT_LABEL_HIDDEN_WIDTH @@ -79,16 +80,15 @@ class Port(_Port, Element): if hasattr(self, '_connector_length'): del self._connector_length return - length = len(filter(lambda p: not p.get_hide(), ports)) #reverse the order of ports for these rotations if rotation in (180, 270): - index = length-index-1 + index = len(ports)-index-1 port_separation = PORT_SEPARATION \ if not self.get_parent().has_busses[self.is_source] \ else max([port.H for port in ports]) + PORT_SPACING - offset = (self.get_parent().H - (length-1)*port_separation - self.H)/2 + offset = (self.get_parent().H - (len(ports)-1)*port_separation - self.H)/2 #create areas and connector coordinates if (self.is_sink and rotation == 0) or (self.is_source and rotation == 180): x = -W diff --git a/grc/gui/Preferences.py b/grc/gui/Preferences.py index 5fbdfe927a..8756a7ab23 100644 --- a/grc/gui/Preferences.py +++ b/grc/gui/Preferences.py @@ -17,9 +17,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import, print_function + import os import sys -import ConfigParser + +from six.moves import configparser HEADER = """\ @@ -31,7 +34,7 @@ HEADER = """\ """ _platform = None -_config_parser = ConfigParser.SafeConfigParser() +_config_parser = configparser.SafeConfigParser() def file_extension(): @@ -45,12 +48,12 @@ def load(platform): for section in ['main', 'files_open', 'files_recent']: try: _config_parser.add_section(section) - except Exception, e: - print e + except Exception as e: + print(e) try: _config_parser.read(_platform.get_prefs_file()) except Exception as err: - print >> sys.stderr, err + print(err, file=sys.stderr) def save(): @@ -59,7 +62,7 @@ def save(): fp.write(HEADER) _config_parser.write(fp) except Exception as err: - print >> sys.stderr, err + print(err, file=sys.stderr) def entry(key, value=None, default=None): @@ -74,7 +77,7 @@ def entry(key, value=None, default=None): }.get(_type, _config_parser.get) try: result = getter('main', key) - except ConfigParser.Error: + except configparser.Error: result = _type() if default is None else default return result @@ -106,7 +109,7 @@ def get_file_list(key): try: files = [value for name, value in _config_parser.items(key) if name.startswith('%s_' % key)] - except ConfigParser.Error: + except configparser.Error: files = [] return files @@ -121,7 +124,7 @@ def set_open_files(files): def get_recent_files(): """ Gets recent files, removes any that do not exist and re-saves it """ - files = filter(os.path.exists, get_file_list('files_recent')) + files = list(filter(os.path.exists, get_file_list('files_recent'))) set_recent_files(files) return files diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py index d6b64944cc..f87ca6e7c1 100644 --- a/grc/gui/PropsDialog.py +++ b/grc/gui/PropsDialog.py @@ -17,10 +17,12 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import from gi.repository import Gtk, Gdk, GObject, Pango from . import Actions, Utils, Constants from .Dialogs import SimpleTextDisplay +import six class PropsDialog(Gtk.Dialog): @@ -160,7 +162,7 @@ class PropsDialog(Gtk.Dialog): # child.destroy() # disabled because it throw errors... # repopulate the params box box_all_valid = True - for param in filter(lambda p: p.get_tab_label() == tab, self._block.get_params()): + for param in [p for p in self._block.get_params() if p.get_tab_label() == tab]: # fixme: why do we even rebuild instead of really hiding params? if param.get_hide() == 'all': continue @@ -212,7 +214,7 @@ class PropsDialog(Gtk.Dialog): docstrings = {block_class: docstrings[block_class]} # show docstring(s) extracted from python sources - for cls_name, docstring in docstrings.iteritems(): + for cls_name, docstring in six.iteritems(docstrings): buf.insert_with_tags_by_name(pos, cls_name + '\n', 'b') buf.insert(pos, docstring + '\n\n') pos.backward_chars(2) diff --git a/grc/gui/StateCache.py b/grc/gui/StateCache.py index 3cdb5f30ce..b109a1281b 100644 --- a/grc/gui/StateCache.py +++ b/grc/gui/StateCache.py @@ -17,8 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -import Actions -from Constants import STATE_CACHE_SIZE +from __future__ import absolute_import +from . import Actions +from .Constants import STATE_CACHE_SIZE class StateCache(object): """ diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py index 311b37f468..e5d4ccaa35 100644 --- a/grc/gui/Utils.py +++ b/grc/gui/Utils.py @@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import + import gi gi.require_version('Gtk', '3.0') from gi.repository import GLib @@ -47,7 +49,7 @@ def get_rotated_coordinate(coor, rotation): return x * cos_r + y * sin_r, -x * sin_r + y * cos_r -def get_angle_from_coordinates((x1, y1), (x2, y2)): +def get_angle_from_coordinates(p1, p2): """ Given two points, calculate the vector direction from point1 to point2, directions are multiples of 90 degrees. @@ -58,6 +60,8 @@ def get_angle_from_coordinates((x1, y1), (x2, y2)): Returns: the direction in degrees """ + (x1, y1) = p1 + (x2, y2) = p2 if y1 == y2: # 0 or 180 return 0 if x2 > x1 else 180 else: # 90 or 270 @@ -78,7 +82,7 @@ def align_to_grid(coor, mode=round): def align(value): return int(mode(value / (1.0 * CANVAS_GRID_SIZE)) * CANVAS_GRID_SIZE) try: - return map(align, coor) + return [align(c) for c in coor] except TypeError: x = coor return align(coor) diff --git a/grc/gui/VariableEditor.py b/grc/gui/VariableEditor.py index d34903e241..399e4ec475 100644 --- a/grc/gui/VariableEditor.py +++ b/grc/gui/VariableEditor.py @@ -17,7 +17,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ -from operator import attrgetter +from __future__ import absolute_import import gi gi.require_version('Gtk', '3.0') @@ -221,8 +221,8 @@ class VariableEditor(Gtk.VBox): sp('foreground', 'red') def update_gui(self, blocks): - self._imports = filter(attrgetter('is_import'), blocks) - self._variables = filter(attrgetter('is_variable'), blocks) + self._imports = [block for block in blocks if block.is_import] + self._variables = [block for block in blocks if block.is_variable] self._rebuild() self.treeview.expand_all() diff --git a/grc/gui/external_editor.py b/grc/gui/external_editor.py index 76f21412b0..11d6fd7ebb 100644 --- a/grc/gui/external_editor.py +++ b/grc/gui/external_editor.py @@ -17,6 +17,8 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ +from __future__ import absolute_import, print_function + import os import sys import time @@ -71,7 +73,7 @@ class ExternalEditor(threading.Thread): time.sleep(1) except Exception as e: - print >> sys.stderr, "file monitor crashed:", str(e) + print("file monitor crashed:", str(e), file=sys.stderr) else: # print "file monitor: done with", filename pass @@ -79,7 +81,7 @@ class ExternalEditor(threading.Thread): if __name__ == '__main__': def p(data): - print data + print(data) e = ExternalEditor('/usr/bin/gedit', "test", "content", p) e.open_editor() diff --git a/grc/main.py b/grc/main.py index cd9863739f..810ac7c66f 100755 --- a/grc/main.py +++ b/grc/main.py @@ -15,6 +15,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA +from __future__ import absolute_import import optparse import gi -- cgit v1.2.3 From 9b39ca3a9a2550c51ee934633ff9c655e1676a3b Mon Sep 17 00:00:00 2001 From: Sebastian Koslowski <koslowski@kit.edu> Date: Wed, 3 Aug 2016 21:38:56 +0200 Subject: grc: gtk3: update various deprecated gtk calls --- grc/gui/Bars.py | 6 +++--- grc/gui/BlockTreeWindow.py | 15 +++++++-------- grc/gui/NotebookPage.py | 2 +- grc/gui/VariableEditor.py | 32 +++++++++++++------------------- 4 files changed, 24 insertions(+), 31 deletions(-) (limited to 'grc/gui/Bars.py') diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index 0c18836c4e..d8d57843d7 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -90,7 +90,7 @@ MENU_BAR_LIST = ( None, Actions.BLOCK_ROTATE_CCW, Actions.BLOCK_ROTATE_CW, - (Gtk.Action('Align', '_Align', None, None), Actions.BLOCK_ALIGNMENTS), + (Gtk.Action(name='Align', label='_Align', tooltip=None, stock_id=None), Actions.BLOCK_ALIGNMENTS), None, Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, @@ -298,7 +298,7 @@ class MenuBar(Gtk.MenuBar, MenuHelperMixin, SubMenuCreator): self.append(self._make_sub_menu(main_action, actions)) def create_flow_graph_new(self): - main = Gtk.ImageMenuItem(Gtk.STOCK_NEW) + main = Gtk.ImageMenuItem(label=Gtk.STOCK_NEW) main.set_label(Actions.FLOW_GRAPH_NEW.get_label()) func = self._fill_flow_graph_new_submenu self.submenus.append((Actions.FLOW_GRAPH_NEW, func, main)) @@ -306,7 +306,7 @@ class MenuBar(Gtk.MenuBar, MenuHelperMixin, SubMenuCreator): return main def create_flow_graph_recent(self): - main = Gtk.ImageMenuItem(Gtk.STOCK_OPEN) + main = Gtk.ImageMenuItem(label=Gtk.STOCK_OPEN) main.set_label(Actions.FLOW_GRAPH_OPEN_RECENT.get_label()) func = self._fill_flow_graph_recent_submenu self.submenus.append((Actions.FLOW_GRAPH_OPEN, func, main)) diff --git a/grc/gui/BlockTreeWindow.py b/grc/gui/BlockTreeWindow.py index e29b6b4b7f..90d4b561b7 100644 --- a/grc/gui/BlockTreeWindow.py +++ b/grc/gui/BlockTreeWindow.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008, 2009 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009, 2016 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -22,8 +22,7 @@ import six from gi.repository import Gtk, Gdk, GObject -from . import Actions, Utils -from . import Constants +from . import Actions, Utils, Constants NAME_INDEX, KEY_INDEX, DOC_INDEX = range(3) @@ -64,7 +63,7 @@ class BlockTreeWindow(Gtk.VBox): """The block selection panel.""" __gsignals__ = { - 'create_new_block': (GObject.SIGNAL_RUN_FIRST, None, (str,)) + 'create_new_block': (GObject.SignalFlags.RUN_FIRST, None, (str,)) } def __init__(self, platform): @@ -83,9 +82,9 @@ class BlockTreeWindow(Gtk.VBox): # search entry self.search_entry = Gtk.Entry() try: - self.search_entry.set_icon_from_stock(Gtk.EntryIconPosition.PRIMARY, Gtk.STOCK_FIND) + self.search_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.PRIMARY, 'edit-find') self.search_entry.set_icon_activatable(Gtk.EntryIconPosition.PRIMARY, False) - self.search_entry.set_icon_from_stock(Gtk.EntryIconPosition.SECONDARY, Gtk.STOCK_CLOSE) + self.search_entry.set_icon_from_icon_name(Gtk.EntryIconPosition.SECONDARY, 'window-close') self.search_entry.connect('icon-release', self._handle_icon_event) except AttributeError: pass # no icon for old pygtk @@ -97,7 +96,7 @@ class BlockTreeWindow(Gtk.VBox): self.treestore = Gtk.TreeStore(GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING) self.treestore_search = Gtk.TreeStore(GObject.TYPE_STRING, GObject.TYPE_STRING, GObject.TYPE_STRING) - self.treeview = Gtk.TreeView(self.treestore) + self.treeview = Gtk.TreeView(model=self.treestore) self.treeview.set_enable_search(False) # disable pop up search box self.treeview.set_search_column(-1) # really disable search self.treeview.set_headers_visible(False) @@ -119,7 +118,7 @@ class BlockTreeWindow(Gtk.VBox): # make the scrolled window to hold the tree view scrolled_window = Gtk.ScrolledWindow() scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) - scrolled_window.add_with_viewport(self.treeview) + scrolled_window.add(self.treeview) scrolled_window.set_size_request(Constants.DEFAULT_BLOCKS_WINDOW_WIDTH, -1) self.pack_start(scrolled_window, True, True, 0) # map categories to iters, automatic mapping for root diff --git a/grc/gui/NotebookPage.py b/grc/gui/NotebookPage.py index 4745035aff..347be8eea0 100644 --- a/grc/gui/NotebookPage.py +++ b/grc/gui/NotebookPage.py @@ -76,7 +76,7 @@ class NotebookPage(Gtk.HBox): self.scrolled_window.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT) self.scrolled_window.set_policy(Gtk.PolicyType.ALWAYS, Gtk.PolicyType.ALWAYS) self.scrolled_window.connect('key-press-event', self._handle_scroll_window_key_press) - self.scrolled_window.add_with_viewport(self.drawing_area) + self.scrolled_window.add(self.drawing_area) self.pack_start(self.scrolled_window, True, True, 0) self.show_all() diff --git a/grc/gui/VariableEditor.py b/grc/gui/VariableEditor.py index 09fe629195..d97b9e9f24 100644 --- a/grc/gui/VariableEditor.py +++ b/grc/gui/VariableEditor.py @@ -19,15 +19,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from __future__ import absolute_import -import gi -gi.require_version('Gtk', '3.0') -from gi.repository import Gtk -from gi.repository import Gdk -from gi.repository import GObject +from gi.repository import Gtk, Gdk, GObject -from . import Actions -from . import Preferences -from .Constants import DEFAULT_BLOCKS_WINDOW_WIDTH +from . import Actions, Preferences, Constants BLOCK_INDEX = 0 ID_INDEX = 1 @@ -39,29 +33,29 @@ class VariableEditorContextMenu(Gtk.Menu): def __init__(self, var_edit): Gtk.Menu.__init__(self) - self.imports = Gtk.MenuItem("Add _Import") + self.imports = Gtk.MenuItem(label="Add _Import") self.imports.connect('activate', var_edit.handle_action, var_edit.ADD_IMPORT) self.add(self.imports) - self.variables = Gtk.MenuItem("Add _Variable") + self.variables = Gtk.MenuItem(label="Add _Variable") self.variables.connect('activate', var_edit.handle_action, var_edit.ADD_VARIABLE) self.add(self.variables) self.add(Gtk.SeparatorMenuItem()) - self.enable = Gtk.MenuItem("_Enable") + self.enable = Gtk.MenuItem(label="_Enable") self.enable.connect('activate', var_edit.handle_action, var_edit.ENABLE_BLOCK) - self.disable = Gtk.MenuItem("_Disable") + self.disable = Gtk.MenuItem(label="_Disable") self.disable.connect('activate', var_edit.handle_action, var_edit.DISABLE_BLOCK) self.add(self.enable) self.add(self.disable) self.add(Gtk.SeparatorMenuItem()) - self.delete = Gtk.MenuItem("_Delete") + self.delete = Gtk.MenuItem(label="_Delete") self.delete.connect('activate', var_edit.handle_action, var_edit.DELETE_BLOCK) self.add(self.delete) self.add(Gtk.SeparatorMenuItem()) - self.properties = Gtk.MenuItem("_Properties...") + self.properties = Gtk.MenuItem(label="_Properties...") self.properties.connect('activate', var_edit.handle_action, var_edit.OPEN_PROPERTIES) self.add(self.properties) self.show_all() @@ -85,8 +79,8 @@ class VariableEditor(Gtk.VBox): DISABLE_BLOCK = 6 __gsignals__ = { - 'create_new_block': (GObject.SIGNAL_RUN_FIRST, None, (str,)), - 'remove_block': (GObject.SIGNAL_RUN_FIRST, None, (str,)) + 'create_new_block': (GObject.SignalFlags.RUN_FIRST, None, (str,)), + 'remove_block': (GObject.SignalFlags.RUN_FIRST, None, (str,)) } def __init__(self): @@ -100,7 +94,7 @@ class VariableEditor(Gtk.VBox): # Generate everything else dynamically self.treestore = Gtk.TreeStore(GObject.TYPE_PYOBJECT, # Block reference GObject.TYPE_STRING) # Category and block name - self.treeview = Gtk.TreeView(self.treestore) + self.treeview = Gtk.TreeView(model=self.treestore) self.treeview.set_enable_search(False) self.treeview.set_search_column(-1) #self.treeview.set_enable_search(True) @@ -150,8 +144,8 @@ class VariableEditor(Gtk.VBox): # Make the scrolled window to hold the tree view scrolled_window = Gtk.ScrolledWindow() scrolled_window.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) - scrolled_window.add_with_viewport(self.treeview) - scrolled_window.set_size_request(DEFAULT_BLOCKS_WINDOW_WIDTH, -1) + scrolled_window.add(self.treeview) + scrolled_window.set_size_request(Constants.DEFAULT_BLOCKS_WINDOW_WIDTH, -1) self.pack_start(scrolled_window, True, True, 0) # Context menus -- cgit v1.2.3 From 5eb34fb72ffe46929fa2e99d84b4ead4f4083ca4 Mon Sep 17 00:00:00 2001 From: Seth Hitefield <sdhitefield@gmail.com> Date: Thu, 22 Sep 2016 12:15:51 -0400 Subject: grc: refactor: Cleaned up imports --- grc/gui/Actions.py | 6 +----- grc/gui/Bars.py | 6 ++---- grc/gui/Config.py | 8 ++++---- grc/gui/DrawingArea.py | 2 +- grc/gui/MainWindow.py | 7 +------ grc/gui/ParserErrorsDialog.py | 5 +---- grc/gui/Platform.py | 1 - grc/gui/canvas/flowgraph.py | 3 ++- 8 files changed, 12 insertions(+), 26 deletions(-) (limited to 'grc/gui/Bars.py') diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index 4759e56294..601d0005fb 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -21,11 +21,7 @@ from __future__ import absolute_import import six -import gi -gi.require_version('Gtk', '3.0') -from gi.repository import Gtk -from gi.repository import Gdk -from gi.repository import GObject +from gi.repository import Gtk, Gdk, GObject from . import Preferences diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index d8d57843d7..1c63f01fa6 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -18,10 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ from __future__ import absolute_import -import gi -gi.require_version('Gtk', '3.0') -from gi.repository import Gtk -from gi.repository import GObject + +from gi.repository import Gtk, GObject from . import Actions diff --git a/grc/gui/Config.py b/grc/gui/Config.py index 0f40e06fce..0558892e2f 100644 --- a/grc/gui/Config.py +++ b/grc/gui/Config.py @@ -22,11 +22,11 @@ from __future__ import absolute_import, print_function import sys import os -from ..core.Config import Config as _Config +from ..core.Config import Config as CoreConfig from . import Constants -class Config(_Config): +class Config(CoreConfig): name = 'GNU Radio Companion' @@ -34,7 +34,7 @@ class Config(_Config): 'GRC_PREFS_PATH', os.path.expanduser('~/.gnuradio/grc.conf')) def __init__(self, install_prefix, *args, **kwargs): - _Config.__init__(self, *args, **kwargs) + CoreConfig.__init__(self, *args, **kwargs) self.install_prefix = install_prefix Constants.update_font_size(self.font_size) @@ -83,4 +83,4 @@ class Config(_Config): @default_qss_theme.setter def default_qss_theme(self, value): self._gr_prefs.set_string("qtgui", "qss", value) - self._gr_prefs.save() \ No newline at end of file + self._gr_prefs.save() diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py index f279d50557..cad813a876 100644 --- a/grc/gui/DrawingArea.py +++ b/grc/gui/DrawingArea.py @@ -18,8 +18,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA """ from __future__ import absolute_import -from gi.repository import Gtk, Gdk, GObject +from gi.repository import Gtk, Gdk, GObject from . import Constants, Colors diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py index e86273e288..5eabf33f67 100644 --- a/grc/gui/MainWindow.py +++ b/grc/gui/MainWindow.py @@ -21,12 +21,7 @@ from __future__ import absolute_import import os -import gi -gi.require_version('Gtk', '3.0') -from gi.repository import Gtk -from gi.repository import Gdk -from gi.repository import GObject - +from gi.repository import Gtk, Gdk, GObject from . import Bars, Actions, Preferences, Utils from .BlockTreeWindow import BlockTreeWindow diff --git a/grc/gui/ParserErrorsDialog.py b/grc/gui/ParserErrorsDialog.py index 93a09287e8..050b9a4f98 100644 --- a/grc/gui/ParserErrorsDialog.py +++ b/grc/gui/ParserErrorsDialog.py @@ -21,10 +21,7 @@ from __future__ import absolute_import import six -import gi -gi.require_version('Gtk', '3.0') -from gi.repository import Gtk -from gi.repository import GObject +from gi.repository import Gtk, GObject from .Constants import MIN_DIALOG_WIDTH, MIN_DIALOG_HEIGHT diff --git a/grc/gui/Platform.py b/grc/gui/Platform.py index 44380c579f..aeade75d78 100644 --- a/grc/gui/Platform.py +++ b/grc/gui/Platform.py @@ -20,7 +20,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from __future__ import absolute_import, print_function import sys - import os from .Config import Config diff --git a/grc/gui/canvas/flowgraph.py b/grc/gui/canvas/flowgraph.py index 5969e00a43..ba13588355 100644 --- a/grc/gui/canvas/flowgraph.py +++ b/grc/gui/canvas/flowgraph.py @@ -26,9 +26,10 @@ from distutils.spawn import find_executable from itertools import count import six -from gi.repository import GLib from six.moves import filter +from gi.repository import GLib + from .drawable import Drawable from .. import Actions, Colors, Constants, Utils, Bars, Dialogs -- cgit v1.2.3 From 59f88d3cc03ed0f0c01433252f0d607330c23321 Mon Sep 17 00:00:00 2001 From: Seth Hitefield <sdhitefield@gmail.com> Date: Thu, 22 Sep 2016 13:10:57 -0400 Subject: grc: refactor: Moved preferences to Config.py --- grc/gui/ActionHandler.py | 15 ++-- grc/gui/Actions.py | 8 +-- grc/gui/Bars.py | 4 +- grc/gui/Config.py | 120 +++++++++++++++++++++++++++++++ grc/gui/Constants.py | 1 + grc/gui/FileDialogs.py | 14 ++-- grc/gui/MainWindow.py | 32 ++++----- grc/gui/Preferences.py | 176 ---------------------------------------------- grc/gui/VariableEditor.py | 6 +- 9 files changed, 163 insertions(+), 213 deletions(-) delete mode 100644 grc/gui/Preferences.py (limited to 'grc/gui/Bars.py') diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py index ad4dc35073..0d7a900e80 100644 --- a/grc/gui/ActionHandler.py +++ b/grc/gui/ActionHandler.py @@ -25,7 +25,7 @@ import subprocess from gi.repository import Gtk, GObject -from . import Dialogs, Preferences, Actions, Executor, FileDialogs, Utils +from . import Dialogs, Actions, Executor, FileDialogs, Utils from .MainWindow import MainWindow from .ParserErrorsDialog import ParserErrorsDialog from .PropsDialog import PropsDialog @@ -55,6 +55,7 @@ class ActionHandler(Gtk.Application): for action in Actions.get_all_actions(): action.connect('activate', self._handle_action) #setup the main window self.platform = platform + self.config = platform.config #initialize self.init_file_paths = [os.path.abspath(file_path) for file_path in file_paths] @@ -121,8 +122,8 @@ class ActionHandler(Gtk.Application): # Initialize/Quit ################################################## if action == Actions.APPLICATION_INITIALIZE: - file_path_to_show = Preferences.file_open() - for file_path in (self.init_file_paths or Preferences.get_open_files()): + 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): main.new_page(file_path, show=file_path_to_show == file_path) if not main.current_page: @@ -517,7 +518,7 @@ class ActionHandler(Gtk.Application): 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)) - Preferences.add_recent_file(file_path) + self.config.add_recent_file(file_path) main.tool_bar.refresh_submenus() main.menu_bar.refresh_submenus() elif action == Actions.FLOW_GRAPH_OPEN_QSS_THEME: @@ -545,7 +546,7 @@ class ActionHandler(Gtk.Application): if file_path is not None: page.file_path = os.path.abspath(file_path) Actions.FLOW_GRAPH_SAVE() - Preferences.add_recent_file(file_path) + self.config.add_recent_file(file_path) main.tool_bar.refresh_submenus() main.menu_bar.refresh_submenus() elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE: @@ -576,10 +577,10 @@ class ActionHandler(Gtk.Application): Actions.FLOW_GRAPH_GEN() xterm = self.platform.config.xterm_executable Dialogs.show_missing_xterm(main, xterm) - if Preferences.xterm_missing() != xterm: + if self.config.xterm_missing() != xterm: if not os.path.exists(xterm): Dialogs.show_missing_xterm(main, xterm) - Preferences.xterm_missing(xterm) + self.config.xterm_missing(xterm) if page.saved and page.file_path: Executor.ExecFlowGraphThread( flow_graph_page=page, diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index 601d0005fb..ef043853a9 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -23,8 +23,6 @@ import six from gi.repository import Gtk, Gdk, GObject -from . import Preferences - NO_MODS_MASK = 0 @@ -166,12 +164,14 @@ class ToggleAction(Gtk.ToggleAction, _ActionBase): def load_from_preferences(self): if self.preference_name is not None: - self.set_active(Preferences.entry( + config = Gtk.Application.get_default().config + self.set_active(config.entry( self.preference_name, default=bool(self.default))) def save_to_preferences(self): if self.preference_name is not None: - Preferences.entry(self.preference_name, value=self.get_active()) + config = Gtk.Application.get_default().config + config.entry(self.preference_name, value=self.get_active()) ######################################################################## # Actions diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index 1c63f01fa6..26fea20024 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -205,9 +205,9 @@ class SubMenuCreator(object): def _fill_flow_graph_recent_submenu(self, action): """menu showing recent flow-graphs""" - from . import Preferences menu = Gtk.Menu() - recent_files = Preferences.get_recent_files() + config = Gtk.Application.get_default().config + recent_files = config.get_recent_files() if len(recent_files) > 0: for i, file_name in enumerate(recent_files): item = Gtk.MenuItem(name="%d. %s" % (i+1, file_name), use_underline=False) diff --git a/grc/gui/Config.py b/grc/gui/Config.py index 0558892e2f..c4d395c0b3 100644 --- a/grc/gui/Config.py +++ b/grc/gui/Config.py @@ -25,6 +25,16 @@ import os from ..core.Config import Config as CoreConfig from . import Constants +from six.moves import configparser + +HEADER = """\ +# This contains only GUI settings for GRC and is not meant for users to edit. +# +# GRC settings not accessible through the GUI are in gnuradio.conf under +# section [grc]. + +""" + class Config(CoreConfig): @@ -38,6 +48,41 @@ class Config(CoreConfig): self.install_prefix = install_prefix Constants.update_font_size(self.font_size) + self.parser = configparser.SafeConfigParser() + for section in ['main', 'files_open', 'files_recent']: + try: + self.parser.add_section(section) + except Exception as e: + print(e) + try: + self.parser.read(self.gui_prefs_file) + except Exception as err: + print(err, file=sys.stderr) + + def save(self): + try: + with open(self.gui_prefs_file, 'w') as fp: + fp.write(HEADER) + self.parser.write(fp) + except Exception as err: + print(err, file=sys.stderr) + + def entry(self, key, value=None, default=None): + if value is not None: + self.parser.set('main', key, str(value)) + result = value + else: + _type = type(default) if default is not None else str + getter = { + bool: self.parser.getboolean, + int: self.parser.getint, + }.get(_type, self.parser.get) + try: + result = getter('main', key) + except (AttributeError, configparser.Error): + result = _type() if default is None else default + return result + @property def editor(self): return self._gr_prefs.get_string('grc', 'editor', '') @@ -84,3 +129,78 @@ class Config(CoreConfig): def default_qss_theme(self, value): self._gr_prefs.set_string("qtgui", "qss", value) self._gr_prefs.save() + + ##### Originally from Preferences.py ##### + def main_window_size(self, size=None): + if size is None: + size = [None, None] + w = self.entry('main_window_width', size[0], default=1) + h = self.entry('main_window_height', size[1], default=1) + return w, h + + def file_open(self, filename=None): + return self.entry('file_open', filename, default='') + + def set_file_list(self, key, files): + self.parser.remove_section(key) # clear section + self.parser.add_section(key) + for i, filename in enumerate(files): + self.parser.set(key, '%s_%d' % (key, i), filename) + + def get_file_list(self, key): + try: + files = [value for name, value in self.parser.items(key) + if name.startswith('%s_' % key)] + except (AttributeError, configparser.Error): + files = [] + return files + + def get_open_files(self): + return self.get_file_list('files_open') + + def set_open_files(self, files): + return self.set_file_list('files_open', files) + + def get_recent_files(self): + """ Gets recent files, removes any that do not exist and re-saves it """ + files = list(filter(os.path.exists, self.get_file_list('files_recent'))) + self.set_recent_files(files) + return files + + def set_recent_files(self, files): + return self.set_file_list('files_recent', files) + + def add_recent_file(self, file_name): + # double check file_name + if os.path.exists(file_name): + recent_files = self.get_recent_files() + if file_name in recent_files: + recent_files.remove(file_name) # Attempt removal + recent_files.insert(0, file_name) # Insert at start + self.set_recent_files(recent_files[:10]) # Keep up to 10 files + + def console_window_position(self, pos=None): + return self.entry('console_window_position', pos, default=-1) or 1 + + def blocks_window_position(self, pos=None): + return self.entry('blocks_window_position', pos, default=-1) or 1 + + def variable_editor_position(self, pos=None, sidebar=False): + # Figure out default + if sidebar: + w, h = self.main_window_size() + return self.entry('variable_editor_sidebar_position', pos, default=int(h*0.7)) + else: + return self.entry('variable_editor_position', pos, default=int(self.blocks_window_position()*0.5)) + + def variable_editor_sidebar(self, pos=None): + return self.entry('variable_editor_sidebar', pos, default=False) + + def variable_editor_confirm_delete(self, pos=None): + return self.entry('variable_editor_confirm_delete', pos, default=True) + + def xterm_missing(self, cmd=None): + return self.entry('xterm_missing', cmd, default='INVALID_XTERM_SETTING') + + def screen_shot_background_transparent(self, transparent=None): + return self.entry('screen_shot_background_transparent', transparent, default=False) diff --git a/grc/gui/Constants.py b/grc/gui/Constants.py index 2f0f7794be..0a555b37c9 100644 --- a/grc/gui/Constants.py +++ b/grc/gui/Constants.py @@ -26,6 +26,7 @@ from ..core.Constants import * # default path for the open/save dialogs DEFAULT_FILE_PATH = os.getcwd() +FILE_EXTENSION = '.grc' # name for new/unsaved flow graphs NEW_FLOGRAPH_TITLE = 'untitled' diff --git a/grc/gui/FileDialogs.py b/grc/gui/FileDialogs.py index cbb7bcaa69..dbcecf91ab 100644 --- a/grc/gui/FileDialogs.py +++ b/grc/gui/FileDialogs.py @@ -23,7 +23,7 @@ from os import path from gi.repository import Gtk -from . import Constants, Preferences, Utils, Dialogs +from . import Constants, Utils, Dialogs class FileDialogHelper(Gtk.FileChooserDialog, object): @@ -59,7 +59,7 @@ class FileDialogHelper(Gtk.FileChooserDialog, object): self.parent = parent self.current_file_path = current_file_path or path.join( - Constants.DEFAULT_FILE_PATH, Constants.NEW_FLOGRAPH_TITLE + Preferences.file_extension()) + Constants.DEFAULT_FILE_PATH, Constants.NEW_FLOGRAPH_TITLE + Constants.FILE_EXTENSION) self.set_current_folder(path.dirname(current_file_path)) # current directory self.setup_filters() @@ -130,7 +130,7 @@ class OpenFileDialog(FileDialogHelper): class OpenFlowGraph(OpenFileDialog): title = 'Open a Flow Graph from a File...' filter_label = 'Flow Graph Files' - filter_ext = Preferences.file_extension() + filter_ext = Constants.FILE_EXTENSION def __init__(self, parent, current_file_path=''): super(OpenFlowGraph, self).__init__(parent, current_file_path) @@ -146,7 +146,7 @@ class OpenQSS(OpenFileDialog): class SaveFlowGraph(SaveFileDialog): title = 'Save a Flow Graph to a File...' filter_label = 'Flow Graph Files' - filter_ext = Preferences.file_extension() + filter_ext = Constants.FILE_EXTENSION class SaveConsole(SaveFileDialog): @@ -163,8 +163,10 @@ class SaveScreenShot(SaveFileDialog): def __init__(self, parent, current_file_path=''): super(SaveScreenShot, self).__init__(parent, current_file_path) + self.config = Gtk.Application.get_default().config + self._button = button = Gtk.CheckButton(label='Background transparent') - self._button.set_active(Preferences.screen_shot_background_transparent()) + self._button.set_active(self.config.screen_shot_background_transparent()) self.set_extra_widget(button) def setup_filters(self, filters=None): @@ -193,6 +195,6 @@ class SaveScreenShot(SaveFileDialog): self.show_missing_message(filename) bg_transparent = self._button.get_active() - Preferences.screen_shot_background_transparent(bg_transparent) + self.config.screen_shot_background_transparent(bg_transparent) self.destroy() return filename, bg_transparent diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py index 5eabf33f67..1caec28aee 100644 --- a/grc/gui/MainWindow.py +++ b/grc/gui/MainWindow.py @@ -23,7 +23,7 @@ import os from gi.repository import Gtk, Gdk, GObject -from . import Bars, Actions, Preferences, Utils +from . import Bars, Actions, Utils from .BlockTreeWindow import BlockTreeWindow from .VariableEditor import VariableEditor from .Constants import \ @@ -52,7 +52,7 @@ class MainWindow(Gtk.ApplicationWindow): Gtk.ApplicationWindow.__init__(self, title="GNU Radio Companion", application=app) self._platform = platform - Preferences.load(platform) + self.config = platform.config # Setup window vbox = Gtk.VBox() @@ -97,7 +97,7 @@ class MainWindow(Gtk.ApplicationWindow): self.right = Gtk.VPaned() #orientation=Gtk.Orientation.VERTICAL) self.left_subpanel = Gtk.HPaned() #orientation=Gtk.Orientation.HORIZONTAL) - self.variable_panel_sidebar = Preferences.variable_editor_sidebar() + self.variable_panel_sidebar = self.config.variable_editor_sidebar() if self.variable_panel_sidebar: self.left.pack1(self.notebook) self.left.pack2(self.console_window, False) @@ -117,13 +117,13 @@ class MainWindow(Gtk.ApplicationWindow): self.main.pack2(self.right, False) # Load preferences and show the main window - self.resize(*Preferences.main_window_size()) - self.main.set_position(Preferences.blocks_window_position()) - self.left.set_position(Preferences.console_window_position()) + self.resize(*self.config.main_window_size()) + self.main.set_position(self.config.blocks_window_position()) + self.left.set_position(self.config.console_window_position()) if self.variable_panel_sidebar: - self.right.set_position(Preferences.variable_editor_position(sidebar=True)) + self.right.set_position(self.config.variable_editor_position(sidebar=True)) else: - self.left_subpanel.set_position(Preferences.variable_editor_position()) + self.left_subpanel.set_position(self.config.variable_editor_position()) self.show_all() self.console_window.hide() @@ -279,16 +279,16 @@ class MainWindow(Gtk.ApplicationWindow): break if self.notebook.get_n_pages(): return False #save state before closing - Preferences.set_open_files(open_files) - Preferences.file_open(open_file) - Preferences.main_window_size(self.get_size()) - Preferences.console_window_position(self.left.get_position()) - Preferences.blocks_window_position(self.main.get_position()) + self.config.set_open_files(open_files) + self.config.file_open(open_file) + self.config.main_window_size(self.get_size()) + self.config.console_window_position(self.left.get_position()) + self.config.blocks_window_position(self.main.get_position()) if self.variable_panel_sidebar: - Preferences.variable_editor_position(self.right.get_position(), sidebar=True) + self.config.variable_editor_position(self.right.get_position(), sidebar=True) else: - Preferences.variable_editor_position(self.left_subpanel.get_position()) - Preferences.save() + self.config.variable_editor_position(self.left_subpanel.get_position()) + self.config.save() return True def close_page(self, ensure=True): diff --git a/grc/gui/Preferences.py b/grc/gui/Preferences.py deleted file mode 100644 index d917537971..0000000000 --- a/grc/gui/Preferences.py +++ /dev/null @@ -1,176 +0,0 @@ -""" -Copyright 2008 Free Software Foundation, Inc. -This file is part of GNU Radio - -GNU Radio Companion is free software; you can redistribute it and/or -modify it under the terms of the GNU General Public License -as published by the Free Software Foundation; either version 2 -of the License, or (at your option) any later version. - -GNU Radio Companion is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA -""" - -from __future__ import absolute_import, print_function - -import os -import sys - -from six.moves import configparser - - -HEADER = """\ -# This contains only GUI settings for GRC and is not meant for users to edit. -# -# GRC settings not accessible through the GUI are in gnuradio.conf under -# section [grc]. - -""" - -_platform = None -_config_parser = configparser.SafeConfigParser() - - -def file_extension(): - return '.grc' - - -def load(platform): - global _platform - _platform = platform - # create sections - for section in ['main', 'files_open', 'files_recent']: - try: - _config_parser.add_section(section) - except Exception as e: - print(e) - try: - _config_parser.read(_platform.get_prefs_file()) - except Exception as err: - print(err, file=sys.stderr) - - -def save(): - try: - with open(_platform.get_prefs_file(), 'w') as fp: - fp.write(HEADER) - _config_parser.write(fp) - except Exception as err: - print(err, file=sys.stderr) - - -def entry(key, value=None, default=None): - if value is not None: - _config_parser.set('main', key, str(value)) - result = value - else: - _type = type(default) if default is not None else str - getter = { - bool: _config_parser.getboolean, - int: _config_parser.getint, - }.get(_type, _config_parser.get) - try: - result = getter('main', key) - except (AttributeError, configparser.Error): - result = _type() if default is None else default - return result - - -########################################################################### -# Special methods for specific program functionalities -########################################################################### - -def main_window_size(size=None): - if size is None: - size = [None, None] - w = entry('main_window_width', size[0], default=1) - h = entry('main_window_height', size[1], default=1) - return w, h - - -def file_open(filename=None): - return entry('file_open', filename, default='') - - -def set_file_list(key, files): - _config_parser.remove_section(key) # clear section - _config_parser.add_section(key) - for i, filename in enumerate(files): - _config_parser.set(key, '%s_%d' % (key, i), filename) - - -def get_file_list(key): - try: - files = [value for name, value in _config_parser.items(key) - if name.startswith('%s_' % key)] - except (AttributeError, configparser.Error): - files = [] - return files - - -def get_open_files(): - return get_file_list('files_open') - - -def set_open_files(files): - return set_file_list('files_open', files) - - -def get_recent_files(): - """ Gets recent files, removes any that do not exist and re-saves it """ - files = list(filter(os.path.exists, get_file_list('files_recent'))) - set_recent_files(files) - return files - - -def set_recent_files(files): - return set_file_list('files_recent', files) - - -def add_recent_file(file_name): - # double check file_name - if os.path.exists(file_name): - recent_files = get_recent_files() - if file_name in recent_files: - recent_files.remove(file_name) # Attempt removal - recent_files.insert(0, file_name) # Insert at start - set_recent_files(recent_files[:10]) # Keep up to 10 files - - -def console_window_position(pos=None): - return entry('console_window_position', pos, default=-1) or 1 - - -def blocks_window_position(pos=None): - return entry('blocks_window_position', pos, default=-1) or 1 - - -def variable_editor_position(pos=None, sidebar=False): - # Figure out default - if sidebar: - w, h = main_window_size() - return entry('variable_editor_sidebar_position', pos, default=int(h*0.7)) - else: - return entry('variable_editor_position', pos, default=int(blocks_window_position()*0.5)) - - -def variable_editor_sidebar(pos=None): - return entry('variable_editor_sidebar', pos, default=False) - - -def variable_editor_confirm_delete(pos=None): - return entry('variable_editor_confirm_delete', pos, default=True) - - -def xterm_missing(cmd=None): - return entry('xterm_missing', cmd, default='INVALID_XTERM_SETTING') - - -def screen_shot_background_transparent(transparent=None): - return entry('screen_shot_background_transparent', transparent, default=False) diff --git a/grc/gui/VariableEditor.py b/grc/gui/VariableEditor.py index d97b9e9f24..44dd2923eb 100644 --- a/grc/gui/VariableEditor.py +++ b/grc/gui/VariableEditor.py @@ -21,7 +21,7 @@ from __future__ import absolute_import from gi.repository import Gtk, Gdk, GObject -from . import Actions, Preferences, Constants +from . import Actions, Constants BLOCK_INDEX = 0 ID_INDEX = 1 @@ -85,6 +85,8 @@ class VariableEditor(Gtk.VBox): def __init__(self): Gtk.VBox.__init__(self) + config = Gtk.Application.get_default().config + self._block = None self._mouse_button_pressed = False self._imports = [] @@ -150,7 +152,7 @@ class VariableEditor(Gtk.VBox): # Context menus self._context_menu = VariableEditorContextMenu(self) - self._confirm_delete = Preferences.variable_editor_confirm_delete() + self._confirm_delete = config.variable_editor_confirm_delete() # Sets cell contents def set_icon(self, col, cell, model, iter, data): -- cgit v1.2.3 From 486e0a9d06e43f3b8669471bef13a5eeedbda4c6 Mon Sep 17 00:00:00 2001 From: Seth Hitefield <sdhitefield@gmail.com> Date: Wed, 3 May 2017 07:06:54 -0700 Subject: grc: gtk3: Converted actions to Gio.Action instead of Gtk.Action --- grc/core/Block.py | 2 +- grc/core/ParseXML.py | 2 +- grc/core/utils/expr_utils.py | 3 +- grc/gui/Actions.py | 633 ++++++++++++++++++++++--------------------- grc/gui/Application.py | 281 ++++++++++++------- grc/gui/Bars.py | 519 +++++++++++++++++------------------ grc/gui/Config.py | 2 +- grc/gui/Console.py | 6 + grc/gui/DrawingArea.py | 44 +++ grc/gui/MainWindow.py | 25 +- grc/gui/Notebook.py | 44 ++- grc/gui/ParamWidgets.py | 2 +- grc/gui/StateCache.py | 4 +- grc/gui/Utils.py | 6 +- grc/gui/VariableEditor.py | 4 +- grc/gui/canvas/param.py | 2 +- grc/main.py | 16 +- 17 files changed, 889 insertions(+), 706 deletions(-) (limited to 'grc/gui/Bars.py') diff --git a/grc/core/Block.py b/grc/core/Block.py index 8350828092..087815b941 100644 --- a/grc/core/Block.py +++ b/grc/core/Block.py @@ -403,7 +403,7 @@ class Block(Element): return itertools.chain(self.active_sources, self.active_sinks) def get_children(self): - return self.get_ports() + self.params.values() + return self.get_ports() + list(self.params.values()) def get_children_gui(self): return self.get_ports_gui() + self.params.values() diff --git a/grc/core/ParseXML.py b/grc/core/ParseXML.py index 163289ba06..430ba5b474 100644 --- a/grc/core/ParseXML.py +++ b/grc/core/ParseXML.py @@ -156,7 +156,7 @@ def to_file(nested_data, xml_file): ), xml_declaration=True, pretty_print=True, encoding='utf-8') xml_data += etree.tostring(_to_file(nested_data)[0], pretty_print=True, encoding='utf-8') - with open(xml_file, 'w') as fp: + with open(xml_file, 'wb') as fp: fp.write(xml_data) diff --git a/grc/core/utils/expr_utils.py b/grc/core/utils/expr_utils.py index 555bd709b1..cc03e9cb1c 100644 --- a/grc/core/utils/expr_utils.py +++ b/grc/core/utils/expr_utils.py @@ -23,7 +23,7 @@ import string import six -VAR_CHARS = string.letters + string.digits + '_' +VAR_CHARS = string.ascii_letters + string.digits + '_' class graph(object): @@ -194,4 +194,3 @@ def sort_objects(objects, get_id, get_expr): sorted_ids = sort_variables(id2expr) # Return list of sorted objects return [id2obj[id] for id in sorted_ids] - diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py index 97162065a6..d214f28049 100644 --- a/grc/gui/Actions.py +++ b/grc/gui/Actions.py @@ -20,286 +20,323 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from __future__ import absolute_import import six +import logging -from gi.repository import Gtk, Gdk, GObject +from gi.repository import Gtk, Gdk, Gio, GLib, GObject -NO_MODS_MASK = 0 +log = logging.getLogger(__name__) -######################################################################## -# Actions API -######################################################################## -_actions_keypress_dict = dict() -_keymap = Gdk.Keymap.get_default() -_used_mods_mask = NO_MODS_MASK - - -def handle_key_press(event): - """ - Call the action associated with the key press event. - Both the key value and the mask must have a match. - - Args: - event: a gtk key press event - - Returns: - true if handled - """ - # extract the key value and the consumed modifiers - _unused, keyval, egroup, level, consumed = _keymap.translate_keyboard_state( - event.hardware_keycode, event.get_state(), event.group) - # get the modifier mask and ignore irrelevant modifiers - mod_mask = event.get_state() & ~consumed & _used_mods_mask - # look up the keypress and call the action - try: - _actions_keypress_dict[(keyval, mod_mask)]() - except KeyError: - return False # not handled - else: - return True # handled here - -_all_actions_list = list() - - -def get_all_actions(): - return _all_actions_list - -_accel_group = Gtk.AccelGroup() - - -def get_accel_group(): - return _accel_group - - -class _ActionBase(object): - """ - Base class for Action and ToggleAction - Register actions and keypresses with this module. - """ - def __init__(self, label, keypresses): - global _used_mods_mask - - _all_actions_list.append(self) - for i in range(len(keypresses)/2): - keyval, mod_mask = keypresses[i*2:(i+1)*2] - # register this keypress - if (keyval, mod_mask) in _actions_keypress_dict: - raise KeyError('keyval/mod_mask pair already registered "%s"' % str((keyval, mod_mask))) - _actions_keypress_dict[(keyval, mod_mask)] = self - _used_mods_mask |= mod_mask - # set the accelerator group, and accelerator path - # register the key name and mod mask with the accelerator path - if label is None: - continue # dont register accel - accel_path = '<main>/' + self.get_name() - self.set_accel_group(get_accel_group()) - self.set_accel_path(accel_path) - Gtk.AccelMap.add_entry(accel_path, keyval, mod_mask) - self.args = None + +def filter_from_dict(vars): + return filter(lambda x: isinstance(x[1], Action), vars.items()) + + +class Namespace(object): + + def __init__(self): + self._actions = {} + + def add(self, action): + key = action.props.name + self._actions[key] = action + + def connect(self, name, handler): + #log.debug("Connecting action <{}> to handler <{}>".format(name, handler.__name__)) + self._actions[name].connect('activate', handler) + + def register(self, name, parameter=None, handler=None, label=None, tooltip=None, + icon_name=None, keypresses=None, preference_name=None, default=None): + # Check types + if not isinstance(name, str): + raise TypeError("Cannot register fuction: 'name' must be a str") + if parameter and not isinstance(parameter, str): + raise TypeError("Cannot register fuction: 'parameter' must be a str") + if handler and not callable(handler): + raise TypeError("Cannot register fuction: 'handler' must be callable") + + # Check if the name has a prefix. + prefix = None + if name.startswith("app.") or name.startswith("win."): + # Set a prefix for later and remove it + prefix = name[0:3] + name = name[4:] + + if handler: + log.debug("Register action [{}, prefix={}, param={}, handler={}]".format( + name, prefix, parameter, handler.__name__)) + else: + log.debug("Register action [{}, prefix={}, param={}, handler=None]".format( + name, prefix, parameter)) + + action = Action(name, parameter, label=label, tooltip=tooltip, + icon_name=icon_name, keypresses=keypresses, prefix=prefix, + preference_name=preference_name, default=default) + if handler: + action.connect('activate', handler) + + key = name + if prefix: + key = "{}.{}".format(prefix, name) + if prefix == "app": + pass + #self.app.add_action(action) + elif prefix == "win": + pass + #self.win.add_action(action) + + #log.debug("Registering action as '{}'".format(key)) + self._actions[key] = action + return action + + + # If the actions namespace is called, trigger an action + def __call__(self, name): + # Try to parse the action string. + valid, action_name, target_value = Action.parse_detailed_name(name) + if not valid: + raise Exception("Invalid action string: '{}'".format(name)) + if action_name not in self._actions: + raise Exception("Action '{}' is not registered!".format(action_name)) + + if target_value: + self._actions[action_name].activate(target_value) + else: + self._actions[action_name].activate() + + def __getitem__(self, key): + return self._actions[key] + + def __iter__(self): + return self._actions.itervalues() + + def __repr__(self): + return str(self) + + def get_actions(self): + return self._actions def __str__(self): - """ - The string representation should be the name of the action id. - Try to find the action id for this action by searching this module. - """ - for name, value in six.iteritems(globals()): - if value == self: - return name - return self.get_name() - - def __repr__(self): return str(self) - - def __call__(self, *args): - """ - Emit the activate signal when called with (). - """ - self.args = args - self.emit('activate') - - -class Action(Gtk.Action, _ActionBase): - """ - A custom Action class based on Gtk.Action. - Pass additional arguments such as keypresses. - """ - - def __init__(self, keypresses=(), name=None, label=None, tooltip=None, - stock_id=None): - """ - Create a new Action instance. - - Args: - key_presses: a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...) - the: regular Gtk.Action parameters (defaults to None) - """ - if name is None: - name = label - GObject.GObject.__init__(self, name=name, label=label, tooltip=tooltip, - stock_id=stock_id) - _ActionBase.__init__(self, label, keypresses) - - -class ToggleAction(Gtk.ToggleAction, _ActionBase): - """ - A custom Action class based on Gtk.ToggleAction. - Pass additional arguments such as keypresses. - """ - - def __init__(self, keypresses=(), name=None, label=None, tooltip=None, - stock_id=None, preference_name=None, default=True): - """ - Create a new ToggleAction instance. - - Args: - key_presses: a tuple of (keyval1, mod_mask1, keyval2, mod_mask2, ...) - the: regular Gtk.Action parameters (defaults to None) - """ - if name is None: - name = label - GObject.GObject.__init__(self, name=name, label=label, - tooltip=tooltip, stock_id=stock_id) - _ActionBase.__init__(self, label, keypresses) + s = "{Actions:" + for key in self._actions: + s += " {},".format(key) + s = s.rstrip(",") + "}" + return s + + +class Action(Gio.SimpleAction): + + # Change these to normal python properties. + #prefs_name + + def __init__(self, name, parameter=None, label=None, tooltip=None, + icon_name=None, keypresses=None, prefix=None, + preference_name=None, default=None): + self.name = name + self.label = label + self.tooltip = tooltip + self.icon_name = icon_name + self.keypresses = keypresses + self.prefix = prefix self.preference_name = preference_name self.default = default - def load_from_preferences(self): + # Don't worry about checking types here, since it's done in register() + # Save the parameter type to use for converting in __call__ + self.type = None + + variant = None + state = None + if parameter: + variant = GLib.VariantType.new(parameter) + if preference_name: + state = GLib.Variant.new_boolean(True) + Gio.SimpleAction.__init__(self, name=name, parameter_type=variant, state=state) + + def enable(self): + self.props.enabled = True + + def disable(self): + self.props.enabled = False + + def set_enabled(self, state): + if not isinstance(state, bool): + raise TypeError("State must be True/False.") + self.props.enabled = state + + def __str__(self): + return self.props.name + + def __repr__(self): + return str(self) + + def get_active(self): + if self.props.state: + return self.props.state.get_boolean() + return False + + def set_active(self, state): + if not isinstance(state, bool): + raise TypeError("State must be True/False.") + self.change_state(GLib.Variant.new_boolean(state)) + + # Allows actions to be directly called. + def __call__(self, parameter=None): + if self.type and parameter: + # Try to convert it to the correct type. + try: + param = GLib.Variant(self.type, parameter) + self.activate(param) + except TypeError: + raise TypeError("Invalid parameter type for action '{}'. Expected: '{}'".format(self.get_name(), self.type)) + else: + self.activate() + + def load_from_preferences(self, *args): + log.debug("load_from_preferences({})".format(args)) if self.preference_name is not None: config = Gtk.Application.get_default().config - self.set_active(config.entry( - self.preference_name, default=bool(self.default))) + self.set_active(config.entry(self.preference_name, default=bool(self.default))) - def save_to_preferences(self): + def save_to_preferences(self, *args): + log.debug("save_to_preferences({})".format(args)) if self.preference_name is not None: config = Gtk.Application.get_default().config config.entry(self.preference_name, value=self.get_active()) + +actions = Namespace() + + +def get_actions(): + return actions.get_actions() + + +def connect(action, handler=None): + return actions.connect(action, handler=handler) + + ######################################################################## -# Actions +# Old Actions ######################################################################## -PAGE_CHANGE = Action() -EXTERNAL_UPDATE = Action() -VARIABLE_EDITOR_UPDATE = Action() -FLOW_GRAPH_NEW = Action( +PAGE_CHANGE = actions.register("win.page_change") +EXTERNAL_UPDATE = actions.register("app.external_update") +VARIABLE_EDITOR_UPDATE = actions.register("app.variable_editor_update") +FLOW_GRAPH_NEW = actions.register("app.flowgraph.new", label='_New', tooltip='Create a new flow graph', - stock_id=Gtk.STOCK_NEW, - keypresses=(Gdk.KEY_n, Gdk.ModifierType.CONTROL_MASK), + icon_name='document-new', + keypresses=["<Ctrl>n"], + parameter="s", ) -FLOW_GRAPH_OPEN = Action( +FLOW_GRAPH_OPEN = actions.register("app.flowgraph.open", label='_Open', tooltip='Open an existing flow graph', - stock_id=Gtk.STOCK_OPEN, - keypresses=(Gdk.KEY_o, Gdk.ModifierType.CONTROL_MASK), + icon_name='document-open', + keypresses=["<Ctrl>o"], ) -FLOW_GRAPH_OPEN_RECENT = Action( +FLOW_GRAPH_OPEN_RECENT = actions.register("app.flowgraph.open_recent", label='Open _Recent', tooltip='Open a recently used flow graph', - stock_id=Gtk.STOCK_OPEN, + icon_name='document-open-recent', + parameter="s", ) -FLOW_GRAPH_SAVE = Action( +FLOW_GRAPH_CLEAR_RECENT = actions.register("app.flowgraph.clear_recent") +FLOW_GRAPH_SAVE = actions.register("app.flowgraph.save", label='_Save', tooltip='Save the current flow graph', - stock_id=Gtk.STOCK_SAVE, - keypresses=(Gdk.KEY_s, Gdk.ModifierType.CONTROL_MASK), + icon_name='document-save', + keypresses=["<Ctrl>s"], ) -FLOW_GRAPH_SAVE_AS = Action( +FLOW_GRAPH_SAVE_AS = actions.register("app.flowgraph.save_as", label='Save _As', tooltip='Save the current flow graph as...', - stock_id=Gtk.STOCK_SAVE_AS, - keypresses=(Gdk.KEY_s, Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK), + icon_name='document-save-as', + keypresses=["<Ctrl><Shift>s"], ) -FLOW_GRAPH_SAVE_A_COPY = Action( - label='Save A Copy', - tooltip='Save the copy of current flow graph', +FLOW_GRAPH_SAVE_COPY = actions.register("app.flowgraph.save_copy", + label='Save Copy', + tooltip='Save a copy of current flow graph', ) -FLOW_GRAPH_DUPLICATE = Action( +FLOW_GRAPH_DUPLICATE = actions.register("app.flowgraph.duplicate", label='_Duplicate', tooltip='Create a duplicate of current flow graph', - stock_id=Gtk.STOCK_COPY, - keypresses=(Gdk.KEY_d, Gdk.ModifierType.CONTROL_MASK | Gdk.ModifierType.SHIFT_MASK), + #stock_id=Gtk.STOCK_COPY, + keypresses=["<Ctrl><Shift>d"], ) -FLOW_GRAPH_CLOSE = Action( +FLOW_GRAPH_CLOSE = actions.register("app.flowgraph.close", label='_Close', tooltip='Close the current flow graph', - stock_id=Gtk.STOCK_CLOSE, - keypresses=(Gdk.KEY_w, Gdk.ModifierType.CONTROL_MASK), + icon_name='window-close', + keypresses=["<Ctrl>w"], ) -APPLICATION_INITIALIZE = Action() -APPLICATION_QUIT = Action( +APPLICATION_INITIALIZE = actions.register("app.initialize") +APPLICATION_QUIT = actions.register("app.quit", label='_Quit', tooltip='Quit program', - stock_id=Gtk.STOCK_QUIT, - keypresses=(Gdk.KEY_q, Gdk.ModifierType.CONTROL_MASK), + icon_name='application-exit', + keypresses=["<Ctrl>q"], ) -FLOW_GRAPH_UNDO = Action( +FLOW_GRAPH_UNDO = actions.register("win.undo", label='_Undo', tooltip='Undo a change to the flow graph', - stock_id=Gtk.STOCK_UNDO, - keypresses=(Gdk.KEY_z, Gdk.ModifierType.CONTROL_MASK), + icon_name='edit-undo', + keypresses=["<Ctrl>z"], ) -FLOW_GRAPH_REDO = Action( +FLOW_GRAPH_REDO = actions.register("win.redo", label='_Redo', tooltip='Redo a change to the flow graph', - stock_id=Gtk.STOCK_REDO, - keypresses=(Gdk.KEY_y, Gdk.ModifierType.CONTROL_MASK), + icon_name='edit-redo', + keypresses=["<Ctrl>y"], ) -NOTHING_SELECT = Action() -SELECT_ALL = Action( +NOTHING_SELECT = actions.register("win.unselect") +SELECT_ALL = actions.register("win.select_all", label='Select _All', tooltip='Select all blocks and connections in the flow graph', - stock_id=Gtk.STOCK_SELECT_ALL, - keypresses=(Gdk.KEY_a, Gdk.ModifierType.CONTROL_MASK), + icon_name='edit-select-all', + keypresses=["<Ctrl>a"], ) -ELEMENT_SELECT = Action() -ELEMENT_CREATE = Action() -ELEMENT_DELETE = Action( +ELEMENT_SELECT = actions.register("win.select") +ELEMENT_CREATE = actions.register("win.add") +ELEMENT_DELETE = actions.register("win.delete", label='_Delete', tooltip='Delete the selected blocks', - stock_id=Gtk.STOCK_DELETE, - keypresses=(Gdk.KEY_Delete, NO_MODS_MASK), + icon_name='edit-delete', ) -BLOCK_MOVE = Action() -BLOCK_ROTATE_CCW = Action( +BLOCK_MOVE = actions.register("win.block_move") +BLOCK_ROTATE_CCW = actions.register("win.block_rotate_ccw", label='Rotate Counterclockwise', tooltip='Rotate the selected blocks 90 degrees to the left', - stock_id=Gtk.STOCK_GO_BACK, - keypresses=(Gdk.KEY_Left, NO_MODS_MASK), + icon_name='object-rotate-left', ) -BLOCK_ROTATE_CW = Action( +BLOCK_ROTATE_CW = actions.register("win.block_rotate", label='Rotate Clockwise', tooltip='Rotate the selected blocks 90 degrees to the right', - stock_id=Gtk.STOCK_GO_FORWARD, - keypresses=(Gdk.KEY_Right, NO_MODS_MASK), + icon_name='object-rotate-right', ) -BLOCK_VALIGN_TOP = Action( +BLOCK_VALIGN_TOP = actions.register("win.block_align_top", label='Vertical Align Top', tooltip='Align tops of selected blocks', - keypresses=(Gdk.KEY_t, Gdk.ModifierType.SHIFT_MASK), ) -BLOCK_VALIGN_MIDDLE = Action( +BLOCK_VALIGN_MIDDLE = actions.register("win.block_align_middle", label='Vertical Align Middle', tooltip='Align centers of selected blocks vertically', - keypresses=(Gdk.KEY_m, Gdk.ModifierType.SHIFT_MASK), ) -BLOCK_VALIGN_BOTTOM = Action( +BLOCK_VALIGN_BOTTOM = actions.register("win.block_align_bottom", label='Vertical Align Bottom', tooltip='Align bottoms of selected blocks', - keypresses=(Gdk.KEY_b, Gdk.ModifierType.SHIFT_MASK), ) -BLOCK_HALIGN_LEFT = Action( +BLOCK_HALIGN_LEFT = actions.register("win.block_align_left", label='Horizontal Align Left', tooltip='Align left edges of blocks selected blocks', - keypresses=(Gdk.KEY_l, Gdk.ModifierType.SHIFT_MASK), ) -BLOCK_HALIGN_CENTER = Action( +BLOCK_HALIGN_CENTER = actions.register("win.block_align_center", label='Horizontal Align Center', tooltip='Align centers of selected blocks horizontally', - keypresses=(Gdk.KEY_c, Gdk.ModifierType.SHIFT_MASK), ) -BLOCK_HALIGN_RIGHT = Action( +BLOCK_HALIGN_RIGHT = actions.register("win.block_align_right", label='Horizontal Align Right', tooltip='Align right edges of selected blocks', - keypresses=(Gdk.KEY_r, Gdk.ModifierType.SHIFT_MASK), ) BLOCK_ALIGNMENTS = [ BLOCK_VALIGN_TOP, @@ -310,234 +347,222 @@ BLOCK_ALIGNMENTS = [ BLOCK_HALIGN_CENTER, BLOCK_HALIGN_RIGHT, ] -BLOCK_PARAM_MODIFY = Action( +BLOCK_PARAM_MODIFY = actions.register("win.block_modify", label='_Properties', tooltip='Modify params for the selected block', - stock_id=Gtk.STOCK_PROPERTIES, - keypresses=(Gdk.KEY_Return, NO_MODS_MASK), + icon_name='document-properties', ) -BLOCK_ENABLE = Action( +BLOCK_ENABLE = actions.register("win.block_enable", label='E_nable', tooltip='Enable the selected blocks', - stock_id=Gtk.STOCK_CONNECT, - keypresses=(Gdk.KEY_e, NO_MODS_MASK), + icon_name='network-wired', ) -BLOCK_DISABLE = Action( +BLOCK_DISABLE = actions.register("win.block_disable", label='D_isable', tooltip='Disable the selected blocks', - stock_id=Gtk.STOCK_DISCONNECT, - keypresses=(Gdk.KEY_d, NO_MODS_MASK), + icon_name='network-wired-disconnected', ) -BLOCK_BYPASS = Action( +BLOCK_BYPASS = actions.register("win.block_bypass", label='_Bypass', tooltip='Bypass the selected block', - stock_id=Gtk.STOCK_MEDIA_FORWARD, - keypresses=(Gdk.KEY_b, NO_MODS_MASK), + icon_name='media-seek-forward', ) -TOGGLE_SNAP_TO_GRID = ToggleAction( +TOGGLE_SNAP_TO_GRID = actions.register("win.snap_to_grid", label='_Snap to grid', tooltip='Snap blocks to a grid for an easier connection alignment', - preference_name='snap_to_grid' + preference_name='snap_to_grid', ) -TOGGLE_HIDE_DISABLED_BLOCKS = ToggleAction( +TOGGLE_HIDE_DISABLED_BLOCKS = actions.register("win.hide_disabled", label='Hide _Disabled Blocks', tooltip='Toggle visibility of disabled blocks and connections', - stock_id=Gtk.STOCK_MISSING_IMAGE, - keypresses=(Gdk.KEY_d, Gdk.ModifierType.CONTROL_MASK), + icon_name='image-missing', + keypresses=["<Ctrl>d"], + preference_name='hide_disabled', ) -TOGGLE_HIDE_VARIABLES = ToggleAction( +TOGGLE_HIDE_VARIABLES = actions.register("win.hide_variables", label='Hide Variables', tooltip='Hide all variable blocks', preference_name='hide_variables', default=False, ) -TOGGLE_FLOW_GRAPH_VAR_EDITOR = ToggleAction( +TOGGLE_FLOW_GRAPH_VAR_EDITOR = actions.register("win.toggle_variable_editor", label='Show _Variable Editor', tooltip='Show the variable editor. Modify variables and imports in this flow graph', - stock_id=Gtk.STOCK_EDIT, + icon_name='accessories-text-editor', default=True, - keypresses=(Gdk.KEY_e, Gdk.ModifierType.CONTROL_MASK), + keypresses=["<Ctrl>e"], preference_name='variable_editor_visable', ) -TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR = ToggleAction( +TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR = actions.register("win.toggle_variable_editor_sidebar", label='Move the Variable Editor to the Sidebar', tooltip='Move the variable editor to the sidebar', default=False, preference_name='variable_editor_sidebar', ) -TOGGLE_AUTO_HIDE_PORT_LABELS = ToggleAction( +TOGGLE_AUTO_HIDE_PORT_LABELS = actions.register("win.auto_hide_port_labels", label='Auto-Hide _Port Labels', tooltip='Automatically hide port labels', preference_name='auto_hide_port_labels' ) -TOGGLE_SHOW_BLOCK_COMMENTS = ToggleAction( +TOGGLE_SHOW_BLOCK_COMMENTS = actions.register("win.show_block_comments", label='Show Block Comments', tooltip="Show comment beneath each block", preference_name='show_block_comments' ) -TOGGLE_SHOW_CODE_PREVIEW_TAB = ToggleAction( +TOGGLE_SHOW_CODE_PREVIEW_TAB = actions.register("win.toggle_code_preview", label='Generated Code Preview', tooltip="Show a preview of the code generated for each Block in its " "Properties Dialog", preference_name='show_generated_code_tab', default=False, ) -TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY = ToggleAction( +TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY = actions.register("win.show_flowgraph_complexity", label='Show Flowgraph Complexity', tooltip="How many Balints is the flowgraph...", preference_name='show_flowgraph_complexity', default=False, ) -BLOCK_CREATE_HIER = Action( +BLOCK_CREATE_HIER = actions.register("win.block_create_hier", label='C_reate Hier', tooltip='Create hier block from selected blocks', - stock_id=Gtk.STOCK_CONNECT, -# keypresses=(Gdk.KEY_c, NO_MODS_MASK), + icon_name='document-new', ) -BLOCK_CUT = Action( +BLOCK_CUT = actions.register("win.block_cut", label='Cu_t', tooltip='Cut', - stock_id=Gtk.STOCK_CUT, - keypresses=(Gdk.KEY_x, Gdk.ModifierType.CONTROL_MASK), + icon_name='edit-cut', + keypresses=["<Ctrl>x"], ) -BLOCK_COPY = Action( +BLOCK_COPY = actions.register("win.block_copy", label='_Copy', tooltip='Copy', - stock_id=Gtk.STOCK_COPY, - keypresses=(Gdk.KEY_c, Gdk.ModifierType.CONTROL_MASK), + icon_name='edit-copy', + keypresses=["<Ctrl>c"], ) -BLOCK_PASTE = Action( +BLOCK_PASTE = actions.register("win.block_paste", label='_Paste', tooltip='Paste', - stock_id=Gtk.STOCK_PASTE, - keypresses=(Gdk.KEY_v, Gdk.ModifierType.CONTROL_MASK), + icon_name='edit-paste', + keypresses=["<Ctrl>v"], ) -ERRORS_WINDOW_DISPLAY = Action( +ERRORS_WINDOW_DISPLAY = actions.register("app.errors", label='Flowgraph _Errors', tooltip='View flow graph errors', - stock_id=Gtk.STOCK_DIALOG_ERROR, + icon_name='dialog-error', ) -TOGGLE_CONSOLE_WINDOW = ToggleAction( +TOGGLE_CONSOLE_WINDOW = actions.register("win.toggle_console_window", label='Show _Console Panel', tooltip='Toggle visibility of the console', - keypresses=(Gdk.KEY_r, Gdk.ModifierType.CONTROL_MASK), + keypresses=["<Ctrl>r"], preference_name='console_window_visible' ) -TOGGLE_BLOCKS_WINDOW = ToggleAction( +# TODO: Might be able to convert this to a Gio.PropertyAction eventually. +# actions would need to be defined in the correct class and not globally +TOGGLE_BLOCKS_WINDOW = actions.register("win.toggle_blocks_window", label='Show _Block Tree Panel', tooltip='Toggle visibility of the block tree widget', - keypresses=(Gdk.KEY_b, Gdk.ModifierType.CONTROL_MASK), + keypresses=["<Ctrl>b"], preference_name='blocks_window_visible' ) -TOGGLE_SCROLL_LOCK = ToggleAction( +TOGGLE_SCROLL_LOCK = actions.register("win.console.scroll_lock", label='Console Scroll _Lock', tooltip='Toggle scroll lock for the console window', preference_name='scroll_lock' ) -ABOUT_WINDOW_DISPLAY = Action( +ABOUT_WINDOW_DISPLAY = actions.register("app.about", label='_About', tooltip='About this program', - stock_id=Gtk.STOCK_ABOUT, + icon_name='help-about', ) -HELP_WINDOW_DISPLAY = Action( +HELP_WINDOW_DISPLAY = actions.register("app.help", label='_Help', tooltip='Usage tips', - stock_id=Gtk.STOCK_HELP, - keypresses=(Gdk.KEY_F1, NO_MODS_MASK), + icon_name='help-contents', + keypresses=["F1"], ) -TYPES_WINDOW_DISPLAY = Action( +TYPES_WINDOW_DISPLAY = actions.register("app.types", label='_Types', tooltip='Types color mapping', - stock_id=Gtk.STOCK_DIALOG_INFO, + icon_name='dialog-information', ) -FLOW_GRAPH_GEN = Action( +FLOW_GRAPH_GEN = actions.register("app.flowgraph.generate", label='_Generate', tooltip='Generate the flow graph', - stock_id=Gtk.STOCK_CONVERT, - keypresses=(Gdk.KEY_F5, NO_MODS_MASK), + icon_name='insert-object', + keypresses=["F5"], ) -FLOW_GRAPH_EXEC = Action( +FLOW_GRAPH_EXEC = actions.register("app.flowgraph.execute", label='_Execute', tooltip='Execute the flow graph', - stock_id=Gtk.STOCK_MEDIA_PLAY, - keypresses=(Gdk.KEY_F6, NO_MODS_MASK), + icon_name='media-playback-start', + keypresses=["F6"], ) -FLOW_GRAPH_KILL = Action( +FLOW_GRAPH_KILL = actions.register("app.flowgraph.kill", label='_Kill', tooltip='Kill the flow graph', - stock_id=Gtk.STOCK_STOP, - keypresses=(Gdk.KEY_F7, NO_MODS_MASK), + icon_name='media-playback-stop', + keypresses=["F7"], ) -FLOW_GRAPH_SCREEN_CAPTURE = Action( +FLOW_GRAPH_SCREEN_CAPTURE = actions.register("app.flowgraph.screen_capture", label='Screen Ca_pture', tooltip='Create a screen capture of the flow graph', - stock_id=Gtk.STOCK_PRINT, - keypresses=(Gdk.KEY_p, Gdk.ModifierType.CONTROL_MASK), -) -PORT_CONTROLLER_DEC = Action( - keypresses=(Gdk.KEY_minus, NO_MODS_MASK, Gdk.KEY_KP_Subtract, NO_MODS_MASK), -) -PORT_CONTROLLER_INC = Action( - keypresses=(Gdk.KEY_plus, NO_MODS_MASK, Gdk.KEY_KP_Add, NO_MODS_MASK), -) -BLOCK_INC_TYPE = Action( - keypresses=(Gdk.KEY_Down, NO_MODS_MASK), -) -BLOCK_DEC_TYPE = Action( - keypresses=(Gdk.KEY_Up, NO_MODS_MASK), -) -RELOAD_BLOCKS = Action( + icon_name='printer', + keypresses=["<Ctrl>p"], +) +PORT_CONTROLLER_DEC = actions.register("win.port_controller_dec") +PORT_CONTROLLER_INC = actions.register("win.port_controller_inc") +BLOCK_INC_TYPE = actions.register("win.block_inc_type") +BLOCK_DEC_TYPE = actions.register("win.block_dec_type") +RELOAD_BLOCKS = actions.register("app.reload_blocks", label='Reload _Blocks', tooltip='Reload Blocks', - stock_id=Gtk.STOCK_REFRESH + icon_name='view-refresh' ) -FIND_BLOCKS = Action( +FIND_BLOCKS = actions.register("win.find_blocks", label='_Find Blocks', tooltip='Search for a block by name (and key)', - stock_id=Gtk.STOCK_FIND, - keypresses=(Gdk.KEY_f, Gdk.ModifierType.CONTROL_MASK, - Gdk.KEY_slash, NO_MODS_MASK), + icon_name='edit-find', + keypresses=["<Ctrl>f", "slash"], ) -CLEAR_CONSOLE = Action( +CLEAR_CONSOLE = actions.register("win.console.clear", label='_Clear Console', tooltip='Clear Console', - stock_id=Gtk.STOCK_CLEAR, + icon_name='edit-clear', ) -SAVE_CONSOLE = Action( +SAVE_CONSOLE = actions.register("win.console.save", label='_Save Console', tooltip='Save Console', - stock_id=Gtk.STOCK_SAVE, + icon_name='edit-save', ) -OPEN_HIER = Action( +OPEN_HIER = actions.register("win.open_hier", label='Open H_ier', tooltip='Open the source of the selected hierarchical block', - stock_id=Gtk.STOCK_JUMP_TO, + icon_name='go-jump', ) -BUSSIFY_SOURCES = Action( +BUSSIFY_SOURCES = actions.register("win.bussify_sources", label='Toggle So_urce Bus', tooltip='Gang source ports into a single bus port', - stock_id=Gtk.STOCK_JUMP_TO, + icon_name='go-jump', ) -BUSSIFY_SINKS = Action( +BUSSIFY_SINKS = actions.register("win.bussify_sinks", label='Toggle S_ink Bus', tooltip='Gang sink ports into a single bus port', - stock_id=Gtk.STOCK_JUMP_TO, + icon_name='go-jump', ) -XML_PARSER_ERRORS_DISPLAY = Action( +XML_PARSER_ERRORS_DISPLAY = actions.register("app.xml_errors", label='_Parser Errors', tooltip='View errors that occurred while parsing XML files', - stock_id=Gtk.STOCK_DIALOG_ERROR, + icon_name='dialog-error', ) -FLOW_GRAPH_OPEN_QSS_THEME = Action( +FLOW_GRAPH_OPEN_QSS_THEME = actions.register("app.open_qss_theme", label='Set Default QT GUI _Theme', tooltip='Set a default QT Style Sheet file to use for QT GUI', - stock_id=Gtk.STOCK_OPEN, + icon_name='document-open', ) -TOOLS_RUN_FDESIGN = Action( +TOOLS_RUN_FDESIGN = actions.register("app.filter_design", label='Filter Design Tool', tooltip='Execute gr_filter_design', - stock_id=Gtk.STOCK_EXECUTE, -) -TOOLS_MORE_TO_COME = Action( - label='More to come', + icon_name='media-playback-start', ) +POST_HANDLER = actions.register("app.post_handler") +READY = actions.register("app.ready") 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) diff --git a/grc/gui/Bars.py b/grc/gui/Bars.py index 1510e109d2..2a8040f5d5 100644 --- a/grc/gui/Bars.py +++ b/grc/gui/Bars.py @@ -1,5 +1,5 @@ """ -Copyright 2007, 2008, 2009, 2015 Free Software Foundation, Inc. +Copyright 2007, 2008, 2009, 2015, 2016 Free Software Foundation, Inc. This file is part of GNU Radio GNU Radio Companion is free software; you can redistribute it and/or @@ -19,306 +19,299 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from __future__ import absolute_import -from gi.repository import Gtk, GObject +import logging + +from gi.repository import Gtk, GObject, Gio, GLib from . import Actions +log = logging.getLogger(__name__) + + +''' +# Menu/Toolbar Lists: +# +# Sub items can be 1 of 3 types +# - List Creates a section within the current menu +# - Tuple Creates a submenu using a string or action as the parent. The child +# can be another menu list or an identifier used to call a helper function. +# - Action Appends a new menu item to the current menu +# + +LIST_NAME = [ + [Action1, Action2], # New section + (Action3, [Action4, Action5]), # Submenu with action as parent + ("Label", [Action6, Action7]), # Submenu with string as parent + ("Label2", "helper") # Submenu with helper function. Calls 'create_helper()' +] +''' + + # The list of actions for the toolbar. -TOOLBAR_LIST = ( - (Actions.FLOW_GRAPH_NEW, 'flow_graph_new'), - (Actions.FLOW_GRAPH_OPEN, 'flow_graph_recent'), - Actions.FLOW_GRAPH_SAVE, - Actions.FLOW_GRAPH_CLOSE, - None, - Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR, - Actions.FLOW_GRAPH_SCREEN_CAPTURE, - None, - Actions.BLOCK_CUT, - Actions.BLOCK_COPY, - Actions.BLOCK_PASTE, - Actions.ELEMENT_DELETE, - None, - Actions.FLOW_GRAPH_UNDO, - Actions.FLOW_GRAPH_REDO, - None, - Actions.ERRORS_WINDOW_DISPLAY, - Actions.FLOW_GRAPH_GEN, - Actions.FLOW_GRAPH_EXEC, - Actions.FLOW_GRAPH_KILL, - None, - Actions.BLOCK_ROTATE_CCW, - Actions.BLOCK_ROTATE_CW, - None, - Actions.BLOCK_ENABLE, - Actions.BLOCK_DISABLE, - Actions.BLOCK_BYPASS, - Actions.TOGGLE_HIDE_DISABLED_BLOCKS, - None, - Actions.FIND_BLOCKS, - Actions.RELOAD_BLOCKS, - Actions.OPEN_HIER, -) +TOOLBAR_LIST = [ + [(Actions.FLOW_GRAPH_NEW, 'flow_graph_new'), Actions.FLOW_GRAPH_OPEN, + (Actions.FLOW_GRAPH_OPEN_RECENT, 'flow_graph_recent'), Actions.FLOW_GRAPH_SAVE, Actions.FLOW_GRAPH_CLOSE], + [Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR, Actions.FLOW_GRAPH_SCREEN_CAPTURE], + [Actions.BLOCK_CUT, Actions.BLOCK_COPY, Actions.BLOCK_PASTE, Actions.ELEMENT_DELETE], + [Actions.FLOW_GRAPH_UNDO, Actions.FLOW_GRAPH_REDO], + [Actions.ERRORS_WINDOW_DISPLAY, Actions.FLOW_GRAPH_GEN, Actions.FLOW_GRAPH_EXEC, Actions.FLOW_GRAPH_KILL], + [Actions.BLOCK_ROTATE_CCW, Actions.BLOCK_ROTATE_CW], + [Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, Actions.BLOCK_BYPASS, Actions.TOGGLE_HIDE_DISABLED_BLOCKS], + [Actions.FIND_BLOCKS, Actions.RELOAD_BLOCKS, Actions.OPEN_HIER] +] # The list of actions and categories for the menu bar. -MENU_BAR_LIST = ( - (Gtk.Action(name='File', label='_File'), [ - 'flow_graph_new', - Actions.FLOW_GRAPH_DUPLICATE, - Actions.FLOW_GRAPH_OPEN, - 'flow_graph_recent', - None, - Actions.FLOW_GRAPH_SAVE, - Actions.FLOW_GRAPH_SAVE_AS, - Actions.FLOW_GRAPH_SAVE_A_COPY, - None, - Actions.FLOW_GRAPH_SCREEN_CAPTURE, - None, - Actions.FLOW_GRAPH_CLOSE, - Actions.APPLICATION_QUIT, - ]), - (Gtk.Action(name='Edit', label='_Edit'), [ - Actions.FLOW_GRAPH_UNDO, - Actions.FLOW_GRAPH_REDO, - None, - Actions.BLOCK_CUT, - Actions.BLOCK_COPY, - Actions.BLOCK_PASTE, - Actions.ELEMENT_DELETE, - Actions.SELECT_ALL, - None, - Actions.BLOCK_ROTATE_CCW, - Actions.BLOCK_ROTATE_CW, - (Gtk.Action(name='Align', label='_Align', tooltip=None, stock_id=None), Actions.BLOCK_ALIGNMENTS), - None, - Actions.BLOCK_ENABLE, - Actions.BLOCK_DISABLE, - Actions.BLOCK_BYPASS, - None, - Actions.BLOCK_PARAM_MODIFY, - ]), - (Gtk.Action(name='View', label='_View'), [ - Actions.TOGGLE_BLOCKS_WINDOW, - None, - Actions.TOGGLE_CONSOLE_WINDOW, - Actions.TOGGLE_SCROLL_LOCK, - Actions.SAVE_CONSOLE, - Actions.CLEAR_CONSOLE, - None, - Actions.TOGGLE_HIDE_VARIABLES, - Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR, - Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR, - None, - Actions.TOGGLE_HIDE_DISABLED_BLOCKS, - Actions.TOGGLE_AUTO_HIDE_PORT_LABELS, - Actions.TOGGLE_SNAP_TO_GRID, - Actions.TOGGLE_SHOW_BLOCK_COMMENTS, - None, - Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB, - None, - Actions.ERRORS_WINDOW_DISPLAY, - Actions.FIND_BLOCKS, - ]), - (Gtk.Action(name='Run', label='_Run'), [ - Actions.FLOW_GRAPH_GEN, - Actions.FLOW_GRAPH_EXEC, - Actions.FLOW_GRAPH_KILL, - ]), - (Gtk.Action(name='Tools', label='_Tools'), [ - Actions.TOOLS_RUN_FDESIGN, - Actions.FLOW_GRAPH_OPEN_QSS_THEME, - None, - Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY, - None, - Actions.TOOLS_MORE_TO_COME, - ]), - (Gtk.Action(name='Help', label='_Help'), [ - Actions.HELP_WINDOW_DISPLAY, - Actions.TYPES_WINDOW_DISPLAY, - Actions.XML_PARSER_ERRORS_DISPLAY, - None, - Actions.ABOUT_WINDOW_DISPLAY, - ]), -) +MENU_BAR_LIST = [ + ('_File', [ + [(Actions.FLOW_GRAPH_NEW, 'flow_graph_new'), Actions.FLOW_GRAPH_DUPLICATE, + Actions.FLOW_GRAPH_OPEN, (Actions.FLOW_GRAPH_OPEN_RECENT, 'flow_graph_recent')], + [Actions.FLOW_GRAPH_SAVE, Actions.FLOW_GRAPH_SAVE_AS, Actions.FLOW_GRAPH_SAVE_COPY], + [Actions.FLOW_GRAPH_SCREEN_CAPTURE], + [Actions.FLOW_GRAPH_CLOSE, Actions.APPLICATION_QUIT] + ]), + ('_Edit', [ + [Actions.FLOW_GRAPH_UNDO, Actions.FLOW_GRAPH_REDO], + [Actions.BLOCK_CUT, Actions.BLOCK_COPY, Actions.BLOCK_PASTE, Actions.ELEMENT_DELETE, Actions.SELECT_ALL], + [Actions.BLOCK_ROTATE_CCW, Actions.BLOCK_ROTATE_CW, ('_Align', Actions.BLOCK_ALIGNMENTS)], + [Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, Actions.BLOCK_BYPASS], + [Actions.BLOCK_PARAM_MODIFY] + ]), + ('_View', [ + [Actions.TOGGLE_BLOCKS_WINDOW], + [Actions.TOGGLE_CONSOLE_WINDOW, Actions.TOGGLE_SCROLL_LOCK, Actions.SAVE_CONSOLE, Actions.CLEAR_CONSOLE], + [Actions.TOGGLE_HIDE_VARIABLES, Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR, Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR], + [Actions.TOGGLE_HIDE_DISABLED_BLOCKS, Actions.TOGGLE_AUTO_HIDE_PORT_LABELS, Actions.TOGGLE_SNAP_TO_GRID, Actions.TOGGLE_SHOW_BLOCK_COMMENTS], + [Actions.TOGGLE_SHOW_CODE_PREVIEW_TAB], + [Actions.ERRORS_WINDOW_DISPLAY, Actions.FIND_BLOCKS], + ]), + ('_Run', [ + Actions.FLOW_GRAPH_GEN, Actions.FLOW_GRAPH_EXEC, Actions.FLOW_GRAPH_KILL + ]), + ('_Tools', [ + [Actions.TOOLS_RUN_FDESIGN, Actions.FLOW_GRAPH_OPEN_QSS_THEME], + [Actions.TOGGLE_SHOW_FLOWGRAPH_COMPLEXITY] + ]), + ('_Help', [ + [Actions.HELP_WINDOW_DISPLAY, Actions.TYPES_WINDOW_DISPLAY, Actions.XML_PARSER_ERRORS_DISPLAY], + [Actions.ABOUT_WINDOW_DISPLAY] + ])] # The list of actions for the context menu. CONTEXT_MENU_LIST = [ - Actions.BLOCK_CUT, - Actions.BLOCK_COPY, - Actions.BLOCK_PASTE, - Actions.ELEMENT_DELETE, - None, - Actions.BLOCK_ROTATE_CCW, - Actions.BLOCK_ROTATE_CW, - Actions.BLOCK_ENABLE, - Actions.BLOCK_DISABLE, - Actions.BLOCK_BYPASS, - None, - (Gtk.Action(name='More', label='_More'), [ - Actions.BLOCK_CREATE_HIER, - Actions.OPEN_HIER, - None, - Actions.BUSSIFY_SOURCES, - Actions.BUSSIFY_SINKS, - ]), - Actions.BLOCK_PARAM_MODIFY + [Actions.BLOCK_CUT, Actions.BLOCK_COPY, Actions.BLOCK_PASTE, Actions.ELEMENT_DELETE], + [Actions.BLOCK_ROTATE_CCW, Actions.BLOCK_ROTATE_CW, Actions.BLOCK_ENABLE, Actions.BLOCK_DISABLE, Actions.BLOCK_BYPASS], + [("_More", [ + [Actions.BLOCK_CREATE_HIER, Actions.OPEN_HIER], + [Actions.BUSSIFY_SOURCES, Actions.BUSSIFY_SINKS]] + )], + [Actions.BLOCK_PARAM_MODIFY], ] -class SubMenuCreator(object): +class SubMenuHelper(object): + ''' Generates custom submenus for the main menu or toolbar. ''' - def __init__(self, generate_modes, action_handler_callback): - self.generate_modes = generate_modes - self.action_handler_callback = action_handler_callback - self.submenus = [] + def __init__(self): + self.submenus = {} - def create_submenu(self, action_tuple, item): - func = getattr(self, '_fill_' + action_tuple[1] + "_submenu") - self.submenus.append((action_tuple[0], func, item)) - self.refresh_submenus() + def build_submenu(self, name, obj, set_func): + # Get the correct helper function + create_func = getattr(self, "create_{}".format(name)) + # Save the helper functions for rebuilding the menu later + self.submenus[name] = (create_func, obj, set_func) + # Actually build the menu + set_func(obj, create_func()) def refresh_submenus(self): - for action, func, item in self.submenus: - try: - item.set_property("menu", func(action)) - except TypeError: - item.set_property("submenu", func(action)) - item.set_property('sensitive', True) - - def callback_adaptor(self, item, action_key): - action, key = action_key - self.action_handler_callback(action, key) - - def _fill_flow_graph_new_submenu(self, action): - """Sub menu to create flow-graph with pre-set generate mode""" - menu = Gtk.Menu() - for key, name, default in self.generate_modes: - if default: - item = Actions.FLOW_GRAPH_NEW.create_menu_item() - item.set_label(name) - else: - item = Gtk.MenuItem(name=name, use_underline=False) - item.connect('activate', self.callback_adaptor, (action, key)) - menu.append(item) - menu.show_all() + for name in self.submenus: + create_func, obj, set_func = self.submenus[name] + print ("refresh", create_func, obj, set_func) + set_func(obj, create_func()) + + def create_flow_graph_new(self): + """ Different flowgraph types """ + menu = Gio.Menu() + platform = Gtk.Application.get_default().platform + generate_modes = platform.get_generate_options() + for key, name, default in generate_modes: + target = "app.flowgraph.new::{}".format(key) + menu.append(name, target) return menu - def _fill_flow_graph_recent_submenu(self, action): - """menu showing recent flow-graphs""" - menu = Gtk.Menu() + def create_flow_graph_recent(self): + """ Recent flow graphs """ + config = Gtk.Application.get_default().config recent_files = config.get_recent_files() + menu = Gio.Menu() if len(recent_files) > 0: + files = Gio.Menu() for i, file_name in enumerate(recent_files): - item = Gtk.MenuItem(name="%d. %s" % (i+1, file_name), use_underline=False) - item.connect('activate', self.callback_adaptor, - (action, file_name)) - menu.append(item) - menu.show_all() - return menu - return None + target = "app.flowgraph.open_recent::{}".format(file_name) + files.append(file_name, target) + menu.append_section(None, files) + #clear = Gio.Menu() + #clear.append("Clear recent files", "app.flowgraph.clear_recent") + #menu.append_section(None, clear) + else: + # Show an empty menu + menuitem = Gio.MenuItem.new("No items found", "app.none") + menu.append_item(menuitem) + return menu -class Toolbar(Gtk.Toolbar, SubMenuCreator): - """The gtk toolbar with actions added from the toolbar list.""" +class MenuHelper(SubMenuHelper): + """ + Recursively builds a menu from a given list of actions. - def __init__(self, generate_modes, action_handler_callback): - """ - Parse the list of action names in the toolbar list. - Look up the action for each name in the action list and add it to the - toolbar. - """ - GObject.GObject.__init__(self) - self.set_style(Gtk.ToolbarStyle.ICONS) - SubMenuCreator.__init__(self, generate_modes, action_handler_callback) - - for action in TOOLBAR_LIST: - if isinstance(action, tuple) and isinstance(action[1], str): - # create a button with a sub-menu - # TODO: Fix later - #action[0].set_tool_item_type(Gtk.MenuToolButton) - item = action[0].create_tool_item() - #self.create_submenu(action, item) - #self.refresh_submenus() - - elif action is None: - item = Gtk.SeparatorToolItem() - - else: - #TODO: Fix later - #action.set_tool_item_type(Gtk.ToolButton) - item = action.create_tool_item() - # this reset of the tooltip property is required - # (after creating the tool item) for the tooltip to show - action.set_property('tooltip', action.get_property('tooltip')) - self.add(item) - - -class MenuHelperMixin(object): - """Mixin class to help build menus from the above action lists""" - - def _fill_menu(self, actions, menu=None): - """Create a menu from list of actions""" - menu = menu or Gtk.Menu() + Args: + - actions: List of actions to build the menu + - menu: Current menu being built + + Notes: + - Tuple: Create a new submenu from the parent (1st) and child (2nd) elements + - Action: Append to current menu + - List: Start a new section + """ + + def __init__(self): + SubMenuHelper.__init__(self) + + def build_menu(self, actions, menu): for item in actions: if isinstance(item, tuple): - menu_item = self._make_sub_menu(*item) - elif isinstance(item, str): - menu_item = getattr(self, 'create_' + item)() - elif item is None: - menu_item = Gtk.SeparatorMenuItem() - else: - menu_item = item.create_menu_item() - menu.append(menu_item) - menu.show_all() - return menu - - def _make_sub_menu(self, main, actions): - """Create a submenu from a main action and a list of actions""" - main = main.create_menu_item() - main.set_submenu(self._fill_menu(actions)) - return main + # Create a new submenu + parent, child = (item[0], item[1]) + + # Create the parent + label, target = (parent, None) + if isinstance(parent, Actions.Action): + label = parent.label + target = "{}.{}".format(parent.prefix, parent.name) + menuitem = Gio.MenuItem.new(label, None) + if hasattr(parent, "icon_name"): + menuitem.set_icon(Gio.Icon.new_for_string(parent.icon_name)) + + # Create the new submenu + if isinstance(child, list): + submenu = Gio.Menu() + self.build_menu(child, submenu) + menuitem.set_submenu(submenu) + elif isinstance(child, str): + # Child is the name of the submenu to create + def set_func(obj, menu): + obj.set_submenu(menu) + self.build_submenu(child, menuitem, set_func) + menu.append_item(menuitem) + + elif isinstance(item, list): + # Create a new section + section = Gio.Menu() + self.build_menu(item, section) + menu.append_section(None, section) + + elif isinstance(item, Actions.Action): + # Append a new menuitem + target = "{}.{}".format(item.prefix, item.name) + menuitem = Gio.MenuItem.new(item.label, target) + if item.icon_name: + menuitem.set_icon(Gio.Icon.new_for_string(item.icon_name)) + menu.append_item(menuitem) + + +class ToolbarHelper(SubMenuHelper): + """ + Builds a toolbar from a given list of actions. + + Args: + - actions: List of actions to build the menu + - item: Current menu being built + + Notes: + - Tuple: Create a new submenu from the parent (1st) and child (2nd) elements + - Action: Append to current menu + - List: Start a new section + """ + def __init__(self): + SubMenuHelper.__init__(self) -class MenuBar(Gtk.MenuBar, MenuHelperMixin, SubMenuCreator): - """The gtk menu bar with actions added from the menu bar list.""" + def build_toolbar(self, actions, current): + for item in actions: + if isinstance(item, list): + # Toolbar's don't have sections like menus, so call this function + # recursively with the "section" and just append a separator. + self.build_toolbar(item, self) + current.insert(Gtk.SeparatorToolItem.new(), -1) + + elif isinstance(item, tuple): + parent, child = (item[0], item[1]) + # Create an item with a submenu + # Generate the submenu and add to the item. + # Add the item to the toolbar + button = Gtk.MenuToolButton.new() + # The tuple should be made up of an Action and something. + button.set_label(parent.label) + button.set_tooltip_text(parent.tooltip) + button.set_icon_name(parent.icon_name) + + target = "{}.{}".format(parent.prefix, parent.name) + button.set_action_name(target) + + def set_func(obj, menu): + obj.set_menu(Gtk.Menu.new_from_model(menu)) + + self.build_submenu(child, button, set_func) + current.insert(button, -1) + + elif isinstance(item, Actions.Action): + button = Gtk.ToolButton.new() + button.set_label(item.label) + button.set_tooltip_text(item.tooltip) + button.set_icon_name(item.icon_name) + target = "{}.{}".format(item.prefix, item.name) + button.set_action_name(target) + current.insert(button, -1) + + +class Menu(Gio.Menu, MenuHelper): + """ Main Menu """ - def __init__(self, generate_modes, action_handler_callback): - """ - Parse the list of submenus from the menubar list. - For each submenu, get a list of action names. - Look up the action for each name in the action list and add it to the - submenu. Add the submenu to the menu bar. - """ + def __init__(self): GObject.GObject.__init__(self) - SubMenuCreator.__init__(self, generate_modes, action_handler_callback) - for main_action, actions in MENU_BAR_LIST: - self.append(self._make_sub_menu(main_action, actions)) + MenuHelper.__init__(self) - def create_flow_graph_new(self): - main = Gtk.ImageMenuItem(label=Gtk.STOCK_NEW) - main.set_label(Actions.FLOW_GRAPH_NEW.get_label()) - func = self._fill_flow_graph_new_submenu - self.submenus.append((Actions.FLOW_GRAPH_NEW, func, main)) - self.refresh_submenus() - return main + log.debug("Building the main menu") + self.build_menu(MENU_BAR_LIST, self) - def create_flow_graph_recent(self): - main = Gtk.ImageMenuItem(label=Gtk.STOCK_OPEN) - main.set_label(Actions.FLOW_GRAPH_OPEN_RECENT.get_label()) - func = self._fill_flow_graph_recent_submenu - self.submenus.append((Actions.FLOW_GRAPH_OPEN, func, main)) - self.refresh_submenus() - if main.get_submenu() is None: - main.set_property('sensitive', False) - return main +class ContextMenu(Gio.Menu, MenuHelper): + """ Context menu for the drawing area """ + + def __init__(self): + GObject.GObject.__init__(self) + + log.debug("Building the context menu") + self.build_menu(CONTEXT_MENU_LIST, self) -class ContextMenu(Gtk.Menu, MenuHelperMixin): - """The gtk menu with actions added from the context menu list.""" + +class Toolbar(Gtk.Toolbar, ToolbarHelper): + """ The gtk toolbar with actions added from the toolbar list. """ def __init__(self): + """ + Parse the list of action names in the toolbar list. + Look up the action for each name in the action list and add it to the + toolbar. + """ GObject.GObject.__init__(self) - self._fill_menu(CONTEXT_MENU_LIST, self) + ToolbarHelper.__init__(self) + + self.set_style(Gtk.ToolbarStyle.ICONS) + #self.get_style_context().add_class(Gtk.STYLE_CLASS_PRIMARY_TOOLBAR) + + #SubMenuCreator.__init__(self) + self.build_toolbar(TOOLBAR_LIST, self) diff --git a/grc/gui/Config.py b/grc/gui/Config.py index c4d395c0b3..6135296660 100644 --- a/grc/gui/Config.py +++ b/grc/gui/Config.py @@ -48,7 +48,7 @@ class Config(CoreConfig): self.install_prefix = install_prefix Constants.update_font_size(self.font_size) - self.parser = configparser.SafeConfigParser() + self.parser = configparser.ConfigParser() for section in ['main', 'files_open', 'files_recent']: try: self.parser.add_section(section) diff --git a/grc/gui/Console.py b/grc/gui/Console.py index d40f300a8a..0ae862493d 100644 --- a/grc/gui/Console.py +++ b/grc/gui/Console.py @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from __future__ import absolute_import import os +import logging import gi gi.require_version('Gtk', '3.0') @@ -31,9 +32,14 @@ from .Dialogs import TextDisplay, MessageDialogWrapper from ..core import Messages +log = logging.getLogger(__name__) + + class Console(Gtk.ScrolledWindow): def __init__(self): Gtk.ScrolledWindow.__init__(self) + log.debug("console()") + self.app = Gtk.Application.get_default() self.text_display = TextDisplay() diff --git a/grc/gui/DrawingArea.py b/grc/gui/DrawingArea.py index 94dfcf1370..2403fa2844 100644 --- a/grc/gui/DrawingArea.py +++ b/grc/gui/DrawingArea.py @@ -23,6 +23,7 @@ from gi.repository import Gtk, Gdk from .canvas.colors import FLOWGRAPH_BACKGROUND_COLOR from . import Constants +from . import Actions class DrawingArea(Gtk.DrawingArea): @@ -42,6 +43,7 @@ class DrawingArea(Gtk.DrawingArea): Gtk.DrawingArea.__init__(self) self._flow_graph = flow_graph + self.set_property('can_focus', True) self.zoom_factor = 1.0 self._update_after_zoom = False @@ -66,6 +68,11 @@ class DrawingArea(Gtk.DrawingArea): # Gdk.EventMask.FOCUS_CHANGE_MASK ) + # This may not be the correct place to be handling the user events + # Should this be in the page instead? + # Or should more of the page functionality move here? + self.connect('key_press_event', self._handle_key_press) + # setup drag and drop self.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.COPY) self.connect('drag-data-received', self._handle_drag_data_received) @@ -78,12 +85,14 @@ class DrawingArea(Gtk.DrawingArea): def _handle_notify_event(widget, event, focus_flag): self._focus_flag = focus_flag + self.connect('leave-notify-event', _handle_notify_event, False) self.connect('enter-notify-event', _handle_notify_event, True) # todo: fix # self.set_flags(Gtk.CAN_FOCUS) # self.set_can_focus(True) # self.connect('focus-out-event', self._handle_focus_lost_event) + ########################################################################## # Handlers ########################################################################## @@ -155,6 +164,41 @@ class DrawingArea(Gtk.DrawingArea): coordinate=self._translate_event_coords(event), ) + def _handle_key_press(self, widget, event): + """ + Handle specific keypresses when the drawing area has focus that + triggers actions by the user. + """ + key = event.keyval + mod = event.state + + # Setup a map of the accelerator keys to the action to trigger + accels = { + Gtk.accelerator_parse('d'): Actions.BLOCK_DISABLE, + Gtk.accelerator_parse('e'): Actions.BLOCK_ENABLE, + Gtk.accelerator_parse('b'): Actions.BLOCK_BYPASS, + Gtk.accelerator_parse('c'): Actions.BLOCK_CREATE_HIER, + Gtk.accelerator_parse('Up'): Actions.BLOCK_DEC_TYPE, + Gtk.accelerator_parse('Down'): Actions.BLOCK_INC_TYPE, + Gtk.accelerator_parse('Left'): Actions.BLOCK_ROTATE_CCW, + Gtk.accelerator_parse('Right'): Actions.BLOCK_ROTATE_CW, + Gtk.accelerator_parse('minus'): Actions.PORT_CONTROLLER_DEC, + Gtk.accelerator_parse('plus'): Actions.PORT_CONTROLLER_INC, + Gtk.accelerator_parse('Add'): Actions.PORT_CONTROLLER_INC, + Gtk.accelerator_parse('Subtract'): Actions.PORT_CONTROLLER_DEC, + Gtk.accelerator_parse('Return'): Actions.BLOCK_PARAM_MODIFY, + Gtk.accelerator_parse('<Shift>t'): Actions.BLOCK_VALIGN_TOP, + Gtk.accelerator_parse('<Shift>m'): Actions.BLOCK_VALIGN_MIDDLE, + Gtk.accelerator_parse('<Shift>b'): Actions.BLOCK_VALIGN_BOTTOM, + Gtk.accelerator_parse('<Shift>l'): Actions.BLOCK_HALIGN_LEFT, + Gtk.accelerator_parse('<Shift>c'): Actions.BLOCK_HALIGN_CENTER, + Gtk.accelerator_parse('<Shift>r'): Actions.BLOCK_HALIGN_RIGHT, + } + # Not sold on this. + if (key, mod) in accels: + accels[(key, mod)]() + return True + def _update_size(self): w, h = self._flow_graph.get_extents()[2:] self.set_size_request(w * self.zoom_factor + 100, h * self.zoom_factor + 100) diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py index 5bb4c52a07..c13a59a16d 100644 --- a/grc/gui/MainWindow.py +++ b/grc/gui/MainWindow.py @@ -35,6 +35,7 @@ from .Notebook import Notebook, Page from ..core import Messages + log = logging.getLogger(__name__) @@ -49,7 +50,7 @@ class MainWindow(Gtk.ApplicationWindow): CONSOLE = 1 VARIABLES = 2 - def __init__(self, app, platform, action_handler_callback): + def __init__(self, app, platform): """ MainWindow constructor Setup the menu, toolbar, flow graph editor notebook, block selection window... @@ -58,18 +59,29 @@ class MainWindow(Gtk.ApplicationWindow): log.debug("__init__()") self._platform = platform + self.app = app self.config = platform.config + # Add all "win" actions to the local + win_actions = filter(lambda x: x.startswith("win."), Actions.get_actions()) + map(lambda x: self.add_action(Actions.actions[x]), win_actions) + # Setup window vbox = Gtk.VBox() self.add(vbox) # Create the menu bar and toolbar generate_modes = platform.get_generate_options() - self.add_accel_group(Actions.get_accel_group()) - self.menu_bar = Bars.MenuBar(generate_modes, action_handler_callback) + + # This needs to be replaced + # Have an option for either the application menu or this menu + self.menu_bar = Gtk.MenuBar.new_from_model(Bars.Menu()) vbox.pack_start(self.menu_bar, False, False, 0) - self.tool_bar = Bars.Toolbar(generate_modes, action_handler_callback) + + self.tool_bar = Bars.Toolbar() + self.tool_bar.set_hexpand(True) + # Show the toolbar + self.tool_bar.show() vbox.pack_start(self.tool_bar, False, False, 0) # Main parent container for the different panels @@ -126,9 +138,7 @@ class MainWindow(Gtk.ApplicationWindow): self.left_subpanel.set_position(self.config.variable_editor_position()) self.show_all() - self.console.hide() - self.vars.hide() - self.btwin.hide() + log.debug("Main window ready") ############################################################ # Event Handlers @@ -206,7 +216,6 @@ class MainWindow(Gtk.ApplicationWindow): def current_page(self, page): self.notebook.current_page = page - def add_console_line(self, line): """ Place line at the end of the text buffer, then scroll its window all the way down. diff --git a/grc/gui/Notebook.py b/grc/gui/Notebook.py index e78b748326..ef08961036 100644 --- a/grc/gui/Notebook.py +++ b/grc/gui/Notebook.py @@ -19,6 +19,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA from __future__ import absolute_import import os +import logging from gi.repository import Gtk, Gdk, GObject @@ -28,15 +29,24 @@ from .Constants import MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT from .DrawingArea import DrawingArea +log = logging.getLogger(__name__) + + class Notebook(Gtk.Notebook): def __init__(self): Gtk.Notebook.__init__(self) - + log.debug("notebook()") + self.app = Gtk.Application.get_default() self.current_page = None + self.set_show_border(False) self.set_scrollable(True) self.connect('switch-page', self._handle_page_change) + self.add_events(Gdk.EventMask.SCROLL_MASK) + self.connect('scroll-event', self._handle_scroll) + self._ignore_consecutive_scrolls = 0 + def _handle_page_change(self, notebook, page, page_num): """ Handle a page change. When the user clicks on a new tab, @@ -51,6 +61,26 @@ class Notebook(Gtk.Notebook): self.current_page = self.get_nth_page(page_num) Actions.PAGE_CHANGE() + def _handle_scroll(self, widget, event): + # Not sure how to handle this at the moment. + natural = True + # Slow it down + if self._ignore_consecutive_scrolls == 0: + if event.direction in (Gdk.ScrollDirection.UP, Gdk.ScrollDirection.LEFT): + if natural: + self.prev_page() + else: + self.next_page() + elif event.direction in (Gdk.ScrollDirection.DOWN, Gdk.ScrollDirection.RIGHT): + if natural: + self.next_page() + else: + self.prev_page() + self._ignore_consecutive_scrolls = 3 + else: + self._ignore_consecutive_scrolls -= 1 + return False + class Page(Gtk.HBox): """A page in the notebook.""" @@ -99,20 +129,12 @@ class Page(Gtk.HBox): self.scrolled_window = Gtk.ScrolledWindow() self.scrolled_window.set_size_request(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT) self.scrolled_window.set_policy(Gtk.PolicyType.ALWAYS, Gtk.PolicyType.ALWAYS) - self.scrolled_window.connect('key-press-event', self._handle_scroll_window_key_press) + self.scrolled_window.add(self.drawing_area) self.pack_start(self.scrolled_window, True, True, 0) - self.show_all() - def _handle_scroll_window_key_press(self, widget, event): - """forward Ctrl-PgUp/Down to NotebookPage (switch fg instead of horiz. scroll""" - is_ctrl_pg = ( - event.state & Gdk.ModifierType.CONTROL_MASK and - event.keyval in (Gdk.KEY_Page_Up, Gdk.KEY_Page_Down) - ) - if is_ctrl_pg: - return self.get_parent().event(event) + def get_generator(self): """ diff --git a/grc/gui/ParamWidgets.py b/grc/gui/ParamWidgets.py index b56eace402..71cb1b7a7d 100644 --- a/grc/gui/ParamWidgets.py +++ b/grc/gui/ParamWidgets.py @@ -25,7 +25,7 @@ from . import Utils style_provider = Gtk.CssProvider() -style_provider.load_from_data(""" +style_provider.load_from_data(b""" #dtype_complex { background-color: #3399FF; } #dtype_real { background-color: #FF8C69; } #dtype_float { background-color: #FF8C69; } diff --git a/grc/gui/StateCache.py b/grc/gui/StateCache.py index b109a1281b..ef260d6091 100644 --- a/grc/gui/StateCache.py +++ b/grc/gui/StateCache.py @@ -99,5 +99,5 @@ class StateCache(object): """ Update the undo and redo actions based on the number of next and prev states. """ - Actions.FLOW_GRAPH_REDO.set_sensitive(self.num_next_states != 0) - Actions.FLOW_GRAPH_UNDO.set_sensitive(self.num_prev_states != 0) + Actions.FLOW_GRAPH_REDO.set_enabled(self.num_next_states != 0) + Actions.FLOW_GRAPH_UNDO.set_enabled(self.num_prev_states != 0) diff --git a/grc/gui/Utils.py b/grc/gui/Utils.py index 3fffe6dd20..969f3759f2 100644 --- a/grc/gui/Utils.py +++ b/grc/gui/Utils.py @@ -21,6 +21,7 @@ from __future__ import absolute_import from gi.repository import GLib import cairo +import six from .canvas.colors import FLOWGRAPH_BACKGROUND_COLOR from . import Constants @@ -107,7 +108,10 @@ def encode(value): Older versions of glib seg fault if the last byte starts a multi-byte character. """ - valid_utf8 = value.decode('utf-8', errors='replace').encode('utf-8') + if six.PY2: + valid_utf8 = value.decode('utf-8', errors='replace').encode('utf-8') + else: + valid_utf8 = value return GLib.markup_escape_text(valid_utf8) diff --git a/grc/gui/VariableEditor.py b/grc/gui/VariableEditor.py index 484395be8c..e310676420 100644 --- a/grc/gui/VariableEditor.py +++ b/grc/gui/VariableEditor.py @@ -254,7 +254,9 @@ class VariableEditor(Gtk.VBox): elif key == self.ADD_VARIABLE: self.emit('create_new_block', 'variable') elif key == self.OPEN_PROPERTIES: - Actions.BLOCK_PARAM_MODIFY(self._block) + # TODO: This probably isn't working because the action doesn't expect a parameter + #Actions.BLOCK_PARAM_MODIFY() + pass elif key == self.DELETE_BLOCK: self.emit('remove_block', self._block.get_id()) elif key == self.DELETE_CONFIRM: diff --git a/grc/gui/canvas/param.py b/grc/gui/canvas/param.py index 2ec99e70d8..b027b7653a 100644 --- a/grc/gui/canvas/param.py +++ b/grc/gui/canvas/param.py @@ -105,7 +105,7 @@ class Param(CoreParam): if style < 0: # Front truncate string = '...' + string[3-max_len:] elif style == 0: # Center truncate - string = string[:max_len/2 - 3] + '...' + string[-max_len/2:] + string = string[:max_len//2 - 3] + '...' + string[-max_len//2:] elif style > 0: # Rear truncate string = string[:max_len-3] + '...' return string diff --git a/grc/main.py b/grc/main.py index 305e8b8f78..224a9b11e8 100755 --- a/grc/main.py +++ b/grc/main.py @@ -22,10 +22,6 @@ gi.require_version('Gtk', '3.0') gi.require_version('PangoCairo', '1.0') from gi.repository import Gtk -from gnuradio import gr -from .gui.Platform import Platform -from .gui.Application import Application - VERSION_AND_DISCLAIMER_TEMPLATE = """\ GNU Radio Companion %s @@ -45,6 +41,7 @@ LOG_LEVELS = { def main(): + from gnuradio import gr parser = argparse.ArgumentParser( description=VERSION_AND_DISCLAIMER_TEMPLATE % gr.version()) parser.add_argument('flow_graphs', nargs='*') @@ -65,7 +62,8 @@ def main(): console = logging.StreamHandler() console.setLevel(LOG_LEVELS[args.log]) - msg_format = '[%(asctime)s - %(levelname)8s] --- %(message)s (%(filename)s:%(lineno)s)' + #msg_format = '[%(asctime)s - %(levelname)8s] --- %(message)s (%(filename)s:%(lineno)s)' + msg_format = '[%(levelname)s] %(message)s (%(filename)s:%(lineno)s)' date_format = '%I:%M' formatter = logging.Formatter(msg_format, datefmt=date_format) @@ -73,8 +71,14 @@ def main(): console.setFormatter(formatter) log.addHandler(console) - log.debug("Loading platform") + log.debug("Running main") + # Delay importing until the logging is setup + # Otherwise, the decorators could not use logging. + from .gui.Platform import Platform + from .gui.Application import Application + + log.debug("Loading platform") platform = Platform( version=gr.version(), version_parts=(gr.major_version(), gr.api_version(), gr.minor_version()), -- cgit v1.2.3