14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
from gi.repository import Gdk
20
from gi.repository import Gtk
21
from gi.repository import GObject
22
from gi.repository import Pango
30
from bzrlib import errors, osutils
31
from bzrlib.trace import mutter
32
from bzrlib.util import bencode
28
revision as _mod_revision,
32
from bzrlib.plugins.gtk.dialog import question_dialog
33
from bzrlib.plugins.gtk.errors import show_bzr_error
34
from bzrlib.plugins.gtk.i18n import _i18n
35
from bzrlib.plugins.gtk.commitmsgs import SavedCommitMessagesManager
34
from bzrlib.plugins.gtk import _i18n
35
from dialog import error_dialog, question_dialog
36
from errors import show_bzr_error
45
def _get_sorted_revisions(tip_revision, revision_ids, parent_map):
46
"""Get an iterator which will return the revisions in merge sorted order.
48
This will build up a list of all nodes, such that only nodes in the list
49
are referenced. It then uses MergeSorter to return them in 'merge-sorted'
52
:param revision_ids: A set of revision_ids
53
:param parent_map: The parent information for each node. Revisions which
54
are considered ghosts should not be present in the map.
55
:return: iterator from MergeSorter.iter_topo_order()
57
# MergeSorter requires that all nodes be present in the graph, so get rid
58
# of any references pointing outside of this graph.
60
for revision_id in revision_ids:
61
if revision_id not in parent_map: # ghost
62
parent_graph[revision_id] = []
64
# Only include parents which are in this sub-graph
65
parent_graph[revision_id] = [p for p in parent_map[revision_id]
67
sorter = tsort.MergeSorter(parent_graph, tip_revision)
68
return sorter.iter_topo_order()
71
46
def pending_revisions(wt):
72
47
"""Return a list of pending merges or None if there are none of them.
87
62
last_revision = parents[0]
89
graph = branch.repository.get_graph()
90
other_revisions = [last_revision]
64
if last_revision is not None:
66
ignore = set(branch.repository.get_ancestry(last_revision,
68
except errors.NoSuchRevision:
69
# the last revision is a ghost : assume everything is new
71
ignore = set([None, last_revision])
93
76
for merge in pending:
95
merge_rev = branch.repository.get_revision(merge)
96
except errors.NoSuchRevision:
97
# If we are missing a revision, just print out the revision id
98
trace.mutter("ghost: %r", merge)
99
other_revisions.append(merge)
102
# Find all of the revisions in the merge source, which are not in the
103
# last committed revision.
104
merge_extra = graph.find_unique_ancestors(merge, other_revisions)
105
other_revisions.append(merge)
106
merge_extra.discard(_mod_revision.NULL_REVISION)
108
# Get a handle to all of the revisions we will need
110
revisions = dict((rev.revision_id, rev) for rev in
111
branch.repository.get_revisions(merge_extra))
112
except errors.NoSuchRevision:
113
# One of the sub nodes is a ghost, check each one
115
for revision_id in merge_extra:
117
rev = branch.repository.get_revisions([revision_id])[0]
118
except errors.NoSuchRevision:
119
revisions[revision_id] = None
121
revisions[revision_id] = rev
123
# Display the revisions brought in by this merge.
124
rev_id_iterator = _get_sorted_revisions(merge, merge_extra,
125
branch.repository.get_parent_map(merge_extra))
126
# Skip the first node
127
num, first, depth, eom = rev_id_iterator.next()
129
raise AssertionError('Somehow we misunderstood how'
130
' iter_topo_order works %s != %s' % (first, merge))
132
for num, sub_merge, depth, eom in rev_id_iterator:
133
rev = revisions[sub_merge]
135
trace.warning("ghost: %r", sub_merge)
138
yield (merge_rev, children)
141
_newline_variants_re = re.compile(r'\r\n?')
142
def _sanitize_and_decode_message(utf8_message):
143
"""Turn a utf-8 message into a sanitized Unicode message."""
144
fixed_newline = _newline_variants_re.sub('\n', utf8_message)
145
return osutils.safe_unicode(fixed_newline)
148
class CommitDialog(Gtk.Dialog):
79
rev = branch.repository.get_revision(merge)
81
pm.append((rev, children))
83
# This does need to be topo sorted, so we search backwards
84
inner_merges = branch.repository.get_ancestry(merge)
85
assert inner_merges[0] is None
87
for mmerge in reversed(inner_merges):
90
rev = branch.repository.get_revision(mmerge)
94
except errors.NoSuchRevision:
95
print "DEBUG: NoSuchRevision:", merge
100
class CommitDialog(gtk.Dialog):
149
101
"""Implementation of Commit."""
151
103
def __init__(self, wt, selected=None, parent=None):
152
super(CommitDialog, self).__init__(
153
title="Commit to %s" % wt.basedir, parent=parent, flags=0)
154
self.connect('delete-event', self._on_delete_window)
104
gtk.Dialog.__init__(self, title="Commit - Olive",
107
buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
155
108
self._question_dialog = question_dialog
157
self.set_type_hint(Gdk.WindowTypeHint.NORMAL)
160
111
# TODO: Do something with this value, it is used by Olive
161
112
# It used to set all changes but this one to False
238
182
all_enabled = (self._selected is None)
239
183
# The first entry is always the 'whole tree'
240
all_iter = store.append(["", "", all_enabled, 'All Files', '', ''])
184
all_iter = store.append([None, None, all_enabled, 'All Files', '', ''])
241
185
initial_cursor = store.get_path(all_iter)
242
186
# should we pass specific_files?
243
187
self._wt.lock_read()
244
188
self._basis_tree.lock_read()
246
190
from diff import iter_changes_to_status
247
saved_file_messages = self._saved_commit_messages_manager.get()[1]
248
191
for (file_id, real_path, change_type, display_path
249
192
) in iter_changes_to_status(self._basis_tree, self._wt):
250
193
if self._selected and real_path != self._selected:
255
default_message = saved_file_messages[file_id]
258
197
item_iter = store.append([
260
199
real_path.encode('UTF-8'),
262
201
display_path.encode('UTF-8'),
264
default_message, # Initial comment
203
'', # Initial comment
266
205
if self._selected and enabled:
267
206
initial_cursor = store.get_path(item_iter)
359
298
self._hpane.set_position(300)
361
300
def _construct_accelerators(self):
362
group = Gtk.AccelGroup()
363
group.connect(Gdk.keyval_from_name('N'),
364
Gdk.ModifierType.CONTROL_MASK, 0, self._on_accel_next)
301
group = gtk.AccelGroup()
302
group.connect_group(gtk.gdk.keyval_from_name('N'),
303
gtk.gdk.CONTROL_MASK, 0, self._on_accel_next)
365
304
self.add_accel_group(group)
367
306
# ignore the escape key (avoid closing the window)
368
307
self.connect_object('close', self.emit_stop_by_name, 'close')
370
309
def _construct_left_pane(self):
371
self._left_pane_box = Gtk.VBox(homogeneous=False, spacing=5)
310
self._left_pane_box = gtk.VBox(homogeneous=False, spacing=5)
372
311
self._construct_file_list()
373
312
self._construct_pending_list()
375
self._check_local = Gtk.CheckButton(_i18n("_Only commit locally"),
314
self._check_local = gtk.CheckButton(_i18n("_Only commit locally"),
376
315
use_underline=True)
377
self._left_pane_box.pack_end(self._check_local, False, False, 0)
316
self._left_pane_box.pack_end(self._check_local, False, False)
378
317
self._check_local.set_active(False)
380
319
self._hpane.pack1(self._left_pane_box, resize=False, shrink=False)
399
338
self._hpane.pack2(self._right_pane_table, resize=True, shrink=True)
401
340
def _construct_action_pane(self):
402
self._button_cancel = Gtk.Button(stock=Gtk.STOCK_CANCEL)
403
self._button_cancel.connect('clicked', self._on_cancel_clicked)
404
self._button_cancel.show()
405
self.get_action_area().pack_end(
406
self._button_cancel, True, True, 0)
407
self._button_commit = Gtk.Button(_i18n("Comm_it"), use_underline=True)
341
self._button_commit = gtk.Button(_i18n("Comm_it"), use_underline=True)
408
342
self._button_commit.connect('clicked', self._on_commit_clicked)
409
self._button_commit.set_can_default(True)
343
self._button_commit.set_flags(gtk.CAN_DEFAULT)
410
344
self._button_commit.show()
411
self.get_action_area().pack_end(
412
self._button_commit, True, True, 0)
345
self.action_area.pack_end(self._button_commit)
413
346
self._button_commit.grab_default()
415
348
def _add_to_right_table(self, widget, weight, expanding=False):
430
363
self._right_pane_table_row = end_row
432
365
def _construct_file_list(self):
433
self._files_box = Gtk.VBox(homogeneous=False, spacing=0)
434
file_label = Gtk.Label(label=_i18n('Files'))
366
self._files_box = gtk.VBox(homogeneous=False, spacing=0)
367
file_label = gtk.Label(_i18n('Files'))
435
368
# file_label.show()
436
self._files_box.pack_start(file_label, False, True, 0)
369
self._files_box.pack_start(file_label, expand=False)
438
self._commit_all_files_radio = Gtk.RadioButton.new_with_label(
371
self._commit_all_files_radio = gtk.RadioButton(
439
372
None, _i18n("Commit all changes"))
440
self._files_box.pack_start(self._commit_all_files_radio, False, True, 0)
373
self._files_box.pack_start(self._commit_all_files_radio, expand=False)
441
374
self._commit_all_files_radio.show()
442
375
self._commit_all_files_radio.connect('toggled',
443
376
self._toggle_commit_selection)
444
self._commit_selected_radio = Gtk.RadioButton.new_with_label_from_widget(
377
self._commit_selected_radio = gtk.RadioButton(
445
378
self._commit_all_files_radio, _i18n("Only commit selected changes"))
446
self._files_box.pack_start(self._commit_selected_radio, False, True, 0)
379
self._files_box.pack_start(self._commit_selected_radio, expand=False)
447
380
self._commit_selected_radio.show()
448
381
self._commit_selected_radio.connect('toggled',
449
382
self._toggle_commit_selection)
452
385
self._commit_all_files_radio.set_sensitive(False)
453
386
self._commit_selected_radio.set_sensitive(False)
455
scroller = Gtk.ScrolledWindow()
456
scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
457
self._treeview_files = Gtk.TreeView()
388
scroller = gtk.ScrolledWindow()
389
scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
390
self._treeview_files = gtk.TreeView()
458
391
self._treeview_files.show()
459
392
scroller.add(self._treeview_files)
460
scroller.set_shadow_type(Gtk.ShadowType.IN)
393
scroller.set_shadow_type(gtk.SHADOW_IN)
462
self._files_box.pack_start(scroller, True, True, 0)
395
self._files_box.pack_start(scroller,
396
expand=True, fill=True)
463
397
self._files_box.show()
464
self._left_pane_box.pack_start(self._files_box, True, True, 0)
398
self._left_pane_box.pack_start(self._files_box)
466
400
# Keep note that all strings stored in a ListStore must be UTF-8
467
401
# strings. GTK does not support directly setting and restoring Unicode
469
liststore = Gtk.ListStore(
470
GObject.TYPE_STRING, # [0] file_id
471
GObject.TYPE_STRING, # [1] real path
472
GObject.TYPE_BOOLEAN, # [2] checkbox
473
GObject.TYPE_STRING, # [3] display path
474
GObject.TYPE_STRING, # [4] changes type
475
GObject.TYPE_STRING, # [5] commit message
403
liststore = gtk.ListStore(
404
gobject.TYPE_STRING, # [0] file_id
405
gobject.TYPE_STRING, # [1] real path
406
gobject.TYPE_BOOLEAN, # [2] checkbox
407
gobject.TYPE_STRING, # [3] display path
408
gobject.TYPE_STRING, # [4] changes type
409
gobject.TYPE_STRING, # [5] commit message
477
411
self._files_store = liststore
478
412
self._treeview_files.set_model(liststore)
479
crt = Gtk.CellRendererToggle()
413
crt = gtk.CellRendererToggle()
480
414
crt.set_property('activatable', not bool(self._pending))
481
415
crt.connect("toggled", self._toggle_commit, self._files_store)
482
416
if self._pending:
483
417
name = _i18n('Commit*')
485
419
name = _i18n('Commit')
486
commit_col = Gtk.TreeViewColumn(name, crt, active=2)
420
commit_col = gtk.TreeViewColumn(name, crt, active=2)
487
421
commit_col.set_visible(False)
488
422
self._treeview_files.append_column(commit_col)
489
self._treeview_files.append_column(Gtk.TreeViewColumn(_i18n('Path'),
490
Gtk.CellRendererText(), text=3))
491
self._treeview_files.append_column(Gtk.TreeViewColumn(_i18n('Type'),
492
Gtk.CellRendererText(), text=4))
423
self._treeview_files.append_column(gtk.TreeViewColumn(_i18n('Path'),
424
gtk.CellRendererText(), text=3))
425
self._treeview_files.append_column(gtk.TreeViewColumn(_i18n('Type'),
426
gtk.CellRendererText(), text=4))
493
427
self._treeview_files.connect('cursor-changed',
494
428
self._on_treeview_files_cursor_changed)
496
430
def _toggle_commit(self, cell, path, model):
497
if model[path][0] == "": # No file_id means 'All Files'
431
if model[path][0] is None: # No file_id means 'All Files'
498
432
new_val = not model[path][2]
499
433
for node in model:
500
434
node[2] = new_val
510
444
checked_col.set_visible(False)
512
446
checked_col.set_visible(True)
513
renderer = checked_col.get_cells()[0]
447
renderer = checked_col.get_cell_renderers()[0]
514
448
renderer.set_property('activatable', not all_files)
516
450
def _construct_pending_list(self):
517
451
# Pending information defaults to hidden, we put it all in 1 box, so
518
452
# that we can show/hide all of them at once
519
self._pending_box = Gtk.VBox()
453
self._pending_box = gtk.VBox()
520
454
self._pending_box.hide()
522
pending_message = Gtk.Label()
456
pending_message = gtk.Label()
523
457
pending_message.set_markup(
524
458
_i18n('<i>* Cannot select specific files when merging</i>'))
525
self._pending_box.pack_start(pending_message, False, True, 5)
459
self._pending_box.pack_start(pending_message, expand=False, padding=5)
526
460
pending_message.show()
528
pending_label = Gtk.Label(label=_i18n('Pending Revisions'))
529
self._pending_box.pack_start(pending_label, False, True, 0)
462
pending_label = gtk.Label(_i18n('Pending Revisions'))
463
self._pending_box.pack_start(pending_label, expand=False, padding=0)
530
464
pending_label.show()
532
scroller = Gtk.ScrolledWindow()
533
scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
534
self._treeview_pending = Gtk.TreeView()
466
scroller = gtk.ScrolledWindow()
467
scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
468
self._treeview_pending = gtk.TreeView()
535
469
scroller.add(self._treeview_pending)
536
scroller.set_shadow_type(Gtk.ShadowType.IN)
470
scroller.set_shadow_type(gtk.SHADOW_IN)
538
self._pending_box.pack_start(scroller, True, True, 5)
472
self._pending_box.pack_start(scroller,
473
expand=True, fill=True, padding=5)
539
474
self._treeview_pending.show()
540
self._left_pane_box.pack_start(self._pending_box, True, True, 0)
475
self._left_pane_box.pack_start(self._pending_box)
542
liststore = Gtk.ListStore(GObject.TYPE_STRING, # revision_id
543
GObject.TYPE_STRING, # date
544
GObject.TYPE_STRING, # committer
545
GObject.TYPE_STRING, # summary
477
liststore = gtk.ListStore(gobject.TYPE_STRING, # revision_id
478
gobject.TYPE_STRING, # date
479
gobject.TYPE_STRING, # committer
480
gobject.TYPE_STRING, # summary
547
482
self._pending_store = liststore
548
483
self._treeview_pending.set_model(liststore)
549
self._treeview_pending.append_column(Gtk.TreeViewColumn(_i18n('Date'),
550
Gtk.CellRendererText(), text=1))
551
self._treeview_pending.append_column(Gtk.TreeViewColumn(_i18n('Committer'),
552
Gtk.CellRendererText(), text=2))
553
self._treeview_pending.append_column(Gtk.TreeViewColumn(_i18n('Summary'),
554
Gtk.CellRendererText(), text=3))
484
self._treeview_pending.append_column(gtk.TreeViewColumn(_i18n('Date'),
485
gtk.CellRendererText(), text=1))
486
self._treeview_pending.append_column(gtk.TreeViewColumn(_i18n('Committer'),
487
gtk.CellRendererText(), text=2))
488
self._treeview_pending.append_column(gtk.TreeViewColumn(_i18n('Summary'),
489
gtk.CellRendererText(), text=3))
556
491
def _construct_diff_view(self):
557
from bzrlib.plugins.gtk.diff import DiffView
492
from diff import DiffView
559
494
# TODO: jam 2007-10-30 The diff label is currently disabled. If we
560
495
# decide that we really don't ever want to display it, we should
561
496
# actually remove it, and other references to it, along with the
562
497
# tests that it is set properly.
563
self._diff_label = Gtk.Label(label=_i18n('Diff for whole tree'))
498
self._diff_label = gtk.Label(_i18n('Diff for whole tree'))
564
499
self._diff_label.set_alignment(0, 0)
565
500
self._right_pane_table.set_row_spacing(self._right_pane_table_row, 0)
566
501
self._add_to_right_table(self._diff_label, 1, False)
571
506
self._diff_view.show()
573
508
def _construct_file_message(self):
574
scroller = Gtk.ScrolledWindow()
575
scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
509
scroller = gtk.ScrolledWindow()
510
scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
577
self._file_message_text_view = Gtk.TextView()
512
self._file_message_text_view = gtk.TextView()
578
513
scroller.add(self._file_message_text_view)
579
scroller.set_shadow_type(Gtk.ShadowType.IN)
514
scroller.set_shadow_type(gtk.SHADOW_IN)
582
self._file_message_text_view.modify_font(Pango.FontDescription("Monospace"))
583
self._file_message_text_view.set_wrap_mode(Gtk.WrapMode.WORD)
517
self._file_message_text_view.modify_font(pango.FontDescription("Monospace"))
518
self._file_message_text_view.set_wrap_mode(gtk.WRAP_WORD)
584
519
self._file_message_text_view.set_accepts_tab(False)
585
520
self._file_message_text_view.show()
587
self._file_message_expander = Gtk.Expander(
588
label=_i18n('File commit message'))
522
self._file_message_expander = gtk.Expander(_i18n('File commit message'))
589
523
self._file_message_expander.set_expanded(True)
590
524
self._file_message_expander.add(scroller)
591
525
self._add_to_right_table(self._file_message_expander, 1, False)
592
526
self._file_message_expander.show()
594
528
def _construct_global_message(self):
595
self._global_message_label = Gtk.Label(label=_i18n('Global Commit Message'))
529
self._global_message_label = gtk.Label(_i18n('Global Commit Message'))
596
530
self._global_message_label.set_markup(
597
531
_i18n('<b>Global Commit Message</b>'))
598
532
self._global_message_label.set_alignment(0, 0)
601
535
# Can we remove the spacing between the label and the box?
602
536
self._global_message_label.show()
604
scroller = Gtk.ScrolledWindow()
605
scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
538
scroller = gtk.ScrolledWindow()
539
scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
607
self._global_message_text_view = Gtk.TextView()
608
self._set_global_commit_message(self._saved_commit_messages_manager.get()[0])
609
self._global_message_text_view.modify_font(Pango.FontDescription("Monospace"))
541
self._global_message_text_view = gtk.TextView()
542
self._global_message_text_view.modify_font(pango.FontDescription("Monospace"))
610
543
scroller.add(self._global_message_text_view)
611
scroller.set_shadow_type(Gtk.ShadowType.IN)
544
scroller.set_shadow_type(gtk.SHADOW_IN)
613
546
self._add_to_right_table(scroller, 2, True)
614
self._file_message_text_view.set_wrap_mode(Gtk.WrapMode.WORD)
547
self._file_message_text_view.set_wrap_mode(gtk.WRAP_WORD)
615
548
self._file_message_text_view.set_accepts_tab(False)
616
549
self._global_message_text_view.show()
618
551
def _on_treeview_files_cursor_changed(self, treeview):
619
552
treeselection = treeview.get_selection()
620
if treeselection is None:
621
# The treeview was probably destroyed as the dialog closes.
623
553
(model, selection) = treeselection.get_selected()
625
555
if selection is not None:
626
556
path, display_path = model.get(selection, 1, 3)
627
557
self._diff_label.set_text(_i18n('Diff for ') + display_path)
629
559
self._diff_view.show_diff(None)
631
self._diff_view.show_diff([osutils.safe_unicode(path)])
561
self._diff_view.show_diff([path.decode('UTF-8')])
632
562
self._update_per_file_info(selection)
634
564
def _on_accel_next(self, accel_group, window, keyval, modifier):
645
575
# We have either made it to the end of the list, or nothing was
646
576
# selected. Either way, select All Files, and jump to the global
647
577
# commit message.
648
self._treeview_files.set_cursor(
649
Gtk.TreePath(path=0), "", False)
578
self._treeview_files.set_cursor((0,))
650
579
self._global_message_text_view.grab_focus()
652
581
# Set the cursor to this entry, and jump to the per-file commit
654
self._treeview_files.set_cursor(model.get_path(next), None, False)
583
self._treeview_files.set_cursor(model.get_path(next))
655
584
self._file_message_text_view.grab_focus()
657
586
def _save_current_file_message(self):
695
624
records = iter(self._files_store)
696
625
rec = records.next() # Skip the All Files record
697
assert rec[0] == "", "Are we skipping the wrong record?"
626
assert rec[0] is None, "Are we skipping the wrong record?"
700
629
for record in records:
701
630
if self._commit_all_changes or record[2]:# [2] checkbox
702
file_id = osutils.safe_utf8(record[0]) # [0] file_id
703
path = osutils.safe_utf8(record[1]) # [1] real path
705
file_message = _sanitize_and_decode_message(record[5])
631
file_id = record[0] # [0] file_id
632
path = record[1] # [1] real path
633
file_message = record[5] # [5] commit message
706
634
files.append(path.decode('UTF-8'))
707
635
if self._enable_per_file_commits and file_message:
708
636
# All of this needs to be utf-8 information
709
file_message = file_message.encode('UTF-8')
710
637
file_info.append({'path':path, 'file_id':file_id,
711
638
'message':file_message})
712
639
file_info.sort(key=lambda x:(x['path'], x['file_id']))
719
def _on_cancel_clicked(self, button):
720
""" Cancel button clicked handler. """
724
def _on_delete_window(self, source, event):
725
""" Delete window handler. """
728
def _do_cancel(self):
729
"""If requested, saves commit messages when cancelling gcommit; they are re-used by a next gcommit"""
730
mgr = SavedCommitMessagesManager()
731
self._saved_commit_messages_manager = mgr
732
mgr.insert(self._get_global_commit_message(),
733
self._get_specific_files()[1])
734
if mgr.is_not_empty(): # maybe worth saving
735
response = self._question_dialog(
736
_i18n('Commit cancelled'),
737
_i18n('Do you want to save your commit messages ?'),
739
if response == Gtk.ResponseType.NO:
740
# save nothing and destroy old comments if any
741
mgr = SavedCommitMessagesManager()
742
mgr.save(self._wt, self._wt.branch)
743
self.response(Gtk.ResponseType.CANCEL) # close window
746
646
def _on_commit_clicked(self, button):
747
647
""" Commit button clicked handler. """
748
648
self._do_commit()
806
702
specific_files=specific_files,
807
703
revprops=revprops)
808
704
self.committed_revision_id = rev_id
809
# destroy old comments if any
810
SavedCommitMessagesManager().save(self._wt, self._wt.branch)
811
self.response(Gtk.ResponseType.OK)
705
self.response(gtk.RESPONSE_OK)
813
707
def _get_global_commit_message(self):
814
708
buf = self._global_message_text_view.get_buffer()
815
709
start, end = buf.get_bounds()
816
text = buf.get_text(start, end, True)
817
return _sanitize_and_decode_message(text)
710
return buf.get_text(start, end).decode('utf-8')
819
712
def _set_global_commit_message(self, message):
820
713
"""Just a helper for the test suite."""