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