/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 commit.py

  • Committer: Jelmer Vernooij
  • Date: 2011-12-20 16:16:57 UTC
  • Revision ID: jelmer@canonical.com-20111220161657-zjn6rqjrw8ouehf8
Drop support for old bencode location.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
16
16
 
17
 
try:
18
 
    import pygtk
19
 
    pygtk.require("2.0")
20
 
except:
21
 
    pass
22
 
 
23
 
import gtk
24
 
import gobject
25
 
import pango
26
 
 
27
 
import os.path
28
17
import re
29
18
 
30
 
from bzrlib import errors, osutils
31
 
from bzrlib.trace import mutter
32
 
from bzrlib.util import bencode
 
19
from gi.repository import Gdk
 
20
from gi.repository import Gtk
 
21
from gi.repository import GObject
 
22
from gi.repository import Pango
33
23
 
34
 
from bzrlib.plugins.gtk import _i18n
35
 
from dialog import error_dialog, question_dialog
36
 
from errors import show_bzr_error
 
24
from bzrlib import (
 
25
    bencode,
 
26
    errors,
 
27
    trace,
 
28
    )
 
29
from bzrlib.plugins.gtk.dialog import question_dialog
 
30
from bzrlib.plugins.gtk.errors import show_bzr_error
 
31
from bzrlib.plugins.gtk.i18n import _i18n
 
32
from bzrlib.plugins.gtk.commitmsgs import SavedCommitMessagesManager
37
33
 
38
34
try:
39
35
    import dbus
62
58
    last_revision = parents[0]
63
59
 
64
60
    if last_revision is not None:
65
 
        try:
66
 
            ignore = set(branch.repository.get_ancestry(last_revision,
67
 
                                                        topo_sorted=False))
68
 
        except errors.NoSuchRevision:
69
 
            # the last revision is a ghost : assume everything is new
70
 
            # except for it
71
 
            ignore = set([None, last_revision])
 
61
        graph = branch.repository.get_graph()
 
62
        ignore = set([r for r,ps in graph.iter_ancestry([last_revision])])
72
63
    else:
73
 
        ignore = set([None])
 
64
        ignore = set([])
74
65
 
75
66
    pm = []
76
67
    for merge in pending:
97
88
    return pm
98
89
 
99
90
 
100
 
class CommitDialog(gtk.Dialog):
 
91
_newline_variants_re = re.compile(r'\r\n?')
 
92
def _sanitize_and_decode_message(utf8_message):
 
93
    """Turn a utf-8 message into a sanitized Unicode message."""
 
94
    fixed_newline = _newline_variants_re.sub('\n', utf8_message)
 
95
    return fixed_newline.decode('utf-8')
 
96
 
 
97
 
 
98
class CommitDialog(Gtk.Dialog):
101
99
    """Implementation of Commit."""
102
100
 
103
101
    def __init__(self, wt, selected=None, parent=None):
104
 
        gtk.Dialog.__init__(self, title="Commit - Olive",
105
 
                                  parent=parent,
106
 
                                  flags=0,
107
 
                                  buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
 
102
        super(CommitDialog, self).__init__(
 
103
            title="Commit to %s" % wt.basedir, parent=parent, flags=0)
 
104
        self.connect('delete-event', self._on_delete_window)
108
105
        self._question_dialog = question_dialog
109
106
 
 
107
        self.set_type_hint(Gdk.WindowTypeHint.NORMAL)
 
108
 
110
109
        self._wt = wt
111
110
        # TODO: Do something with this value, it is used by Olive
112
111
        #       It used to set all changes but this one to False
114
113
        self._enable_per_file_commits = True
115
114
        self._commit_all_changes = True
116
115
        self.committed_revision_id = None # Nothing has been committed yet
 
116
        self._saved_commit_messages_manager = SavedCommitMessagesManager(
 
117
            self._wt, self._wt.branch)
117
118
 
118
119
        self.setup_params()
119
120
        self.construct()
123
124
        """Setup the member variables for state."""
124
125
        self._basis_tree = self._wt.basis_tree()
125
126
        self._delta = None
126
 
        self._pending = pending_revisions(self._wt)
 
127
        self._wt.lock_read()
 
128
        try:
 
129
            self._pending = pending_revisions(self._wt)
 
130
        finally:
 
131
            self._wt.unlock()
127
132
 
128
133
        self._is_checkout = (self._wt.branch.get_bound_location() is not None)
129
134
 
188
193
        self._basis_tree.lock_read()
189
194
        try:
190
195
            from diff import iter_changes_to_status
 
196
            saved_file_messages = self._saved_commit_messages_manager.get()[1]
191
197
            for (file_id, real_path, change_type, display_path
192
198
                ) in iter_changes_to_status(self._basis_tree, self._wt):
193
199
                if self._selected and real_path != self._selected:
194
200
                    enabled = False
195
201
                else:
196
202
                    enabled = True
 
203
                try:
 
204
                    default_message = saved_file_messages[file_id]
 
205
                except KeyError:
 
206
                    default_message = ''
197
207
                item_iter = store.append([
198
208
                    file_id,
199
209
                    real_path.encode('UTF-8'),
200
210
                    enabled,
201
211
                    display_path.encode('UTF-8'),
202
212
                    change_type,
203
 
                    '', # Initial comment
 
213
                    default_message, # Initial comment
204
214
                    ])
205
215
                if self._selected and enabled:
206
216
                    initial_cursor = store.get_path(item_iter)
213
223
        # This sets the cursor, which causes the expander to close, which
214
224
        # causes the _file_message_text_view to never get realized. So we have
215
225
        # to give it a little kick, or it warns when we try to grab the focus
216
 
        self._treeview_files.set_cursor(initial_cursor)
 
226
        self._treeview_files.set_cursor(initial_cursor, None, False)
217
227
 
218
228
        def _realize_file_message_tree_view(*args):
219
229
            self._file_message_text_view.realize()
232
242
                proxy_obj = bus.get_object('org.freedesktop.NetworkManager',
233
243
                                           '/org/freedesktop/NetworkManager')
234
244
            except dbus.DBusException:
235
 
                mutter("networkmanager not available.")
 
245
                trace.mutter("networkmanager not available.")
236
246
                self._check_local.show()
237
247
                return
238
248
            
244
254
            except dbus.DBusException, e:
245
255
                # Silently drop errors. While DBus may be
246
256
                # available, NetworkManager doesn't necessarily have to be
247
 
                mutter("unable to get networkmanager state: %r" % e)
 
257
                trace.mutter("unable to get networkmanager state: %r" % e)
248
258
        self._check_local.show()
249
259
 
250
260
    def _fill_in_per_file_info(self):
267
277
        """Build up the dialog widgets."""
268
278
        # The primary pane which splits it into left and right (adjustable)
269
279
        # sections.
270
 
        self._hpane = gtk.HPaned()
 
280
        self._hpane = Gtk.HPaned()
271
281
 
272
282
        self._construct_left_pane()
273
283
        self._construct_right_pane()
274
284
        self._construct_action_pane()
275
285
 
276
 
        self.vbox.pack_start(self._hpane)
 
286
        self.get_content_area().pack_start(self._hpane, True, True, 0)
277
287
        self._hpane.show()
278
288
        self.set_focus(self._global_message_text_view)
279
289
 
298
308
        self._hpane.set_position(300)
299
309
 
300
310
    def _construct_accelerators(self):
301
 
        group = gtk.AccelGroup()
302
 
        group.connect_group(gtk.gdk.keyval_from_name('N'),
303
 
                            gtk.gdk.CONTROL_MASK, 0, self._on_accel_next)
 
311
        group = Gtk.AccelGroup()
 
312
        group.connect(Gdk.keyval_from_name('N'),
 
313
                      Gdk.ModifierType.CONTROL_MASK, 0, self._on_accel_next)
304
314
        self.add_accel_group(group)
305
315
 
306
316
        # ignore the escape key (avoid closing the window)
307
317
        self.connect_object('close', self.emit_stop_by_name, 'close')
308
318
 
309
319
    def _construct_left_pane(self):
310
 
        self._left_pane_box = gtk.VBox(homogeneous=False, spacing=5)
 
320
        self._left_pane_box = Gtk.VBox(homogeneous=False, spacing=5)
311
321
        self._construct_file_list()
312
322
        self._construct_pending_list()
313
323
 
314
 
        self._check_local = gtk.CheckButton(_i18n("_Only commit locally"),
 
324
        self._check_local = Gtk.CheckButton(_i18n("_Only commit locally"),
315
325
                                            use_underline=True)
316
 
        self._left_pane_box.pack_end(self._check_local, False, False)
 
326
        self._left_pane_box.pack_end(self._check_local, False, False, 0)
317
327
        self._check_local.set_active(False)
318
328
 
319
329
        self._hpane.pack1(self._left_pane_box, resize=False, shrink=False)
326
336
        # commit, and 1 for file commit, and it looked good. But I don't seem
327
337
        # to have a way to do that with the gtk boxes... :( (Which is extra
328
338
        # weird since wx uses gtk on Linux...)
329
 
        self._right_pane_table = gtk.Table(rows=10, columns=1, homogeneous=False)
 
339
        self._right_pane_table = Gtk.Table(rows=10, columns=1, homogeneous=False)
330
340
        self._right_pane_table.set_row_spacings(5)
331
341
        self._right_pane_table.set_col_spacings(5)
332
342
        self._right_pane_table_row = 0
338
348
        self._hpane.pack2(self._right_pane_table, resize=True, shrink=True)
339
349
 
340
350
    def _construct_action_pane(self):
341
 
        self._button_commit = gtk.Button(_i18n("Comm_it"), use_underline=True)
 
351
        self._button_cancel = Gtk.Button(stock=Gtk.STOCK_CANCEL)
 
352
        self._button_cancel.connect('clicked', self._on_cancel_clicked)
 
353
        self._button_cancel.show()
 
354
        self.get_action_area().pack_end(
 
355
            self._button_cancel, True, True, 0)
 
356
        self._button_commit = Gtk.Button(_i18n("Comm_it"), use_underline=True)
342
357
        self._button_commit.connect('clicked', self._on_commit_clicked)
343
 
        self._button_commit.set_flags(gtk.CAN_DEFAULT)
 
358
        self._button_commit.set_can_default(True)
344
359
        self._button_commit.show()
345
 
        self.action_area.pack_end(self._button_commit)
 
360
        self.get_action_area().pack_end(
 
361
            self._button_commit, True, True, 0)
346
362
        self._button_commit.grab_default()
347
363
 
348
364
    def _add_to_right_table(self, widget, weight, expanding=False):
354
370
        """
355
371
        end_row = self._right_pane_table_row + weight
356
372
        options = 0
357
 
        expand_opts = gtk.EXPAND | gtk.FILL | gtk.SHRINK
 
373
        expand_opts = Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL | Gtk.AttachOptions.SHRINK
358
374
        if expanding:
359
375
            options = expand_opts
360
376
        self._right_pane_table.attach(widget, 0, 1,
363
379
        self._right_pane_table_row = end_row
364
380
 
365
381
    def _construct_file_list(self):
366
 
        self._files_box = gtk.VBox(homogeneous=False, spacing=0)
367
 
        file_label = gtk.Label(_i18n('Files'))
 
382
        self._files_box = Gtk.VBox(homogeneous=False, spacing=0)
 
383
        file_label = Gtk.Label(label=_i18n('Files'))
368
384
        # file_label.show()
369
 
        self._files_box.pack_start(file_label, expand=False)
 
385
        self._files_box.pack_start(file_label, False, True, 0)
370
386
 
371
 
        self._commit_all_files_radio = gtk.RadioButton(
 
387
        self._commit_all_files_radio = Gtk.RadioButton.new_with_label(
372
388
            None, _i18n("Commit all changes"))
373
 
        self._files_box.pack_start(self._commit_all_files_radio, expand=False)
 
389
        self._files_box.pack_start(self._commit_all_files_radio, False, True, 0)
374
390
        self._commit_all_files_radio.show()
375
391
        self._commit_all_files_radio.connect('toggled',
376
392
            self._toggle_commit_selection)
377
 
        self._commit_selected_radio = gtk.RadioButton(
 
393
        self._commit_selected_radio = Gtk.RadioButton.new_with_label_from_widget(
378
394
            self._commit_all_files_radio, _i18n("Only commit selected changes"))
379
 
        self._files_box.pack_start(self._commit_selected_radio, expand=False)
 
395
        self._files_box.pack_start(self._commit_selected_radio, False, True, 0)
380
396
        self._commit_selected_radio.show()
381
397
        self._commit_selected_radio.connect('toggled',
382
398
            self._toggle_commit_selection)
385
401
            self._commit_all_files_radio.set_sensitive(False)
386
402
            self._commit_selected_radio.set_sensitive(False)
387
403
 
388
 
        scroller = gtk.ScrolledWindow()
389
 
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
390
 
        self._treeview_files = gtk.TreeView()
 
404
        scroller = Gtk.ScrolledWindow()
 
405
        scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
 
406
        self._treeview_files = Gtk.TreeView()
391
407
        self._treeview_files.show()
392
408
        scroller.add(self._treeview_files)
393
 
        scroller.set_shadow_type(gtk.SHADOW_IN)
 
409
        scroller.set_shadow_type(Gtk.ShadowType.IN)
394
410
        scroller.show()
395
 
        self._files_box.pack_start(scroller,
396
 
                                   expand=True, fill=True)
 
411
        self._files_box.pack_start(scroller, True, True, 0)
397
412
        self._files_box.show()
398
 
        self._left_pane_box.pack_start(self._files_box)
 
413
        self._left_pane_box.pack_start(self._files_box, True, True, 0)
399
414
 
400
415
        # Keep note that all strings stored in a ListStore must be UTF-8
401
416
        # strings. GTK does not support directly setting and restoring Unicode
402
417
        # objects.
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
 
418
        liststore = Gtk.ListStore(
 
419
            GObject.TYPE_STRING,  # [0] file_id
 
420
            GObject.TYPE_STRING,  # [1] real path
 
421
            GObject.TYPE_BOOLEAN, # [2] checkbox
 
422
            GObject.TYPE_STRING,  # [3] display path
 
423
            GObject.TYPE_STRING,  # [4] changes type
 
424
            GObject.TYPE_STRING,  # [5] commit message
410
425
            )
411
426
        self._files_store = liststore
412
427
        self._treeview_files.set_model(liststore)
413
 
        crt = gtk.CellRendererToggle()
 
428
        crt = Gtk.CellRendererToggle()
414
429
        crt.set_property('activatable', not bool(self._pending))
415
430
        crt.connect("toggled", self._toggle_commit, self._files_store)
416
431
        if self._pending:
417
432
            name = _i18n('Commit*')
418
433
        else:
419
434
            name = _i18n('Commit')
420
 
        commit_col = gtk.TreeViewColumn(name, crt, active=2)
 
435
        commit_col = Gtk.TreeViewColumn(name, crt, active=2)
421
436
        commit_col.set_visible(False)
422
437
        self._treeview_files.append_column(commit_col)
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))
 
438
        self._treeview_files.append_column(Gtk.TreeViewColumn(_i18n('Path'),
 
439
                                           Gtk.CellRendererText(), text=3))
 
440
        self._treeview_files.append_column(Gtk.TreeViewColumn(_i18n('Type'),
 
441
                                           Gtk.CellRendererText(), text=4))
427
442
        self._treeview_files.connect('cursor-changed',
428
443
                                     self._on_treeview_files_cursor_changed)
429
444
 
444
459
                checked_col.set_visible(False)
445
460
            else:
446
461
                checked_col.set_visible(True)
447
 
            renderer = checked_col.get_cell_renderers()[0]
 
462
            renderer = checked_col.get_cells()[0]
448
463
            renderer.set_property('activatable', not all_files)
449
464
 
450
465
    def _construct_pending_list(self):
451
466
        # Pending information defaults to hidden, we put it all in 1 box, so
452
467
        # that we can show/hide all of them at once
453
 
        self._pending_box = gtk.VBox()
 
468
        self._pending_box = Gtk.VBox()
454
469
        self._pending_box.hide()
455
470
 
456
 
        pending_message = gtk.Label()
 
471
        pending_message = Gtk.Label()
457
472
        pending_message.set_markup(
458
473
            _i18n('<i>* Cannot select specific files when merging</i>'))
459
 
        self._pending_box.pack_start(pending_message, expand=False, padding=5)
 
474
        self._pending_box.pack_start(pending_message, False, True, 5)
460
475
        pending_message.show()
461
476
 
462
 
        pending_label = gtk.Label(_i18n('Pending Revisions'))
463
 
        self._pending_box.pack_start(pending_label, expand=False, padding=0)
 
477
        pending_label = Gtk.Label(label=_i18n('Pending Revisions'))
 
478
        self._pending_box.pack_start(pending_label, False, True, 0)
464
479
        pending_label.show()
465
480
 
466
 
        scroller = gtk.ScrolledWindow()
467
 
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
468
 
        self._treeview_pending = gtk.TreeView()
 
481
        scroller = Gtk.ScrolledWindow()
 
482
        scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
 
483
        self._treeview_pending = Gtk.TreeView()
469
484
        scroller.add(self._treeview_pending)
470
 
        scroller.set_shadow_type(gtk.SHADOW_IN)
 
485
        scroller.set_shadow_type(Gtk.ShadowType.IN)
471
486
        scroller.show()
472
 
        self._pending_box.pack_start(scroller,
473
 
                                     expand=True, fill=True, padding=5)
 
487
        self._pending_box.pack_start(scroller, True, True, 5)
474
488
        self._treeview_pending.show()
475
 
        self._left_pane_box.pack_start(self._pending_box)
 
489
        self._left_pane_box.pack_start(self._pending_box, True, True, 0)
476
490
 
477
 
        liststore = gtk.ListStore(gobject.TYPE_STRING, # revision_id
478
 
                                  gobject.TYPE_STRING, # date
479
 
                                  gobject.TYPE_STRING, # committer
480
 
                                  gobject.TYPE_STRING, # summary
 
491
        liststore = Gtk.ListStore(GObject.TYPE_STRING, # revision_id
 
492
                                  GObject.TYPE_STRING, # date
 
493
                                  GObject.TYPE_STRING, # committer
 
494
                                  GObject.TYPE_STRING, # summary
481
495
                                 )
482
496
        self._pending_store = liststore
483
497
        self._treeview_pending.set_model(liststore)
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))
 
498
        self._treeview_pending.append_column(Gtk.TreeViewColumn(_i18n('Date'),
 
499
                                             Gtk.CellRendererText(), text=1))
 
500
        self._treeview_pending.append_column(Gtk.TreeViewColumn(_i18n('Committer'),
 
501
                                             Gtk.CellRendererText(), text=2))
 
502
        self._treeview_pending.append_column(Gtk.TreeViewColumn(_i18n('Summary'),
 
503
                                             Gtk.CellRendererText(), text=3))
490
504
 
491
505
    def _construct_diff_view(self):
492
 
        from diff import DiffView
 
506
        from bzrlib.plugins.gtk.diff import DiffView
493
507
 
494
508
        # TODO: jam 2007-10-30 The diff label is currently disabled. If we
495
509
        #       decide that we really don't ever want to display it, we should
496
510
        #       actually remove it, and other references to it, along with the
497
511
        #       tests that it is set properly.
498
 
        self._diff_label = gtk.Label(_i18n('Diff for whole tree'))
 
512
        self._diff_label = Gtk.Label(label=_i18n('Diff for whole tree'))
499
513
        self._diff_label.set_alignment(0, 0)
500
514
        self._right_pane_table.set_row_spacing(self._right_pane_table_row, 0)
501
515
        self._add_to_right_table(self._diff_label, 1, False)
506
520
        self._diff_view.show()
507
521
 
508
522
    def _construct_file_message(self):
509
 
        scroller = gtk.ScrolledWindow()
510
 
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 
523
        scroller = Gtk.ScrolledWindow()
 
524
        scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
511
525
 
512
 
        self._file_message_text_view = gtk.TextView()
 
526
        self._file_message_text_view = Gtk.TextView()
513
527
        scroller.add(self._file_message_text_view)
514
 
        scroller.set_shadow_type(gtk.SHADOW_IN)
 
528
        scroller.set_shadow_type(Gtk.ShadowType.IN)
515
529
        scroller.show()
516
530
 
517
 
        self._file_message_text_view.modify_font(pango.FontDescription("Monospace"))
518
 
        self._file_message_text_view.set_wrap_mode(gtk.WRAP_WORD)
 
531
        self._file_message_text_view.modify_font(Pango.FontDescription("Monospace"))
 
532
        self._file_message_text_view.set_wrap_mode(Gtk.WrapMode.WORD)
519
533
        self._file_message_text_view.set_accepts_tab(False)
520
534
        self._file_message_text_view.show()
521
535
 
522
 
        self._file_message_expander = gtk.Expander(_i18n('File commit message'))
 
536
        self._file_message_expander = Gtk.Expander(
 
537
            label=_i18n('File commit message'))
523
538
        self._file_message_expander.set_expanded(True)
524
539
        self._file_message_expander.add(scroller)
525
540
        self._add_to_right_table(self._file_message_expander, 1, False)
526
541
        self._file_message_expander.show()
527
542
 
528
543
    def _construct_global_message(self):
529
 
        self._global_message_label = gtk.Label(_i18n('Global Commit Message'))
 
544
        self._global_message_label = Gtk.Label(label=_i18n('Global Commit Message'))
530
545
        self._global_message_label.set_markup(
531
546
            _i18n('<b>Global Commit Message</b>'))
532
547
        self._global_message_label.set_alignment(0, 0)
535
550
        # Can we remove the spacing between the label and the box?
536
551
        self._global_message_label.show()
537
552
 
538
 
        scroller = gtk.ScrolledWindow()
539
 
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 
553
        scroller = Gtk.ScrolledWindow()
 
554
        scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
540
555
 
541
 
        self._global_message_text_view = gtk.TextView()
542
 
        self._global_message_text_view.modify_font(pango.FontDescription("Monospace"))
 
556
        self._global_message_text_view = Gtk.TextView()
 
557
        self._set_global_commit_message(self._saved_commit_messages_manager.get()[0])
 
558
        self._global_message_text_view.modify_font(Pango.FontDescription("Monospace"))
543
559
        scroller.add(self._global_message_text_view)
544
 
        scroller.set_shadow_type(gtk.SHADOW_IN)
 
560
        scroller.set_shadow_type(Gtk.ShadowType.IN)
545
561
        scroller.show()
546
562
        self._add_to_right_table(scroller, 2, True)
547
 
        self._file_message_text_view.set_wrap_mode(gtk.WRAP_WORD)
 
563
        self._file_message_text_view.set_wrap_mode(Gtk.WrapMode.WORD)
548
564
        self._file_message_text_view.set_accepts_tab(False)
549
565
        self._global_message_text_view.show()
550
566
 
575
591
            # We have either made it to the end of the list, or nothing was
576
592
            # selected. Either way, select All Files, and jump to the global
577
593
            # commit message.
578
 
            self._treeview_files.set_cursor((0,))
 
594
            self._treeview_files.set_cursor(
 
595
                Gtk.TreePath(path=0), None, False)
579
596
            self._global_message_text_view.grab_focus()
580
597
        else:
581
598
            # Set the cursor to this entry, and jump to the per-file commit
582
599
            # message
583
 
            self._treeview_files.set_cursor(model.get_path(next))
 
600
            self._treeview_files.set_cursor(model.get_path(next), None, False)
584
601
            self._file_message_text_view.grab_focus()
585
602
 
586
603
    def _save_current_file_message(self):
588
605
            return # Nothing to save
589
606
        text_buffer = self._file_message_text_view.get_buffer()
590
607
        cur_text = text_buffer.get_text(text_buffer.get_start_iter(),
591
 
                                        text_buffer.get_end_iter())
 
608
                                        text_buffer.get_end_iter(), True)
592
609
        last_selected = self._files_store.get_iter(self._last_selected_file)
593
610
        self._files_store.set_value(last_selected, 5, cur_text)
594
611
 
630
647
            if self._commit_all_changes or record[2]:# [2] checkbox
631
648
                file_id = record[0] # [0] file_id
632
649
                path = record[1]    # [1] real path
633
 
                file_message = record[5] # [5] commit message
 
650
                # [5] commit message
 
651
                file_message = _sanitize_and_decode_message(record[5])
634
652
                files.append(path.decode('UTF-8'))
635
653
                if self._enable_per_file_commits and file_message:
636
654
                    # All of this needs to be utf-8 information
 
655
                    file_message = file_message.encode('UTF-8')
637
656
                    file_info.append({'path':path, 'file_id':file_id,
638
657
                                     'message':file_message})
639
658
        file_info.sort(key=lambda x:(x['path'], x['file_id']))
643
662
            return files, []
644
663
 
645
664
    @show_bzr_error
 
665
    def _on_cancel_clicked(self, button):
 
666
        """ Cancel button clicked handler. """
 
667
        self._do_cancel()
 
668
 
 
669
    @show_bzr_error
 
670
    def _on_delete_window(self, source, event):
 
671
        """ Delete window handler. """
 
672
        self._do_cancel()
 
673
 
 
674
    def _do_cancel(self):
 
675
        """If requested, saves commit messages when cancelling gcommit; they are re-used by a next gcommit"""
 
676
        mgr = SavedCommitMessagesManager()
 
677
        self._saved_commit_messages_manager = mgr
 
678
        mgr.insert(self._get_global_commit_message(),
 
679
                   self._get_specific_files()[1])
 
680
        if mgr.is_not_empty(): # maybe worth saving
 
681
            response = self._question_dialog(
 
682
                _i18n('Commit cancelled'),
 
683
                _i18n('Do you want to save your commit messages ?'),
 
684
                parent=self)
 
685
            if response == Gtk.ResponseType.NO:
 
686
                 # save nothing and destroy old comments if any
 
687
                mgr = SavedCommitMessagesManager()
 
688
        mgr.save(self._wt, self._wt.branch)
 
689
        self.response(Gtk.ResponseType.CANCEL) # close window
 
690
 
 
691
    @show_bzr_error
646
692
    def _on_commit_clicked(self, button):
647
693
        """ Commit button clicked handler. """
648
694
        self._do_commit()
653
699
        if message == '':
654
700
            response = self._question_dialog(
655
701
                _i18n('Commit with an empty message?'),
656
 
                _i18n('You can describe your commit intent in the message.'))
657
 
            if response == gtk.RESPONSE_NO:
 
702
                _i18n('You can describe your commit intent in the message.'),
 
703
                parent=self)
 
704
            if response == Gtk.ResponseType.NO:
658
705
                # Kindly give focus to message area
659
706
                self._global_message_text_view.grab_focus()
660
707
                return
673
720
        for path in self._wt.unknowns():
674
721
            response = self._question_dialog(
675
722
                _i18n("Commit with unknowns?"),
676
 
                _i18n("Unknown files exist in the working tree. Commit anyway?"))
677
 
            if response == gtk.RESPONSE_NO:
 
723
                _i18n("Unknown files exist in the working tree. Commit anyway?"),
 
724
                parent=self)
 
725
                # Doesn't set a parent for the dialog..
 
726
            if response == Gtk.ResponseType.NO:
678
727
                return
679
728
            break
680
729
 
693
742
            response = self._question_dialog(
694
743
                _i18n('Commit with no changes?'),
695
744
                _i18n('There are no changes in the working tree.'
696
 
                      ' Do you want to commit anyway?'))
697
 
            if response == gtk.RESPONSE_YES:
 
745
                      ' Do you want to commit anyway?'),
 
746
                parent=self)
 
747
            if response == Gtk.ResponseType.YES:
698
748
                rev_id = self._wt.commit(message,
699
749
                               allow_pointless=True,
700
750
                               strict=False,
702
752
                               specific_files=specific_files,
703
753
                               revprops=revprops)
704
754
        self.committed_revision_id = rev_id
705
 
        self.response(gtk.RESPONSE_OK)
 
755
        # destroy old comments if any
 
756
        SavedCommitMessagesManager().save(self._wt, self._wt.branch)
 
757
        self.response(Gtk.ResponseType.OK)
706
758
 
707
759
    def _get_global_commit_message(self):
708
760
        buf = self._global_message_text_view.get_buffer()
709
761
        start, end = buf.get_bounds()
710
 
        return buf.get_text(start, end).decode('utf-8')
 
762
        text = buf.get_text(start, end, True)
 
763
        return _sanitize_and_decode_message(text)
711
764
 
712
765
    def _set_global_commit_message(self, message):
713
766
        """Just a helper for the test suite."""
734
787
                                       show_offset=False)
735
788
        rev_dict['revision_id'] = rev.revision_id
736
789
        return rev_dict
 
790