~ubuntu-branches/ubuntu/saucy/gaupol/saucy-proposed

« back to all changes in this revision

Viewing changes to gaupol/dialogs/debug.py

  • Committer: Package Import Robot
  • Author(s): Piotr Ożarowski
  • Date: 2013-01-06 17:10:10 UTC
  • mfrom: (1.2.8)
  • mto: (10.2.3 experimental)
  • mto: This revision was merged to the branch mainline in revision 22.
  • Revision ID: package-import@ubuntu.com-20130106171010-kmlq0sy324jlp9zz
Tags: upstream-0.21
Import upstream version 0.21

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright (C) 2005-2008,2010 Osmo Salomaa
 
1
# -*- coding: utf-8 -*-
 
2
 
 
3
# Copyright (C) 2005-2008,2010-2012 Osmo Salomaa
2
4
#
3
5
# This file is part of Gaupol.
4
6
#
16
18
 
17
19
"""Dialog for displaying a traceback in case of an unhandled exception."""
18
20
 
19
 
# This file has been originally adapted from Gazpacho with copyright notice
20
 
# Copyright (C) 2005 by Async Open Source and Sicem S.L.
21
 
 
22
21
import aeidon
23
22
import gaupol
24
 
import glib
25
 
import gtk
26
23
import linecache
27
24
import os
28
 
import pango
29
25
import platform
30
26
import string
31
27
import sys
32
28
import traceback
33
29
_ = aeidon.i18n._
34
30
 
 
31
from gi.repository import Gdk
 
32
from gi.repository import GLib
 
33
from gi.repository import GObject
 
34
from gi.repository import Gtk
 
35
from gi.repository import Pango
 
36
 
35
37
__all__ = ("DebugDialog",)
36
38
 
37
39
 
46
48
        gaupol.BuilderDialog.__init__(self, "debug-dialog.ui")
47
49
        self._init_text_tags()
48
50
        self._init_signal_handlers()
49
 
        self._dialog.set_default_response(gtk.RESPONSE_CLOSE)
 
51
        self._dialog.set_default_response(Gtk.ResponseType.CLOSE)
50
52
 
51
53
    def _init_signal_handlers(self):
52
54
        """Initialize signal handlers."""
56
58
    def _init_text_tags(self):
57
59
        """Initialize tags for the text buffer."""
58
60
        text_buffer = self._text_view.get_buffer()
59
 
        text_buffer.create_tag("bold", weight=pango.WEIGHT_BOLD)
60
 
        text_buffer.create_tag("large", scale=pango.SCALE_LARGE)
 
61
        text_buffer.create_tag("bold", weight=Pango.Weight.BOLD)
 
62
        text_buffer.create_tag("large", scale=1.2)
61
63
        text_buffer.create_tag("monospace", family="monospace")
62
64
 
 
65
    def _insert_environment(self):
 
66
        """Insert environment information."""
 
67
        locale = aeidon.locales.get_system_code()
 
68
        encoding = aeidon.encodings.get_locale_code()
 
69
        ins = self._insert_text
 
70
        ins("Platform: {}\n".format(platform.platform(True)))
 
71
        ins("Locale: {}.{}\n\n".format(locale, encoding))
 
72
 
 
73
    def _insert_library_versions(self):
 
74
        """Insert version numbers of libraries."""
 
75
        dotjoin = lambda seq: ".".join(map(str, seq))
 
76
        python_version = dotjoin(sys.version_info[:3])
 
77
        gtk_version = dotjoin((Gtk.get_major_version(),
 
78
                               Gtk.get_minor_version(),
 
79
                               Gtk.get_micro_version()))
 
80
 
 
81
        pygobject_version = dotjoin(GObject.pygobject_version)
 
82
        gst_version = gaupol.util.get_gst_version()
 
83
        ins = self._insert_text
 
84
        ins("Python: {}\n".format(python_version))
 
85
        ins("GTK+: {}\n".format(gtk_version))
 
86
        ins("PyGObject: {}\n".format(pygobject_version))
 
87
        ins("GStreamer: {}\n\n".format(gst_version))
 
88
 
63
89
    def _insert_link(self, path, lineno, *tags):
64
90
        """Insert `path` as a link into the text view."""
65
91
        text_buffer = self._text_view.get_buffer()
66
92
        tag = text_buffer.create_tag(None, foreground="blue")
67
 
        tag.props.underline = pango.UNDERLINE_SINGLE
 
93
        tag.props.underline = Pango.Underline.SINGLE
68
94
        tag.connect("event", self._on_text_view_link_tag_event)
69
95
        path = os.path.abspath(path)
70
 
        tag.set_data("path", path)
71
 
        tag.set_data("lineno", lineno)
 
96
        tag.gaupol_path = path
 
97
        tag.gaupol_lineno = lineno
72
98
        if path.startswith(os.getcwd()):
73
99
            path = path.replace(os.getcwd(), "")
74
 
        while path.startswith(os.sep):
75
 
            path = path.replace(os.sep, "", 1)
 
100
            while path.startswith(os.sep):
 
101
                path = path.replace(os.sep, "", 1)
76
102
        itr = text_buffer.get_end_iter()
77
103
        tag_table = text_buffer.get_tag_table()
78
 
        tags = map(tag_table.lookup, tags + ("monospace",))
 
104
        tags = list(map(tag_table.lookup, tags + ("monospace",)))
79
105
        text_buffer.insert_with_tags(itr, path, tag, *tags)
80
106
 
81
 
    def _insert_platform(self):
82
 
        """Insert platform information."""
83
 
        self._insert_text("%s\n\n" % platform.platform(True))
 
107
    def _insert_python_package_versions(self):
 
108
        """Insert version numbers of Python packages."""
 
109
        ins = self._insert_text
 
110
        ins("aeidon: {}\n".format(aeidon.__version__))
 
111
        ins("gaupol: {}\n".format(gaupol.__version__))
 
112
        ins("enchant: {}\n".format(aeidon.util.get_enchant_version()))
 
113
        ins("chardet: {}\n".format(aeidon.util.get_chardet_version()))
84
114
 
85
115
    def _insert_text(self, text, *tags):
86
116
        """Insert `text` with `tags` to the text view."""
96
126
 
97
127
    def _insert_traceback(self, exctype, value, tb, limit=100):
98
128
        """Insert up to `limit` stack trace entries from `tb`."""
 
129
        # This function has been originally adapted from Gazpacho
 
130
        # Copyright (C) 2005 by Async Open Source and Sicem S.L.
99
131
        for i in range(limit):
100
132
            if tb is None: break
101
 
            frame = tb.tb_frame
102
 
            code = frame.f_code
103
 
            line = linecache.getline(code.co_filename,
104
 
                                     tb.tb_lineno).strip()
105
 
 
 
133
            lineno = tb.tb_lineno
 
134
            filename = tb.tb_frame.f_code.co_filename
 
135
            name = tb.tb_frame.f_code.co_name
 
136
            line = linecache.getline(filename, lineno)
 
137
            line = line.strip()
106
138
            self._insert_text("File: ")
107
 
            self._insert_link(code.co_filename, tb.tb_lineno)
 
139
            self._insert_link(filename, lineno)
108
140
            self._insert_text("\n")
109
 
            self._insert_text("Line: %s\n" % str(tb.tb_lineno))
110
 
            self._insert_text("In: %s\n\n" % code.co_name)
 
141
            self._insert_text("Line: {}\n".format(str(lineno)))
 
142
            self._insert_text("In: {}\n\n".format(name))
111
143
            if line.strip():
112
 
                self._insert_text("    %s\n\n" % line)
 
144
                indent = "    "
 
145
                self._insert_text("{}{}\n\n".format(indent, line))
113
146
            tb = tb.tb_next
114
147
        exception = traceback.format_exception_only(exctype, value)[0]
115
148
        exception, space, message = exception.partition(" ")
116
149
        self._insert_text(exception, "bold")
117
 
        self._insert_text("%s%s\n" % (space, message))
118
 
 
119
 
    def _insert_versions(self):
120
 
        """Insert version numbers of dependencies."""
121
 
        self._insert_text("Aeidon: %s\n" % aeidon.__version__)
122
 
        self._insert_text("Gaupol: %s\n" % gaupol.__version__)
123
 
        self._insert_text("Python: %d.%d.%d\n" % sys.version_info[:3])
124
 
        self._insert_text("GTK+: %d.%d.%d\n" % gtk.gtk_version)
125
 
        self._insert_text("PyGTK: %d.%d.%d\n" % gtk.pygtk_version)
126
 
        self._insert_text("PyEnchant: %s\n"
127
 
                          % aeidon.util.get_enchant_version() or "N/A")
128
 
 
129
 
        self._insert_text("Universal Encoding Detector: %s\n"
130
 
                          % aeidon.util.get_chardet_version() or "N/A")
 
150
        self._insert_text("{}{}\n".format(space, message))
131
151
 
132
152
    def _on_editor_exit(self, pid, return_value, command):
133
153
        """Print an error message if editor process failed."""
134
154
        if return_value == 0: return
135
 
        print ("Command '%s' failed with return value %d"
136
 
               % (command, return_value))
 
155
        print(("Command {} failed with return value {}"
 
156
               .format(repr(command), repr(return_value))),
 
157
              file=sys.stderr)
137
158
 
138
159
    def _on_response(self, dialog, response):
139
160
        """Do not send response if reporting bug."""
140
 
        if response != gtk.RESPONSE_YES: return
 
161
        if response != Gtk.ResponseType.YES: return
141
162
        gaupol.util.show_uri(gaupol.BUG_REPORT_URL)
142
163
        self.stop_emission("response")
143
164
 
144
165
    def _on_text_view_link_tag_event(self, tag, text_view, event, itr):
145
166
        """Open linked file in editor."""
146
 
        if event.type != gtk.gdk.BUTTON_RELEASE: return
147
 
        if event.button != 1: return
 
167
        if event.type != Gdk.EventType.BUTTON_RELEASE: return
148
168
        text_buffer = self._text_view.get_buffer()
149
 
        assert not text_buffer.get_selection_bounds()
 
169
        if text_buffer.get_selection_bounds(): return
150
170
        self._open_link(tag)
151
171
 
152
172
    def _on_text_view_motion_notify_event(self, text_view, event):
153
173
        """Change mouse pointer when hovering over a link."""
154
174
        x = int(event.x)
155
175
        y = int(event.y)
156
 
        window = gtk.TEXT_WINDOW_WIDGET
 
176
        window = Gtk.TextWindowType.WIDGET
157
177
        x, y = text_view.window_to_buffer_coords(window, x, y)
158
 
        window = text_view.get_window(gtk.TEXT_WINDOW_TEXT)
 
178
        window = text_view.get_window(Gtk.TextWindowType.TEXT)
159
179
        for tag in text_view.get_iter_at_location(x, y).get_tags():
160
 
            if tag.get_data("path") is not None:
161
 
                window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
162
 
                return text_view.window.get_pointer()
163
 
        window.set_cursor(gtk.gdk.Cursor(gtk.gdk.XTERM))
164
 
        text_view.window.get_pointer()
 
180
            if hasattr(tag, "gaupol_path"):
 
181
                window.set_cursor(Gdk.Cursor(cursor_type=Gdk.CursorType.HAND2))
 
182
                return True
 
183
        window.set_cursor(Gdk.Cursor(cursor_type=Gdk.CursorType.XTERM))
 
184
        return False
165
185
 
166
186
    def _open_link(self, tag):
167
187
        """Open linked file in editor."""
168
 
        path = aeidon.util.shell_quote(tag.get_data("path"))
 
188
        path = aeidon.util.shell_quote(tag.gaupol_path)
169
189
        command = string.Template(gaupol.conf.debug.text_editor)
170
 
        command = command.safe_substitute(LINENO=tag.get_data("lineno"),
 
190
        command = command.safe_substitute(LINENO=tag.gaupol_lineno,
171
191
                                          FILE=path)
172
192
 
173
193
        process = aeidon.util.start_process(command)
174
 
        glib.child_watch_add(process.pid, self._on_editor_exit, command)
 
194
        GLib.child_watch_add(process.pid, self._on_editor_exit, command)
175
195
        tag.props.foreground = "purple"
176
196
 
177
197
    def set_text(self, exctype, value, tb):
178
198
        """Set text from `tb` to the text view."""
179
199
        self._insert_title("Traceback")
180
200
        self._insert_traceback(exctype, value, tb)
181
 
        self._insert_title("Platform")
182
 
        self._insert_platform()
183
 
        self._insert_title("Versions")
184
 
        self._insert_versions()
 
201
        self._insert_title("Environment")
 
202
        self._insert_environment()
 
203
        self._insert_title("Libraries")
 
204
        self._insert_library_versions()
 
205
        self._insert_title("Python Packages")
 
206
        self._insert_python_package_versions()
185
207
        gaupol.util.scale_to_content(self._text_view,
186
 
                                     min_nchar=10,
 
208
                                     min_nchar=40,
 
209
                                     max_nchar=100,
187
210
                                     min_nlines=5,
188
 
                                     max_nchar=85,
189
 
                                     max_nlines=35,
 
211
                                     max_nlines=30,
190
212
                                     font="monospace")