commit-gnuradio
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Commit-gnuradio] [gnuradio] 71/101: grc: gtk3: fixup dialogs


From: git
Subject: [Commit-gnuradio] [gnuradio] 71/101: grc: gtk3: fixup dialogs
Date: Thu, 16 Mar 2017 14:58:09 +0000 (UTC)

This is an automated email from the git hooks/post-receive script.

jcorgan pushed a commit to branch python3
in repository gnuradio.

commit cbe1e43b0f0d1ee0d356b7110700400578855ac6
Author: Glenn Richardson <address@hidden>
Date:   Tue Aug 2 22:45:02 2016 +0200

    grc: gtk3: fixup dialogs
---
 grc/gui/ActionHandler.py |  30 ++--
 grc/gui/Dialogs.py       | 401 +++++++++++++++++++++++++++++------------------
 grc/gui/FileDialogs.py   | 101 ++++++------
 grc/gui/FlowGraph.py     |   6 +-
 grc/gui/MainWindow.py    |   8 +-
 grc/gui/ParamWidgets.py  |   2 +-
 grc/gui/PropsDialog.py   |   1 +
 7 files changed, 326 insertions(+), 223 deletions(-)

diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py
index 237dd6c..9e57565 100644
--- a/grc/gui/ActionHandler.py
+++ b/grc/gui/ActionHandler.py
@@ -26,10 +26,7 @@ import subprocess
 from gi.repository import Gtk
 from gi.repository import GObject
 
-from . import Dialogs, Preferences, Actions, Executor, Constants
-from .FileDialogs import (OpenFlowGraphFileDialog, SaveFlowGraphFileDialog,
-                          SaveConsoleFileDialog, SaveScreenShotDialog,
-                          OpenQSSFileDialog)
+from . import Dialogs, Preferences, Actions, Executor, Constants, FileDialogs
 from .MainWindow import MainWindow
 from .ParserErrorsDialog import ParserErrorsDialog
 from .PropsDialog import PropsDialog
@@ -379,13 +376,13 @@ class ActionHandler:
         # Window stuff
         ##################################################
         elif action == Actions.ABOUT_WINDOW_DISPLAY:
-            Dialogs.AboutDialog(self.platform.config)
+            Dialogs.show_about(main, self.platform.config)
         elif action == Actions.HELP_WINDOW_DISPLAY:
-            Dialogs.HelpDialog()
+            Dialogs.show_help(main)
         elif action == Actions.TYPES_WINDOW_DISPLAY:
-            Dialogs.TypesDialog(self.platform)
+            Dialogs.show_types(main)
         elif action == Actions.ERRORS_WINDOW_DISPLAY:
-            Dialogs.ErrorsDialog(flow_graph)
+            Dialogs.ErrorsDialog(main, flow_graph).run_and_destroy()
         elif action == Actions.TOGGLE_CONSOLE_WINDOW:
             main.update_panel_visibility(main.CONSOLE, action.get_active())
             action.save_to_preferences()
@@ -401,7 +398,7 @@ class ActionHandler:
         elif action == Actions.CLEAR_CONSOLE:
             main.text_display.clear()
         elif action == Actions.SAVE_CONSOLE:
-            file_path = SaveConsoleFileDialog(page.file_path).run()
+            file_path = FileDialogs.SaveConsole(main, page.file_path).run()
             if file_path is not None:
                 main.text_display.save(file_path)
         elif action == Actions.TOGGLE_HIDE_DISABLED_BLOCKS:
@@ -437,7 +434,7 @@ class ActionHandler:
                     # Leave it enabled
                     action.set_sensitive(True)
                     action.set_active(True)
-            
#Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR.set_sensitive(action.get_active())
+            # 
Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR.set_sensitive(action.get_active())
             action.save_to_preferences()
         elif action == Actions.TOGGLE_FLOW_GRAPH_VAR_EDITOR_SIDEBAR:
             if self.init:
@@ -511,7 +508,7 @@ class ActionHandler:
                 
flow_graph._options_block.get_param('generate_options').set_value(args[0])
                 flow_graph_update()
         elif action == Actions.FLOW_GRAPH_OPEN:
-            file_paths = args if args else 
OpenFlowGraphFileDialog(page.file_path).run()
+            file_paths = args if args 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))
@@ -519,8 +516,8 @@ class ActionHandler:
                     main.tool_bar.refresh_submenus()
                     main.menu_bar.refresh_submenus()
         elif action == Actions.FLOW_GRAPH_OPEN_QSS_THEME:
-            file_paths = OpenQSSFileDialog(self.platform.config.install_prefix 
+
-                                           '/share/gnuradio/themes/').run()
+            file_paths = FileDialogs.OpenQSS(main, 
self.platform.config.install_prefix +
+                                             '/share/gnuradio/themes/').run()
             if file_paths:
                 try:
                     prefs = self.platform.config.prefs
@@ -544,7 +541,7 @@ class ActionHandler:
                     Messages.send_fail_save(page.file_path)
                     page.saved = False
         elif action == Actions.FLOW_GRAPH_SAVE_AS:
-            file_path = SaveFlowGraphFileDialog(page.file_path).run()
+            file_path = FileDialogs.SaveFlowGraph(main, page.file_path).run()
             if file_path is not None:
                 page.file_path = os.path.abspath(file_path)
                 Actions.FLOW_GRAPH_SAVE()
@@ -552,7 +549,7 @@ class ActionHandler:
                 main.tool_bar.refresh_submenus()
                 main.menu_bar.refresh_submenus()
         elif action == Actions.FLOW_GRAPH_SCREEN_CAPTURE:
-            file_path, background_transparent = 
SaveScreenShotDialog(page.file_path).run()
+            file_path, background_transparent = 
FileDialogs.SaveScreenShot(main, page.file_path).run()
             if file_path is not None:
                 pixbuf = 
flow_graph.get_drawing_area().get_screenshot(background_transparent)
                 pixbuf.save(file_path, Constants.IMAGE_FILE_EXTENSION[1:])
@@ -576,9 +573,10 @@ class ActionHandler:
             if not page.process:
                 Actions.FLOW_GRAPH_GEN()
                 xterm = self.platform.config.xterm_executable
+                Dialogs.show_missing_xterm(main, xterm)
                 if Preferences.xterm_missing() != xterm:
                     if not os.path.exists(xterm):
-                        Dialogs.MissingXTermDialog(xterm)
+                        Dialogs.show_missing_xterm(main, xterm)
                     Preferences.xterm_missing(xterm)
                 if page.saved and page.file_path:
                     Executor.ExecFlowGraphThread(
diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py
index da271fe..da4b11a 100644
--- a/grc/gui/Dialogs.py
+++ b/grc/gui/Dialogs.py
@@ -1,38 +1,36 @@
-"""
-Copyright 2008, 2009 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
-"""
+# Copyright 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
+# 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
-import gi
-gi.require_version('Gtk', '3.0')
-from gi.repository import Gtk
-from gi.repository import Gdk
-from gi.repository import GObject
 
 import sys
+import textwrap
 from distutils.spawn import find_executable
 
+from gi.repository import Gtk
+
 from . import Utils, Actions, Constants
 from ..core import Messages
 
 
 class SimpleTextDisplay(Gtk.TextView):
-    """A non editable gtk text view."""
+    """
+    A non user-editable gtk text view.
+    """
 
     def __init__(self, text=''):
         """
@@ -41,16 +39,18 @@ class SimpleTextDisplay(Gtk.TextView):
         Args:
             text: the text to display (string)
         """
-        text_buffer = Gtk.TextBuffer()
-        text_buffer.set_text(text)
-        self.set_text = text_buffer.set_text
-        GObject.GObject.__init__(self)
+        Gtk.TextView.__init__(self)
+        self.set_text = self.get_buffer().set_text
+        self.set_text(text)
         self.set_editable(False)
         self.set_cursor_visible(False)
         self.set_wrap_mode(Gtk.WrapMode.WORD_CHAR)
 
 
 class TextDisplay(SimpleTextDisplay):
+    """
+    A non user-editable scrollable text view with popup menu.
+    """
 
     def __init__(self, text=''):
         """
@@ -64,54 +64,77 @@ class TextDisplay(SimpleTextDisplay):
         self.connect("populate-popup", self.populate_popup)
 
     def insert(self, line):
-        # make backspaces work
+        """
+        Append text after handling backspaces and auto-scroll.
+
+        Args:
+            line: the text to append (string)
+        """
         line = self._consume_backspaces(line)
-        # add the remaining text to buffer
         self.get_buffer().insert(self.get_buffer().get_end_iter(), line)
-        # Automatically scroll on insert
         self.scroll_to_end()
 
     def _consume_backspaces(self, line):
-        """removes text from the buffer if line starts with \b*"""
-        if not line: return
+        """
+        Removes text from the buffer if line starts with '\b'
+
+        Args:
+            line: a string which may contain backspaces
+
+        Returns:
+            The string that remains from 'line' with leading '\b's removed.
+        """
+        if not line:
+            return
+
         # for each \b delete one char from the buffer
         back_count = 0
         start_iter = self.get_buffer().get_end_iter()
         while line[back_count] == '\b':
             # stop at the beginning of a line
-            if not start_iter.starts_line(): start_iter.backward_char()
+            if not start_iter.starts_line():
+                start_iter.backward_char()
             back_count += 1
-        # remove chars
+        # remove chars from buffer
         self.get_buffer().delete(start_iter, self.get_buffer().get_end_iter())
-        # return remaining text
         return line[back_count:]
 
     def scroll_to_end(self):
+        """ Update view's scroll position. """
         if self.scroll_lock:
-            buffer = self.get_buffer()
-            buffer.move_mark(buffer.get_insert(), buffer.get_end_iter())
+            buf = self.get_buffer()
+            buf.move_mark(buf.get_insert(), buf.get_end_iter())
             # TODO: Fix later
             #self.scroll_to_mark(buffer.get_insert(), 0.0)
 
     def clear(self):
-        buffer = self.get_buffer()
-        buffer.delete(buffer.get_start_iter(), buffer.get_end_iter())
+        """ Clear all text from buffer. """
+        buf = self.get_buffer()
+        buf.delete(buf.get_start_iter(), buf.get_end_iter())
 
     def save(self, file_path):
-        console_file = open(file_path, 'w')
-        buffer = self.get_buffer()
-        console_file.write(buffer.get_text(buffer.get_start_iter(), 
buffer.get_end_iter(), True))
-        console_file.close()
+        """
+        Save context of buffer to the given file.
+
+        Args:
+            file_path: location to save buffer contents
+        """
+        with open(file_path, 'w') as logfile:
+            buf = self.get_buffer()
+            logfile.write(buf.get_text(buf.get_start_iter(),
+                                       buf.get_end_iter(), True))
 
-    # Callback functions to handle the scrolling lock and clear context menus 
options
     # Action functions are set by the ActionHandler's init function
     def clear_cb(self, menu_item, web_view):
+        """ Callback function to clear the text buffer """
         Actions.CLEAR_CONSOLE()
 
     def scroll_back_cb(self, menu_item, web_view):
+        """ Callback function to toggle scroll lock """
         Actions.TOGGLE_SCROLL_LOCK()
 
     def save_cb(self, menu_item, web_view):
+        """ Callback function to save the buffer """
         Actions.SAVE_CONSOLE()
 
     def populate_popup(self, view, menu):
@@ -134,79 +157,151 @@ class TextDisplay(SimpleTextDisplay):
         return False
 
 
-def MessageDialogHelper(type, buttons, title=None, markup=None, 
default_response=None, extra_buttons=None):
-    """
-    Create a modal message dialog and run it.
+class MessageDialogWrapper(Gtk.MessageDialog):
+    """ Run a message dialog. """
 
-    Args:
-        type: the type of message: Gtk.MessageType.INFO, 
Gtk.MessageType.WARNING, Gtk.MessageType.QUESTION or Gtk.MessageType.ERROR
-        buttons: the predefined set of buttons to use:
-        Gtk.ButtonsType.NONE, Gtk.ButtonsType.OK, Gtk.ButtonsType.CLOSE, 
Gtk.ButtonsType.CANCEL, Gtk.ButtonsType.YES_NO, Gtk.ButtonsType.OK_CANCEL
-
-    Args:
-        title: the title of the window (string)
-        markup: the message text with pango markup
-        default_response: if set, determines which button is highlighted by 
default
-        extra_buttons: a tuple containing pairs of values; each value is the 
button's text and the button's return value
-
-    Returns:
-        the gtk response from run()
-    """
-    message_dialog = Gtk.MessageDialog(None, Gtk.DialogFlags.MODAL, type, 
buttons)
-    if title: message_dialog.set_title(title)
-    if markup: message_dialog.set_markup(markup)
-    if extra_buttons: message_dialog.add_buttons(*extra_buttons)
-    if default_response: message_dialog.set_default_response(default_response)
-    response = message_dialog.run()
-    message_dialog.destroy()
-    return response
-
-
-def ErrorsDialog(flowgraph):
-    MessageDialogHelper(
-        type=Gtk.MessageType.ERROR,
-        buttons=Gtk.ButtonsType.CLOSE,
-        title='Flow Graph Errors',
-        markup='\n\n'.join(
-            '<b>Error {num}:</b>\n{msg}'.format(num=i, 
msg=Utils.encode(msg.replace('\t', '  ')))
-            for i, msg in enumerate(flowgraph.get_error_messages())
-        ),
-    )
-
-
-class AboutDialog(Gtk.AboutDialog):
-    """A cute little about dialog."""
-
-    def __init__(self, config):
-        """AboutDialog constructor."""
-        GObject.GObject.__init__(self)
-        self.set_name(config.name)
-        self.set_version(config.version)
-        self.set_license(config.license)
-        self.set_copyright(config.license.splitlines()[0])
-        self.set_website(config.website)
-        self.run()
-        self.destroy()
-
-
-def HelpDialog(): MessageDialogHelper(
-    type=Gtk.MessageType.INFO,
-    buttons=Gtk.ButtonsType.CLOSE,
-    title='Help',
-    markup="""\
-<b>Usage Tips</b>
-
-<u>Add block</u>: drag and drop or double click a block in the block selection 
window.
-<u>Rotate block</u>: Select a block, press left/right on the keyboard.
-<u>Change type</u>: Select a block, press up/down on the keyboard.
-<u>Edit parameters</u>: double click on a block in the flow graph.
-<u>Make connection</u>: click on the source port of one block, then click on 
the sink port of another block.
-<u>Remove connection</u>: select the connection and press delete, or drag the 
connection.
-
-* See the menu for other keyboard shortcuts.""")
+    def __init__(self, parent, message_type, buttons, title=None, markup=None,
+                 default_response=None, extra_buttons=None):
+        """
+        Create a modal message dialog.
 
+        Args:
+            message_type: the type of message may be one of:
+                            Gtk.MessageType.INFO
+                            Gtk.MessageType.WARNING
+                            Gtk.MessageType.QUESTION or Gtk.MessageType.ERROR
+            buttons: the predefined set of buttons to use:
+                            Gtk.ButtonsType.NONE
+                            Gtk.ButtonsType.OK
+                            Gtk.ButtonsType.CLOSE
+                            Gtk.ButtonsType.CANCEL
+                            Gtk.ButtonsType.YES_NO
+                            Gtk.ButtonsType.OK_CANCEL
+            title: the title of the window (string)
+            markup: the message text with pango markup
+            default_response: if set, determines which button is highlighted 
by default
+            extra_buttons: a tuple containing pairs of values:
+                            each value is the button's text and the button's 
return value
 
-def TypesDialog(platform):
+        """
+        Gtk.MessageDialog.__init__(
+            self, transient_for=parent, modal=True, destroy_with_parent=True,
+            message_type=message_type, buttons=buttons
+        )
+        if title:
+            self.set_title(title)
+        if markup:
+            self.set_markup(markup)
+        if extra_buttons:
+            self.add_buttons(*extra_buttons)
+        if default_response:
+            self.set_default_response(default_response)
+
+    def run_and_destroy(self):
+        response = self.run()
+        self.hide()
+        return response
+
+
+class ErrorsDialog(Gtk.Dialog):
+    """ Display flowgraph errors. """
+
+    def __init__(self, parent, flowgraph):
+        """Create a listview of errors"""
+        Gtk.Dialog.__init__(
+            self,
+            title='Errors and Warnings',
+            transient_for=parent,
+            modal=True,
+            destroy_with_parent=True,
+        )
+        self.add_buttons(Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT)
+        self.set_size_request(750, Constants.MIN_DIALOG_HEIGHT)
+        self.set_border_width(10)
+
+        self.store = Gtk.ListStore(str, str, str)
+        self.update(flowgraph)
+
+        self.treeview = Gtk.TreeView(model=self.store)
+        for i, column_title in enumerate(["Block", "Aspect", "Message"]):
+            renderer = Gtk.CellRendererText()
+            column = Gtk.TreeViewColumn(column_title, renderer, text=i)
+            column.set_sort_column_id(i)  # liststore id matches treeview id
+            column.set_resizable(True)
+            self.treeview.append_column(column)
+
+        self.scrollable = Gtk.ScrolledWindow()
+        self.scrollable.set_vexpand(True)
+        self.scrollable.add(self.treeview)
+
+        self.vbox.pack_start(self.scrollable, True, True, 0)
+        self.show_all()
+
+    def update(self, flowgraph):
+        self.store.clear()
+        for element, message in flowgraph.iter_error_messages():
+            if element.is_block:
+                src, aspect = element.get_id(), ''
+            elif element.is_connection:
+                src = element.source_block.get_id()
+                aspect = "Connection to 
'{}'".format(element.sink_block.get_id())
+            elif element.is_port:
+                src = element.parent_block.get_id()
+                aspect = "{} '{}'".format('Sink' if element.is_sink else 
'Source', element.name)
+            elif element.is_param:
+                src = element.parent_block.get_id()
+                aspect = "Param '{}'".format(element.name)
+            else:
+                src = aspect = ''
+            self.store.append([src, aspect, message])
+
+    def run_and_destroy(self):
+        response = self.run()
+        self.hide()
+        return response
+
+
+def show_about(parent, config):
+    ad = Gtk.AboutDialog(transient_for=parent)
+    ad.set_program_name(config.name)
+    ad.set_name('')
+    ad.set_version(config.version)
+    ad.set_license(config.license)
+
+    try:
+        ad.set_logo(Gtk.IconTheme().load_icon('gnuradio-grc', 64, 0))
+    except:
+        pass
+
+    ad.set_copyright(config.license.splitlines()[0])
+    ad.set_website(config.website)
+
+    ad.connect("response", lambda action, param: action.hide())
+    ad.show()
+
+
+def show_help(parent):
+    """ Display basic usage tips. """
+    markup = textwrap.dedent("""\
+        <b>Usage Tips</b>
+        \n\
+        <u>Add block</u>: drag and drop or double click a block in the block 
selection window.
+        <u>Rotate block</u>: Select a block, press left/right on the keyboard.
+        <u>Change type</u>: Select a block, press up/down on the keyboard.
+        <u>Edit parameters</u>: double click on a block in the flow graph.
+        <u>Make connection</u>: click on the source port of one block, then 
click on the sink port of another block.
+        <u>Remove connection</u>: select the connection and press delete, or 
drag the connection.
+        \n\
+        * See the menu for other keyboard shortcuts.\
+    """)
+
+    MessageDialogWrapper(
+        parent, Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE, title='Help', 
markup=markup
+    ).run_and_destroy()
+
+
+def show_types(parent):
+    """ Display information about standard data types. """
     colors = [(name, color) for name, key, sizeof, color in 
Constants.CORE_TYPES]
     max_len = 10 + max(len(name) for name, code in colors)
 
@@ -215,62 +310,65 @@ def TypesDialog(platform):
         ''.format(color=color, name=Utils.encode(name).center(max_len))
         for name, color in colors
     )
-    MessageDialogHelper(
-        type=Gtk.MessageType.INFO,
-        buttons=Gtk.ButtonsType.CLOSE,
-        title='Types - Color Mapping',
-        markup=message
-    )
 
+    MessageDialogWrapper(
+        parent, Gtk.MessageType.INFO, Gtk.ButtonsType.CLOSE, title='Types - 
Color Mapping', markup=message
+    ).run_and_destroy()
 
-def MissingXTermDialog(xterm):
-    MessageDialogHelper(
-        type=Gtk.MessageType.WARNING,
-        buttons=Gtk.ButtonsType.OK,
-        title='Warning: missing xterm executable',
-        markup=("The xterm executable {0!r} is missing.\n\n"
-                "You can change this setting in your gnuradio.conf, in "
-                "section [grc], 'xterm_executable'.\n"
-                "\n"
-                "(This message is shown only once)").format(xterm)
-    )
 
+def show_missing_xterm(parent, xterm):
+    markup = textwrap.dedent("""\
+        The xterm executable {0!r} is missing.
+        You can change this setting in your gnurado.conf, in section [grc], 
'xterm_executable'.
+        \n\
+        (This message is shown only once)\
+    """).format(xterm)
+
+    MessageDialogWrapper(
+        parent, message_type=Gtk.MessageType.WARNING, 
buttons=Gtk.ButtonsType.OK,
+        title='Warning: missing xterm executable', markup=markup
+    ).run_and_destroy()
+
+
+def choose_editor(parent, config):
+    """
+    Give the option to either choose an editor or use the default.
+    """
+    if config.editor and find_executable(config.editor):
+        return config.editor
 
-def ChooseEditorDialog(config):
-    # Give the option to either choose an editor or use the default
-    # Always return true/false so the caller knows it was successful
     buttons = (
         'Choose Editor', Gtk.ResponseType.YES,
         'Use Default', Gtk.ResponseType.NO,
         Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL
     )
-    response = MessageDialogHelper(
-        Gtk.MessageType.QUESTION, Gtk.ButtonsType.NONE, 'Choose Editor',
-        'Would you like to choose the editor to use?', Gtk.ResponseType.YES, 
buttons
-    )
+    response = MessageDialogWrapper(
+        parent, message_type=Gtk.MessageType.QUESTION, 
buttons=Gtk.ButtonsType.NONE,
+        title='Choose Editor', markup='Would you like to choose the editor to 
use?',
+        default_response=Gtk.ResponseType.YES, extra_buttons=buttons
+    ).run_and_destroy()
 
-    # Handle the inital default/choose/cancel response
+    # Handle the initial default/choose/cancel response
     # User wants to choose the editor to use
+    editor = ''
     if response == Gtk.ResponseType.YES:
         file_dialog = Gtk.FileChooserDialog(
             'Select an Editor...', None,
             Gtk.FileChooserAction.OPEN,
-            ('gtk-cancel', Gtk.ResponseType.CANCEL, 'gtk-open', 
Gtk.ResponseType.OK)
+            ('gtk-cancel', Gtk.ResponseType.CANCEL, 'gtk-open', 
Gtk.ResponseType.OK),
+            transient_for=parent
         )
         file_dialog.set_select_multiple(False)
         file_dialog.set_local_only(True)
         file_dialog.set_current_folder('/usr/bin')
         try:
             if file_dialog.run() == Gtk.ResponseType.OK:
-                config.editor = file_path = file_dialog.get_filename()
-                file_dialog.destroy()
-                return file_path
+                editor = file_dialog.get_filename()
         finally:
-            file_dialog.destroy()
+            file_dialog.hide()
 
     # Go with the default editor
     elif response == Gtk.ResponseType.NO:
-        # Determine the platform
         try:
             process = None
             if sys.platform.startswith('linux'):
@@ -280,13 +378,10 @@ def ChooseEditorDialog(config):
             if process is None:
                 raise ValueError("Can't find default editor executable")
             # Save
-            config.editor = process
-            return process
+            editor = config.editor = process
         except Exception:
             Messages.send('>>> Unable to load the default editor. Please 
choose an editor.\n')
-            # Just reset of the constant and force the user to select an 
editor the next time
-            config.editor = ''
-            return
 
-    Messages.send('>>> No editor selected.\n')
-    return
+    if editor == '':
+        Messages.send('>>> No editor selected.\n')
+    return editor
diff --git a/grc/gui/FileDialogs.py b/grc/gui/FileDialogs.py
index 23fd7e7..afd41af 100644
--- a/grc/gui/FileDialogs.py
+++ b/grc/gui/FileDialogs.py
@@ -18,18 +18,14 @@ 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 \
-    DEFAULT_FILE_PATH, IMAGE_FILE_EXTENSION, TEXT_FILE_EXTENSION, \
-    NEW_FLOGRAPH_TITLE
-from . import Preferences
 from os import path
-from . import Utils
+
+from gi.repository import Gtk
+
+from . import Constants, Preferences, Utils
+from .Dialogs import MessageDialogWrapper
+
 
 ##################################################
 # Constants
@@ -52,14 +48,14 @@ def get_flow_graph_files_filter():
 def get_text_files_filter():
     filter = Gtk.FileFilter()
     filter.set_name('Text Files')
-    filter.add_pattern('*'+TEXT_FILE_EXTENSION)
+    filter.add_pattern('*' + Constants.TEXT_FILE_EXTENSION)
     return filter
 
 
 def get_image_files_filter():
     filter = Gtk.FileFilter()
     filter.set_name('Image Files')
-    filter.add_pattern('*'+IMAGE_FILE_EXTENSION)
+    filter.add_pattern('*' + Constants.IMAGE_FILE_EXTENSION)
     return filter
 
 
@@ -84,7 +80,7 @@ class FileDialogHelper(Gtk.FileChooserDialog):
     Implement a file chooser dialog with only necessary parameters.
     """
 
-    def __init__(self, action, title):
+    def __init__(self, parent, action, title):
         """
         FileDialogHelper contructor.
         Create a save or open dialog with cancel and ok buttons.
@@ -94,8 +90,16 @@ class FileDialogHelper(Gtk.FileChooserDialog):
             action: Gtk.FileChooserAction.OPEN or Gtk.FileChooserAction.SAVE
             title: the title of the dialog (string)
         """
-        ok_stock = {Gtk.FileChooserAction.OPEN : 'gtk-open', 
Gtk.FileChooserAction.SAVE : 'gtk-save'}[action]
-        Gtk.FileChooserDialog.__init__(self, title, None, action, 
('gtk-cancel', Gtk.ResponseType.CANCEL, ok_stock, Gtk.ResponseType.OK))
+        ok_stock = {
+            Gtk.FileChooserAction.OPEN: 'gtk-open',
+            Gtk.FileChooserAction.SAVE: 'gtk-save'
+        }[action]
+
+        Gtk.FileChooserDialog.__init__(
+            self, title=title, action=action,
+            transient_for=parent
+        )
+        self.add_buttons('gtk-cancel', Gtk.ResponseType.CANCEL, ok_stock, 
Gtk.ResponseType.OK)
         self.set_select_multiple(False)
         self.set_local_only(True)
         self.add_filter(get_all_files_filter())
@@ -104,37 +108,39 @@ class FileDialogHelper(Gtk.FileChooserDialog):
 class FileDialog(FileDialogHelper):
     """A dialog box to save or open flow graph files. This is a base class, do 
not use."""
 
-    def __init__(self, current_file_path=''):
+    def __init__(self, parent, current_file_path=''):
         """
         FileDialog constructor.
 
         Args:
             current_file_path: the current directory or path to the open flow 
graph
         """
-        if not current_file_path: current_file_path = 
path.join(DEFAULT_FILE_PATH, NEW_FLOGRAPH_TITLE + Preferences.file_extension())
+        if not current_file_path:
+            current_file_path = path.join(Constants.DEFAULT_FILE_PATH,
+                                          Constants.NEW_FLOGRAPH_TITLE + 
Preferences.file_extension())
         if self.type == OPEN_FLOW_GRAPH:
-            FileDialogHelper.__init__(self, Gtk.FileChooserAction.OPEN, 'Open 
a Flow Graph from a File...')
+            FileDialogHelper.__init__(self, parent, 
Gtk.FileChooserAction.OPEN, 'Open a Flow Graph from a File...')
             self.add_and_set_filter(get_flow_graph_files_filter())
             self.set_select_multiple(True)
         elif self.type == SAVE_FLOW_GRAPH:
-            FileDialogHelper.__init__(self, Gtk.FileChooserAction.SAVE, 'Save 
a Flow Graph to a File...')
+            FileDialogHelper.__init__(self, parent, 
Gtk.FileChooserAction.SAVE, 'Save a Flow Graph to a File...')
             self.add_and_set_filter(get_flow_graph_files_filter())
             self.set_current_name(path.basename(current_file_path))
         elif self.type == SAVE_CONSOLE:
-            FileDialogHelper.__init__(self, Gtk.FileChooserAction.SAVE, 'Save 
Console to a File...')
+            FileDialogHelper.__init__(self, parent, 
Gtk.FileChooserAction.SAVE, 'Save Console to a File...')
             self.add_and_set_filter(get_text_files_filter())
             file_path = path.splitext(path.basename(current_file_path))[0]
-            self.set_current_name(file_path) #show the current filename
+            self.set_current_name(file_path)  # show the current filename
         elif self.type == SAVE_IMAGE:
-            FileDialogHelper.__init__(self, Gtk.FileChooserAction.SAVE, 'Save 
a Flow Graph Screen Shot...')
+            FileDialogHelper.__init__(self, parent, 
Gtk.FileChooserAction.SAVE, 'Save a Flow Graph Screen Shot...')
             self.add_and_set_filter(get_image_files_filter())
-            current_file_path = current_file_path + IMAGE_FILE_EXTENSION
-            self.set_current_name(path.basename(current_file_path)) #show the 
current filename
+            current_file_path = current_file_path + 
Constants.IMAGE_FILE_EXTENSION
+            self.set_current_name(path.basename(current_file_path))  # show 
the current filename
         elif self.type == OPEN_QSS_THEME:
-            FileDialogHelper.__init__(self, Gtk.FileChooserAction.OPEN, 'Open 
a QSS theme...')
+            FileDialogHelper.__init__(self, parent, 
Gtk.FileChooserAction.OPEN, 'Open a QSS theme...')
             self.add_and_set_filter(get_qss_themes_filter())
             self.set_select_multiple(False)
-        self.set_current_folder(path.dirname(current_file_path)) #current 
directory
+        self.set_current_folder(path.dirname(current_file_path))  # current 
directory
 
     def add_and_set_filter(self, filter):
         """
@@ -156,7 +162,7 @@ class FileDialog(FileDialogHelper):
         Returns:
             the complete file path
         """
-        if Gtk.FileChooserDialog.run(self) != Gtk.ResponseType.OK: return None 
#response was cancel
+        if Gtk.FileChooserDialog.run(self) != Gtk.ResponseType.OK: return None 
 # response was cancel
         #############################################
         # Handle Save Dialogs
         #############################################
@@ -164,18 +170,21 @@ class FileDialog(FileDialogHelper):
             filename = self.get_filename()
             extension = {
                 SAVE_FLOW_GRAPH: Preferences.file_extension(),
-                SAVE_CONSOLE: TEXT_FILE_EXTENSION,
-                SAVE_IMAGE: IMAGE_FILE_EXTENSION,
+                SAVE_CONSOLE: Constants.TEXT_FILE_EXTENSION,
+                SAVE_IMAGE: Constants.IMAGE_FILE_EXTENSION,
             }[self.type]
-            #append the missing file extension if the filter matches
-            if path.splitext(filename)[1].lower() != extension: filename += 
extension
-            self.set_current_name(path.basename(filename)) #show the filename 
with extension
-            if path.exists(filename): #ask the user to confirm overwrite
-                if MessageDialogHelper(
+            # append the missing file extension if the filter matches
+            if path.splitext(filename)[1].lower() != extension:
+                filename += extension
+            self.set_current_name(path.basename(filename))  # show the 
filename with extension
+            if path.exists(filename):  # ask the user to confirm overwrite
+                response = MessageDialogWrapper(
                     Gtk.MessageType.QUESTION, Gtk.ButtonsType.YES_NO, 'Confirm 
Overwrite!',
                     'File <b>{filename}</b> Exists!\nWould you like to 
overwrite the existing file?'
                     ''.format(filename=Utils.encode(filename)),
-                ) == Gtk.ResponseType.NO: return self.get_rectified_filename()
+                ).run_and_destroy()
+                if response == Gtk.ResponseType.NO:
+                    return self.get_rectified_filename()
             return filename
         #############################################
         # Handle Open Dialogs
@@ -183,11 +192,11 @@ class FileDialog(FileDialogHelper):
         elif self.type in (OPEN_FLOW_GRAPH, OPEN_QSS_THEME):
             filenames = self.get_filenames()
             for filename in filenames:
-                if not path.exists(filename): #show a warning and re-run
-                    MessageDialogHelper(
+                if not path.exists(filename):  # show a warning and re-run
+                    MessageDialogWrapper(
                         Gtk.MessageType.WARNING, Gtk.ButtonsType.CLOSE, 
'Cannot Open!',
                         'File <b>{filename}</b> Does not 
Exist!'.format(filename=Utils.encode(filename)),
-                    )
+                    ).run_and_destroy()
                     return self.get_rectified_filename()
             return filenames
 
@@ -203,19 +212,19 @@ class FileDialog(FileDialogHelper):
         return filename
 
 
-class OpenFlowGraphFileDialog(FileDialog):
+class OpenFlowGraph(FileDialog):
     type = OPEN_FLOW_GRAPH
 
 
-class SaveFlowGraphFileDialog(FileDialog):
+class SaveFlowGraph(FileDialog):
     type = SAVE_FLOW_GRAPH
 
 
-class OpenQSSFileDialog(FileDialog):
+class OpenQSS(FileDialog):
     type = OPEN_QSS_THEME
 
 
-class SaveConsoleFileDialog(FileDialog):
+class SaveConsole(FileDialog):
     type = SAVE_CONSOLE
 
 
@@ -223,11 +232,11 @@ class SaveImageFileDialog(FileDialog):
     type = SAVE_IMAGE
 
 
-class SaveScreenShotDialog(SaveImageFileDialog):
+class SaveScreenShot(SaveImageFileDialog):
 
-    def __init__(self, current_file_path=''):
-        SaveImageFileDialog.__init__(self, current_file_path)
-        self._button = button = Gtk.CheckButton('_Background transparent')
+    def __init__(self, parent, current_file_path=''):
+        SaveImageFileDialog.__init__(self, parent, current_file_path)
+        self._button = button = Gtk.CheckButton(label='Background transparent')
         
self._button.set_active(Preferences.screen_shot_background_transparent())
         self.set_extra_widget(button)
 
diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py
index 83796f3..7333519 100644
--- a/grc/gui/FlowGraph.py
+++ b/grc/gui/FlowGraph.py
@@ -28,7 +28,7 @@ from itertools import count
 import six
 from six.moves import filter
 
-from gi.repository import GObject
+from gi.repository import GLib
 
 from . import Actions, Colors, Utils, Bars, Dialogs
 from .Element import Element
@@ -95,7 +95,7 @@ class FlowGraph(CoreFlowgraph, Element):
         else:
             config = self.parent_platform.config
             editor = (find_executable(config.editor) or
-                      Dialogs.ChooseEditorDialog(config))
+                      Dialogs.choose_editor(None, config))  # todo: pass in 
parent
             if not editor:
                 return
             updater = functools.partial(
@@ -103,7 +103,7 @@ class FlowGraph(CoreFlowgraph, Element):
             editor = self._external_updaters[target] = ExternalEditor(
                 editor=editor,
                 name=target[0], value=param.get_value(),
-                callback=functools.partial(GObject.idle_add, updater)
+                callback=functools.partial(GLib.idle_add, updater)
             )
             editor.start()
         try:
diff --git a/grc/gui/MainWindow.py b/grc/gui/MainWindow.py
index 97f9033..efa8573 100644
--- a/grc/gui/MainWindow.py
+++ b/grc/gui/MainWindow.py
@@ -33,7 +33,7 @@ from .BlockTreeWindow import BlockTreeWindow
 from .VariableEditor import VariableEditor
 from .Constants import \
     NEW_FLOGRAPH_TITLE, DEFAULT_CONSOLE_WINDOW_WIDTH
-from .Dialogs import TextDisplay, MessageDialogHelper
+from .Dialogs import TextDisplay, MessageDialogWrapper
 from .NotebookPage import NotebookPage
 
 from ..core import Messages
@@ -398,10 +398,10 @@ class MainWindow(Gtk.Window):
             Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL,
             Gtk.STOCK_SAVE, Gtk.ResponseType.OK
         )
-        return MessageDialogHelper(
-            Gtk.MessageType.QUESTION, Gtk.ButtonsType.NONE, 'Unsaved Changes!',
+        return MessageDialogWrapper(
+            self, Gtk.MessageType.QUESTION, Gtk.ButtonsType.NONE, 'Unsaved 
Changes!',
             'Would you like to save changes before closing?', 
Gtk.ResponseType.OK, buttons
-        )
+        ).run_and_destroy()
 
     def _get_files(self):
         """
diff --git a/grc/gui/ParamWidgets.py b/grc/gui/ParamWidgets.py
index 4ab7da6..e5657c2 100644
--- a/grc/gui/ParamWidgets.py
+++ b/grc/gui/ParamWidgets.py
@@ -168,7 +168,7 @@ class PythonEditorParam(InputParam):
 
     def __init__(self, *args, **kwargs):
         InputParam.__init__(self, *args, **kwargs)
-        button = self._button = Gtk.Button('Open in Editor')
+        button = self._button = Gtk.Button(label='Open in Editor')
         button.connect('clicked', self.open_editor)
         self.pack_start(button, True, True, True)
 
diff --git a/grc/gui/PropsDialog.py b/grc/gui/PropsDialog.py
index 9543a62..3a0f6ae 100644
--- a/grc/gui/PropsDialog.py
+++ b/grc/gui/PropsDialog.py
@@ -43,6 +43,7 @@ class PropsDialog(Gtk.Dialog):
             title='Properties: ' + block.name,
             transient_for=parent,
             modal=True,
+            destroy_with_parent=True,
         )
         self.add_buttons(
             Gtk.STOCK_OK, Gtk.ResponseType.ACCEPT,



reply via email to

[Prev in Thread] Current Thread [Next in Thread]