commit-gnuradio
[Top][All Lists]
Advanced

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

[Commit-gnuradio] [gnuradio] 04/08: grc: open and update params from ext


From: git
Subject: [Commit-gnuradio] [gnuradio] 04/08: grc: open and update params from external editor
Date: Wed, 11 Nov 2015 23:08:07 +0000 (UTC)

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

jcorgan pushed a commit to branch master
in repository gnuradio.

commit 2fee267dfee11bd687b4d780cb6b82924d59af3c
Author: Sebastian Koslowski <address@hidden>
Date:   Thu Jul 23 16:36:22 2015 +0200

    grc: open and update params from external editor
---
 grc/gui/ActionHandler.py   |  4 ++
 grc/gui/Actions.py         |  1 +
 grc/gui/CMakeLists.txt     |  1 +
 grc/gui/Constants.py       | 14 ++++---
 grc/gui/Dialogs.py         | 23 +++++++++++-
 grc/gui/FlowGraph.py       | 37 +++++++++++++++++-
 grc/gui/Param.py           | 67 ++++++++++++++++++++++++++++++++-
 grc/gui/external_editor.py | 93 ++++++++++++++++++++++++++++++++++++++++++++++
 8 files changed, 228 insertions(+), 12 deletions(-)

diff --git a/grc/gui/ActionHandler.py b/grc/gui/ActionHandler.py
index ee01595..6273178 100644
--- a/grc/gui/ActionHandler.py
+++ b/grc/gui/ActionHandler.py
@@ -441,6 +441,10 @@ class ActionHandler:
                         # null action, that updates the main window
                         Actions.ELEMENT_SELECT()
                 dialog.destroy()
+        elif action == Actions.EXTERNAL_UPDATE:
+            
self.get_page().get_state_cache().save_new_state(self.get_flow_graph().export_data())
+            self.get_flow_graph().update()
+            self.get_page().set_saved(False)
         ##################################################
         # View Parser Errors
         ##################################################
diff --git a/grc/gui/Actions.py b/grc/gui/Actions.py
index 2092934..c3ae6c9 100644
--- a/grc/gui/Actions.py
+++ b/grc/gui/Actions.py
@@ -170,6 +170,7 @@ class ToggleAction(gtk.ToggleAction, _ActionBase):
 # Actions
 ########################################################################
 PAGE_CHANGE = Action()
+EXTERNAL_UPDATE = Action()
 FLOW_GRAPH_NEW = Action(
     label='_New',
     tooltip='Create a new flow graph',
diff --git a/grc/gui/CMakeLists.txt b/grc/gui/CMakeLists.txt
index 08aaf3e..99140df 100644
--- a/grc/gui/CMakeLists.txt
+++ b/grc/gui/CMakeLists.txt
@@ -19,6 +19,7 @@
 
 ########################################################################
 GR_PYTHON_INSTALL(FILES
+    external_editor.py
     Block.py
     Colors.py
     Constants.py
diff --git a/grc/gui/Constants.py b/grc/gui/Constants.py
index 980396f..741c6fd 100644
--- a/grc/gui/Constants.py
+++ b/grc/gui/Constants.py
@@ -17,16 +17,18 @@ 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
+import os
+import sys
 
+import pygtk
 pygtk.require('2.0')
 import gtk
-import os
-import sys
+
 from gnuradio import gr
 
-_gr_prefs = gr.prefs()
+prefs = gr.prefs()
 GR_PREFIX = gr.prefix()
+EDITOR = prefs.get_string('grc', 'editor', '')
 
 # default path for the open/save dialogs
 DEFAULT_FILE_PATH = os.getcwd()
@@ -49,7 +51,7 @@ DEFAULT_BLOCKS_WINDOW_WIDTH = 100
 DEFAULT_REPORTS_WINDOW_WIDTH = 100
 
 try:  # ugly, but matches current code style
-    raw = _gr_prefs.get_string('grc', 'canvas_default_size', '1280, 1024')
+    raw = prefs.get_string('grc', 'canvas_default_size', '1280, 1024')
     DEFAULT_CANVAS_SIZE = tuple(int(x.strip('() ')) for x in raw.split(','))
     if len(DEFAULT_CANVAS_SIZE) != 2 or not all(300 < x < 4096 for x in 
DEFAULT_CANVAS_SIZE):
         raise Exception()
@@ -59,7 +61,7 @@ except:
 
 #  flow-graph canvas fonts
 try:  # ugly, but matches current code style
-    FONT_SIZE = _gr_prefs.get_long('grc', 'canvas_font_size', 8)
+    FONT_SIZE = prefs.get_long('grc', 'canvas_font_size', 8)
     if FONT_SIZE <= 0:
         raise Exception()
 except:
diff --git a/grc/gui/Dialogs.py b/grc/gui/Dialogs.py
index 6c01219..631dc0f 100644
--- a/grc/gui/Dialogs.py
+++ b/grc/gui/Dialogs.py
@@ -20,8 +20,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 
 02110-1301, USA
 import pygtk
 pygtk.require('2.0')
 import gtk
-import Utils
-import Actions
+
+from . import Utils, Actions, Constants
 
 
 class SimpleTextDisplay(gtk.TextView):
@@ -234,3 +234,22 @@ def MissingXTermDialog(xterm):
                 "\n"
                 "(This message is shown only once)").format(xterm)
     )
+
+
+def ChooseEditorDialog():
+    file_dialog = gtk.FileChooserDialog(
+        'Open a Data File...', None,
+        gtk.FILE_CHOOSER_ACTION_OPEN,
+        ('gtk-cancel', gtk.RESPONSE_CANCEL, 'gtk-open', gtk.RESPONSE_OK)
+    )
+    file_dialog.set_select_multiple(False)
+    file_dialog.set_local_only(True)
+    file_dialog.set_current_folder('/usr/bin')
+    response = file_dialog.run()
+
+    if response == gtk.RESPONSE_OK:
+        file_path = file_dialog.get_filename()
+        Constants.prefs.set_string('grc', 'editor', file_path)
+        Constants.prefs.save()
+        Constants.EDITOR = file_path
+    file_dialog.destroy()
diff --git a/grc/gui/FlowGraph.py b/grc/gui/FlowGraph.py
index fc6a711..b27f015 100644
--- a/grc/gui/FlowGraph.py
+++ b/grc/gui/FlowGraph.py
@@ -18,12 +18,16 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 
MA  02110-1301, USA
 """
 
 import random
+import functools
 from itertools import chain
 from operator import methodcaller
 
+import gobject
+
 from . import Actions, Colors, Utils, Messages, Bars
-from .Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE
-from .Element import Element
+from . Element import Element
+from . Constants import SCROLL_PROXIMITY_SENSITIVITY, SCROLL_DISTANCE
+from . external_editor import ExternalEditor
 
 
 class FlowGraph(Element):
@@ -55,6 +59,35 @@ class FlowGraph(Element):
         self._context_menu = Bars.ContextMenu()
         self.get_context_menu = lambda: self._context_menu
 
+        self._external_updaters = {}
+
+    def install_external_editor(self, param):
+        target = (param.get_parent().get_id(), param.get_key())
+
+        if target in self._external_updaters:
+            editor = self._external_updaters[target]
+        else:
+            updater = functools.partial(
+                self.handle_external_editor_change, target=target)
+            editor = self._external_updaters[target] = ExternalEditor(
+                name=target[0], value=param.get_value(),
+                callback=functools.partial(gobject.idle_add, updater)
+            )
+            editor.start()
+        editor.open_editor()
+
+    def handle_external_editor_change(self, new_value, target):
+        try:
+            block_id, param_key = target
+            self.get_block(block_id).get_param(param_key).set_value(new_value)
+
+        except (IndexError, ValueError):  # block no longer exists
+            self._external_updaters[target].stop()
+            del self._external_updaters[target]
+            return
+        Actions.EXTERNAL_UPDATE()
+
+
     ###########################################################################
     # Access Drawing Area
     ###########################################################################
diff --git a/grc/gui/Param.py b/grc/gui/Param.py
index 6bd45fa..3588b81 100644
--- a/grc/gui/Param.py
+++ b/grc/gui/Param.py
@@ -23,7 +23,7 @@ import pygtk
 pygtk.require('2.0')
 import gtk
 
-from . import Colors, Utils, Constants
+from . import Colors, Utils, Constants, Dialogs
 from . Element import Element
 
 
@@ -173,6 +173,66 @@ class MultiLineEntryParam(InputParam):
             pass  # no tooltips for old GTK
 
 
+# try:
+#     import gtksourceview
+#     lang_manager = gtksourceview.SourceLanguagesManager()
+#     py_lang = lang_manager.get_language_from_mime_type('text/x-python')
+#
+#     class PythonEditorParam(InputParam):
+#         expand = True
+#
+#         def __init__(self, *args, **kwargs):
+#             InputParam.__init__(self, *args, **kwargs)
+#
+#             buf = self._buffer = gtksourceview.SourceBuffer()
+#             buf.set_language(py_lang)
+#             buf.set_highlight(True)
+#             buf.set_text(self.param.get_value())
+#             buf.connect('changed', self._mark_changed)
+#
+#             view = self._view = gtksourceview.SourceView(self._buffer)
+#             view.connect('focus-out-event', self._apply_change)
+#             view.connect('key-press-event', self._handle_key_press)
+#             view.set_tabs_width(4)
+#             view.set_insert_spaces_instead_of_tabs(True)
+#             view.set_auto_indent(True)
+#             view.set_border_width(2)
+#
+#             scroll = gtk.ScrolledWindow()
+#             scroll.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
+#             scroll.add_with_viewport(view)
+#             self.pack_start(scroll, True)
+#
+#         def get_text(self):
+#             buf = self._buffer
+#             return buf.get_text(buf.get_start_iter(),
+#                                 buf.get_end_iter()).strip()
+#
+# except ImportError:
+#     print "Package 'gtksourceview' not found. No Syntax highlighting."
+#     PythonEditorParam = MultiLineEntryParam
+
+class PythonEditorParam(InputParam):
+
+    def __init__(self, *args, **kwargs):
+        InputParam.__init__(self, *args, **kwargs)
+        input = gtk.Button('Open in Editor')
+        input.connect('clicked', self.open_editor)
+        self.pack_start(input, True)
+
+    def open_editor(self, widget=None):
+        if not os.path.exists(Constants.EDITOR):
+            Dialogs.ChooseEditorDialog()
+        flowgraph = self.param.get_parent().get_parent()
+        flowgraph.install_external_editor(self.param)
+
+    def get_text(self):
+        pass  # we never update the value from here
+
+    def _apply_change(self, *args):
+        pass
+
+
 class EnumParam(InputParam):
     """Provide an entry box for Enum types with a drop down menu."""
 
@@ -341,9 +401,12 @@ class Param(Element):
         elif self.get_options():
             input_widget = EnumEntryParam(self, *args, **kwargs)
 
-        elif self.get_type() in ('_multiline', '_multiline_python_external'):
+        elif self.get_type() == '_multiline':
             input_widget = MultiLineEntryParam(self, *args, **kwargs)
 
+        elif self.get_type() == '_multiline_python_external':
+            input_widget = PythonEditorParam(self, *args, **kwargs)
+
         else:
             input_widget = EntryParam(self, *args, **kwargs)
 
diff --git a/grc/gui/external_editor.py b/grc/gui/external_editor.py
new file mode 100644
index 0000000..3322556
--- /dev/null
+++ b/grc/gui/external_editor.py
@@ -0,0 +1,93 @@
+"""
+Copyright 2015 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
+"""
+
+import os
+import sys
+import time
+import threading
+import tempfile
+import subprocess
+
+import Constants
+
+
+class ExternalEditor(threading.Thread):
+
+    def __init__(self, name, value, callback):
+        threading.Thread.__init__(self)
+        self.daemon = True
+        self._stop_event = threading.Event()
+
+        self.callback = callback
+        self.tempfile = self._create_tempfile(name, value)
+
+    def _create_tempfile(self, name, value):
+        fp = tempfile.NamedTemporaryFile(mode='w', suffix='.py',
+                                         prefix=name + '_')
+        fp.write(value)
+        fp.flush()
+        return fp
+
+    @property
+    def filename(self):
+        return self.tempfile.name
+
+    def open_editor(self):
+        proc = subprocess.Popen(
+            args=(Constants.EDITOR, self.filename)
+        )
+        proc.poll()
+        return proc
+
+    def stop(self):
+        self._stop_event.set()
+
+    def run(self):
+        filename = self.filename
+        # print "file monitor: started for", filename
+        last_change = os.path.getmtime(filename)
+        try:
+            while not self._stop_event.is_set():
+                mtime = os.path.getmtime(filename)
+                if mtime > last_change:
+                    # print "file monitor: reload trigger for", filename
+                    last_change = mtime
+                    with open(filename) as fp:
+                        data = fp.read()
+                    self.callback(data)
+                time.sleep(1)
+
+        except Exception as e:
+            print >> sys.stderr, "file monitor crashed:", str(e)
+        else:
+            # print "file monitor: done with", filename
+            pass
+
+
+if __name__ == '__main__':
+    def p(data):
+        print data
+
+    Constants.EDITOR = '/usr/bin/gedit'
+    editor = ExternalEditor("test", "content", p)
+    editor.open_editor()
+    editor.start()
+    time.sleep(15)
+    editor.stop()
+    editor.join()



reply via email to

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