summaryrefslogtreecommitdiff
path: root/plugins/externaltools/tools/outputpanel.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/externaltools/tools/outputpanel.py')
-rwxr-xr-xplugins/externaltools/tools/outputpanel.py224
1 files changed, 224 insertions, 0 deletions
diff --git a/plugins/externaltools/tools/outputpanel.py b/plugins/externaltools/tools/outputpanel.py
new file mode 100755
index 00000000..a30aad72
--- /dev/null
+++ b/plugins/externaltools/tools/outputpanel.py
@@ -0,0 +1,224 @@
+# -*- coding: utf-8 -*-
+# Gedit External Tools plugin
+# Copyright (C) 2005-2006 Steve Frécinaux <[email protected]>
+# Copyright (C) 2010 Per Arneng <[email protected]>
+#
+# 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 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, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+__all__ = ('OutputPanel', 'UniqueById')
+
+import gtk, gedit
+import pango
+import gobject
+import os
+from weakref import WeakKeyDictionary
+from capture import *
+from gtk import gdk
+import re
+import gio
+import linkparsing
+import filelookup
+
+class UniqueById:
+ __shared_state = WeakKeyDictionary()
+
+ def __init__(self, i):
+ if i in self.__class__.__shared_state:
+ self.__dict__ = self.__class__.__shared_state[i]
+ return True
+ else:
+ self.__class__.__shared_state[i] = self.__dict__
+ return False
+
+ def states(self):
+ return self.__class__.__shared_state
+
+class OutputPanel(UniqueById):
+ def __init__(self, datadir, window):
+ if UniqueById.__init__(self, window):
+ return
+
+ callbacks = {
+ 'on_stop_clicked' : self.on_stop_clicked,
+ 'on_view_visibility_notify_event': self.on_view_visibility_notify_event,
+ 'on_view_motion_notify_event': self.on_view_motion_notify_event,
+ 'on_view_button_press_event': self.on_view_button_press_event
+ }
+
+ self.window = window
+ self.ui = gtk.Builder()
+ self.ui.add_from_file(os.path.join(datadir, 'ui', 'outputpanel.ui'))
+ self.ui.connect_signals(callbacks)
+
+ self.panel = self["output-panel"]
+ self['view'].modify_font(pango.FontDescription('Monospace'))
+
+ buffer = self['view'].get_buffer()
+
+ self.normal_tag = buffer.create_tag('normal')
+
+ self.error_tag = buffer.create_tag('error')
+ self.error_tag.set_property('foreground', 'red')
+
+ self.italic_tag = buffer.create_tag('italic')
+ self.italic_tag.set_property('style', pango.STYLE_OBLIQUE)
+
+ self.bold_tag = buffer.create_tag('bold')
+ self.bold_tag.set_property('weight', pango.WEIGHT_BOLD)
+
+ self.invalid_link_tag = buffer.create_tag('invalid_link')
+
+ self.link_tag = buffer.create_tag('link')
+ self.link_tag.set_property('underline', pango.UNDERLINE_SINGLE)
+
+ self.link_cursor = gdk.Cursor(gdk.HAND2)
+ self.normal_cursor = gdk.Cursor(gdk.XTERM)
+
+ self.process = None
+
+ self.links = []
+
+ self.link_parser = linkparsing.LinkParser()
+ self.file_lookup = filelookup.FileLookup()
+
+ def set_process(self, process):
+ self.process = process
+
+ def __getitem__(self, key):
+ # Convenience function to get an object from its name
+ return self.ui.get_object(key)
+
+ def on_stop_clicked(self, widget, *args):
+ if self.process is not None:
+ self.write("\n" + _('Stopped.') + "\n",
+ self.italic_tag)
+ self.process.stop(-1)
+
+ def scroll_to_end(self):
+ iter = self['view'].get_buffer().get_end_iter()
+ self['view'].scroll_to_iter(iter, 0.0)
+ return False # don't requeue this handler
+
+ def clear(self):
+ self['view'].get_buffer().set_text("")
+ self.links = []
+
+ def visible(self):
+ panel = self.window.get_bottom_panel()
+ return panel.props.visible and panel.item_is_active(self.panel)
+
+ def write(self, text, tag = None):
+ buffer = self['view'].get_buffer()
+
+ end_iter = buffer.get_end_iter()
+ insert = buffer.create_mark(None, end_iter, True)
+
+ if tag is None:
+ buffer.insert(end_iter, text)
+ else:
+ buffer.insert_with_tags(end_iter, text, tag)
+
+ # find all links and apply the appropriate tag for them
+ links = self.link_parser.parse(text)
+ for lnk in links:
+
+ insert_iter = buffer.get_iter_at_mark(insert)
+ lnk.start = insert_iter.get_offset() + lnk.start
+ lnk.end = insert_iter.get_offset() + lnk.end
+
+ start_iter = buffer.get_iter_at_offset(lnk.start)
+ end_iter = buffer.get_iter_at_offset(lnk.end)
+
+ tag = None
+
+ # if the link points to an existing file then it is a valid link
+ if self.file_lookup.lookup(lnk.path) is not None:
+ self.links.append(lnk)
+ tag = self.link_tag
+ else:
+ tag = self.invalid_link_tag
+
+ buffer.apply_tag(tag, start_iter, end_iter)
+
+ buffer.delete_mark(insert)
+ gobject.idle_add(self.scroll_to_end)
+
+ def show(self):
+ panel = self.window.get_bottom_panel()
+ panel.show()
+ panel.activate_item(self.panel)
+
+ def update_cursor_style(self, view, x, y):
+ if self.get_link_at_location(view, x, y) is not None:
+ cursor = self.link_cursor
+ else:
+ cursor = self.normal_cursor
+
+ view.get_window(gtk.TEXT_WINDOW_TEXT).set_cursor(cursor)
+
+ def on_view_motion_notify_event(self, view, event):
+ if event.window == view.get_window(gtk.TEXT_WINDOW_TEXT):
+ self.update_cursor_style(view, int(event.x), int(event.y))
+
+ return False
+
+ def on_view_visibility_notify_event(self, view, event):
+ if event.window == view.get_window(gtk.TEXT_WINDOW_TEXT):
+ x, y, m = event.window.get_pointer()
+ self.update_cursor_style(view, x, y)
+
+ return False
+
+ def idle_grab_focus(self):
+ self.window.get_active_view().grab_focus()
+ return False
+
+ def get_link_at_location(self, view, x, y):
+ """
+ Get the link under a specified x,y coordinate. If no link exists then
+ None is returned.
+ """
+
+ # get the offset within the buffer from the x,y coordinates
+ buff_x, buff_y = view.window_to_buffer_coords(gtk.TEXT_WINDOW_TEXT,
+ x, y)
+ iter_at_xy = view.get_iter_at_location(buff_x, buff_y)
+ offset = iter_at_xy.get_offset()
+
+ # find the first link that contains the offset
+ for lnk in self.links:
+ if offset >= lnk.start and offset <= lnk.end:
+ return lnk
+
+ # no link was found at x,y
+ return None
+
+ def on_view_button_press_event(self, view, event):
+ if event.button != 1 or event.type != gdk.BUTTON_PRESS or \
+ event.window != view.get_window(gtk.TEXT_WINDOW_TEXT):
+ return False
+
+ link = self.get_link_at_location(view, int(event.x), int(event.y))
+ if link is None:
+ return False
+
+ gfile = self.file_lookup.lookup(link.path)
+
+ if gfile:
+ gedit.commands.load_uri(self.window, gfile.get_uri(), None,
+ link.line_nr)
+ gobject.idle_add(self.idle_grab_focus)
+
+# ex:ts=4:et: