11
11
from cStringIO import StringIO
13
from gi.repository import Gtk
14
from gi.repository import Pango
20
from xml.etree.ElementTree import Element, SubElement, tostring
22
from elementtree.ElementTree import Element, SubElement, tostring
20
from xml.etree.ElementTree import Element, SubElement, tostring
25
from gi.repository import GtkSource
26
24
have_gtksourceview = True
27
25
except ImportError:
28
26
have_gtksourceview = False
30
from gi.repository import GConf
32
30
except ImportError:
35
33
from bzrlib import (
37
34
merge as _mod_merge,
42
from bzrlib.diff import show_diff_trees
40
from bzrlib.diff import show_diff_trees, internal_diff
41
from bzrlib.errors import NoSuchFile
43
42
from bzrlib.patches import parse_patches
44
43
from bzrlib.trace import warning
45
from bzrlib.plugins.gtk.dialog import (
50
from bzrlib.plugins.gtk.i18n import _i18n
44
from bzrlib.plugins.gtk import _i18n
51
45
from bzrlib.plugins.gtk.window import Window
54
def fallback_guess_language(slm, content_type):
55
for lang_id in slm.get_language_ids():
56
lang = slm.get_language(lang_id)
57
if "text/x-patch" in lang.get_mime_types():
46
from dialog import error_dialog, info_dialog, warning_dialog
62
49
class SelectCancelled(Exception):
67
class DiffFileView(Gtk.ScrolledWindow):
54
class DiffFileView(gtk.ScrolledWindow):
68
55
"""Window for displaying diffs from a diff file"""
70
57
def __init__(self):
71
super(DiffFileView, self).__init__()
58
gtk.ScrolledWindow.__init__(self)
75
62
def construct(self):
76
self.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
77
self.set_shadow_type(Gtk.ShadowType.IN)
63
self.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
64
self.set_shadow_type(gtk.SHADOW_IN)
79
66
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")
67
self.buffer = gtksourceview2.Buffer()
68
slm = gtksourceview2.LanguageManager()
69
gsl = slm.guess_language(content_type="text/x-patch")
84
71
self.apply_gedit_colors(self.buffer)
85
72
self.apply_colordiff_colors(self.buffer)
86
self.buffer.set_language(language)
73
self.buffer.set_language(gsl)
87
74
self.buffer.set_highlight_syntax(True)
89
self.sourceview = GtkSource.View(buffer=self.buffer)
76
self.sourceview = gtksourceview2.View(self.buffer)
91
self.buffer = Gtk.TextBuffer()
92
self.sourceview = Gtk.TextView(self.buffer)
78
self.buffer = gtk.TextBuffer()
79
self.sourceview = gtk.TextView(self.buffer)
94
81
self.sourceview.set_editable(False)
95
self.sourceview.modify_font(Pango.FontDescription("Monospace"))
82
self.sourceview.modify_font(pango.FontDescription("Monospace"))
96
83
self.add(self.sourceview)
97
84
self.sourceview.show()
103
90
This method needs the gconf module.
105
:param buf: a GtkSource.Buffer object.
92
:param buf: a gtksourceview2.Buffer object.
107
94
GEDIT_SCHEME_PATH = '/apps/gedit-2/preferences/editor/colors/scheme'
108
GEDIT_USER_STYLES_PATH = os.path.expanduser('~/.gnome2/gedit/styles')
110
client = GConf.Client.get_default()
96
client = gconf.client_get_default()
111
97
style_scheme_name = client.get_string(GEDIT_SCHEME_PATH)
112
98
if style_scheme_name is not None:
113
style_scheme_mgr = GtkSource.StyleSchemeManager()
114
style_scheme_mgr.append_search_path(GEDIT_USER_STYLES_PATH)
116
style_scheme = style_scheme_mgr.get_scheme(style_scheme_name)
118
if style_scheme is not None:
119
buf.set_style_scheme(style_scheme)
99
style_scheme = gtksourceview2.StyleSchemeManager().get_scheme(style_scheme_name)
101
buf.set_style_scheme(style_scheme)
122
104
def apply_colordiff_colors(klass, buf):
125
107
Both ~/.colordiffrc and ~/.colordiffrc.bzr-gtk are read.
127
:param buf: a "Diff" GtkSource.Buffer object.
109
:param buf: a "Diff" gtksourceview2.Buffer object.
129
scheme_manager = GtkSource.StyleSchemeManager()
111
scheme_manager = gtksourceview2.StyleSchemeManager()
130
112
style_scheme = scheme_manager.get_scheme('colordiff')
132
114
# if style scheme not found, we'll generate it from colordiffrc
288
270
super(DiffWidget, self).__init__()
290
272
# 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)
273
scrollwin = gtk.ScrolledWindow()
274
scrollwin.set_policy(gtk.POLICY_NEVER, gtk.POLICY_AUTOMATIC)
275
scrollwin.set_shadow_type(gtk.SHADOW_IN)
294
276
self.pack1(scrollwin)
297
self.model = Gtk.TreeStore(str, str)
298
self.treeview = Gtk.TreeView(model=self.model)
279
self.model = gtk.TreeStore(str, str)
280
self.treeview = gtk.TreeView(self.model)
299
281
self.treeview.set_headers_visible(False)
300
282
self.treeview.set_search_column(1)
301
283
self.treeview.connect("cursor-changed", self._treeview_cursor_cb)
302
284
scrollwin.add(self.treeview)
303
285
self.treeview.show()
305
cell = Gtk.CellRendererText()
287
cell = gtk.CellRendererText()
306
288
cell.set_property("width-chars", 20)
307
column = Gtk.TreeViewColumn()
308
column.pack_start(cell, True)
289
column = gtk.TreeViewColumn()
290
column.pack_start(cell, expand=True)
309
291
column.add_attribute(cell, "text", 0)
310
292
self.treeview.append_column(column)
381
363
tv_path = child.path
383
365
if tv_path is None:
384
raise errors.NoSuchFile(file_path)
385
self.treeview.set_cursor(tv_path, None, False)
366
raise NoSuchFile(file_path)
367
self.treeview.set_cursor(tv_path)
386
368
self.treeview.scroll_to_cell(tv_path)
388
370
def _treeview_cursor_cb(self, *args):
399
381
def _on_wraplines_toggled(self, widget=None, wrap=False):
400
382
"""Callback for when the wrap lines checkbutton is toggled"""
401
383
if wrap or widget.get_active():
402
self.diff_view.sourceview.set_wrap_mode(Gtk.WrapMode.WORD)
384
self.diff_view.sourceview.set_wrap_mode(gtk.WRAP_WORD)
404
self.diff_view.sourceview.set_wrap_mode(Gtk.WrapMode.NONE)
386
self.diff_view.sourceview.set_wrap_mode(gtk.WRAP_NONE)
406
388
class DiffWindow(Window):
413
395
def __init__(self, parent=None, operations=None):
414
super(DiffWindow, self).__init__(parent=parent)
396
Window.__init__(self, parent)
415
397
self.set_border_width(0)
416
398
self.set_title("bzrk diff")
442
424
def _get_menu_bar(self):
443
menubar = Gtk.MenuBar()
425
menubar = gtk.MenuBar()
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"))
427
mb_view = gtk.MenuItem(_i18n("_View"))
428
mb_view_menu = gtk.Menu()
429
mb_view_wrapsource = gtk.CheckMenuItem(_i18n("Wrap _Long Lines"))
449
430
mb_view_wrapsource.connect('activate', self.diff._on_wraplines_toggled)
450
431
mb_view_wrapsource.show()
451
432
mb_view_menu.append(mb_view_wrapsource)
464
445
if operations is None:
466
hbox = Gtk.HButtonBox()
467
hbox.set_layout(Gtk.ButtonBoxStyle.START)
447
hbox = gtk.HButtonBox()
448
hbox.set_layout(gtk.BUTTONBOX_START)
468
449
for title, method in operations:
469
merge_button = Gtk.Button(title)
450
merge_button = gtk.Button(title)
470
451
merge_button.show()
471
merge_button.set_relief(Gtk.ReliefStyle.NONE)
452
merge_button.set_relief(gtk.RELIEF_NONE)
472
453
merge_button.connect("clicked", method)
473
454
hbox.pack_start(merge_button, expand=False, fill=True)
477
458
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,
482
Gtk.ResponseType.CANCEL,))
459
d = gtk.FileChooserDialog('Merge branch', self,
460
gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER,
461
buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
463
gtk.RESPONSE_CANCEL,))
485
if result != Gtk.ResponseType.OK:
466
if result != gtk.RESPONSE_OK:
486
467
raise SelectCancelled()
487
468
return d.get_current_folder_uri()
502
483
error_dialog('Error', str(e))
504
485
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,
509
Gtk.ResponseType.CANCEL,))
486
d = gtk.FileChooserDialog('Save As', self,
487
gtk.FILE_CHOOSER_ACTION_SAVE,
488
buttons=(gtk.STOCK_OK, gtk.RESPONSE_OK,
490
gtk.RESPONSE_CANCEL,))
510
491
d.set_current_name(basename)
513
if result != Gtk.ResponseType.OK:
494
if result != gtk.RESPONSE_OK:
514
495
raise SelectCancelled()
515
496
return urlutils.local_path_from_url(d.get_uri())
532
513
class DiffController(object):
534
def __init__(self, path, patch, window=None, allow_dirty=False):
515
def __init__(self, path, patch, window=None):
536
517
self.patch = patch
537
self.allow_dirty = allow_dirty
538
518
if window is None:
539
519
window = DiffWindow(operations=self._provide_operations())
540
520
self.initialize_window(window)
547
527
def get_diff_sections(self):
548
528
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)
553
patches = parse_patches(self.patch)
554
for patch in patches:
529
for patch in parse_patches(self.patch):
555
530
oldname = patch.oldname.split('\t')[0]
556
531
newname = patch.newname.split('\t')[0]
557
532
yield oldname, newname, str(patch)
578
553
class MergeDirectiveController(DiffController):
580
555
def __init__(self, path, directive, window=None):
581
super(MergeDirectiveController, self).__init__(
582
path, directive.patch.splitlines(True), window)
556
DiffController.__init__(self, path, directive.patch.splitlines(True),
583
558
self.directive = directive
584
559
self.merge_target = None
596
571
tree.lock_write()
599
if tree.has_changes():
600
raise errors.UncommittedChanges(tree)
601
merger, verified = _mod_merge.Merger.from_mergeable(
602
tree, self.directive, pb=None)
574
merger, verified = _mod_merge.Merger.from_mergeable(tree,
575
self.directive, progress.DummyProgress())
576
merger.check_basis(True)
603
577
merger.merge_type = _mod_merge.Merge3Merger
604
578
conflict_count = merger.do_merge()
605
579
merger.set_pending()