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