/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
0.8.19 by Szilveszter Farkas (Phanatic)
2006-07-21 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
1
# Copyright (C) 2006 by Szilveszter Farkas (Phanatic) <szilveszter.farkas@gmail.com>
0.8.46 by Szilveszter Farkas (Phanatic)
Modified OliveDialog class interface; huge cleanups.
2
#
0.8.19 by Szilveszter Farkas (Phanatic)
2006-07-21 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
0.8.46 by Szilveszter Farkas (Phanatic)
Modified OliveDialog class interface; huge cleanups.
7
#
0.8.19 by Szilveszter Farkas (Phanatic)
2006-07-21 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
0.8.46 by Szilveszter Farkas (Phanatic)
Modified OliveDialog class interface; huge cleanups.
12
#
0.8.19 by Szilveszter Farkas (Phanatic)
2006-07-21 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
576.1.1 by Jasper Groenewegen
Add parent setting to dialogs and implement in gcommit
17
import re
18
734.1.4 by Curtis Hovey
Updated commit to gtk3.
19
from gi.repository import Gdk
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
20
from gi.repository import Gtk
21
from gi.repository import GObject
22
from gi.repository import Pango
0.8.19 by Szilveszter Farkas (Phanatic)
2006-07-21 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
23
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
24
from bzrlib import (
768 by Jelmer Vernooij
Drop support for old bencode location.
25
    bencode,
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
26
    errors,
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
27
    osutils,
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
28
    trace,
29
    )
576.1.1 by Jasper Groenewegen
Add parent setting to dialogs and implement in gcommit
30
from bzrlib.plugins.gtk.dialog import question_dialog
31
from bzrlib.plugins.gtk.errors import show_bzr_error
729.1.1 by Jelmer Vernooij
Move i18n support to a separate file, so gettext files aren't loaded unless bzr-gtk is used.
32
from bzrlib.plugins.gtk.i18n import _i18n
742 by Jelmer Vernooij
Move commit message saving to separate file.
33
from bzrlib.plugins.gtk.commitmsgs import SavedCommitMessagesManager
93.1.6 by Alexander Belchenko
detecting name of glade file doing in separate module (olive.gladefile)
34
158 by Jelmer Vernooij
If available, use NetworkManager to find out whether a commit should be local or not.
35
try:
36
    import dbus
37
    import dbus.glib
180 by Jelmer Vernooij
Don't obtain handle to network manager until it's actually needed.
38
    have_dbus = True
158 by Jelmer Vernooij
If available, use NetworkManager to find out whether a commit should be local or not.
39
except ImportError:
180 by Jelmer Vernooij
Don't obtain handle to network manager until it's actually needed.
40
    have_dbus = False
158 by Jelmer Vernooij
If available, use NetworkManager to find out whether a commit should be local or not.
41
278.1.4 by John Arbash Meinel
Just playing around.
42
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
43
def pending_revisions(wt):
44
    """Return a list of pending merges or None if there are none of them.
45
46
    Arguably this should be a core function, and
47
    ``bzrlib.status.show_pending_merges`` should be built on top of it.
48
49
    :return: [(rev, [children])]
50
    """
51
    parents = wt.get_parent_ids()
52
    if len(parents) < 2:
53
        return None
54
55
    # The basic pending merge algorithm uses the same algorithm as
56
    # bzrlib.status.show_pending_merges
57
    pending = parents[1:]
58
    branch = wt.branch
59
    last_revision = parents[0]
60
61
    if last_revision is not None:
762 by Jelmer Vernooij
Avoid call to Repository.get_ancestry.
62
        graph = branch.repository.get_graph()
63
        ignore = set([r for r,ps in graph.iter_ancestry([last_revision])])
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
64
    else:
762 by Jelmer Vernooij
Avoid call to Repository.get_ancestry.
65
        ignore = set([])
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
66
67
    pm = []
68
    for merge in pending:
69
        ignore.add(merge)
70
        try:
71
            rev = branch.repository.get_revision(merge)
72
            children = []
73
            pm.append((rev, children))
74
75
            # This does need to be topo sorted, so we search backwards
76
            inner_merges = branch.repository.get_ancestry(merge)
77
            assert inner_merges[0] is None
78
            inner_merges.pop(0)
79
            for mmerge in reversed(inner_merges):
80
                if mmerge in ignore:
81
                    continue
82
                rev = branch.repository.get_revision(mmerge)
83
                children.append(rev)
84
85
                ignore.add(mmerge)
86
        except errors.NoSuchRevision:
87
            print "DEBUG: NoSuchRevision:", merge
88
89
    return pm
90
91
622.1.1 by John Arbash Meinel
Ensure that per-file commit messages and global commit messages get sanitized.
92
_newline_variants_re = re.compile(r'\r\n?')
93
def _sanitize_and_decode_message(utf8_message):
94
    """Turn a utf-8 message into a sanitized Unicode message."""
95
    fixed_newline = _newline_variants_re.sub('\n', utf8_message)
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
96
    return osutils.safe_unicode(fixed_newline)
622.1.1 by John Arbash Meinel
Ensure that per-file commit messages and global commit messages get sanitized.
97
98
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
99
class CommitDialog(Gtk.Dialog):
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
100
    """Implementation of Commit."""
101
102
    def __init__(self, wt, selected=None, parent=None):
734.1.51 by Curtis Hovey
Fix the initializer for many classes.
103
        super(CommitDialog, self).__init__(
104
            title="Commit to %s" % wt.basedir, parent=parent, flags=0)
635.2.7 by Vincent Ladeuil
Land Anne Mohsen's patch for bug 215674.
105
        self.connect('delete-event', self._on_delete_window)
606 by Vincent Ladeuil
Fix gtk dialogs popping up and asking for input during selftest.
106
        self._question_dialog = question_dialog
635.2.7 by Vincent Ladeuil
Land Anne Mohsen's patch for bug 215674.
107
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
108
        self.set_type_hint(Gdk.WindowTypeHint.NORMAL)
278.1.24 by John Arbash Meinel
Actually show the commit button.
109
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
110
        self._wt = wt
278.1.34 by John Arbash Meinel
Cleanup, we are still ignoring the 'selected' property, and the 'wtpath'
111
        # TODO: Do something with this value, it is used by Olive
112
        #       It used to set all changes but this one to False
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
113
        self._selected = selected
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
114
        self._enable_per_file_commits = True
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
115
        self._commit_all_changes = True
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
116
        self.committed_revision_id = None # Nothing has been committed yet
769.1.1 by Curtis Hovey
Define _last_selected_file in init so that async signal callbacks can use it.
117
        self._last_selected_file = None
734.1.4 by Curtis Hovey
Updated commit to gtk3.
118
        self._saved_commit_messages_manager = SavedCommitMessagesManager(
119
            self._wt, self._wt.branch)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
120
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
121
        self.setup_params()
122
        self.construct()
123
        self.fill_in_data()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
124
125
    def setup_params(self):
126
        """Setup the member variables for state."""
127
        self._basis_tree = self._wt.basis_tree()
278.1.12 by John Arbash Meinel
Delay computing the delta, and clean up some of the diff view names.
128
        self._delta = None
762 by Jelmer Vernooij
Avoid call to Repository.get_ancestry.
129
        self._wt.lock_read()
130
        try:
131
            self._pending = pending_revisions(self._wt)
132
        finally:
133
            self._wt.unlock()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
134
135
        self._is_checkout = (self._wt.branch.get_bound_location() is not None)
136
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
137
    def fill_in_data(self):
138
        # Now that we are built, handle changes to the view based on the state
139
        self._fill_in_pending()
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
140
        self._fill_in_diff()
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
141
        self._fill_in_files()
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
142
        self._fill_in_checkout()
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
143
        self._fill_in_per_file_info()
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
144
145
    def _fill_in_pending(self):
146
        if not self._pending:
147
            self._pending_box.hide()
148
            return
149
150
        # TODO: We'd really prefer this to be a nested list
151
        for rev, children in self._pending:
152
            rev_info = self._rev_to_pending_info(rev)
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
153
            self._pending_store.append([
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
154
                rev_info['revision_id'],
155
                rev_info['date'],
156
                rev_info['committer'],
157
                rev_info['summary'],
158
                ])
159
            for child in children:
160
                rev_info = self._rev_to_pending_info(child)
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
161
                self._pending_store.append([
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
162
                    rev_info['revision_id'],
163
                    rev_info['date'],
164
                    rev_info['committer'],
165
                    rev_info['summary'],
166
                    ])
167
        self._pending_box.show()
168
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
169
    def _fill_in_files(self):
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
170
        # We should really use add a progress bar of some kind.
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
171
        # While we fill in the view, hide the store
172
        store = self._files_store
173
        self._treeview_files.set_model(None)
174
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
175
        added = _i18n('added')
176
        removed = _i18n('removed')
177
        renamed = _i18n('renamed')
178
        renamed_and_modified = _i18n('renamed and modified')
179
        modified = _i18n('modified')
180
        kind_changed = _i18n('kind changed')
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
181
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
182
        # The store holds:
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
183
        # [file_id, real path, checkbox, display path, changes type, message]
450 by Aaron Bentley
Update to use new Tree.iter_changes
184
        # iter_changes returns:
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
185
        # (file_id, (path_in_source, path_in_target),
186
        #  changed_content, versioned, parent, name, kind,
187
        #  executable)
188
278.1.35 by John Arbash Meinel
Make use of the 'selected' parameter to CommitDialog.
189
        all_enabled = (self._selected is None)
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
190
        # The first entry is always the 'whole tree'
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
191
        all_iter = store.append(["", "", all_enabled, 'All Files', '', ''])
278.1.35 by John Arbash Meinel
Make use of the 'selected' parameter to CommitDialog.
192
        initial_cursor = store.get_path(all_iter)
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
193
        # should we pass specific_files?
194
        self._wt.lock_read()
195
        self._basis_tree.lock_read()
196
        try:
450 by Aaron Bentley
Update to use new Tree.iter_changes
197
            from diff import iter_changes_to_status
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
198
            saved_file_messages = self._saved_commit_messages_manager.get()[1]
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
199
            for (file_id, real_path, change_type, display_path
450 by Aaron Bentley
Update to use new Tree.iter_changes
200
                ) in iter_changes_to_status(self._basis_tree, self._wt):
278.1.35 by John Arbash Meinel
Make use of the 'selected' parameter to CommitDialog.
201
                if self._selected and real_path != self._selected:
202
                    enabled = False
203
                else:
204
                    enabled = True
635.2.7 by Vincent Ladeuil
Land Anne Mohsen's patch for bug 215674.
205
                try:
206
                    default_message = saved_file_messages[file_id]
207
                except KeyError:
208
                    default_message = ''
278.1.35 by John Arbash Meinel
Make use of the 'selected' parameter to CommitDialog.
209
                item_iter = store.append([
210
                    file_id,
211
                    real_path.encode('UTF-8'),
212
                    enabled,
213
                    display_path.encode('UTF-8'),
214
                    change_type,
635.2.7 by Vincent Ladeuil
Land Anne Mohsen's patch for bug 215674.
215
                    default_message, # Initial comment
278.1.35 by John Arbash Meinel
Make use of the 'selected' parameter to CommitDialog.
216
                    ])
217
                if self._selected and enabled:
218
                    initial_cursor = store.get_path(item_iter)
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
219
        finally:
220
            self._basis_tree.unlock()
221
            self._wt.unlock()
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
222
223
        self._treeview_files.set_model(store)
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
224
        self._last_selected_file = None
278.1.32 by John Arbash Meinel
Add the Ctrl+n accelerator to jump through the commit messages.
225
        # This sets the cursor, which causes the expander to close, which
226
        # causes the _file_message_text_view to never get realized. So we have
227
        # to give it a little kick, or it warns when we try to grab the focus
734.1.22 by Curtis Hovey
GtkTreeView.set_cursor(tree_path, None, False) is the default args.
228
        self._treeview_files.set_cursor(initial_cursor, None, False)
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
229
278.1.32 by John Arbash Meinel
Add the Ctrl+n accelerator to jump through the commit messages.
230
        def _realize_file_message_tree_view(*args):
231
            self._file_message_text_view.realize()
232
        self.connect_after('realize', _realize_file_message_tree_view)
233
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
234
    def _fill_in_diff(self):
235
        self._diff_view.set_trees(self._wt, self._basis_tree)
236
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
237
    def _fill_in_checkout(self):
238
        if not self._is_checkout:
239
            self._check_local.hide()
240
            return
241
        if have_dbus:
242
            bus = dbus.SystemBus()
445 by Szilveszter Farkas (Phanatic)
Fix a traceback if NetworkManager is not available (#199513).
243
            try:
244
                proxy_obj = bus.get_object('org.freedesktop.NetworkManager',
245
                                           '/org/freedesktop/NetworkManager')
446 by Szilveszter Farkas (Phanatic)
Hot fix. Sorry dudes.
246
            except dbus.DBusException:
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
247
                trace.mutter("networkmanager not available.")
445 by Szilveszter Farkas (Phanatic)
Fix a traceback if NetworkManager is not available (#199513).
248
                self._check_local.show()
249
                return
250
            
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
251
            dbus_iface = dbus.Interface(proxy_obj,
252
                                        'org.freedesktop.NetworkManager')
253
            try:
254
                # 3 is the enum value for STATE_CONNECTED
255
                self._check_local.set_active(dbus_iface.state() != 3)
256
            except dbus.DBusException, e:
257
                # Silently drop errors. While DBus may be
258
                # available, NetworkManager doesn't necessarily have to be
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
259
                trace.mutter("unable to get networkmanager state: %r" % e)
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
260
        self._check_local.show()
261
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
262
    def _fill_in_per_file_info(self):
263
        config = self._wt.branch.get_config()
264
        enable_per_file_commits = config.get_user_option('per_file_commits')
265
        if (enable_per_file_commits is None
266
            or enable_per_file_commits.lower()
267
                not in ('y', 'yes', 'on', 'enable', '1', 't', 'true')):
268
            self._enable_per_file_commits = False
269
        else:
270
            self._enable_per_file_commits = True
271
        if not self._enable_per_file_commits:
272
            self._file_message_expander.hide()
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
273
            self._global_message_label.set_markup(_i18n('<b>Commit Message</b>'))
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
274
278.1.12 by John Arbash Meinel
Delay computing the delta, and clean up some of the diff view names.
275
    def _compute_delta(self):
276
        self._delta = self._wt.changes_from(self._basis_tree)
277
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
278
    def construct(self):
279
        """Build up the dialog widgets."""
280
        # The primary pane which splits it into left and right (adjustable)
281
        # sections.
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
282
        self._hpane = Gtk.HPaned()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
283
284
        self._construct_left_pane()
285
        self._construct_right_pane()
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
286
        self._construct_action_pane()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
287
734.1.4 by Curtis Hovey
Updated commit to gtk3.
288
        self.get_content_area().pack_start(self._hpane, True, True, 0)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
289
        self._hpane.show()
290
        self.set_focus(self._global_message_text_view)
291
278.1.32 by John Arbash Meinel
Add the Ctrl+n accelerator to jump through the commit messages.
292
        self._construct_accelerators()
293
        self._set_sizes()
294
295
    def _set_sizes(self):
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
296
        # This seems like a reasonable default, we might like it to
297
        # be a bit wider, so that by default we can fit an 80-line diff in the
298
        # diff window.
299
        # Alternatively, we should be saving the last position/size rather than
300
        # setting it to a fixed value every time we start up.
301
        screen = self.get_screen()
302
        monitor = 0 # We would like it to be the monitor we are going to
303
                    # display on, but I don't know how to figure that out
304
                    # Only really useful for freaks like me that run dual
305
                    # monitor, with different sizes on the monitors
306
        monitor_rect = screen.get_monitor_geometry(monitor)
307
        width = int(monitor_rect.width * 0.66)
308
        height = int(monitor_rect.height * 0.66)
309
        self.set_default_size(width, height)
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
310
        self._hpane.set_position(300)
311
278.1.32 by John Arbash Meinel
Add the Ctrl+n accelerator to jump through the commit messages.
312
    def _construct_accelerators(self):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
313
        group = Gtk.AccelGroup()
734.1.4 by Curtis Hovey
Updated commit to gtk3.
314
        group.connect(Gdk.keyval_from_name('N'),
315
                      Gdk.ModifierType.CONTROL_MASK, 0, self._on_accel_next)
278.1.32 by John Arbash Meinel
Add the Ctrl+n accelerator to jump through the commit messages.
316
        self.add_accel_group(group)
317
500.2.1 by Scott Scriven
Made 'gcommit' ignore the escape key ('close' signal).
318
        # ignore the escape key (avoid closing the window)
500.2.2 by Scott Scriven
Simpler/cleaner way to ignore the 'close' signal.
319
        self.connect_object('close', self.emit_stop_by_name, 'close')
500.2.1 by Scott Scriven
Made 'gcommit' ignore the escape key ('close' signal).
320
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
321
    def _construct_left_pane(self):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
322
        self._left_pane_box = Gtk.VBox(homogeneous=False, spacing=5)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
323
        self._construct_file_list()
324
        self._construct_pending_list()
325
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
326
        self._check_local = Gtk.CheckButton(_i18n("_Only commit locally"),
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
327
                                            use_underline=True)
734.1.4 by Curtis Hovey
Updated commit to gtk3.
328
        self._left_pane_box.pack_end(self._check_local, False, False, 0)
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
329
        self._check_local.set_active(False)
330
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
331
        self._hpane.pack1(self._left_pane_box, resize=False, shrink=False)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
332
        self._left_pane_box.show()
333
334
    def _construct_right_pane(self):
335
        # TODO: I really want to make it so the diff view gets more space than
336
        # the global commit message, and the per-file commit message gets even
337
        # less. When I did it with wxGlade, I set it to 4 for diff, 2 for
338
        # commit, and 1 for file commit, and it looked good. But I don't seem
339
        # to have a way to do that with the gtk boxes... :( (Which is extra
340
        # weird since wx uses gtk on Linux...)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
341
        self._right_pane_table = Gtk.Table(rows=10, columns=1, homogeneous=False)
278.1.11 by John Arbash Meinel
Worked out the rest of the spacing.
342
        self._right_pane_table.set_row_spacings(5)
343
        self._right_pane_table.set_col_spacings(5)
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
344
        self._right_pane_table_row = 0
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
345
        self._construct_diff_view()
346
        self._construct_file_message()
347
        self._construct_global_message()
348
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
349
        self._right_pane_table.show()
350
        self._hpane.pack2(self._right_pane_table, resize=True, shrink=True)
351
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
352
    def _construct_action_pane(self):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
353
        self._button_cancel = Gtk.Button(stock=Gtk.STOCK_CANCEL)
635.2.7 by Vincent Ladeuil
Land Anne Mohsen's patch for bug 215674.
354
        self._button_cancel.connect('clicked', self._on_cancel_clicked)
355
        self._button_cancel.show()
734.1.4 by Curtis Hovey
Updated commit to gtk3.
356
        self.get_action_area().pack_end(
357
            self._button_cancel, True, True, 0)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
358
        self._button_commit = Gtk.Button(_i18n("Comm_it"), use_underline=True)
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
359
        self._button_commit.connect('clicked', self._on_commit_clicked)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
360
        self._button_commit.set_can_default(True)
278.1.24 by John Arbash Meinel
Actually show the commit button.
361
        self._button_commit.show()
734.1.4 by Curtis Hovey
Updated commit to gtk3.
362
        self.get_action_area().pack_end(
363
            self._button_commit, True, True, 0)
278.1.24 by John Arbash Meinel
Actually show the commit button.
364
        self._button_commit.grab_default()
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
365
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
366
    def _add_to_right_table(self, widget, weight, expanding=False):
367
        """Add another widget to the table
368
369
        :param widget: The object to add
370
        :param weight: How many rows does this widget get to request
371
        :param expanding: Should expand|fill|shrink be set?
372
        """
373
        end_row = self._right_pane_table_row + weight
374
        options = 0
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
375
        expand_opts = Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL | Gtk.AttachOptions.SHRINK
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
376
        if expanding:
377
            options = expand_opts
378
        self._right_pane_table.attach(widget, 0, 1,
379
                                      self._right_pane_table_row, end_row,
380
                                      xoptions=expand_opts, yoptions=options)
381
        self._right_pane_table_row = end_row
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
382
383
    def _construct_file_list(self):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
384
        self._files_box = Gtk.VBox(homogeneous=False, spacing=0)
385
        file_label = Gtk.Label(label=_i18n('Files'))
278.1.41 by John Arbash Meinel
For the moment, just hide the section headings Files and Diff for *.
386
        # file_label.show()
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
387
        self._files_box.pack_start(file_label, False, True, 0)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
388
734.1.19 by Curtis Hovey
Updated RadioButtons to gtk3.
389
        self._commit_all_files_radio = Gtk.RadioButton.new_with_label(
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
390
            None, _i18n("Commit all changes"))
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
391
        self._files_box.pack_start(self._commit_all_files_radio, False, True, 0)
278.1.42 by John Arbash Meinel
start playing with using a radial box, rather than an entry in the list
392
        self._commit_all_files_radio.show()
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
393
        self._commit_all_files_radio.connect('toggled',
394
            self._toggle_commit_selection)
734.1.19 by Curtis Hovey
Updated RadioButtons to gtk3.
395
        self._commit_selected_radio = Gtk.RadioButton.new_with_label_from_widget(
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
396
            self._commit_all_files_radio, _i18n("Only commit selected changes"))
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
397
        self._files_box.pack_start(self._commit_selected_radio, False, True, 0)
278.1.42 by John Arbash Meinel
start playing with using a radial box, rather than an entry in the list
398
        self._commit_selected_radio.show()
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
399
        self._commit_selected_radio.connect('toggled',
400
            self._toggle_commit_selection)
401
        if self._pending:
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
402
            self._commit_all_files_radio.set_label(_i18n('Commit all changes*'))
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
403
            self._commit_all_files_radio.set_sensitive(False)
404
            self._commit_selected_radio.set_sensitive(False)
278.1.42 by John Arbash Meinel
start playing with using a radial box, rather than an entry in the list
405
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
406
        scroller = Gtk.ScrolledWindow()
407
        scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
408
        self._treeview_files = Gtk.TreeView()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
409
        self._treeview_files.show()
410
        scroller.add(self._treeview_files)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
411
        scroller.set_shadow_type(Gtk.ShadowType.IN)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
412
        scroller.show()
734.1.4 by Curtis Hovey
Updated commit to gtk3.
413
        self._files_box.pack_start(scroller, True, True, 0)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
414
        self._files_box.show()
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
415
        self._left_pane_box.pack_start(self._files_box, True, True, 0)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
416
278.1.31 by John Arbash Meinel
We can make bencode work again by a simple decode/encode step.
417
        # Keep note that all strings stored in a ListStore must be UTF-8
418
        # strings. GTK does not support directly setting and restoring Unicode
419
        # objects.
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
420
        liststore = Gtk.ListStore(
421
            GObject.TYPE_STRING,  # [0] file_id
422
            GObject.TYPE_STRING,  # [1] real path
423
            GObject.TYPE_BOOLEAN, # [2] checkbox
424
            GObject.TYPE_STRING,  # [3] display path
425
            GObject.TYPE_STRING,  # [4] changes type
426
            GObject.TYPE_STRING,  # [5] commit message
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
427
            )
428
        self._files_store = liststore
429
        self._treeview_files.set_model(liststore)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
430
        crt = Gtk.CellRendererToggle()
278.1.39 by John Arbash Meinel
To disable a checkbox it is set_property('activatable', False),
431
        crt.set_property('activatable', not bool(self._pending))
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
432
        crt.connect("toggled", self._toggle_commit, self._files_store)
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
433
        if self._pending:
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
434
            name = _i18n('Commit*')
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
435
        else:
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
436
            name = _i18n('Commit')
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
437
        commit_col = Gtk.TreeViewColumn(name, crt, active=2)
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
438
        commit_col.set_visible(False)
439
        self._treeview_files.append_column(commit_col)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
440
        self._treeview_files.append_column(Gtk.TreeViewColumn(_i18n('Path'),
441
                                           Gtk.CellRendererText(), text=3))
442
        self._treeview_files.append_column(Gtk.TreeViewColumn(_i18n('Type'),
443
                                           Gtk.CellRendererText(), text=4))
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
444
        self._treeview_files.connect('cursor-changed',
445
                                     self._on_treeview_files_cursor_changed)
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
446
447
    def _toggle_commit(self, cell, path, model):
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
448
        if model[path][0] == "": # No file_id means 'All Files'
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
449
            new_val = not model[path][2]
450
            for node in model:
451
                node[2] = new_val
452
        else:
453
            model[path][2] = not model[path][2]
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
454
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
455
    def _toggle_commit_selection(self, button):
456
        all_files = self._commit_all_files_radio.get_active()
457
        if self._commit_all_changes != all_files:
458
            checked_col = self._treeview_files.get_column(0)
459
            self._commit_all_changes = all_files
460
            if all_files:
461
                checked_col.set_visible(False)
462
            else:
463
                checked_col.set_visible(True)
734.1.20 by Curtis Hovey
col.get_cell_renderers => col.get_cells.
464
            renderer = checked_col.get_cells()[0]
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
465
            renderer.set_property('activatable', not all_files)
466
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
467
    def _construct_pending_list(self):
468
        # Pending information defaults to hidden, we put it all in 1 box, so
469
        # that we can show/hide all of them at once
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
470
        self._pending_box = Gtk.VBox()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
471
        self._pending_box.hide()
472
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
473
        pending_message = Gtk.Label()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
474
        pending_message.set_markup(
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
475
            _i18n('<i>* Cannot select specific files when merging</i>'))
734.1.4 by Curtis Hovey
Updated commit to gtk3.
476
        self._pending_box.pack_start(pending_message, False, True, 5)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
477
        pending_message.show()
478
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
479
        pending_label = Gtk.Label(label=_i18n('Pending Revisions'))
734.1.4 by Curtis Hovey
Updated commit to gtk3.
480
        self._pending_box.pack_start(pending_label, False, True, 0)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
481
        pending_label.show()
482
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
483
        scroller = Gtk.ScrolledWindow()
484
        scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
485
        self._treeview_pending = Gtk.TreeView()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
486
        scroller.add(self._treeview_pending)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
487
        scroller.set_shadow_type(Gtk.ShadowType.IN)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
488
        scroller.show()
734.1.4 by Curtis Hovey
Updated commit to gtk3.
489
        self._pending_box.pack_start(scroller, True, True, 5)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
490
        self._treeview_pending.show()
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
491
        self._left_pane_box.pack_start(self._pending_box, True, True, 0)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
492
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
493
        liststore = Gtk.ListStore(GObject.TYPE_STRING, # revision_id
494
                                  GObject.TYPE_STRING, # date
495
                                  GObject.TYPE_STRING, # committer
496
                                  GObject.TYPE_STRING, # summary
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
497
                                 )
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
498
        self._pending_store = liststore
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
499
        self._treeview_pending.set_model(liststore)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
500
        self._treeview_pending.append_column(Gtk.TreeViewColumn(_i18n('Date'),
501
                                             Gtk.CellRendererText(), text=1))
502
        self._treeview_pending.append_column(Gtk.TreeViewColumn(_i18n('Committer'),
503
                                             Gtk.CellRendererText(), text=2))
504
        self._treeview_pending.append_column(Gtk.TreeViewColumn(_i18n('Summary'),
505
                                             Gtk.CellRendererText(), text=3))
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
506
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
507
    def _construct_diff_view(self):
729.1.1 by Jelmer Vernooij
Move i18n support to a separate file, so gettext files aren't loaded unless bzr-gtk is used.
508
        from bzrlib.plugins.gtk.diff import DiffView
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
509
278.1.41 by John Arbash Meinel
For the moment, just hide the section headings Files and Diff for *.
510
        # TODO: jam 2007-10-30 The diff label is currently disabled. If we
511
        #       decide that we really don't ever want to display it, we should
512
        #       actually remove it, and other references to it, along with the
513
        #       tests that it is set properly.
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
514
        self._diff_label = Gtk.Label(label=_i18n('Diff for whole tree'))
278.1.11 by John Arbash Meinel
Worked out the rest of the spacing.
515
        self._diff_label.set_alignment(0, 0)
516
        self._right_pane_table.set_row_spacing(self._right_pane_table_row, 0)
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
517
        self._add_to_right_table(self._diff_label, 1, False)
278.1.41 by John Arbash Meinel
For the moment, just hide the section headings Files and Diff for *.
518
        # self._diff_label.show()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
519
278.1.12 by John Arbash Meinel
Delay computing the delta, and clean up some of the diff view names.
520
        self._diff_view = DiffView()
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
521
        self._add_to_right_table(self._diff_view, 4, True)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
522
        self._diff_view.show()
523
524
    def _construct_file_message(self):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
525
        scroller = Gtk.ScrolledWindow()
526
        scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
278.1.9 by John Arbash Meinel
Move all text entry boxes into a ScrolledWindow, so that they don't change size constantly.
527
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
528
        self._file_message_text_view = Gtk.TextView()
278.1.9 by John Arbash Meinel
Move all text entry boxes into a ScrolledWindow, so that they don't change size constantly.
529
        scroller.add(self._file_message_text_view)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
530
        scroller.set_shadow_type(Gtk.ShadowType.IN)
278.1.9 by John Arbash Meinel
Move all text entry boxes into a ScrolledWindow, so that they don't change size constantly.
531
        scroller.show()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
532
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
533
        self._file_message_text_view.modify_font(Pango.FontDescription("Monospace"))
534
        self._file_message_text_view.set_wrap_mode(Gtk.WrapMode.WORD)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
535
        self._file_message_text_view.set_accepts_tab(False)
536
        self._file_message_text_view.show()
537
734.1.4 by Curtis Hovey
Updated commit to gtk3.
538
        self._file_message_expander = Gtk.Expander(
539
            label=_i18n('File commit message'))
278.1.32 by John Arbash Meinel
Add the Ctrl+n accelerator to jump through the commit messages.
540
        self._file_message_expander.set_expanded(True)
541
        self._file_message_expander.add(scroller)
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
542
        self._add_to_right_table(self._file_message_expander, 1, False)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
543
        self._file_message_expander.show()
544
545
    def _construct_global_message(self):
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
546
        self._global_message_label = Gtk.Label(label=_i18n('Global Commit Message'))
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
547
        self._global_message_label.set_markup(
548
            _i18n('<b>Global Commit Message</b>'))
278.1.11 by John Arbash Meinel
Worked out the rest of the spacing.
549
        self._global_message_label.set_alignment(0, 0)
550
        self._right_pane_table.set_row_spacing(self._right_pane_table_row, 0)
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
551
        self._add_to_right_table(self._global_message_label, 1, False)
278.1.11 by John Arbash Meinel
Worked out the rest of the spacing.
552
        # Can we remove the spacing between the label and the box?
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
553
        self._global_message_label.show()
554
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
555
        scroller = Gtk.ScrolledWindow()
556
        scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
278.1.9 by John Arbash Meinel
Move all text entry boxes into a ScrolledWindow, so that they don't change size constantly.
557
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
558
        self._global_message_text_view = Gtk.TextView()
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
559
        self._set_global_commit_message(self._saved_commit_messages_manager.get()[0])
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
560
        self._global_message_text_view.modify_font(Pango.FontDescription("Monospace"))
278.1.9 by John Arbash Meinel
Move all text entry boxes into a ScrolledWindow, so that they don't change size constantly.
561
        scroller.add(self._global_message_text_view)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
562
        scroller.set_shadow_type(Gtk.ShadowType.IN)
278.1.9 by John Arbash Meinel
Move all text entry boxes into a ScrolledWindow, so that they don't change size constantly.
563
        scroller.show()
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
564
        self._add_to_right_table(scroller, 2, True)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
565
        self._file_message_text_view.set_wrap_mode(Gtk.WrapMode.WORD)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
566
        self._file_message_text_view.set_accepts_tab(False)
567
        self._global_message_text_view.show()
568
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
569
    def _on_treeview_files_cursor_changed(self, treeview):
278.1.18 by John Arbash Meinel
Start checking the diff view is correct.
570
        treeselection = treeview.get_selection()
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
571
        (model, selection) = treeselection.get_selected()
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
572
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
573
        if selection is not None:
574
            path, display_path = model.get(selection, 1, 3)
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
575
            self._diff_label.set_text(_i18n('Diff for ') + display_path)
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
576
            if path == "":
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
577
                self._diff_view.show_diff(None)
578
            else:
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
579
                self._diff_view.show_diff([osutils.safe_unicode(path)])
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
580
            self._update_per_file_info(selection)
581
278.1.32 by John Arbash Meinel
Add the Ctrl+n accelerator to jump through the commit messages.
582
    def _on_accel_next(self, accel_group, window, keyval, modifier):
583
        # We don't really care about any of the parameters, because we know
584
        # where this message came from
585
        tree_selection = self._treeview_files.get_selection()
586
        (model, selection) = tree_selection.get_selected()
587
        if selection is None:
588
            next = None
589
        else:
590
            next = model.iter_next(selection)
591
592
        if next is None:
593
            # We have either made it to the end of the list, or nothing was
594
            # selected. Either way, select All Files, and jump to the global
595
            # commit message.
734.1.23 by Curtis Hovey
Always pass a Gtk.TreePath instead of an int or tuple.
596
            self._treeview_files.set_cursor(
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
597
                Gtk.TreePath(path=0), "", False)
278.1.32 by John Arbash Meinel
Add the Ctrl+n accelerator to jump through the commit messages.
598
            self._global_message_text_view.grab_focus()
599
        else:
600
            # Set the cursor to this entry, and jump to the per-file commit
601
            # message
734.1.13 by Curtis Hovey
Fixed search in diff.
602
            self._treeview_files.set_cursor(model.get_path(next), None, False)
278.1.32 by John Arbash Meinel
Add the Ctrl+n accelerator to jump through the commit messages.
603
            self._file_message_text_view.grab_focus()
604
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
605
    def _save_current_file_message(self):
606
        if self._last_selected_file is None:
607
            return # Nothing to save
608
        text_buffer = self._file_message_text_view.get_buffer()
609
        cur_text = text_buffer.get_text(text_buffer.get_start_iter(),
734.1.4 by Curtis Hovey
Updated commit to gtk3.
610
                                        text_buffer.get_end_iter(), True)
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
611
        last_selected = self._files_store.get_iter(self._last_selected_file)
612
        self._files_store.set_value(last_selected, 5, cur_text)
613
614
    def _update_per_file_info(self, selection):
615
        # The node is changing, so cache the current message
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
616
        if not self._enable_per_file_commits:
617
            return
618
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
619
        self._save_current_file_message()
620
        text_buffer = self._file_message_text_view.get_buffer()
621
        file_id, display_path, message = self._files_store.get(selection, 0, 3, 5)
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
622
        if file_id == "": # Whole tree
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
623
            self._file_message_expander.set_label(_i18n('File commit message'))
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
624
            self._file_message_expander.set_expanded(False)
625
            self._file_message_expander.set_sensitive(False)
626
            text_buffer.set_text('')
627
            self._last_selected_file = None
628
        else:
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
629
            self._file_message_expander.set_label(_i18n('Commit message for ')
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
630
                                                  + display_path)
631
            self._file_message_expander.set_expanded(True)
632
            self._file_message_expander.set_sensitive(True)
633
            text_buffer.set_text(message)
634
            self._last_selected_file = self._files_store.get_path(selection)
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
635
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
636
    def _get_specific_files(self):
278.1.31 by John Arbash Meinel
We can make bencode work again by a simple decode/encode step.
637
        """Return the list of selected paths, and file info.
638
639
        :return: ([unicode paths], [{utf-8 file info}]
640
        """
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
641
        self._save_current_file_message()
642
        files = []
643
        records = iter(self._files_store)
644
        rec = records.next() # Skip the All Files record
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
645
        assert rec[0] == "", "Are we skipping the wrong record?"
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
646
647
        file_info = []
648
        for record in records:
278.1.43 by John Arbash Meinel
Finish connecting the 'Commit all changes' radio buttons.
649
            if self._commit_all_changes or record[2]:# [2] checkbox
769 by Jelmer Vernooij
Cope with some strings being unicode when returned by some versions of gtk.
650
                file_id = osutils.safe_utf8(record[0]) # [0] file_id
651
                path = osutils.safe_utf8(record[1])    # [1] real path
622.1.1 by John Arbash Meinel
Ensure that per-file commit messages and global commit messages get sanitized.
652
                # [5] commit message
653
                file_message = _sanitize_and_decode_message(record[5])
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
654
                files.append(path.decode('UTF-8'))
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
655
                if self._enable_per_file_commits and file_message:
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
656
                    # All of this needs to be utf-8 information
622.1.1 by John Arbash Meinel
Ensure that per-file commit messages and global commit messages get sanitized.
657
                    file_message = file_message.encode('UTF-8')
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
658
                    file_info.append({'path':path, 'file_id':file_id,
659
                                     'message':file_message})
660
        file_info.sort(key=lambda x:(x['path'], x['file_id']))
278.1.33 by John Arbash Meinel
Only enable the per-file dialog if 'per_file_commits' is enabled in the config.
661
        if self._enable_per_file_commits:
662
            return files, file_info
663
        else:
664
            return files, []
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
665
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
666
    @show_bzr_error
635.2.7 by Vincent Ladeuil
Land Anne Mohsen's patch for bug 215674.
667
    def _on_cancel_clicked(self, button):
668
        """ Cancel button clicked handler. """
669
        self._do_cancel()
670
671
    @show_bzr_error
672
    def _on_delete_window(self, source, event):
673
        """ Delete window handler. """
674
        self._do_cancel()
675
676
    def _do_cancel(self):
677
        """If requested, saves commit messages when cancelling gcommit; they are re-used by a next gcommit"""
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
678
        mgr = SavedCommitMessagesManager()
679
        self._saved_commit_messages_manager = mgr
680
        mgr.insert(self._get_global_commit_message(),
681
                   self._get_specific_files()[1])
682
        if mgr.is_not_empty(): # maybe worth saving
683
            response = self._question_dialog(
684
                _i18n('Commit cancelled'),
685
                _i18n('Do you want to save your commit messages ?'),
686
                parent=self)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
687
            if response == Gtk.ResponseType.NO:
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
688
                 # save nothing and destroy old comments if any
689
                mgr = SavedCommitMessagesManager()
690
        mgr.save(self._wt, self._wt.branch)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
691
        self.response(Gtk.ResponseType.CANCEL) # close window
635.2.7 by Vincent Ladeuil
Land Anne Mohsen's patch for bug 215674.
692
693
    @show_bzr_error
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
694
    def _on_commit_clicked(self, button):
695
        """ Commit button clicked handler. """
696
        self._do_commit()
697
698
    def _do_commit(self):
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
699
        message = self._get_global_commit_message()
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
700
701
        if message == '':
606 by Vincent Ladeuil
Fix gtk dialogs popping up and asking for input during selftest.
702
            response = self._question_dialog(
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
703
                _i18n('Commit with an empty message?'),
576.1.1 by Jasper Groenewegen
Add parent setting to dialogs and implement in gcommit
704
                _i18n('You can describe your commit intent in the message.'),
705
                parent=self)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
706
            if response == Gtk.ResponseType.NO:
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
707
                # Kindly give focus to message area
708
                self._global_message_text_view.grab_focus()
709
                return
710
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
711
        specific_files, file_info = self._get_specific_files()
278.1.28 by John Arbash Meinel
Ensure that we can set per-file messages even during a merge.
712
        if self._pending:
713
            specific_files = None
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
714
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
715
        local = self._check_local.get_active()
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
716
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
717
        # All we care about is if there is a single unknown, so if this loop is
718
        # entered, then there are unknown files.
719
        # TODO: jam 20071002 It seems like this should cancel the dialog
720
        #       entirely, since there isn't a way for them to add the unknown
721
        #       files at this point.
722
        for path in self._wt.unknowns():
606 by Vincent Ladeuil
Fix gtk dialogs popping up and asking for input during selftest.
723
            response = self._question_dialog(
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
724
                _i18n("Commit with unknowns?"),
576.1.1 by Jasper Groenewegen
Add parent setting to dialogs and implement in gcommit
725
                _i18n("Unknown files exist in the working tree. Commit anyway?"),
726
                parent=self)
727
                # Doesn't set a parent for the dialog..
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
728
            if response == Gtk.ResponseType.NO:
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
729
                return
730
            break
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
731
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
732
        rev_id = None
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
733
        revprops = {}
734
        if file_info:
278.1.31 by John Arbash Meinel
We can make bencode work again by a simple decode/encode step.
735
            revprops['file-info'] = bencode.bencode(file_info).decode('UTF-8')
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
736
        try:
737
            rev_id = self._wt.commit(message,
738
                       allow_pointless=False,
739
                       strict=False,
740
                       local=local,
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
741
                       specific_files=specific_files,
742
                       revprops=revprops)
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
743
        except errors.PointlessCommit:
606 by Vincent Ladeuil
Fix gtk dialogs popping up and asking for input during selftest.
744
            response = self._question_dialog(
475.1.2 by Vincent Ladeuil
Fix bug #187283 fix replacing _() by _i18n().
745
                _i18n('Commit with no changes?'),
746
                _i18n('There are no changes in the working tree.'
576.1.1 by Jasper Groenewegen
Add parent setting to dialogs and implement in gcommit
747
                      ' Do you want to commit anyway?'),
748
                parent=self)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
749
            if response == Gtk.ResponseType.YES:
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
750
                rev_id = self._wt.commit(message,
751
                               allow_pointless=True,
752
                               strict=False,
753
                               local=local,
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
754
                               specific_files=specific_files,
755
                               revprops=revprops)
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
756
        self.committed_revision_id = rev_id
635.2.7 by Vincent Ladeuil
Land Anne Mohsen's patch for bug 215674.
757
        # destroy old comments if any
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
758
        SavedCommitMessagesManager().save(self._wt, self._wt.branch)
734.1.1 by Curtis Hovey
Mechanical changes made by pygi.convert.sh.
759
        self.response(Gtk.ResponseType.OK)
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
760
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
761
    def _get_global_commit_message(self):
762
        buf = self._global_message_text_view.get_buffer()
763
        start, end = buf.get_bounds()
734.1.4 by Curtis Hovey
Updated commit to gtk3.
764
        text = buf.get_text(start, end, True)
622.1.1 by John Arbash Meinel
Ensure that per-file commit messages and global commit messages get sanitized.
765
        return _sanitize_and_decode_message(text)
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
766
767
    def _set_global_commit_message(self, message):
768
        """Just a helper for the test suite."""
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
769
        if isinstance(message, unicode):
770
            message = message.encode('UTF-8')
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
771
        self._global_message_text_view.get_buffer().set_text(message)
772
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
773
    def _set_file_commit_message(self, message):
774
        """Helper for the test suite."""
278.1.29 by John Arbash Meinel
Start testing with Unicode data.
775
        if isinstance(message, unicode):
776
            message = message.encode('UTF-8')
278.1.27 by John Arbash Meinel
Add the ability to commit just specific files.
777
        self._file_message_text_view.get_buffer().set_text(message)
778
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
779
    @staticmethod
780
    def _rev_to_pending_info(rev):
781
        """Get the information from a pending merge."""
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
782
        from bzrlib.osutils import format_date
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
783
        rev_dict = {}
784
        rev_dict['committer'] = re.sub('<.*@.*>', '', rev.committer).strip(' ')
785
        rev_dict['summary'] = rev.get_summary()
786
        rev_dict['date'] = format_date(rev.timestamp,
787
                                       rev.timezone or 0,
788
                                       'original', date_fmt="%Y-%m-%d",
789
                                       show_offset=False)
790
        rev_dict['revision_id'] = rev.revision_id
791
        return rev_dict
635.2.12 by Vincent Ladeuil
Implement commit message saving without modifying bzrlib.
792