/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz

« back to all changes in this revision

Viewing changes to diff.py

  • Committer: Jelmer Vernooij
  • Date: 2007-03-09 17:47:28 UTC
  • Revision ID: jelmer@samba.org-20070309174728-gljlmt9b7fu0rrn9
Add simple test for tortoise_bzr

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
1
2
# -*- coding: UTF-8 -*-
2
3
"""Difference window.
3
4
 
11
12
 
12
13
from cStringIO import StringIO
13
14
 
14
 
import pygtk
15
 
pygtk.require("2.0")
16
15
import gtk
17
16
import pango
18
 
import os
19
 
import re
20
17
import sys
21
18
 
22
19
try:
24
21
    have_gtksourceview = True
25
22
except ImportError:
26
23
    have_gtksourceview = False
27
 
try:
28
 
    import gconf
29
 
    have_gconf = True
30
 
except ImportError:
31
 
    have_gconf = False
32
24
 
33
25
import bzrlib
34
26
 
35
27
from bzrlib.diff import show_diff_trees
36
28
from bzrlib.errors import NoSuchFile
37
 
from bzrlib.trace import warning
38
 
 
39
 
 
40
 
class DiffDisplay(gtk.ScrolledWindow):
41
 
    """This is the soft and chewy filling for a DiffWindow."""
42
 
 
43
 
    def __init__(self):
44
 
        gtk.ScrolledWindow.__init__(self)
45
 
 
46
 
        self.construct()
47
 
        self.rev_tree = None
48
 
        self.parent_tree = None
49
 
 
50
 
    def construct(self):
51
 
        self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
52
 
        self.set_shadow_type(gtk.SHADOW_IN)
53
 
 
54
 
        if have_gtksourceview:
55
 
            self.buffer = gtksourceview.SourceBuffer()
56
 
            slm = gtksourceview.SourceLanguagesManager()
57
 
            gsl = slm.get_language_from_mime_type("text/x-patch")
58
 
            if have_gconf:
59
 
                self.apply_gedit_colors(gsl)
60
 
            self.apply_colordiff_colors(gsl)
61
 
            self.buffer.set_language(gsl)
62
 
            self.buffer.set_highlight(True)
63
 
 
64
 
            sourceview = gtksourceview.SourceView(self.buffer)
65
 
        else:
66
 
            self.buffer = gtk.TextBuffer()
67
 
            sourceview = gtk.TextView(self.buffer)
68
 
 
69
 
        sourceview.set_editable(False)
70
 
        sourceview.modify_font(pango.FontDescription("Monospace"))
71
 
        self.add(sourceview)
72
 
        sourceview.show()
73
 
 
74
 
    @staticmethod
75
 
    def apply_gedit_colors(lang):
76
 
        """Set style for lang to that specified in gedit configuration.
77
 
 
78
 
        This method needs the gconf module.
79
 
 
80
 
        :param lang: a gtksourceview.SourceLanguage object.
81
 
        """
82
 
        GEDIT_SYNTAX_PATH = '/apps/gedit-2/preferences/syntax_highlighting'
83
 
        GEDIT_LANG_PATH = GEDIT_SYNTAX_PATH + '/' + lang.get_id()
84
 
 
85
 
        client = gconf.client_get_default()
86
 
        client.add_dir(GEDIT_LANG_PATH, gconf.CLIENT_PRELOAD_NONE)
87
 
 
88
 
        for tag in lang.get_tags():
89
 
            tag_id = tag.get_id()
90
 
            gconf_key = GEDIT_LANG_PATH + '/' + tag_id
91
 
            style_string = client.get_string(gconf_key)
92
 
 
93
 
            if style_string is None:
94
 
                continue
95
 
 
96
 
            # function to get a bool from a string that's either '0' or '1'
97
 
            string_bool = lambda x: bool(int(x))
98
 
 
99
 
            # style_string is a string like "2/#FFCCAA/#000000/0/1/0/0"
100
 
            # values are: mask, fg, bg, italic, bold, underline, strike
101
 
            # this packs them into (str_value, attr_name, conv_func) tuples
102
 
            items = zip(style_string.split('/'), ['mask', 'foreground',
103
 
                'background', 'italic', 'bold', 'underline', 'strikethrough' ],
104
 
                [ int, gtk.gdk.color_parse, gtk.gdk.color_parse, string_bool,
105
 
                    string_bool, string_bool, string_bool ]
106
 
            )
107
 
 
108
 
            style = gtksourceview.SourceTagStyle()
109
 
 
110
 
            # XXX The mask attribute controls whether the present values of
111
 
            # foreground and background color should in fact be used. Ideally
112
 
            # (and that's what gedit does), one could set all three attributes,
113
 
            # and let the TagStyle object figure out which colors to use.
114
 
            # However, in the GtkSourceview python bindings, the mask attribute
115
 
            # is read-only, and it's derived instead from the colors being
116
 
            # set or not. This means that we have to sometimes refrain from
117
 
            # setting fg or bg colors, depending on the value of the mask.
118
 
            # This code could go away if mask were writable.
119
 
            mask = int(items[0][0])
120
 
            if not (mask & 1): # GTK_SOURCE_TAG_STYLE_USE_BACKGROUND
121
 
                items[2:3] = []
122
 
            if not (mask & 2): # GTK_SOURCE_TAG_STYLE_USE_FOREGROUND
123
 
                items[1:2] = []
124
 
            items[0:1] = [] # skip the mask unconditionally
125
 
 
126
 
            for value, attr, func in items:
127
 
                try:
128
 
                    value = func(value)
129
 
                except ValueError:
130
 
                    warning('gconf key %s contains an invalid value: %s'
131
 
                            % gconf_key, value)
132
 
                else:
133
 
                    setattr(style, attr, value)
134
 
 
135
 
            lang.set_tag_style(tag_id, style)
136
 
 
137
 
    @staticmethod
138
 
    def apply_colordiff_colors(lang):
139
 
        """Set style colors for lang using the colordiff configuration file.
140
 
 
141
 
        Both ~/.colordiffrc and ~/.colordiffrc.bzr-gtk are read.
142
 
 
143
 
        :param lang: a "Diff" gtksourceview.SourceLanguage object.
144
 
        """
145
 
        colors = {}
146
 
 
147
 
        for f in ('~/.colordiffrc', '~/.colordiffrc.bzr-gtk'):
148
 
            f = os.path.expanduser(f)
149
 
            if os.path.exists(f):
150
 
                try:
151
 
                    f = file(f)
152
 
                except IOError, e:
153
 
                    warning('could not open file %s: %s' % (f, str(e)))
154
 
                else:
155
 
                    colors.update(DiffDisplay.parse_colordiffrc(f))
156
 
                    f.close()
157
 
 
158
 
        if not colors:
159
 
            # ~/.colordiffrc does not exist
160
 
            return
161
 
 
162
 
        mapping = {
163
 
                # map GtkSourceView tags to colordiff names
164
 
                # since GSV is richer, accept new names for extra bits,
165
 
                # defaulting to old names if they're not present
166
 
                'Added@32@line': ['newtext'],
167
 
                'Removed@32@line': ['oldtext'],
168
 
                'Location': ['location', 'diffstuff'],
169
 
                'Diff@32@file': ['file', 'diffstuff'],
170
 
                'Special@32@case': ['specialcase', 'diffstuff'],
171
 
        }
172
 
 
173
 
        for tag in lang.get_tags():
174
 
            tag_id = tag.get_id()
175
 
            keys = mapping.get(tag_id, [])
176
 
            color = None
177
 
 
178
 
            for key in keys:
179
 
                color = colors.get(key, None)
180
 
                if color is not None:
181
 
                    break
182
 
 
183
 
            if color is None:
184
 
                continue
185
 
 
186
 
            style = gtksourceview.SourceTagStyle()
187
 
            try:
188
 
                style.foreground = gtk.gdk.color_parse(color)
189
 
            except ValueError:
190
 
                warning('not a valid color: %s' % color)
191
 
            else:
192
 
                lang.set_tag_style(tag_id, style)
193
 
 
194
 
    @staticmethod
195
 
    def parse_colordiffrc(fileobj):
196
 
        """Parse fileobj as a colordiff configuration file.
197
 
 
198
 
        :return: A dict with the key -> value pairs.
199
 
        """
200
 
        colors = {}
201
 
        for line in fileobj:
202
 
            if re.match(r'^\s*#', line):
203
 
                continue
204
 
            if '=' not in line:
205
 
                continue
206
 
            key, val = line.split('=', 1)
207
 
            colors[key.strip()] = val.strip()
208
 
        return colors
209
 
 
210
 
    def set_trees(self, rev_tree, parent_tree):
211
 
        self.rev_tree = rev_tree
212
 
        self.parent_tree = parent_tree
213
 
 
214
 
    def show_diff(self, specific_files):
215
 
        s = StringIO()
216
 
        show_diff_trees(self.parent_tree, self.rev_tree, s, specific_files)
217
 
        self.buffer.set_text(s.getvalue().decode(sys.getdefaultencoding(), 'replace'))
218
29
 
219
30
 
220
31
class DiffWindow(gtk.Window):
271
82
 
272
83
        # The diffs of the  selected file: a scrollable source or
273
84
        # text view
274
 
        self.diff_win = DiffDisplay()
275
 
        pane.pack2(self.diff_win)
276
 
        self.diff_win.show()
 
85
        scrollwin = gtk.ScrolledWindow()
 
86
        scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 
87
        scrollwin.set_shadow_type(gtk.SHADOW_IN)
 
88
        pane.pack2(scrollwin)
 
89
        scrollwin.show()
 
90
 
 
91
        if have_gtksourceview:
 
92
            self.buffer = gtksourceview.SourceBuffer()
 
93
            slm = gtksourceview.SourceLanguagesManager()
 
94
            gsl = slm.get_language_from_mime_type("text/x-patch")
 
95
            self.buffer.set_language(gsl)
 
96
            self.buffer.set_highlight(True)
 
97
 
 
98
            sourceview = gtksourceview.SourceView(self.buffer)
 
99
        else:
 
100
            self.buffer = gtk.TextBuffer()
 
101
            sourceview = gtk.TextView(self.buffer)
 
102
 
 
103
        sourceview.set_editable(False)
 
104
        sourceview.modify_font(pango.FontDescription("Monospace"))
 
105
        scrollwin.add(sourceview)
 
106
        sourceview.show()
277
107
 
278
108
    def set_diff(self, description, rev_tree, parent_tree):
279
109
        """Set the differences showed by this window.
281
111
        Compares the two trees and populates the window with the
282
112
        differences.
283
113
        """
284
 
        self.diff_win.set_trees(rev_tree, parent_tree)
285
114
        self.rev_tree = rev_tree
286
115
        self.parent_tree = parent_tree
287
116
 
333
162
        if specific_files == [ None ]:
334
163
            return
335
164
        elif specific_files == [ "" ]:
336
 
            specific_files = None
 
165
            specific_files = []
337
166
 
338
 
        self.diff_win.show_diff(specific_files)
 
167
        s = StringIO()
 
168
        show_diff_trees(self.parent_tree, self.rev_tree, s, specific_files)
 
169
        self.buffer.set_text(s.getvalue().decode(sys.getdefaultencoding(), 'replace'))