/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: Martin Pool
  • Date: 2010-05-27 03:07:30 UTC
  • mfrom: (688.1.5 201956-help)
  • Revision ID: mbp@canonical.com-20100527030730-os0opv1xroetccm9
Make find/goto more discoverable

Show diffs side-by-side

added added

removed removed

Lines of Context:
10
10
 
11
11
from cStringIO import StringIO
12
12
 
13
 
from gi.repository import Gtk
14
 
from gi.repository import Pango
 
13
import pygtk
 
14
pygtk.require("2.0")
 
15
import gtk
 
16
import pango
15
17
import os
16
18
import re
17
19
import sys
18
 
import inspect
19
20
try:
20
21
    from xml.etree.ElementTree import Element, SubElement, tostring
21
22
except ImportError:
22
23
    from elementtree.ElementTree import Element, SubElement, tostring
23
24
 
24
25
try:
25
 
    from gi.repository import GtkSource
 
26
    import gtksourceview2
26
27
    have_gtksourceview = True
27
28
except ImportError:
28
29
    have_gtksourceview = False
29
30
try:
30
 
    from gi.repository import GConf
 
31
    import gconf
31
32
    have_gconf = True
32
33
except ImportError:
33
34
    have_gconf = False
39
40
    urlutils,
40
41
    workingtree,
41
42
)
42
 
from bzrlib.diff import show_diff_trees
 
43
from bzrlib.diff import show_diff_trees, internal_diff
43
44
from bzrlib.patches import parse_patches
44
45
from bzrlib.trace import warning
45
 
from bzrlib.plugins.gtk.dialog import (
46
 
    error_dialog,
47
 
    info_dialog,
48
 
    warning_dialog,
49
 
    )
50
 
from bzrlib.plugins.gtk.i18n import _i18n
 
46
from bzrlib.plugins.gtk import _i18n
51
47
from bzrlib.plugins.gtk.window import Window
 
48
from dialog import error_dialog, info_dialog, warning_dialog
52
49
 
53
50
 
54
51
def fallback_guess_language(slm, content_type):
64
61
    pass
65
62
 
66
63
 
67
 
class DiffFileView(Gtk.ScrolledWindow):
 
64
class DiffFileView(gtk.ScrolledWindow):
68
65
    """Window for displaying diffs from a diff file"""
69
66
 
70
67
    def __init__(self):
71
 
        super(DiffFileView, self).__init__()
 
68
        gtk.ScrolledWindow.__init__(self)
72
69
        self.construct()
73
70
        self._diffs = {}
74
71
 
75
72
    def construct(self):
76
 
        self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
77
 
        self.set_shadow_type(Gtk.ShadowType.IN)
 
73
        self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 
74
        self.set_shadow_type(gtk.SHADOW_IN)
78
75
 
79
76
        if have_gtksourceview:
80
 
            self.buffer = GtkSource.Buffer()
81
 
            lang_manager = GtkSource.LanguageManager.get_default()
82
 
            language = lang_manager.guess_language(None, "text/x-patch")
 
77
            self.buffer = gtksourceview2.Buffer()
 
78
            slm = gtksourceview2.LanguageManager()
 
79
            guess_language = getattr(gtksourceview2.LanguageManager, 
 
80
                "guess_language", fallback_guess_language)
 
81
            gsl = guess_language(slm, content_type="text/x-patch")
83
82
            if have_gconf:
84
83
                self.apply_gedit_colors(self.buffer)
85
84
            self.apply_colordiff_colors(self.buffer)
86
 
            self.buffer.set_language(language)
 
85
            self.buffer.set_language(gsl)
87
86
            self.buffer.set_highlight_syntax(True)
88
87
 
89
 
            self.sourceview = GtkSource.View(buffer=self.buffer)
 
88
            self.sourceview = gtksourceview2.View(self.buffer)
90
89
        else:
91
 
            self.buffer = Gtk.TextBuffer()
92
 
            self.sourceview = Gtk.TextView(self.buffer)
 
90
            self.buffer = gtk.TextBuffer()
 
91
            self.sourceview = gtk.TextView(self.buffer)
93
92
 
94
93
        self.sourceview.set_editable(False)
95
 
        self.sourceview.modify_font(Pango.FontDescription("Monospace"))
 
94
        self.sourceview.modify_font(pango.FontDescription("Monospace"))
96
95
        self.add(self.sourceview)
97
96
        self.sourceview.show()
98
97
 
102
101
 
103
102
        This method needs the gconf module.
104
103
 
105
 
        :param buf: a GtkSource.Buffer object.
 
104
        :param buf: a gtksourceview2.Buffer object.
106
105
        """
107
106
        GEDIT_SCHEME_PATH = '/apps/gedit-2/preferences/editor/colors/scheme'
108
 
        GEDIT_USER_STYLES_PATH = os.path.expanduser('~/.gnome2/gedit/styles')
109
107
 
110
 
        client = GConf.Client.get_default()
 
108
        client = gconf.client_get_default()
111
109
        style_scheme_name = client.get_string(GEDIT_SCHEME_PATH)
112
110
        if style_scheme_name is not None:
113
 
            style_scheme_mgr = GtkSource.StyleSchemeManager()
114
 
            style_scheme_mgr.append_search_path(GEDIT_USER_STYLES_PATH)
115
 
            
116
 
            style_scheme = style_scheme_mgr.get_scheme(style_scheme_name)
117
 
            
118
 
            if style_scheme is not None:
119
 
                buf.set_style_scheme(style_scheme)
 
111
            style_scheme = gtksourceview2.StyleSchemeManager().get_scheme(style_scheme_name)
 
112
            
 
113
            buf.set_style_scheme(style_scheme)
120
114
 
121
115
    @classmethod
122
116
    def apply_colordiff_colors(klass, buf):
124
118
 
125
119
        Both ~/.colordiffrc and ~/.colordiffrc.bzr-gtk are read.
126
120
 
127
 
        :param buf: a "Diff" GtkSource.Buffer object.
 
121
        :param buf: a "Diff" gtksourceview2.Buffer object.
128
122
        """
129
 
        scheme_manager = GtkSource.StyleSchemeManager()
 
123
        scheme_manager = gtksourceview2.StyleSchemeManager()
130
124
        style_scheme = scheme_manager.get_scheme('colordiff')
131
125
        
132
126
        # if style scheme not found, we'll generate it from colordiffrc
250
244
    """This is the soft and chewy filling for a DiffWindow."""
251
245
 
252
246
    def __init__(self):
253
 
        super(DiffView, self).__init__()
 
247
        DiffFileView.__init__(self)
254
248
        self.rev_tree = None
255
249
        self.parent_tree = None
256
250
 
280
274
        self.buffer.set_text(decoded.encode('UTF-8'))
281
275
 
282
276
 
283
 
class DiffWidget(Gtk.HPaned):
 
277
class DiffWidget(gtk.HPaned):
284
278
    """Diff widget
285
279
 
286
280
    """
288
282
        super(DiffWidget, self).__init__()
289
283
 
290
284
        # The file hierarchy: a scrollable treeview
291
 
        scrollwin = Gtk.ScrolledWindow()
292
 
        scrollwin.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC)
293
 
        scrollwin.set_shadow_type(Gtk.ShadowType.IN)
 
285
        scrollwin = gtk.ScrolledWindow()
 
286
        scrollwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
 
287
        scrollwin.set_shadow_type(gtk.SHADOW_IN)
294
288
        self.pack1(scrollwin)
295
289
        scrollwin.show()
296
290
        
297
 
        self.model = Gtk.TreeStore(str, str)
298
 
        self.treeview = Gtk.TreeView(model=self.model)
 
291
        self.model = gtk.TreeStore(str, str)
 
292
        self.treeview = gtk.TreeView(self.model)
299
293
        self.treeview.set_headers_visible(False)
300
294
        self.treeview.set_search_column(1)
301
295
        self.treeview.connect("cursor-changed", self._treeview_cursor_cb)
302
296
        scrollwin.add(self.treeview)
303
297
        self.treeview.show()
304
298
 
305
 
        cell = Gtk.CellRendererText()
 
299
        cell = gtk.CellRendererText()
306
300
        cell.set_property("width-chars", 20)
307
 
        column = Gtk.TreeViewColumn()
308
 
        column.pack_start(cell, True)
 
301
        column = gtk.TreeViewColumn()
 
302
        column.pack_start(cell, expand=True)
309
303
        column.add_attribute(cell, "text", 0)
310
304
        self.treeview.append_column(column)
311
305
 
382
376
                    break
383
377
        if tv_path is None:
384
378
            raise errors.NoSuchFile(file_path)
385
 
        self.treeview.set_cursor(tv_path, None, False)
 
379
        self.treeview.set_cursor(tv_path)
386
380
        self.treeview.scroll_to_cell(tv_path)
387
381
 
388
382
    def _treeview_cursor_cb(self, *args):
399
393
    def _on_wraplines_toggled(self, widget=None, wrap=False):
400
394
        """Callback for when the wrap lines checkbutton is toggled"""
401
395
        if wrap or widget.get_active():
402
 
            self.diff_view.sourceview.set_wrap_mode(Gtk.WrapMode.WORD)
 
396
            self.diff_view.sourceview.set_wrap_mode(gtk.WRAP_WORD)
403
397
        else:
404
 
            self.diff_view.sourceview.set_wrap_mode(Gtk.WrapMode.NONE)
 
398
            self.diff_view.sourceview.set_wrap_mode(gtk.WRAP_NONE)
405
399
 
406
400
class DiffWindow(Window):
407
401
    """Diff window.
411
405
    """
412
406
 
413
407
    def __init__(self, parent=None, operations=None):
414
 
        super(DiffWindow, self).__init__(parent=parent)
 
408
        Window.__init__(self, parent)
415
409
        self.set_border_width(0)
416
410
        self.set_title("bzrk diff")
417
411
 
425
419
 
426
420
    def construct(self, operations):
427
421
        """Construct the window contents."""
428
 
        self.vbox = Gtk.VBox()
 
422
        self.vbox = gtk.VBox()
429
423
        self.add(self.vbox)
430
424
        self.vbox.show()
431
425
        self.diff = DiffWidget()
440
434
        
441
435
    
442
436
    def _get_menu_bar(self):
443
 
        menubar = Gtk.MenuBar()
 
437
        menubar = gtk.MenuBar()
444
438
        # View menu
445
 
        mb_view = Gtk.MenuItem.new_with_mnemonic(_i18n("_View"))
446
 
        mb_view_menu = Gtk.Menu()
447
 
        mb_view_wrapsource = Gtk.CheckMenuItem.new_with_mnemonic(
448
 
            _i18n("Wrap _Long Lines"))
 
439
        mb_view = gtk.MenuItem(_i18n("_View"))
 
440
        mb_view_menu = gtk.Menu()
 
441
        mb_view_wrapsource = gtk.CheckMenuItem(_i18n("Wrap _Long Lines"))
449
442
        mb_view_wrapsource.connect('activate', self.diff._on_wraplines_toggled)
450
443
        mb_view_wrapsource.show()
451
444
        mb_view_menu.append(mb_view_wrapsource)
463
456
        """
464
457
        if operations is None:
465
458
            return None
466
 
        hbox = Gtk.HButtonBox()
467
 
        hbox.set_layout(Gtk.ButtonBoxStyle.START)
 
459
        hbox = gtk.HButtonBox()
 
460
        hbox.set_layout(gtk.BUTTONBOX_START)
468
461
        for title, method in operations:
469
 
            merge_button = Gtk.Button(title)
 
462
            merge_button = gtk.Button(title)
470
463
            merge_button.show()
471
 
            merge_button.set_relief(Gtk.ReliefStyle.NONE)
 
464
            merge_button.set_relief(gtk.RELIEF_NONE)
472
465
            merge_button.connect("clicked", method)
473
466
            hbox.pack_start(merge_button, expand=False, fill=True)
474
467
        hbox.show()
475
468
        return hbox
476
469
 
477
470
    def _get_merge_target(self):
478
 
        d = Gtk.FileChooserDialog('Merge branch', self,
479
 
                                  Gtk.FileChooserAction.SELECT_FOLDER,
480
 
                                  buttons=(Gtk.STOCK_OK, Gtk.ResponseType.OK,
481
 
                                           Gtk.STOCK_CANCEL,
482
 
                                           Gtk.ResponseType.CANCEL,))
 
471
        d = gtk.FileChooserDialog('Merge branch', self,
 
472
                                  gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
 
473
                                  buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
 
474
                                           gtk.STOCK_CANCEL,
 
475
                                           gtk.RESPONSE_CANCEL,))
483
476
        try:
484
477
            result = d.run()
485
 
            if result != Gtk.ResponseType.OK:
 
478
            if result != gtk.RESPONSE_OK:
486
479
                raise SelectCancelled()
487
480
            return d.get_current_folder_uri()
488
481
        finally:
502
495
        error_dialog('Error', str(e))
503
496
 
504
497
    def _get_save_path(self, basename):
505
 
        d = Gtk.FileChooserDialog('Save As', self,
506
 
                                  Gtk.FileChooserAction.SAVE,
507
 
                                  buttons=(Gtk.STOCK_OK, Gtk.ResponseType.OK,
508
 
                                           Gtk.STOCK_CANCEL,
509
 
                                           Gtk.ResponseType.CANCEL,))
 
498
        d = gtk.FileChooserDialog('Save As', self,
 
499
                                  gtk.FILE_CHOOSER_ACTION_SAVE,
 
500
                                  buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
 
501
                                           gtk.STOCK_CANCEL,
 
502
                                           gtk.RESPONSE_CANCEL,))
510
503
        d.set_current_name(basename)
511
504
        try:
512
505
            result = d.run()
513
 
            if result != Gtk.ResponseType.OK:
 
506
            if result != gtk.RESPONSE_OK:
514
507
                raise SelectCancelled()
515
508
            return urlutils.local_path_from_url(d.get_uri())
516
509
        finally:
531
524
 
532
525
class DiffController(object):
533
526
 
534
 
    def __init__(self, path, patch, window=None, allow_dirty=False):
 
527
    def __init__(self, path, patch, window=None):
535
528
        self.path = path
536
529
        self.patch = patch
537
 
        self.allow_dirty = allow_dirty
538
530
        if window is None:
539
531
            window = DiffWindow(operations=self._provide_operations())
540
532
            self.initialize_window(window)
546
538
 
547
539
    def get_diff_sections(self):
548
540
        yield "Complete Diff", None, ''.join(self.patch)
549
 
        # allow_dirty was added to parse_patches in bzrlib 2.2b1
550
 
        if 'allow_dirty' in inspect.getargspec(parse_patches).args:
551
 
            patches = parse_patches(self.patch, allow_dirty=self.allow_dirty)
552
 
        else:
553
 
            patches = parse_patches(self.patch)
554
 
        for patch in patches:
 
541
        for patch in parse_patches(self.patch):
555
542
            oldname = patch.oldname.split('\t')[0]
556
543
            newname = patch.newname.split('\t')[0]
557
544
            yield oldname, newname, str(patch)
578
565
class MergeDirectiveController(DiffController):
579
566
 
580
567
    def __init__(self, path, directive, window=None):
581
 
        super(MergeDirectiveController, self).__init__(
582
 
            path, directive.patch.splitlines(True), window)
 
568
        DiffController.__init__(self, path, directive.patch.splitlines(True),
 
569
                                window)
583
570
        self.directive = directive
584
571
        self.merge_target = None
585
572