[gimp] plug-ins: port python-console to new GObject-introspected API.



commit 62d87f15d9f61717e33a170d581e3e215d729ff2
Author: Jehan <jehan girinstud io>
Date:   Mon Jul 29 23:01:46 2019 +0200

    plug-ins: port python-console to new GObject-introspected API.
    
    I may have missed things. That is the problem of non-compiled script
    languages. There is also a known warning:
    > DeprecationWarning: Gtk.Dialog.set_alternative_button_order_from_array is deprecated
    I'll see later about this one.
    
    Push-time note: calling various functions is actually broken right now
    in the console since the late API changes (it was working fine yesterday
    evening when I tested the same python-console code). Pushing anyway for
    now.

 configure.ac                                       |   1 +
 plug-ins/pygimp/plug-ins/python-console.py         | 245 -------------------
 plug-ins/python/Makefile.am                        |  11 +-
 plug-ins/python/python-console/Makefile.am         |   7 +
 .../python-console}/pyconsole.py                   | 140 ++++++-----
 plug-ins/python/python-console/python-console.py   | 269 +++++++++++++++++++++
 6 files changed, 354 insertions(+), 319 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 9d48a084f2..097d62ab75 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2870,6 +2870,7 @@ dnl plug-ins/pygimp/Makefile
 dnl plug-ins/pygimp/plug-ins/Makefile
 [
 plug-ins/python/Makefile
+plug-ins/python/python-console/Makefile
 plug-ins/screenshot/Makefile
 plug-ins/script-fu/Makefile
 plug-ins/script-fu/ftx/Makefile
diff --git a/plug-ins/python/Makefile.am b/plug-ins/python/Makefile.am
index 039d10d2fc..f347e921ad 100644
--- a/plug-ins/python/Makefile.am
+++ b/plug-ins/python/Makefile.am
@@ -1,5 +1,8 @@
 ## Process this file with automake to produce Makefile.in
 
+SUBDIRS = \
+       python-console
+
 pluginexecdir = $(gimpplugindir)/plug-ins
 
 source_scripts = \
@@ -50,16 +53,8 @@ if GIMP_UNSTABLE
 nobase_pluginexec_SCRIPTS += $(test_scripts)
 endif
 
-# python-console has a data file.
-# Therefore let's move it to its own sub-directory.
-#consoleexecdir = $(gimpplugindir)/plug-ins/python-console
-#console_scripts = python-console.py
-#consoleexec_SCRIPTS = $(console_scripts)
-#dist_consoleexec_DATA = pyconsole.py
-
 EXTRA_DIST = \
        $(source_scripts)
-#      $(console_scripts)
 
 CLEANFILES = $(scripts) $(test_scripts)
 
diff --git a/plug-ins/python/python-console/Makefile.am b/plug-ins/python/python-console/Makefile.am
new file mode 100644
index 0000000000..6c2b7494b0
--- /dev/null
+++ b/plug-ins/python/python-console/Makefile.am
@@ -0,0 +1,7 @@
+consoleexecdir = $(gimpplugindir)/plug-ins/python-console
+console_scripts = python-console.py
+consoleexec_SCRIPTS = $(console_scripts)
+dist_consoleexec_DATA = pyconsole.py
+
+EXTRA_DIST = \
+       $(console_scripts)
diff --git a/plug-ins/pygimp/plug-ins/pyconsole.py b/plug-ins/python/python-console/pyconsole.py
similarity index 86%
rename from plug-ins/pygimp/plug-ins/pyconsole.py
rename to plug-ins/python/python-console/pyconsole.py
index d69da1b16e..ab0ee2d306 100644
--- a/plug-ins/pygimp/plug-ins/pyconsole.py
+++ b/plug-ins/python/python-console/pyconsole.py
@@ -38,16 +38,24 @@
 # The use case is: you have a python program, you create this widget,
 # and inspect your program interiors.
 
-import gtk
-import gtk.gdk as gdk
-import gobject
-import pango
-import gtk.keysyms as _keys
+import gi
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk
+gi.require_version('Gdk', '3.0')
+from gi.repository import Gdk
+from gi.repository import GObject
+from gi.repository import Pango
 import code
 import sys
 import keyword
 import re
 
+def pango_pixels(value):
+    # The PANGO_PIXELS macro is not accessible through GObject
+    # Introspection. Just reimplement it:
+    # #define PANGO_PIXELS(d) (((int)(d) + 512) >> 10)
+    return (value + 512) >> 10
+
 # commonprefix() from posixpath
 def _commonprefix(m):
     "Given a list of pathnames, returns the longest common leading component"
@@ -92,7 +100,7 @@ class _ReadLine(object):
 
             if text != self.items[self.ptr]:
                 self.edited[self.ptr] = text
-            elif self.edited.has_key(self.ptr):
+            elif self.ptr in self.edited:
                 del self.edited[self.ptr]
 
             self.ptr = self.ptr + dir
@@ -111,8 +119,8 @@ class _ReadLine(object):
 
         self.quit_func = quit_func
 
-        self.set_wrap_mode(gtk.WRAP_CHAR)
-        self.modify_font(pango.FontDescription("Monospace"))
+        self.set_wrap_mode(Gtk.WrapMode.CHAR)
+        self.modify_font(Pango.FontDescription("Monospace"))
 
         self.buffer = self.get_buffer()
         self.buffer.connect("insert-text", self.on_buf_insert)
@@ -166,7 +174,7 @@ class _ReadLine(object):
             self.thaw_undo()
 
         self.__move_cursor_to(iter)
-        self.scroll_to_mark(self.cursor, 0.2)
+        self.scroll_to_mark(self.cursor, 0.2, False, 0.0, 0.0)
 
         self.in_raw_input = True
 
@@ -184,7 +192,7 @@ class _ReadLine(object):
         self.in_modal_raw_input = True
 
         while self.in_modal_raw_input:
-            gtk.main_iteration()
+            Gtk.main_iteration()
 
         self.ps = orig_ps
         self.in_modal_raw_input = False
@@ -204,7 +212,7 @@ class _ReadLine(object):
         if iter.compare(self.__get_start()) >= 0 and \
            iter.compare(self.__get_end()) <= 0:
                 buffer.move_mark_by_name("cursor", iter)
-                self.scroll_to_mark(self.cursor, 0.2)
+                self.scroll_to_mark(self.cursor, 0.2, False, 0.0, 0.0)
 
     def __insert(self, iter, text):
         self.do_insert = True
@@ -267,37 +275,37 @@ class _ReadLine(object):
 
     # We overload the key press event handler to handle "special keys"
     # when in input mode to make history browsing, completions, etc. work.
-    def do_key_press_event(self, event, parent_type):
+    def do_key_press_event(self, event):
         if not self.in_raw_input:
-            return parent_type.do_key_press_event(self, event)
+            return Gtk.TextView.do_key_press_event(self, event)
 
         tab_pressed = self.tab_pressed
         self.tab_pressed = 0
         handled = True
 
-        state = event.state & (gdk.SHIFT_MASK |
-                                gdk.CONTROL_MASK |
-                                gdk.MOD1_MASK)
+        state = event.state & (Gdk.ModifierType.SHIFT_MASK |
+                               Gdk.ModifierType.CONTROL_MASK |
+                               Gdk.ModifierType.MOD1_MASK)
         keyval = event.keyval
 
         if not state:
-            if keyval == _keys.Escape:
+            if keyval == Gdk.KEY_Escape:
                 pass
-            elif keyval == _keys.Return:
+            elif keyval == Gdk.KEY_Return:
                 self._commit()
-            elif keyval == _keys.Up:
+            elif keyval == Gdk.KEY_Up:
                 self.__history(-1)
-            elif keyval == _keys.Down:
+            elif keyval == Gdk.KEY_Down:
                 self.__history(1)
-            elif keyval == _keys.Left:
+            elif keyval == Gdk.KEY_Left:
                 self.__move_cursor(-1)
-            elif keyval == _keys.Right:
+            elif keyval == Gdk.KEY_Right:
                 self.__move_cursor(1)
-            elif keyval == _keys.Home:
+            elif keyval == Gdk.KEY_Home:
                 self.__move_cursor(-10000)
-            elif keyval == _keys.End:
+            elif keyval == Gdk.KEY_End:
                 self.__move_cursor(10000)
-            elif keyval == _keys.Tab:
+            elif keyval == Gdk.KEY_Tab:
                 cursor = self.__get_cursor()
                 if cursor.starts_line():
                     handled = False
@@ -310,12 +318,12 @@ class _ReadLine(object):
                         self.__complete()
             else:
                 handled = False
-        elif state == gdk.CONTROL_MASK:
-            if keyval == _keys.u:
+        elif state == Gdk.ModifierType.CONTROL_MASK:
+            if keyval == Gdk.KEY_u:
                 start = self.__get_start()
                 end = self.__get_cursor()
                 self.__delete(start, end)
-            elif keyval == _keys.d:
+            elif keyval == Gdk.KEY_d:
                 if self.quit_func:
                     self.quit_func()
             else:
@@ -325,7 +333,7 @@ class _ReadLine(object):
 
         # Handle ordinary keys
         if not handled:
-            return parent_type.do_key_press_event(self, event)
+            return Gtk.TextView.do_key_press_event(self, event)
         else:
             return True
 
@@ -335,7 +343,7 @@ class _ReadLine(object):
         if not new_text is None:
             self.__replace_line(new_text)
         self.__move_cursor(0)
-        self.scroll_to_mark(self.cursor, 0.2)
+        self.scroll_to_mark(self.cursor, 0.2, False, 0.0, 0.0)
 
     def __get_cursor(self):
         '''Returns an iterator at the current cursor position.'''
@@ -393,14 +401,15 @@ class _ReadLine(object):
         '''Estimate the number of characters that will fit in the area
         currently allocated to this widget.'''
 
-        if not (self.flags() & gtk.REALIZED):
+        if not self.get_realized():
             return 80
 
         context = self.get_pango_context()
         metrics = context.get_metrics(context.get_font_description(),
                                       context.get_language())
         pix_width = metrics.get_approximate_char_width()
-        return self.allocation.width * pango.SCALE / pix_width
+        allocation = Gtk.Widget.get_allocation(self)
+        return allocation.width * Pango.SCALE / pix_width
 
     def __print_completions(self, completions):
         line_start = self.__get_text(self.__get_start(), self.__get_cursor())
@@ -423,21 +432,21 @@ class _ReadLine(object):
             n_columns = total
             col_width = width / total
 
-        for i in range(col_length):
+        for i in range(int(col_length)):
             for j in range(n_columns):
                 ind = i + j*col_length
                 if ind < total:
                     if j == n_columns - 1:
                         n_spaces = 0
                     else:
-                        n_spaces = col_width - len(completions[ind])
-                    self.__insert(iter, completions[ind] + " " * n_spaces)
+                        n_spaces = int(col_width - len(completions[int(ind)]))
+                    self.__insert(iter, completions[int(ind)] + " " * n_spaces)
             self.__insert(iter, "\n")
 
         self.__insert(iter, "%s%s%s" % (self.ps, line_start, line_end))
         iter.set_line_offset(len(self.ps) + len(line_start))
         self.__move_cursor_to(iter)
-        self.scroll_to_mark(self.cursor, 0.2)
+        self.scroll_to_mark(self.cursor, 0.2, False, 0.0, 0.0)
 
     def __complete(self):
         text = self.__get_text(self.__get_start(), self.__get_cursor())
@@ -524,9 +533,9 @@ class _Console(_ReadLine, code.InteractiveInterpreter):
         # The builtin raw_input function reads from stdin, we don't want
         # this. Therefore, replace this function with our own modal raw
         # input function.
-        exec "import __builtin__" in self.locals
-        self.locals['__builtin__'].__dict__['raw_input'] = lambda text='': self.modal_raw_input(text)
-        self.locals['__builtin__'].__dict__['input'] = lambda text='': self.modal_input(text)
+        exec ("import builtins", self.locals)
+        #self.locals['builtins'].__dict__['raw_input'] = lambda text='': self.modal_raw_input(text)
+        self.locals['builtins'].__dict__['input'] = lambda text='': self.modal_input(text)
 
         self.start_script = start_script
         self.completer = completer
@@ -601,10 +610,10 @@ class _Console(_ReadLine, code.InteractiveInterpreter):
             self.showtraceback()
 
     def runcode(self, code):
-        if gtk.pygtk_version[1] < 8:
-            self.do_command(code)
-        else:
-            self.emit("command", code)
+        #if gtk.pygtk_version[1] < 8:
+        self.do_command(code)
+        #else:
+            #self.emit("command", code)
 
     def complete_attr(self, start, end):
         try:
@@ -655,7 +664,7 @@ class _Console(_ReadLine, code.InteractiveInterpreter):
         except: pass
 
         try:
-            exec "import __builtin__" in self.locals
+            exec("import __builtin__", self.locals)
             strings.extend(eval("dir(__builtin__)", self.locals))
         except:
             pass
@@ -668,35 +677,34 @@ class _Console(_ReadLine, code.InteractiveInterpreter):
         return completions
 
 
-def ReadLineType(t=gtk.TextView):
+def ReadLineType(t=Gtk.TextView):
     class readline(t, _ReadLine):
         def __init__(self, *args, **kwargs):
             t.__init__(self)
             _ReadLine.__init__(self, *args, **kwargs)
         def do_key_press_event(self, event):
-            return _ReadLine.do_key_press_event(self, event, t)
-    gobject.type_register(readline)
+            return _ReadLine.do_key_press_event(self, event)
+    GObject.type_register(readline)
     return readline
 
-def ConsoleType(t=gtk.TextView):
+def ConsoleType(t=Gtk.TextView):
     class console_type(t, _Console):
         __gsignals__ = {
-            'command' : (gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, (object,)),
-            'key-press-event' : 'override'
+            'command' : (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, (object,)),
           }
 
         def __init__(self, *args, **kwargs):
-            if gtk.pygtk_version[1] < 8:
-                gobject.GObject.__init__(self)
-            else:
-                t.__init__(self)
+            #if gtk.pygtk_version[1] < 8:
+            GObject.GObject.__init__(self)
+            #else:
+                #t.__init__(self)
             _Console.__init__(self, *args, **kwargs)
 
         def do_command(self, code):
             return _Console.do_command(self, code)
 
         def do_key_press_event(self, event):
-            return _Console.do_key_press_event(self, event, t)
+            return _Console.do_key_press_event(self, event)
 
         def get_default_size(self):
             context = self.get_pango_context()
@@ -706,13 +714,13 @@ def ConsoleType(t=gtk.TextView):
             height = metrics.get_ascent() + metrics.get_descent()
 
             # Default to a 80x40 console
-            width = pango.PIXELS(int(width * 80 * 1.05))
-            height = pango.PIXELS(height * 40)
+            width = pango_pixels(int(width * 80 * 1.05))
+            height = pango_pixels(height * 40)
 
             return width, height
 
-    if gtk.pygtk_version[1] < 8:
-        gobject.type_register(console_type)
+    #if gtk.pygtk_version[1] < 8:
+    GObject.type_register(console_type)
 
     return console_type
 
@@ -720,14 +728,14 @@ ReadLine = ReadLineType()
 Console = ConsoleType()
 
 def _make_window():
-    window = gtk.Window()
+    window = Gtk.Window()
     window.set_title("pyconsole.py")
-    swin = gtk.ScrolledWindow()
-    swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_ALWAYS)
+    swin = Gtk.ScrolledWindow()
+    swin.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.ALWAYS)
     window.add(swin)
     console = Console(banner="Hello there!",
                       use_rlcompleter=False,
-                      start_script="from gtk import *\n")
+                      start_script="gi.require_version('Gimp', '3.0')\nfrom gi.repository import Gimp\n")
     swin.add(console)
 
     width, height = console.get_default_size()
@@ -736,9 +744,9 @@ def _make_window():
     window.set_default_size(width + sb_width, height)
     window.show_all()
 
-    if not gtk.main_level():
-        window.connect("destroy", gtk.main_quit)
-        gtk.main()
+    if not Gtk.main_level():
+        window.connect("destroy", Gtk.main_quit)
+        Gtk.main()
 
     return console
 
diff --git a/plug-ins/python/python-console/python-console.py 
b/plug-ins/python/python-console/python-console.py
new file mode 100755
index 0000000000..1ec384000d
--- /dev/null
+++ b/plug-ins/python/python-console/python-console.py
@@ -0,0 +1,269 @@
+#!/usr/bin/python3
+
+#   Gimp-Python - allows the writing of Gimp plugins in Python.
+#   Copyright (C) 1997  James Henstridge <james daa com au>
+#
+#   This program 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 3 of the License, or
+#   (at your option) any later version.
+#
+#   This program 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, see <https://www.gnu.org/licenses/>.
+
+import gi
+gi.require_version('Gimp', '3.0')
+from gi.repository import Gimp
+gi.require_version('Gtk', '3.0')
+from gi.repository import Gtk
+
+import sys
+import pyconsole
+#import gimpshelf, gimpui, pyconsole
+
+import gettext
+_ = gettext.gettext
+def N_(message): return message
+
+PROC_NAME = 'python-fu-console'
+
+RESPONSE_BROWSE, RESPONSE_CLEAR, RESPONSE_SAVE = range(3)
+
+def run(name, n_params, params):
+    Gimp.ui_init ("python-console.py", False)
+
+    namespace = {'__builtins__': __builtins__,
+                 '__name__': '__main__', '__doc__': None,
+                 'cairo': gi.repository.cairo,
+                 'Gdk': gi.repository.Gdk,
+                 'Gegl': gi.repository.Gegl,
+                 'Gimp': gi.repository.Gimp,
+                 'Gio': gi.repository.Gio,
+                 'Gtk': gi.repository.Gtk,
+                 'GdkPixbuf': gi.repository.GdkPixbuf,
+                 'GLib': gi.repository.GLib,
+                 'GObject': gi.repository.GObject,
+                 'Pango': gi.repository.Pango }
+
+    class GimpConsole(pyconsole.Console):
+        def __init__(self, quit_func=None):
+            banner = ('GIMP %s Python Console\nPython %s\n' %
+                      (Gimp.version(), sys.version))
+            pyconsole.Console.__init__(self,
+                                       locals=namespace, banner=banner,
+                                       quit_func=quit_func)
+        def _commit(self):
+            pyconsole.Console._commit(self)
+            Gimp.displays_flush()
+
+    class ConsoleDialog(Gimp.Dialog):
+        def __init__(self):
+            Gimp.Dialog.__init__(self)
+            self.set_property("help-id", PROC_NAME)
+            Gtk.Window.set_title(self, _("Python Console"))
+            Gtk.Window.set_role(self, PROC_NAME)
+            Gtk.Dialog.add_button(self, "Save", Gtk.ResponseType.OK)
+            Gtk.Dialog.add_button(self, "Clear", RESPONSE_CLEAR)
+            Gtk.Dialog.add_button(self, _("_Browse..."), RESPONSE_BROWSE)
+            Gtk.Dialog.add_button(self, "Close", Gtk.ResponseType.CLOSE)
+
+            Gtk.Widget.set_name (self, PROC_NAME)
+            Gtk.Dialog.set_alternative_button_order_from_array(self,
+                                                               [ Gtk.ResponseType.CLOSE,
+                                                                 RESPONSE_BROWSE,
+                                                                 RESPONSE_CLEAR,
+                                                                 Gtk.ResponseType.OK ])
+
+            self.cons = GimpConsole(quit_func=lambda: Gtk.main_quit())
+
+            self.style_set (None, None)
+
+            self.connect('response', self.response)
+            self.connect('style-set', self.style_set)
+
+            self.browse_dlg = None
+            self.save_dlg = None
+
+            vbox = Gtk.VBox(homogeneous=False, spacing=12)
+            vbox.set_border_width(12)
+            contents_area = Gtk.Dialog.get_content_area(self)
+            contents_area.pack_start(vbox, True, True, 0)
+
+            scrl_win = Gtk.ScrolledWindow()
+            scrl_win.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.ALWAYS)
+            vbox.pack_start(scrl_win, True, True, 0)
+
+            scrl_win.add(self.cons)
+
+            width, height = self.cons.get_default_size()
+            minreq, requisition = Gtk.Widget.get_preferred_size(scrl_win.get_vscrollbar())
+            sb_width  = requisition.width
+            sb_height = requisition.height
+
+            # Account for scrollbar width and border width to ensure
+            # the text view gets a width of 80 characters. We don't care
+            # so much whether the height will be exactly 40 characters.
+            Gtk.Window.set_default_size(self, width + sb_width + 2 * 12, height)
+
+        def style_set(self, old_style, user_data):
+            pass
+            #style = Gtk.Widget.get_style (self)
+            #self.cons.stdout_tag.set_property ("foreground", style.text[Gtk.StateType.NORMAL])
+            #self.cons.stderr_tag.set_property ("foreground", style.text[Gtk.StateType.INSENSITIVE])
+
+        def response(self, dialog, response_id):
+            if response_id == RESPONSE_BROWSE:
+                self.browse()
+            elif response_id == RESPONSE_CLEAR:
+                self.cons.banner = None
+                self.cons.clear()
+            elif response_id == Gtk.ResponseType.OK:
+                self.save_dialog()
+            else:
+                Gtk.main_quit()
+
+            self.cons.grab_focus()
+
+        def browse_response(self, dlg, response_id):
+            if response_id != Gtk.ResponseType.APPLY:
+                Gtk.Widget.hide(dlg)
+                return
+
+            proc_name = dlg.get_selected()
+
+            if not proc_name:
+                return
+
+            proc = pdb[proc_name]
+
+            cmd = ''
+
+            if len(proc.return_vals) > 0:
+                cmd = ', '.join(x[1].replace('-', '_')
+                                for x in proc.return_vals) + ' = '
+
+            cmd = cmd + 'pdb.%s' % proc.proc_name.replace('-', '_')
+
+            if len(proc.params) > 0 and proc.params[0][1] == 'run-mode':
+                params = proc.params[1:]
+            else:
+                params = proc.params
+
+            cmd = cmd + '(%s)' % ', '.join(x[1].replace('-', '_')
+                                           for x in params)
+
+            buffer = self.cons.buffer
+
+            lines = buffer.get_line_count()
+            iter = buffer.get_iter_at_line_offset(lines - 1, 4)
+            buffer.delete(iter, buffer.get_end_iter())
+            buffer.place_cursor(buffer.get_end_iter())
+            buffer.insert_at_cursor(cmd)
+
+        def browse(self):
+            if not self.browse_dlg:
+                dlg = Gimp.ProcBrowserDialog()
+                Gtk.Window.set_title(dlg, _("Python Procedure Browser"))
+                Gtk.Window.set_role(dlg, PROC_NAME)
+                Gtk.Dialog.add_button(dlg, "Apply", Gtk.ResponseType.APPLY)
+                Gtk.Dialog.add_button(dlg, "Close", Gtk.ResponseType.CLOSE)
+
+                Gtk.Dialog.set_default_response(self, Gtk.ResponseType.OK)
+                Gtk.Dialog.set_alternative_button_order_from_array(dlg,
+                                                                   [ Gtk.ResponseType.CLOSE,
+                                                                     Gtk.ResponseType.APPLY ])
+
+                dlg.connect('response', self.browse_response)
+                dlg.connect('row-activated',
+                            lambda dlg: dlg.response(Gtk.ResponseType.APPLY))
+
+                self.browse_dlg = dlg
+
+            Gtk.Window.present(self.browse_dlg)
+
+        def save_response(self, dlg, response_id):
+            if response_id == Gtk.ResponseType.DELETE_EVENT:
+                self.save_dlg = None
+                return
+            elif response_id == Gtk.ResponseType.OK:
+                filename = dlg.get_filename()
+
+                try:
+                    logfile = open(filename, 'w')
+                except IOError as e:
+                    Gimp.message(_("Could not open '%s' for writing: %s") %
+                                 (filename, e.strerror))
+                    return
+
+                buffer = self.cons.buffer
+
+                start = buffer.get_start_iter()
+                end = buffer.get_end_iter()
+
+                log = buffer.get_text(start, end, False)
+
+                try:
+                    logfile.write(log)
+                    logfile.close()
+                except IOError as e:
+                    Gimp.message(_("Could not write to '%s': %s") %
+                                 (filename, e.strerror))
+                    return
+
+            Gtk.Widget.hide(dlg)
+
+        def save_dialog(self):
+            if not self.save_dlg:
+                dlg = Gtk.FileChooserDialog()
+                Gtk.Window.set_title(dlg, _("Save Python-Fu Console Output"))
+                Gtk.Window.set_transient_for(dlg, self)
+                Gtk.Dialog.add_button(dlg, "Cancel", Gtk.ResponseType.CANCEL)
+                Gtk.Dialog.add_button(dlg, "Save", Gtk.ResponseType.OK)
+                Gtk.Dialog.set_default_response(self, Gtk.ResponseType.OK)
+                Gtk.Dialog.set_alternative_button_order_from_array(dlg,
+                                                                   [ Gtk.ResponseType.OK,
+                                                                     Gtk.ResponseType.CANCEL ])
+
+                dlg.connect('response', self.save_response)
+
+                self.save_dlg = dlg
+
+            self.save_dlg.present()
+
+        def run(self):
+            Gtk.Widget.show_all(self)
+            Gtk.main()
+
+    ConsoleDialog().run()
+    retval = [Gimp.param_from_status (Gimp.PDBStatusType.SUCCESS)]
+    return len(retval), retval
+
+def query():
+    param = Gimp.ParamDef()
+    param.type = Gimp.PDBArgType.INT32
+    param.name = "run-mode"
+    param.description = _("Run mode")
+
+    Gimp.install_procedure(
+        PROC_NAME,
+        N_("Interactive GIMP Python interpreter"),
+        "Type in commands and see results",
+        "James Henstridge",
+        "James Henstridge",
+        "1997-1999",
+        N_("_Console"),
+        "",
+        Gimp.PDBProcType.PLUGIN,
+        [ param ],
+        [])
+    Gimp.plugin_menu_register(PROC_NAME, "<Image>/Filters/Languages/Python-Fu")
+    Gimp.plugin_domain_register("gimp30-python", Gimp.locale_directory())
+
+info = Gimp.PlugInInfo ()
+info.set_callbacks (None, None, query, run)
+Gimp.main_legacy (info, sys.argv)


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