[eog-plugins] pythonconsole: Import changes from gedit's pythonconsole plugin



commit 3d2ec1ef54cfa21bd245a943ff68e04fa3c950d8
Author: Felix Riemann <friemann gnome org>
Date:   Tue Feb 14 19:07:55 2012 +0100

    pythonconsole: Import changes from gedit's pythonconsole plugin
    
    This imports 3-4 years of changes done to the gedit variant of the
    plugin. It contains mostly under the hood stuff but is also slightly
    more configurable (colors, fonts). So, kudos go to the original authors.
    We only use some slightly different defaults in eog.

 configure.ac                                       |   14 +
 plugins/pythonconsole/Makefile.am                  |   26 ++-
 plugins/pythonconsole/__init__.py                  |   13 +-
 plugins/pythonconsole/config.py                    |   74 +++++
 plugins/pythonconsole/config.ui                    |  136 ++++++++++
 plugins/pythonconsole/console.py                   |  286 ++++++++++++++------
 ...ome.eog.plugins.pythonconsole.gschema.xml.in.in |   30 ++
 po/POTFILES.in                                     |    2 +
 po/POTFILES.skip                                   |    1 +
 9 files changed, 488 insertions(+), 94 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 5e3fc08..9ec4f26 100644
--- a/configure.ac
+++ b/configure.ac
@@ -294,6 +294,19 @@ then
     fi
 fi
 
+# ***********
+# PythonConsole
+# ***********
+plugin_defined pythonconsole
+if test "$?" = 1
+then
+
+    PKG_CHECK_EXISTS([ gsettings-desktop-schemas ],
+        [],
+	undef_plugin pythonconsole "gsettings-desktop-schemas missing"
+    )
+fi
+
 
 if test -z "$disabled_plugins"
 then
@@ -332,6 +345,7 @@ plugins/slideshowshuffle/Makefile
 plugins/postr/Makefile
 plugins/postasa/Makefile
 plugins/pythonconsole/Makefile
+plugins/pythonconsole/org.gnome.eog.plugins.pythonconsole.gschema.xml.in
 po/Makefile.in])
 
 AC_OUTPUT
diff --git a/plugins/pythonconsole/Makefile.am b/plugins/pythonconsole/Makefile.am
index c1dbc90..dbcd76d 100644
--- a/plugins/pythonconsole/Makefile.am
+++ b/plugins/pythonconsole/Makefile.am
@@ -1,19 +1,33 @@
 # Python Console plugin
-plugindir = $(libdir)/eog/plugins
+plugindir = $(EOG_PLUGINS_LIBS_DIR)
 pythonconsoledir = $(plugindir)/pythonconsole
+uidir = $(EOG_PLUGINS_DATA_DIR)/pythonconsole
 plugin_in_files = pythonconsole.plugin.desktop.in
 
-pythonconsole_PYTHON = \
-	__init__.py \
+pythonconsole_PYTHON =	\
+	__init__.py	\
+	config.py	\
 	console.py
 
+UI_FILES = config.ui
+ui_DATA = $(UI_FILES)
+
 %.plugin: %.plugin.desktop.in $(INTLTOOL_MERGE) $(wildcard $(top_srcdir)/po/*po) ; $(AM_V_GEN)$(INTLTOOL_MERGE) $(top_srcdir)/po $< $@ -d -u -c $(top_builddir)/po/.intltool-merge-cache
 
 plugin_DATA = $(plugin_in_files:.plugin.desktop.in=.plugin)
 
-EXTRA_DIST = $(plugin_in_files)
+gsettings_SCHEMAS = org.gnome.eog.plugins.pythonconsole.gschema.xml
+ INTLTOOL_XML_NOMERGE_RULE@
+ GSETTINGS_RULES@
+
+EXTRA_DIST = \
+	$(plugin_in_files)	\
+	$(UI_FILES)		\
+	org.gnome.eog.plugins.pythonconsole.gschema.xml.in.in
+
 
-CLEANFILES = $(plugin_DATA)
-DISTCLEANFILES = $(plugin_DATA)
+CLEANFILES = $(plugin_DATA) $(gsettings_SCHEMAS)
+DISTCLEANFILES = $(plugin_DATA) $(gsettings_SCHEMAS)
+MAINTAINERCLEANFILES = $(gsettings_SCHEMAS:.xml=.valid)
 
 -include $(top_srcdir)/git.mk
diff --git a/plugins/pythonconsole/__init__.py b/plugins/pythonconsole/__init__.py
index 592f211..285e65e 100644
--- a/plugins/pythonconsole/__init__.py
+++ b/plugins/pythonconsole/__init__.py
@@ -25,8 +25,10 @@
 #     Copyright (C), 2005 Adam Hooper <adamh densi com>
 #     Copyrignt (C), 2005 RaphaÃl Slinckx
 
-from gi.repository import GObject, Gtk, Eog
+from gi.repository import GObject, Gtk, Eog, PeasGtk
+
 from console import PythonConsole
+from config import PythonConsoleConfigWidget
 
 ui_str = """
     <ui>
@@ -41,7 +43,7 @@ ui_str = """
     """
 
 
-class PythonConsolePlugin(GObject.Object, Eog.WindowActivatable):
+class PythonConsolePlugin(GObject.Object, Eog.WindowActivatable, PeasGtk.Configurable):
 
     # Override EogWindowActivatable's window property
     window = GObject.property(type=Eog.Window)
@@ -74,7 +76,7 @@ class PythonConsolePlugin(GObject.Object, Eog.WindowActivatable):
         if not self.console_window:
             self.console_window = Gtk.Window()
             console = PythonConsole(namespace = {'__builtins__' : __builtins__,
-                                                 'eog' : Eog,
+                                                 'Eog' : Eog,
                                                  'window' : window})
             console.set_size_request(600, 400)
             console.eval('print "You can access the main window through ' \
@@ -93,3 +95,8 @@ class PythonConsolePlugin(GObject.Object, Eog.WindowActivatable):
     def on_delete_cb(self, window, event):
         window.destroy()
         self.console_window = None
+
+    def do_create_configure_widget(self):
+        config_widget = PythonConsoleConfigWidget(self.plugin_info.get_data_dir())
+
+        return config_widget.configure_widget()
diff --git a/plugins/pythonconsole/config.py b/plugins/pythonconsole/config.py
new file mode 100644
index 0000000..51cb2f6
--- /dev/null
+++ b/plugins/pythonconsole/config.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+
+# config.py -- Config dialog
+#
+# Copyright (C) 2008 - B. Clausius
+#
+# 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 2, 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Parts from "Interactive Python-GTK Console" (stolen from epiphany's console.py)
+#     Copyright (C), 1998 James Henstridge <james daa com au>
+#     Copyright (C), 2005 Adam Hooper <adamh densi com>
+# Bits from gedit Python Console Plugin
+#     Copyrignt (C), 2005 RaphaÃl Slinckx
+
+import os
+from gi.repository import Gio, Gtk, Gdk
+
+__all__ = ('PythonConsoleConfigWidget')
+
+class PythonConsoleConfigWidget(object):
+
+    CONSOLE_KEY_BASE = 'org.gnome.eog.plugins.pythonconsole'
+    CONSOLE_KEY_COMMAND_COLOR = 'command-color'
+    CONSOLE_KEY_ERROR_COLOR = 'error-color'
+
+    def __init__(self, datadir):
+        object.__init__(self)
+
+        self._ui_path = os.path.join(datadir, 'config.ui')
+        self._settings = Gio.Settings.new(self.CONSOLE_KEY_BASE)
+        self._ui = Gtk.Builder()
+
+    def configure_widget(self):
+        self._ui.add_objects_from_file(self._ui_path, ["grid"])
+
+        self.set_colorbutton_color(self._ui.get_object('colorbutton-command'),
+                                   self._settings.get_string(self.CONSOLE_KEY_COMMAND_COLOR))
+        self.set_colorbutton_color(self._ui.get_object('colorbutton-error'),
+                                   self._settings.get_string(self.CONSOLE_KEY_ERROR_COLOR))
+
+        self._ui.connect_signals(self)
+
+        widget = self._ui.get_object('grid')
+
+        return widget
+
+    @staticmethod
+    def set_colorbutton_color(colorbutton, value):
+        color = Gdk.color_parse(value)
+
+        if color is not None:
+            colorbutton.set_color(color)
+
+    def on_colorbutton_command_color_set(self, colorbutton):
+        self._settings.set_string(self.CONSOLE_KEY_COMMAND_COLOR,
+                                  colorbutton.get_color().to_string())
+
+    def on_colorbutton_error_color_set(self, colorbutton):
+        self._settings.set_string(self.CONSOLE_KEY_ERROR_COLOR,
+                                  colorbutton.get_color().to_string())
+
+# ex:et:ts=4:
diff --git a/plugins/pythonconsole/config.ui b/plugins/pythonconsole/config.ui
new file mode 100644
index 0000000..5899644
--- /dev/null
+++ b/plugins/pythonconsole/config.ui
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <object class="GtkDialog" id="dialog-config">
+    <property name="can_focus">False</property>
+    <property name="window_position">center-on-parent</property>
+    <property name="destroy_with_parent">True</property>
+    <property name="type_hint">dialog</property>
+    <signal name="destroy" handler="on_dialog_config_destroy" swapped="no"/>
+    <signal name="response" handler="on_dialog_config_response" swapped="no"/>
+    <child internal-child="vbox">
+      <object class="GtkBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="orientation">vertical</property>
+        <child>
+          <object class="GtkGrid" id="grid">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="margin_left">12</property>
+            <property name="margin_right">12</property>
+            <property name="margin_top">12</property>
+            <property name="margin_bottom">12</property>
+            <property name="row_spacing">6</property>
+            <property name="column_spacing">12</property>
+            <child>
+              <object class="GtkLabel" id="label-command">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">C_ommand color:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">colorbutton-command</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkLabel" id="label-error">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">_Error color:</property>
+                <property name="use_underline">True</property>
+                <property name="mnemonic_widget">colorbutton-error</property>
+              </object>
+              <packing>
+                <property name="left_attach">0</property>
+                <property name="top_attach">1</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkColorButton" id="colorbutton-command">
+                <property name="use_action_appearance">False</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="hexpand">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="color">#31314e4e6c6c</property>
+                <signal name="color-set" handler="on_colorbutton_command_color_set" swapped="no"/>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">0</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkColorButton" id="colorbutton-error">
+                <property name="use_action_appearance">False</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="hexpand">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="color">#999900000000</property>
+                <signal name="color-set" handler="on_colorbutton_error_color_set" swapped="no"/>
+              </object>
+              <packing>
+                <property name="left_attach">1</property>
+                <property name="top_attach">1</property>
+                <property name="width">1</property>
+                <property name="height">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="button1">
+                <property name="label">gtk-close</property>
+                <property name="use_action_appearance">False</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+                <property name="use_action_appearance">False</property>
+                <property name="use_stock">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="fill">True</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="-7">button1</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/plugins/pythonconsole/console.py b/plugins/pythonconsole/console.py
index f7ce04b..8e13ddc 100644
--- a/plugins/pythonconsole/console.py
+++ b/plugins/pythonconsole/console.py
@@ -28,30 +28,54 @@ import string
 import sys
 import re
 import traceback
-from gi.repository import GObject, Gdk, Gtk, Pango
+
+from gi.repository import GObject, Gio, Gtk, Gdk, Pango
 
 __all__ = ('PythonConsole', 'OutFile')
 
 
 class PythonConsole(Gtk.ScrolledWindow):
+
+    __gsignals__ = {
+        'grab-focus' : 'override',
+    }
+
+    DEFAULT_FONT = "Monospace 11"
+
+    CONSOLE_KEY_BASE = 'org.gnome.eog.plugins.pythonconsole'
+    SETTINGS_INTERFACE_DIR = "org.gnome.desktop.interface"
+
+    CONSOLE_KEY_COMMAND_COLOR = 'command-color'
+    CONSOLE_KEY_ERROR_COLOR = 'error-color'
+
     def __init__(self, namespace = {}):
         Gtk.ScrolledWindow.__init__(self)
 
+        self._settings = Gio.Settings.new(self.CONSOLE_KEY_BASE)
+        self._settings.connect("changed", self.on_color_settings_changed)
+
+        self._interface_settings = Gio.Settings.new(self.SETTINGS_INTERFACE_DIR)
+        self._interface_settings.connect("changed", self.on_settings_changed)
+
+        self._profile_settings = self.get_profile_settings()
+        self._profile_settings.connect("changed", self.on_settings_changed)
+
         self.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
         self.set_shadow_type(Gtk.ShadowType.IN)
         self.view = Gtk.TextView()
-        self.view.modify_font(Pango.FontDescription('Monospace'))
+        self.reconfigure()
         self.view.set_editable(True)
         self.view.set_wrap_mode(Gtk.WrapMode.WORD_CHAR)
         self.add(self.view)
         self.view.show()
 
-        buffer = self.view.get_buffer()
-        self.normal = buffer.create_tag("normal")
-        self.error  = buffer.create_tag("error")
-        self.error.set_property("foreground", "red")
-        self.command = buffer.create_tag("command")
-        self.command.set_property("foreground", "blue")
+        buf = self.view.get_buffer()
+        self.normal = buf.create_tag("normal")
+        self.error  = buf.create_tag("error")
+        self.command = buf.create_tag("command")
+
+        # Load the default settings
+        self.on_color_settings_changed(self._settings, None)
 
         self.__spaces_pattern = re.compile(r'^\s+')
         self.namespace = namespace
@@ -59,9 +83,9 @@ class PythonConsole(Gtk.ScrolledWindow):
         self.block_command = False
 
         # Init first line
-        buffer.create_mark("input-line", buffer.get_end_iter(), True)
-        buffer.insert(buffer.get_end_iter(), ">>> ")
-        buffer.create_mark("input", buffer.get_end_iter(), True)
+        buf.create_mark("input-line", buf.get_end_iter(), True)
+        buf.insert(buf.get_end_iter(), ">>> ")
+        buf.create_mark("input", buf.get_end_iter(), True)
 
         # Init history
         self.history = ['']
@@ -75,56 +99,104 @@ class PythonConsole(Gtk.ScrolledWindow):
 
         # Signals
         self.view.connect("key-press-event", self.__key_press_event_cb)
-        buffer.connect("mark-set", self.__mark_set_cb)
+        buf.connect("mark-set", self.__mark_set_cb)
+
+    def get_profile_settings(self):
+        #FIXME return either the gnome-terminal settings or the eog one
+        return Gio.Settings.new(self.CONSOLE_KEY_BASE)
+
+    def do_grab_focus(self):
+        self.view.grab_focus()
+
+    def reconfigure(self):
+        # Font
+        font_desc = None
+        system_font = self._interface_settings.get_string("monospace-font-name")
+
+        if self._profile_settings.get_boolean("use-system-font"):
+            font_name = system_font
+        else:
+            font_name = self._profile_settings.get_string("font")
+
+        try:
+            font_desc = Pango.FontDescription(font_name)
+        except:
+            if font_name != self.DEFAULT_FONT:
+                if font_name != system_font:
+                    try:
+                        font_desc = Pango.FontDescription(system_font)
+                    except:
+                        pass
+
+                if font_desc == None:
+                    try:
+                        font_desc = Pango.FontDescription(self.DEFAULT_FONT)
+                    except:
+                        pass
 
+        if font_desc != None:
+            self.view.modify_font(font_desc)
+
+    def on_settings_changed(self, settings, key):
+        self.reconfigure()
+
+    def on_color_settings_changed(self, settings, key):
+        self.error.set_property("foreground", settings.get_string(self.CONSOLE_KEY_ERROR_COLOR))
+        self.command.set_property("foreground", settings.get_string(self.CONSOLE_KEY_COMMAND_COLOR))
+
+    def stop(self):
+        self.namespace = None
 
     def __key_press_event_cb(self, view, event):
-        if event.keyval == Gdk.KEY_d and event.state == Gdk.ModifierType.CONTROL_MASK:
+        modifier_mask = Gtk.accelerator_get_default_mod_mask()
+        event_state = event.state & modifier_mask
+
+        if event.keyval == Gdk.KEY_D and event_state == Gdk.ModifierType.CONTROL_MASK:
             self.destroy()
 
-        elif event.keyval == Gdk.KEY_Return and event.state == Gdk.ModifierType.CONTROL_MASK:
+        elif event.keyval == Gdk.KEY_Return and event_state == Gdk.ModifierType.CONTROL_MASK:
             # Get the command
-            buffer = view.get_buffer()
-            inp_mark = buffer.get_mark("input")
-            inp = buffer.get_iter_at_mark(inp_mark)
-            cur = buffer.get_end_iter()
-            line = buffer.get_text(inp, cur, False)
+            buf = view.get_buffer()
+            inp_mark = buf.get_mark("input")
+            inp = buf.get_iter_at_mark(inp_mark)
+            cur = buf.get_end_iter()
+            line = buf.get_text(inp, cur, False)
             self.current_command = self.current_command + line + "\n"
             self.history_add(line)
 
             # Prepare the new line
-            cur = buffer.get_end_iter()
-            buffer.insert(cur, "\n... ")
-            cur = buffer.get_end_iter()
-            buffer.move_mark(inp_mark, cur)
+            cur = buf.get_end_iter()
+            buf.insert(cur, "\n... ")
+            cur = buf.get_end_iter()
+            buf.move_mark(inp_mark, cur)
 
             # Keep indentation of precendent line
             spaces = re.match(self.__spaces_pattern, line)
             if spaces is not None:
-                buffer.insert(cur, line[spaces.start() : spaces.end()])
-                cur = buffer.get_end_iter()
+                buf.insert(cur, line[spaces.start() : spaces.end()])
+                cur = buf.get_end_iter()
 
-            buffer.place_cursor(cur)
+            buf.place_cursor(cur)
             GObject.idle_add(self.scroll_to_end)
             return True
 
         elif event.keyval == Gdk.KEY_Return:
             # Get the marks
-            buffer = view.get_buffer()
-            lin_mark = buffer.get_mark("input-line")
-            inp_mark = buffer.get_mark("input")
+            buf = view.get_buffer()
+            lin_mark = buf.get_mark("input-line")
+            inp_mark = buf.get_mark("input")
 
             # Get the command line
-            inp = buffer.get_iter_at_mark(inp_mark)
-            cur = buffer.get_end_iter()
-            line = buffer.get_text(inp, cur, False)
+            inp = buf.get_iter_at_mark(inp_mark)
+            cur = buf.get_end_iter()
+            line = buf.get_text(inp, cur, False)
             self.current_command = self.current_command + line + "\n"
             self.history_add(line)
 
             # Make the line blue
-            lin = buffer.get_iter_at_mark(lin_mark)
-            buffer.apply_tag(self.command, lin, cur)
-            buffer.insert(cur, "\n")
+            lin = buf.get_iter_at_mark(lin_mark)
+            buf.apply_tag(self.command, lin, cur)
+            buf.insert(cur, "\n")
 
             cur_strip = self.current_command.rstrip()
 
@@ -143,12 +215,12 @@ class PythonConsole(Gtk.ScrolledWindow):
                 com_mark = ">>> "
 
             # Prepare the new line
-            cur = buffer.get_end_iter()
-            buffer.move_mark(lin_mark, cur)
-            buffer.insert(cur, com_mark)
-            cur = buffer.get_end_iter()
-            buffer.move_mark(inp_mark, cur)
-            buffer.place_cursor(cur)
+            cur = buf.get_end_iter()
+            buf.move_mark(lin_mark, cur)
+            buf.insert(cur, com_mark)
+            cur = buf.get_end_iter()
+            buf.move_mark(inp_mark, cur)
+            buf.place_cursor(cur)
             GObject.idle_add(self.scroll_to_end)
             return True
 
@@ -168,40 +240,78 @@ class PythonConsole(Gtk.ScrolledWindow):
 
         elif event.keyval == Gdk.KEY_KP_Left or event.keyval == Gdk.KEY_Left or \
              event.keyval == Gdk.KEY_BackSpace:
-            buffer = view.get_buffer()
-            inp = buffer.get_iter_at_mark(buffer.get_mark("input"))
-            cur = buffer.get_iter_at_mark(buffer.get_insert())
-            return inp.compare(cur) == 0
-
-        elif event.keyval == Gdk.KEY_Home:
+            buf = view.get_buffer()
+            inp = buf.get_iter_at_mark(buf.get_mark("input"))
+            cur = buf.get_iter_at_mark(buf.get_insert())
+            if inp.compare(cur) == 0:
+                if not event_state:
+                    buf.place_cursor(inp)
+                return True
+            return False
+
+        # For the console we enable smart/home end behavior incoditionally
+        # since it is useful when editing python
+
+        elif (event.keyval == Gdk.KEY_KP_Home or event.keyval == Gdk.KEY_Home) and \
+             event_state == event_state & (Gdk.ModifierType.SHIFT_MASK|Gdk.ModifierType.CONTROL_MASK):
             # Go to the begin of the command instead of the begin of the line
-            buffer = view.get_buffer()
-            inp = buffer.get_iter_at_mark(buffer.get_mark("input"))
-            if event.state == Gdk.ModifierType.SHIFT_MASK:
-                buffer.move_mark_by_name("insert", inp)
+            buf = view.get_buffer()
+            it = buf.get_iter_at_mark(buf.get_mark("input"))
+            ins = buf.get_iter_at_mark(buf.get_insert())
+
+            while it.get_char().isspace():
+                it.forward_char()
+
+            if it.equal(ins):
+                it = buf.get_iter_at_mark(buf.get_mark("input"))
+
+            if event_state & Gdk.ModifierType.SHIFT_MASK:
+                buf.move_mark_by_name("insert", it)
             else:
-                buffer.place_cursor(inp)
+                buf.place_cursor(it)
             return True
 
-    def __mark_set_cb(self, buffer, iter, name):
-        input = buffer.get_iter_at_mark(buffer.get_mark("input"))
-        pos   = buffer.get_iter_at_mark(buffer.get_insert())
+        elif (event.keyval == Gdk.KEY_KP_End or event.keyval == Gdk.KEY_End) and \
+             event_state == event_state & (Gdk.ModifierType.SHIFT_MASK|Gdk.ModifierType.CONTROL_MASK):
+
+            buf = view.get_buffer()
+            it = buf.get_end_iter()
+            ins = buf.get_iter_at_mark(buf.get_insert())
+
+            it.backward_char()
+
+            while it.get_char().isspace():
+                it.backward_char()
+
+            it.forward_char()
+
+            if it.equal(ins):
+                it = buf.get_end_iter()
+
+            if event_state & Gdk.ModifierType.SHIFT_MASK:
+                buf.move_mark_by_name("insert", it)
+            else:
+                buf.place_cursor(it)
+            return True
+
+    def __mark_set_cb(self, buf, it, name):
+        input = buf.get_iter_at_mark(buf.get_mark("input"))
+        pos   = buf.get_iter_at_mark(buf.get_insert())
         self.view.set_editable(pos.compare(input) != -1)
 
     def get_command_line(self):
-        buffer = self.view.get_buffer()
-        inp = buffer.get_iter_at_mark(buffer.get_mark("input"))
-        cur = buffer.get_end_iter()
-        return buffer.get_text(inp, cur, False)
+        buf = self.view.get_buffer()
+        inp = buf.get_iter_at_mark(buf.get_mark("input"))
+        cur = buf.get_end_iter()
+        return buf.get_text(inp, cur, False)
 
     def set_command_line(self, command):
-        buffer = self.view.get_buffer()
-        mark = buffer.get_mark("input")
-        inp = buffer.get_iter_at_mark(mark)
-        cur = buffer.get_end_iter()
-        buffer.delete(inp, cur)
-        buffer.insert(inp, command)
-        buffer.select_range(buffer.get_iter_at_mark(mark), buffer.get_end_iter())
+        buf = self.view.get_buffer()
+        mark = buf.get_mark("input")
+        inp = buf.get_iter_at_mark(mark)
+        cur = buf.get_end_iter()
+        buf.delete(inp, cur)
+        buf.insert(inp, command)
         self.view.grab_focus()
 
     def history_add(self, line):
@@ -223,23 +333,24 @@ class PythonConsole(Gtk.ScrolledWindow):
             self.set_command_line(self.history[self.history_pos])
 
     def scroll_to_end(self):
-        iter = self.view.get_buffer().get_end_iter()
-        self.view.scroll_to_iter(iter, 0.0, False, 0.5, 0.5)
+        i = self.view.get_buffer().get_end_iter()
+        self.view.scroll_to_iter(i, 0.0, False, 0.5, 0.5)
         return False
 
     def write(self, text, tag = None):
-        buffer = self.view.get_buffer()
+        buf = self.view.get_buffer()
         if tag is None:
-            buffer.insert(buffer.get_end_iter(), text)
+            buf.insert(buf.get_end_iter(), text)
         else:
-            buffer.insert_with_tags(buffer.get_end_iter(), text, tag)
+            buf.insert_with_tags(buf.get_end_iter(), text, tag)
+
         GObject.idle_add(self.scroll_to_end)
 
     def eval(self, command, display_command = False):
-        buffer = self.view.get_buffer()
-        lin = buffer.get_mark("input-line")
-        buffer.delete(buffer.get_iter_at_mark(lin),
-                      buffer.get_end_iter())
+        buf = self.view.get_buffer()
+        lin = buf.get_mark("input-line")
+        buf.delete(buf.get_iter_at_mark(lin),
+                   buf.get_end_iter())
 
         if isinstance(command, list) or isinstance(command, tuple):
             for c in command:
@@ -251,24 +362,29 @@ class PythonConsole(Gtk.ScrolledWindow):
                 self.write(">>> " + c + "\n", self.command)
             self.__run(command)
 
-        cur = buffer.get_end_iter()
-        buffer.move_mark_by_name("input-line", cur)
-        buffer.insert(cur, ">>> ")
-        cur = buffer.get_end_iter()
-        buffer.move_mark_by_name("input", cur)
-        self.view.scroll_to_iter(buffer.get_end_iter(), 0.0, False, 0.5, 0.5)
+        cur = buf.get_end_iter()
+        buf.move_mark_by_name("input-line", cur)
+        buf.insert(cur, ">>> ")
+        cur = buf.get_end_iter()
+        buf.move_mark_by_name("input", cur)
+        self.view.scroll_to_iter(buf.get_end_iter(), 0.0, False, 0.5, 0.5)
 
     def __run(self, command):
         sys.stdout, self.stdout = self.stdout, sys.stdout
         sys.stderr, self.stderr = self.stderr, sys.stderr
 
+        # eval and exec are broken in how they deal with utf8-encoded
+        # strings so we have to explicitly decode the command before
+        # passing it along
+        command = command.decode('utf8')
+
         try:
             try:
                 r = eval(command, self.namespace, self.namespace)
                 if r is not None:
-                    print `r`
+                    print(r)
             except SyntaxError:
-                exec command in self.namespace
+                exec(command, self.namespace)
         except:
             if hasattr(sys, 'last_type') and sys.last_type == SystemExit:
                 self.destroy()
@@ -299,6 +415,6 @@ class OutFile:
     def readlines(self):     return []
     def write(self, s):      self.console.write(s, self.tag)
     def writelines(self, l): self.console.write(l, self.tag)
-    def seek(self, a):       raise IOError, (29, 'Illegal seek')
-    def tell(self):          raise IOError, (29, 'Illegal seek')
+    def seek(self, a):       raise IOError((29, 'Illegal seek'))
+    def tell(self):          raise IOError((29, 'Illegal seek'))
     truncate = tell
diff --git a/plugins/pythonconsole/org.gnome.eog.plugins.pythonconsole.gschema.xml.in.in b/plugins/pythonconsole/org.gnome.eog.plugins.pythonconsole.gschema.xml.in.in
new file mode 100644
index 0000000..07e18f1
--- /dev/null
+++ b/plugins/pythonconsole/org.gnome.eog.plugins.pythonconsole.gschema.xml.in.in
@@ -0,0 +1,30 @@
+<schemalist>
+  <schema gettext-domain="@GETTEXT_PACKAGE@" id="org.gnome.eog.plugins.pythonconsole" path="/org/gnome/eog/plugins/pythonconsole/">
+    <key name="command-color" type="s">
+      <default>'#0000FF'</default>
+      <_summary>Command Text Color</_summary>
+      <_description>The color used for commands.</_description>
+    </key>
+    <key name="error-color" type="s">
+      <default>'#FF0000'</default>
+      <_summary>Error Text Color</_summary>
+      <_description>The color used for errors.</_description>
+    </key>
+    <key name="use-system-font" type="b">
+      <default>true</default>
+      <_summary>Whether to use the system font</_summary>
+      <_description>
+        If true, the terminal will use the desktop-global standard
+        font if it's monospace (and the most similar font it can
+        come up with otherwise).
+      </_description>
+    </key>
+    <key name="font" type="s">
+      <default>'Monospace 10'</default>
+      <_summary>Font used by Python Console</_summary>
+      <_description>
+        A Pango font name. Examples are "Sans 12" or "Monospace Bold 14".
+      </_description>
+    </key>
+  </schema>
+</schemalist>
diff --git a/po/POTFILES.in b/po/POTFILES.in
index d217c0b..fe26f94 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -15,6 +15,8 @@ plugins/postasa/eog-postasa-plugin.c
 plugins/postasa/postasa.plugin.desktop.in
 plugins/postr/eog-postr-plugin.c
 plugins/postr/postr.plugin.desktop.in
+[type: gettext/glade]plugins/pythonconsole/config.ui
+plugins/pythonconsole/org.gnome.eog.plugins.pythonconsole.gschema.xml.in.in
 plugins/pythonconsole/pythonconsole.plugin.desktop.in
 plugins/send-by-mail/eog-send-by-mail-plugin.c
 plugins/send-by-mail/send-by-mail.plugin.desktop.in
diff --git a/po/POTFILES.skip b/po/POTFILES.skip
index cb6cc37..05e8edd 100644
--- a/po/POTFILES.skip
+++ b/po/POTFILES.skip
@@ -1 +1,2 @@
 plugins/fullscreenbg/org.gnome.eog.plugins.fullscreenbg.gschema.xml.in
+plugins/pythonconsole/org.gnome.eog.plugins.pythonconsole.gschema.xml.in



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