19
from gi.repository import Gdk
20
25
from gi.repository import Gtk
21
26
from gi.repository import GObject
22
27
from gi.repository import Pango
25
from bzrlib import bencode
27
from bzrlib.util import bencode
29
29
from bzrlib import (
35
from bzrlib import bencode
37
from bzrlib.util import bencode
33
39
from bzrlib.plugins.gtk.dialog import question_dialog
34
40
from bzrlib.plugins.gtk.errors import show_bzr_error
35
41
from bzrlib.plugins.gtk.i18n import _i18n
36
from bzrlib.plugins.gtk.commitmsgs import SavedCommitMessagesManager
108
113
"""Implementation of Commit."""
110
115
def __init__(self, wt, selected=None, parent=None):
111
super(CommitDialog, self).__init__(
112
title="Commit to %s" % wt.basedir, parent=parent, flags=0)
116
GObject.GObject.__init__(self, title="Commit to %s" % wt.basedir,
117
parent=parent, flags=0,)
113
118
self.connect('delete-event', self._on_delete_window)
114
119
self._question_dialog = question_dialog
356
360
self._button_cancel = Gtk.Button(stock=Gtk.STOCK_CANCEL)
357
361
self._button_cancel.connect('clicked', self._on_cancel_clicked)
358
362
self._button_cancel.show()
359
self.get_action_area().pack_end(
360
self._button_cancel, True, True, 0)
363
self.action_area.pack_end(self._button_cancel)
361
364
self._button_commit = Gtk.Button(_i18n("Comm_it"), use_underline=True)
362
365
self._button_commit.connect('clicked', self._on_commit_clicked)
363
366
self._button_commit.set_can_default(True)
364
367
self._button_commit.show()
365
self.get_action_area().pack_end(
366
self._button_commit, True, True, 0)
368
self.action_area.pack_end(self._button_commit)
367
369
self._button_commit.grab_default()
369
371
def _add_to_right_table(self, widget, weight, expanding=False):
389
391
# file_label.show()
390
392
self._files_box.pack_start(file_label, False, True, 0)
392
self._commit_all_files_radio = Gtk.RadioButton.new_with_label(
394
self._commit_all_files_radio = Gtk.RadioButton(
393
395
None, _i18n("Commit all changes"))
394
396
self._files_box.pack_start(self._commit_all_files_radio, False, True, 0)
395
397
self._commit_all_files_radio.show()
396
398
self._commit_all_files_radio.connect('toggled',
397
399
self._toggle_commit_selection)
398
self._commit_selected_radio = Gtk.RadioButton.new_with_label_from_widget(
400
self._commit_selected_radio = Gtk.RadioButton(
399
401
self._commit_all_files_radio, _i18n("Only commit selected changes"))
400
402
self._files_box.pack_start(self._commit_selected_radio, False, True, 0)
401
403
self._commit_selected_radio.show()
476
479
pending_message = Gtk.Label()
477
480
pending_message.set_markup(
478
481
_i18n('<i>* Cannot select specific files when merging</i>'))
479
self._pending_box.pack_start(pending_message, False, True, 5)
482
self._pending_box.pack_start(pending_message, expand=False, padding=5)
480
483
pending_message.show()
482
485
pending_label = Gtk.Label(label=_i18n('Pending Revisions'))
483
self._pending_box.pack_start(pending_label, False, True, 0)
486
self._pending_box.pack_start(pending_label, expand=False, padding=0)
484
487
pending_label.show()
486
489
scroller = Gtk.ScrolledWindow()
489
492
scroller.add(self._treeview_pending)
490
493
scroller.set_shadow_type(Gtk.ShadowType.IN)
492
self._pending_box.pack_start(scroller, True, True, 5)
495
self._pending_box.pack_start(scroller,
496
expand=True, fill=True, padding=5)
493
497
self._treeview_pending.show()
494
498
self._left_pane_box.pack_start(self._pending_box, True, True, 0)
596
599
# We have either made it to the end of the list, or nothing was
597
600
# selected. Either way, select All Files, and jump to the global
598
601
# commit message.
599
self._treeview_files.set_cursor(
600
Gtk.TreePath(path=0), None, False)
602
self._treeview_files.set_cursor((0,))
601
603
self._global_message_text_view.grab_focus()
603
605
# Set the cursor to this entry, and jump to the per-file commit
605
self._treeview_files.set_cursor(model.get_path(next), None, False)
607
self._treeview_files.set_cursor(model.get_path(next))
606
608
self._file_message_text_view.grab_focus()
608
610
def _save_current_file_message(self):
793
795
rev_dict['revision_id'] = rev.revision_id
799
class SavedCommitMessagesManager:
800
"""Save glogal and per-file commit messages.
802
Saves global commit message and utf-8 file_id->message dictionary
803
of per-file commit messages on disk. Re-reads them later for re-using.
806
def __init__(self, tree=None, branch=None):
807
"""If branch is None, builds empty messages, otherwise reads them
808
from branch's disk storage. 'tree' argument is for the future."""
810
self.global_message = u''
811
self.file_messages = {}
813
config = branch.get_config()
814
self.global_message = config.get_user_option(
815
'gtk_global_commit_message')
816
if self.global_message is None:
817
self.global_message = u''
818
file_messages = config.get_user_option('gtk_file_commit_messages')
819
if file_messages: # unicode and B-encoded:
820
self.file_messages = bencode.bdecode(
821
file_messages.encode('UTF-8'))
823
self.file_messages = {}
826
return self.global_message, self.file_messages
828
def is_not_empty(self):
829
return bool(self.global_message or self.file_messages)
831
def insert(self, global_message, file_info):
832
"""Formats per-file commit messages (list of dictionaries, one per file)
833
into one utf-8 file_id->message dictionary and merges this with
834
previously existing dictionary. Merges global commit message too."""
837
file_message = fi['message']
839
file_messages[fi['file_id']] = file_message # utf-8 strings
840
for k,v in file_messages.iteritems():
842
self.file_messages[k] = v + '\n******\n' + self.file_messages[k]
844
self.file_messages[k] = v
845
if self.global_message:
846
self.global_message = global_message + '\n******\n' \
847
+ self.global_message
849
self.global_message = global_message
851
def save(self, tree, branch):
852
# We store in branch's config, which can be a problem if two gcommit
853
# are done in two checkouts of one single branch (comments overwrite
854
# each other). Ideally should be in working tree. But uncommit does
855
# not always have a working tree, though it always has a branch.
856
# 'tree' argument is for the future
857
config = branch.get_config()
858
# should it be named "gtk_" or some more neutral name ("gui_" ?) to
859
# be compatible with qbzr in the future?
860
config.set_user_option('gtk_global_commit_message', self.global_message)
861
# bencode() does not know unicode objects but set_user_option()
863
config.set_user_option(
864
'gtk_file_commit_messages',
865
bencode.bencode(self.file_messages).decode('UTF-8'))
868
def save_commit_messages(local, master, old_revno, old_revid,
869
new_revno, new_revid):
873
mgr = SavedCommitMessagesManager(None, b)
874
revid_iterator = b.repository.iter_reverse_revision_history(old_revid)
875
cur_revno = old_revno
876
new_revision_id = old_revid
877
graph = b.repository.get_graph()
878
for rev_id in revid_iterator:
879
if cur_revno == new_revno:
882
rev = b.repository.get_revision(rev_id)
883
file_info = rev.properties.get('file-info', None)
884
if file_info is None:
887
file_info = bencode.bdecode(file_info.encode('UTF-8'))
888
global_message = osutils.safe_unicode(rev.message)
889
# Concatenate comment of the uncommitted revision
890
mgr.insert(global_message, file_info)
892
parents = graph.get_parent_map([rev_id]).get(rev_id, None)