/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
17
try:
18
    import pygtk
19
    pygtk.require("2.0")
20
except:
21
    pass
0.8.98 by Szilveszter Farkas (Phanatic)
Loads of fixes. Pyflakes cleanup.
22
0.13.11 by Jelmer Vernooij
Bunch of small fixes, cleanups and simplifications.
23
import gtk
24
import gobject
25
import pango
0.8.19 by Szilveszter Farkas (Phanatic)
2006-07-21 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
26
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
27
import os.path
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
28
import re
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
29
248 by Jelmer Vernooij
Merge fixes for #127392 and #127381)
30
from bzrlib import errors, osutils
235.1.5 by Mateusz Korniak
Missing mutter import added.
31
from bzrlib.trace import mutter
0.8.20 by Szilveszter Farkas (Phanatic)
2006-07-24 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
32
153 by Jelmer Vernooij
Fix references to dialog.
33
from dialog import error_dialog, question_dialog
132 by Jelmer Vernooij
Use decorator for catching and showing bzr-gtk errors graphically. Eventually, this should go away and should be handled by the ui factory.
34
from errors import show_bzr_error
93.1.6 by Alexander Belchenko
detecting name of glade file doing in separate module (olive.gladefile)
35
158 by Jelmer Vernooij
If available, use NetworkManager to find out whether a commit should be local or not.
36
try:
37
    import dbus
38
    import dbus.glib
180 by Jelmer Vernooij
Don't obtain handle to network manager until it's actually needed.
39
    have_dbus = True
158 by Jelmer Vernooij
If available, use NetworkManager to find out whether a commit should be local or not.
40
except ImportError:
180 by Jelmer Vernooij
Don't obtain handle to network manager until it's actually needed.
41
    have_dbus = False
158 by Jelmer Vernooij
If available, use NetworkManager to find out whether a commit should be local or not.
42
278.1.4 by John Arbash Meinel
Just playing around.
43
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
44
def pending_revisions(wt):
45
    """Return a list of pending merges or None if there are none of them.
46
47
    Arguably this should be a core function, and
48
    ``bzrlib.status.show_pending_merges`` should be built on top of it.
49
50
    :return: [(rev, [children])]
51
    """
52
    parents = wt.get_parent_ids()
53
    if len(parents) < 2:
54
        return None
55
56
    # The basic pending merge algorithm uses the same algorithm as
57
    # bzrlib.status.show_pending_merges
58
    pending = parents[1:]
59
    branch = wt.branch
60
    last_revision = parents[0]
61
62
    if last_revision is not None:
63
        try:
64
            ignore = set(branch.repository.get_ancestry(last_revision,
65
                                                        topo_sorted=False))
66
        except errors.NoSuchRevision:
67
            # the last revision is a ghost : assume everything is new
68
            # except for it
69
            ignore = set([None, last_revision])
70
    else:
71
        ignore = set([None])
72
73
    pm = []
74
    for merge in pending:
75
        ignore.add(merge)
76
        try:
77
            rev = branch.repository.get_revision(merge)
78
            children = []
79
            pm.append((rev, children))
80
81
            # This does need to be topo sorted, so we search backwards
82
            inner_merges = branch.repository.get_ancestry(merge)
83
            assert inner_merges[0] is None
84
            inner_merges.pop(0)
85
            for mmerge in reversed(inner_merges):
86
                if mmerge in ignore:
87
                    continue
88
                rev = branch.repository.get_revision(mmerge)
89
                children.append(rev)
90
91
                ignore.add(mmerge)
92
        except errors.NoSuchRevision:
93
            print "DEBUG: NoSuchRevision:", merge
94
95
    return pm
96
97
135 by Jelmer Vernooij
Throw out the old CommitDialog code and use the new code instead, also for 'gcommit'.
98
class CommitDialog(gtk.Dialog):
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
99
    """Implementation of Commit."""
100
101
    def __init__(self, wt, selected=None, parent=None):
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
102
        gtk.Dialog.__init__(self, title="Commit - Olive",
103
                                  parent=parent,
104
                                  flags=0,
105
                                  buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
278.1.24 by John Arbash Meinel
Actually show the commit button.
106
        self._question_dialog = question_dialog
107
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
108
        self._wt = wt
109
        self._selected = selected
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
110
        self.committed_revision_id = None # Nothing has been committed yet
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
111
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
112
        self.setup_params()
113
        self.construct()
114
        self.fill_in_data()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
115
116
    def setup_params(self):
117
        """Setup the member variables for state."""
118
        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.
119
        self._delta = None
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
120
        self._pending = pending_revisions(self._wt)
121
122
        self._is_checkout = (self._wt.branch.get_bound_location() is not None)
123
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
124
    def fill_in_data(self):
125
        # Now that we are built, handle changes to the view based on the state
126
        self._fill_in_pending()
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
127
        self._fill_in_diff()
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
128
        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.
129
        self._fill_in_checkout()
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
130
131
    def _fill_in_pending(self):
132
        if not self._pending:
133
            self._pending_box.hide()
134
            return
135
136
        # TODO: We'd really prefer this to be a nested list
137
        for rev, children in self._pending:
138
            rev_info = self._rev_to_pending_info(rev)
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
139
            self._pending_store.append([
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
140
                rev_info['revision_id'],
141
                rev_info['date'],
142
                rev_info['committer'],
143
                rev_info['summary'],
144
                ])
145
            for child in children:
146
                rev_info = self._rev_to_pending_info(child)
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
147
                self._pending_store.append([
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
148
                    rev_info['revision_id'],
149
                    rev_info['date'],
150
                    rev_info['committer'],
151
                    rev_info['summary'],
152
                    ])
153
        self._pending_box.show()
154
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
155
    def _fill_in_files(self):
156
        # We should really use _iter_changes, and then add a progress bar of
157
        # some kind.
158
        # While we fill in the view, hide the store
159
        store = self._files_store
160
        self._treeview_files.set_model(None)
161
162
        added = _('added')
163
        removed = _('removed')
164
        renamed = _('renamed')
165
        renamed_and_modified = _('renamed and modified')
166
        modified = _('modified')
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
167
        kind_changed = _('kind changed')
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
168
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
169
        # The store holds:
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
170
        # [file_id, real path, checkbox, display path, changes type, message]
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
171
        # _iter_changes returns:
172
        # (file_id, (path_in_source, path_in_target),
173
        #  changed_content, versioned, parent, name, kind,
174
        #  executable)
175
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
176
        # The first entry is always the 'whole tree'
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
177
        store.append([None, None, True, 'All Files', '', ''])
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
178
        # should we pass specific_files?
179
        self._wt.lock_read()
180
        self._basis_tree.lock_read()
181
        try:
182
            for (file_id, paths, changed_content, versioned, parent_ids, names,
183
                 kinds, executables) in self._wt._iter_changes(self._basis_tree):
184
185
                # Skip the root entry.
186
                if parent_ids == (None, None):
187
                    continue
188
189
                change_type = None
190
                if kinds[0] is None:
191
                    source_marker = ''
192
                else:
193
                    source_marker = osutils.kind_marker(kinds[0])
194
                if kinds[1] is None:
195
                    assert kinds[0] is not None
196
                    marker = osutils.kind_marker(kinds[0])
197
                else:
198
                    marker = osutils.kind_marker(kinds[1])
199
200
                real_path = paths[1]
201
                if real_path is None:
202
                    real_path = paths[0]
203
                assert real_path is not None
204
                display_path = real_path + marker
205
206
                present_source = versioned[0] and kinds[0] is not None
207
                present_target = versioned[1] and kinds[1] is not None
208
209
                if present_source != present_target:
210
                    if present_target:
211
                        change_type = added
212
                    else:
213
                        change_type = removed
214
                elif names[0] != names[1] or parent_ids[0] != parent_ids[1]:
215
                    # Renamed
216
                    if changed_content or executables[0] != executables[1]:
217
                        # and modified
218
                        change_type = renamed_and_modified
219
                    else:
220
                        change_type = renamed
221
                    display_path = (paths[0] + source_marker
222
                                    + ' => ' + paths[1] + marker)
223
                elif kinds[0] != kinds[1]:
224
                    change_type = kind_changed
225
                    display_path = (paths[0] + source_marker
226
                                    + ' => ' + paths[1] + marker)
227
                elif changed_content is True or executables[0] != executables[1]:
228
                    change_type = modified
229
                else:
230
                    assert False, "How did we get here?"
231
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
232
                store.append([file_id, real_path, True, display_path,
233
                              change_type, ''])
278.1.16 by John Arbash Meinel
Implement the file changes list on top of _iter_changes rather than
234
        finally:
235
            self._basis_tree.unlock()
236
            self._wt.unlock()
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
237
238
        self._treeview_files.set_model(store)
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
239
        self._last_selected_file = None
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
240
        self._treeview_files.set_cursor(0)
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
241
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
242
    def _fill_in_diff(self):
243
        self._diff_view.set_trees(self._wt, self._basis_tree)
244
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
245
    def _fill_in_checkout(self):
246
        if not self._is_checkout:
247
            self._check_local.hide()
248
            return
249
        if have_dbus:
250
            bus = dbus.SystemBus()
251
            proxy_obj = bus.get_object('org.freedesktop.NetworkManager',
252
                                       '/org/freedesktop/NetworkManager')
253
            dbus_iface = dbus.Interface(proxy_obj,
254
                                        'org.freedesktop.NetworkManager')
255
            try:
256
                # 3 is the enum value for STATE_CONNECTED
257
                self._check_local.set_active(dbus_iface.state() != 3)
258
            except dbus.DBusException, e:
259
                # Silently drop errors. While DBus may be
260
                # available, NetworkManager doesn't necessarily have to be
261
                mutter("unable to get networkmanager state: %r" % e)
262
        self._check_local.show()
263
278.1.12 by John Arbash Meinel
Delay computing the delta, and clean up some of the diff view names.
264
    def _compute_delta(self):
265
        self._delta = self._wt.changes_from(self._basis_tree)
266
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
267
    def construct(self):
268
        """Build up the dialog widgets."""
269
        # The primary pane which splits it into left and right (adjustable)
270
        # sections.
278.1.4 by John Arbash Meinel
Just playing around.
271
        self._hpane = gtk.HPaned()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
272
273
        self._construct_left_pane()
274
        self._construct_right_pane()
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
275
        self._construct_action_pane()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
276
277
        self.vbox.pack_start(self._hpane)
278
        self._hpane.show()
279
        self.set_focus(self._global_message_text_view)
280
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
281
        # This seems like a reasonable default, we might like it to
282
        # be a bit wider, so that by default we can fit an 80-line diff in the
283
        # diff window.
284
        # Alternatively, we should be saving the last position/size rather than
285
        # setting it to a fixed value every time we start up.
286
        screen = self.get_screen()
287
        monitor = 0 # We would like it to be the monitor we are going to
288
                    # display on, but I don't know how to figure that out
289
                    # Only really useful for freaks like me that run dual
290
                    # monitor, with different sizes on the monitors
291
        monitor_rect = screen.get_monitor_geometry(monitor)
292
        width = int(monitor_rect.width * 0.66)
293
        height = int(monitor_rect.height * 0.66)
294
        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
295
        self._hpane.set_position(300)
296
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
297
    def _construct_left_pane(self):
278.1.11 by John Arbash Meinel
Worked out the rest of the spacing.
298
        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.
299
        self._construct_file_list()
300
        self._construct_pending_list()
301
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
302
        self._check_local = gtk.CheckButton(_("_Only commit locally"),
303
                                            use_underline=True)
304
        self._left_pane_box.pack_end(self._check_local, False, False)
305
        self._check_local.set_active(False)
306
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
307
        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.
308
        self._left_pane_box.show()
309
310
    def _construct_right_pane(self):
311
        # TODO: I really want to make it so the diff view gets more space than
312
        # the global commit message, and the per-file commit message gets even
313
        # less. When I did it with wxGlade, I set it to 4 for diff, 2 for
314
        # commit, and 1 for file commit, and it looked good. But I don't seem
315
        # to have a way to do that with the gtk boxes... :( (Which is extra
316
        # weird since wx uses gtk on Linux...)
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
317
        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.
318
        self._right_pane_table.set_row_spacings(5)
319
        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.
320
        self._right_pane_table_row = 0
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
321
        self._construct_diff_view()
322
        self._construct_file_message()
323
        self._construct_global_message()
324
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
325
        self._right_pane_table.show()
326
        self._hpane.pack2(self._right_pane_table, resize=True, shrink=True)
327
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
328
    def _construct_action_pane(self):
329
        self._button_commit = gtk.Button(_("Comm_it"), use_underline=True)
330
        self._button_commit.connect('clicked', self._on_commit_clicked)
331
        self._button_commit.set_flags(gtk.CAN_DEFAULT)
278.1.24 by John Arbash Meinel
Actually show the commit button.
332
        self._button_commit.show()
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
333
        self.action_area.pack_end(self._button_commit)
278.1.24 by John Arbash Meinel
Actually show the commit button.
334
        self._button_commit.grab_default()
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
335
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
336
    def _add_to_right_table(self, widget, weight, expanding=False):
337
        """Add another widget to the table
338
339
        :param widget: The object to add
340
        :param weight: How many rows does this widget get to request
341
        :param expanding: Should expand|fill|shrink be set?
342
        """
343
        end_row = self._right_pane_table_row + weight
344
        options = 0
345
        expand_opts = gtk.EXPAND | gtk.FILL | gtk.SHRINK
346
        if expanding:
347
            options = expand_opts
348
        self._right_pane_table.attach(widget, 0, 1,
349
                                      self._right_pane_table_row, end_row,
350
                                      xoptions=expand_opts, yoptions=options)
351
        self._right_pane_table_row = end_row
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
352
353
    def _construct_file_list(self):
278.1.11 by John Arbash Meinel
Worked out the rest of the spacing.
354
        self._files_box = gtk.VBox(homogeneous=False, spacing=0)
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
355
        file_label = gtk.Label(_('Files'))
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
356
        file_label.show()
357
        self._files_box.pack_start(file_label, expand=False)
358
359
        scroller = gtk.ScrolledWindow()
360
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
361
        self._treeview_files = gtk.TreeView()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
362
        self._treeview_files.show()
363
        scroller.add(self._treeview_files)
364
        scroller.show()
365
        scroller.set_shadow_type(gtk.SHADOW_IN)
366
        self._files_box.pack_start(scroller,
367
                                   expand=True, fill=True)
368
        self._files_box.show()
369
        self._left_pane_box.pack_start(self._files_box)
370
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
371
        liststore = gtk.ListStore(
372
            gobject.TYPE_STRING,  # [0] file_id
373
            gobject.TYPE_STRING,  # [1] real path
374
            gobject.TYPE_BOOLEAN, # [2] checkbox
375
            gobject.TYPE_STRING,  # [3] display path
376
            gobject.TYPE_STRING,  # [4] changes type
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
377
            gobject.TYPE_STRING,  # [5] commit message
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
378
            )
379
        self._files_store = liststore
380
        self._treeview_files.set_model(liststore)
381
        crt = gtk.CellRendererToggle()
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
382
        crt.set_active(not bool(self._pending))
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
383
        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.
384
        if self._pending:
385
            name = _('Commit*')
386
        else:
387
            name = _('Commit')
388
        self._treeview_files.append_column(gtk.TreeViewColumn(name,
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
389
                                           crt, active=2))
390
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Path'),
391
                                           gtk.CellRendererText(), text=3))
392
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Type'),
393
                                           gtk.CellRendererText(), text=4))
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
394
        self._treeview_files.connect('cursor-changed',
395
                                     self._on_treeview_files_cursor_changed)
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
396
397
    def _toggle_commit(self, cell, path, model):
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
398
        if model[path][0] is None: # No file_id means 'All Files'
399
            new_val = not model[path][2]
400
            for node in model:
401
                node[2] = new_val
402
        else:
403
            model[path][2] = not model[path][2]
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
404
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
405
    def _construct_pending_list(self):
406
        # Pending information defaults to hidden, we put it all in 1 box, so
407
        # that we can show/hide all of them at once
408
        self._pending_box = gtk.VBox()
409
        self._pending_box.hide()
410
411
        pending_message = gtk.Label()
412
        pending_message.set_markup(
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
413
            _('<i>* Cannot select specific files when merging</i>'))
278.1.11 by John Arbash Meinel
Worked out the rest of the spacing.
414
        self._pending_box.pack_start(pending_message, expand=False, padding=5)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
415
        pending_message.show()
416
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
417
        pending_label = gtk.Label(_('Pending Revisions'))
278.1.11 by John Arbash Meinel
Worked out the rest of the spacing.
418
        self._pending_box.pack_start(pending_label, expand=False, padding=0)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
419
        pending_label.show()
420
421
        scroller = gtk.ScrolledWindow()
422
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
423
        self._treeview_pending = gtk.TreeView()
424
        scroller.add(self._treeview_pending)
425
        scroller.show()
426
        scroller.set_shadow_type(gtk.SHADOW_IN)
427
        self._pending_box.pack_start(scroller,
278.1.11 by John Arbash Meinel
Worked out the rest of the spacing.
428
                                     expand=True, fill=True, padding=5)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
429
        self._treeview_pending.show()
430
        self._left_pane_box.pack_start(self._pending_box)
431
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
432
        liststore = gtk.ListStore(gobject.TYPE_STRING, # revision_id
433
                                  gobject.TYPE_STRING, # date
434
                                  gobject.TYPE_STRING, # committer
435
                                  gobject.TYPE_STRING, # summary
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
436
                                 )
278.1.15 by John Arbash Meinel
Hook up the list of modified files.
437
        self._pending_store = liststore
278.1.14 by John Arbash Meinel
Tests that we fill out the pending list correctly.
438
        self._treeview_pending.set_model(liststore)
439
        self._treeview_pending.append_column(gtk.TreeViewColumn(_('Date'),
440
                                             gtk.CellRendererText(), text=1))
441
        self._treeview_pending.append_column(gtk.TreeViewColumn(_('Committer'),
442
                                             gtk.CellRendererText(), text=2))
443
        self._treeview_pending.append_column(gtk.TreeViewColumn(_('Summary'),
444
                                             gtk.CellRendererText(), text=3))
445
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
446
    def _construct_diff_view(self):
278.1.12 by John Arbash Meinel
Delay computing the delta, and clean up some of the diff view names.
447
        from diff import DiffView
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
448
449
        self._diff_label = gtk.Label(_('Diff for whole tree'))
278.1.11 by John Arbash Meinel
Worked out the rest of the spacing.
450
        self._diff_label.set_alignment(0, 0)
451
        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.
452
        self._add_to_right_table(self._diff_label, 1, False)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
453
        self._diff_label.show()
454
278.1.12 by John Arbash Meinel
Delay computing the delta, and clean up some of the diff view names.
455
        self._diff_view = DiffView()
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
456
        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.
457
        self._diff_view.show()
458
459
    def _construct_file_message(self):
460
        file_message_box = gtk.VBox()
278.1.9 by John Arbash Meinel
Move all text entry boxes into a ScrolledWindow, so that they don't change size constantly.
461
        scroller = gtk.ScrolledWindow()
462
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
463
464
        self._file_message_text_view = gtk.TextView()
465
        scroller.add(self._file_message_text_view)
466
        scroller.show()
467
        scroller.set_shadow_type(gtk.SHADOW_IN)
468
        file_message_box.pack_start(scroller, expand=True, fill=True)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
469
470
        self._file_message_text_view.modify_font(pango.FontDescription("Monospace"))
471
        self._file_message_text_view.set_wrap_mode(gtk.WRAP_WORD)
472
        self._file_message_text_view.set_accepts_tab(False)
473
        self._file_message_text_view.show()
474
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
475
        self._file_message_expander = gtk.Expander(_('File commit message'))
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
476
        self._file_message_expander.add(file_message_box)
477
        file_message_box.show()
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
478
        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.
479
        self._file_message_expander.show()
480
481
    def _construct_global_message(self):
482
        self._global_message_label = gtk.Label(_('Global Commit Message'))
278.1.11 by John Arbash Meinel
Worked out the rest of the spacing.
483
        self._global_message_label.set_alignment(0, 0)
484
        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.
485
        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.
486
        # 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.
487
        self._global_message_label.show()
488
278.1.9 by John Arbash Meinel
Move all text entry boxes into a ScrolledWindow, so that they don't change size constantly.
489
        scroller = gtk.ScrolledWindow()
490
        scroller.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
491
492
        self._global_message_text_view = gtk.TextView()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
493
        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.
494
        scroller.add(self._global_message_text_view)
495
        scroller.show()
496
        scroller.set_shadow_type(gtk.SHADOW_IN)
278.1.10 by John Arbash Meinel
To get the space weighting I wanted, I turned to a Table.
497
        self._add_to_right_table(scroller, 2, True)
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
498
        self._file_message_text_view.set_wrap_mode(gtk.WRAP_WORD)
499
        self._file_message_text_view.set_accepts_tab(False)
500
        self._global_message_text_view.show()
501
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
502
    def _on_treeview_files_cursor_changed(self, treeview):
278.1.18 by John Arbash Meinel
Start checking the diff view is correct.
503
        treeselection = treeview.get_selection()
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
504
        (model, selection) = treeselection.get_selected()
278.1.17 by John Arbash Meinel
Add a * reference for why you can't change the commit selection.
505
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
506
        if selection is not None:
507
            path, display_path = model.get(selection, 1, 3)
278.1.18 by John Arbash Meinel
Start checking the diff view is correct.
508
            self._diff_label.set_text(_('Diff for ') + display_path)
278.1.20 by John Arbash Meinel
We always select the All Files record in the files view,
509
            if path is None:
510
                self._diff_view.show_diff(None)
511
            else:
512
                self._diff_view.show_diff([path])
278.1.21 by John Arbash Meinel
Start tracking the per-file commit messages.
513
            self._update_per_file_info(selection)
514
515
    def _save_current_file_message(self):
516
        if self._last_selected_file is None:
517
            return # Nothing to save
518
        text_buffer = self._file_message_text_view.get_buffer()
519
        cur_text = text_buffer.get_text(text_buffer.get_start_iter(),
520
                                        text_buffer.get_end_iter())
521
        last_selected = self._files_store.get_iter(self._last_selected_file)
522
        self._files_store.set_value(last_selected, 5, cur_text)
523
524
    def _update_per_file_info(self, selection):
525
        # The node is changing, so cache the current message
526
        self._save_current_file_message()
527
        text_buffer = self._file_message_text_view.get_buffer()
528
        file_id, display_path, message = self._files_store.get(selection, 0, 3, 5)
529
        if file_id is None: # Whole tree
530
            self._file_message_expander.set_label(_('File commit message'))
531
            self._file_message_expander.set_expanded(False)
532
            self._file_message_expander.set_sensitive(False)
533
            text_buffer.set_text('')
534
            self._last_selected_file = None
535
        else:
536
            self._file_message_expander.set_label(_('Commit message for ')
537
                                                  + display_path)
538
            self._file_message_expander.set_expanded(True)
539
            self._file_message_expander.set_sensitive(True)
540
            text_buffer.set_text(message)
541
            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.
542
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
543
    @show_bzr_error
544
    def _on_commit_clicked(self, button):
545
        """ Commit button clicked handler. """
546
        self._do_commit()
547
548
    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.
549
        message = self._get_global_commit_message()
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
550
551
        if message == '':
552
            response = self._question_dialog(
553
                            _('Commit with an empty message?'),
554
                            _('You can describe your commit intent in the message.'))
555
            if response == gtk.RESPONSE_NO:
556
                # Kindly give focus to message area
557
                self._global_message_text_view.grab_focus()
558
                return
559
560
        # if not self.pending:
561
        #     specific_files = self._get_specific_files()
562
        # else:
563
        #     specific_files = None
564
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
565
        local = self._check_local.get_active()
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
566
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
567
        # All we care about is if there is a single unknown, so if this loop is
568
        # entered, then there are unknown files.
569
        # TODO: jam 20071002 It seems like this should cancel the dialog
570
        #       entirely, since there isn't a way for them to add the unknown
571
        #       files at this point.
572
        for path in self._wt.unknowns():
573
            response = self._question_dialog(
574
                _("Commit with unknowns?"),
575
                _("Unknown files exist in the working tree. Commit anyway?"))
576
            if response == gtk.RESPONSE_NO:
577
                return
578
            break
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
579
580
        specific_files = None
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
581
        rev_id = None
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
582
        try:
583
            rev_id = self._wt.commit(message,
584
                       allow_pointless=False,
585
                       strict=False,
586
                       local=local,
587
                       specific_files=specific_files)
588
        except errors.PointlessCommit:
278.1.26 by John Arbash Meinel
Handle pointless commits and trees with unknown files.
589
            response = self._question_dialog(
590
                                _('Commit with no changes?'),
591
                                _('There are no changes in the working tree.'
592
                                  ' Do you want to commit anyway?'))
278.1.23 by John Arbash Meinel
Beginning to support actual commit.
593
            if response == gtk.RESPONSE_YES:
594
                rev_id = self._wt.commit(message,
595
                               allow_pointless=True,
596
                               strict=False,
597
                               local=local,
598
                               specific_files=specific_files)
599
        self.committed_revision_id = rev_id
600
        self.response(gtk.RESPONSE_OK)
601
278.1.25 by John Arbash Meinel
Add the 'Only Commit Locally' checkbox, we may want to put it elsewhere, though.
602
    def _get_global_commit_message(self):
603
        buf = self._global_message_text_view.get_buffer()
604
        start, end = buf.get_bounds()
605
        return buf.get_text(start, end).decode('utf-8')
606
607
    def _set_global_commit_message(self, message):
608
        """Just a helper for the test suite."""
609
        self._global_message_text_view.get_buffer().set_text(message)
610
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
611
    @staticmethod
612
    def _rev_to_pending_info(rev):
613
        """Get the information from a pending merge."""
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
614
        from bzrlib.osutils import format_date
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
615
616
        rev_dict = {}
617
        rev_dict['committer'] = re.sub('<.*@.*>', '', rev.committer).strip(' ')
618
        rev_dict['summary'] = rev.get_summary()
619
        rev_dict['date'] = format_date(rev.timestamp,
620
                                       rev.timezone or 0,
621
                                       'original', date_fmt="%Y-%m-%d",
622
                                       show_offset=False)
623
        rev_dict['revision_id'] = rev.revision_id
624
        return rev_dict
625
626
627
# class CommitDialog(gtk.Dialog):
628
#     """ New implementation of the Commit dialog. """
629
#     def __init__(self, wt, wtpath, notbranch, selected=None, parent=None):
630
#         """ Initialize the Commit Dialog. """
631
#         gtk.Dialog.__init__(self, title="Commit - Olive",
632
#                                   parent=parent,
633
#                                   flags=0,
634
#                                   buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
635
#         
636
#         # Get arguments
637
#         self.wt = wt
638
#         self.wtpath = wtpath
639
#         self.notbranch = notbranch
640
#         self.selected = selected
641
#         
642
#         # Set the delta
643
#         self.old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
644
#         self.delta = self.wt.changes_from(self.old_tree)
645
#         
646
#         # Get pending merges
647
#         self.pending = self._pending_merges(self.wt)
648
#         
649
#         # Do some preliminary checks
650
#         self._is_checkout = False
651
#         self._is_pending = False
652
#         if self.wt is None and not self.notbranch:
653
#             error_dialog(_('Directory does not have a working tree'),
654
#                          _('Operation aborted.'))
655
#             self.close()
656
#             return
657
# 
658
#         if self.notbranch:
659
#             error_dialog(_('Directory is not a branch'),
660
#                          _('You can perform this action only in a branch.'))
661
#             self.close()
662
#             return
663
#         else:
664
#             if self.wt.branch.get_bound_location() is not None:
665
#                 # we have a checkout, so the local commit checkbox must appear
666
#                 self._is_checkout = True
667
#             
668
#             if self.pending:
669
#                 # There are pending merges, file selection not supported
670
#                 self._is_pending = True
671
#         
672
#         # Create the widgets
673
#         # This is the main horizontal box, which is used to separate the commit
674
#         # info from the diff window.
675
#         self._hpane = gtk.HPaned()
676
#         self._button_commit = gtk.Button(_("Comm_it"), use_underline=True)
677
#         self._expander_files = gtk.Expander(_("File(s) to commit"))
678
#         self._vpaned_main = gtk.VPaned()
679
#         self._scrolledwindow_files = gtk.ScrolledWindow()
680
#         self._scrolledwindow_message = gtk.ScrolledWindow()
681
#         self._treeview_files = gtk.TreeView()
682
#         self._vbox_message = gtk.VBox()
683
#         self._label_message = gtk.Label(_("Commit message:"))
684
#         self._textview_message = gtk.TextView()
685
#         
686
#         if self._is_pending:
687
#             self._expander_merges = gtk.Expander(_("Pending merges"))
688
#             self._vpaned_list = gtk.VPaned()
689
#             self._scrolledwindow_merges = gtk.ScrolledWindow()
690
#             self._treeview_merges = gtk.TreeView()
691
# 
692
#         # Set callbacks
693
#         self._button_commit.connect('clicked', self._on_commit_clicked)
694
#         self._treeview_files.connect('cursor-changed', self._on_treeview_files_cursor_changed)
695
#         self._treeview_files.connect('row-activated', self._on_treeview_files_row_activated)
696
#         
697
#         # Set properties
698
#         self._scrolledwindow_files.set_policy(gtk.POLICY_AUTOMATIC,
699
#                                               gtk.POLICY_AUTOMATIC)
700
#         self._scrolledwindow_message.set_policy(gtk.POLICY_AUTOMATIC,
701
#                                                 gtk.POLICY_AUTOMATIC)
702
#         self._textview_message.modify_font(pango.FontDescription("Monospace"))
703
#         self.set_default_size(500, 500)
704
#         self._vpaned_main.set_position(200)
705
#         self._button_commit.set_flags(gtk.CAN_DEFAULT)
706
# 
707
#         if self._is_pending:
708
#             self._scrolledwindow_merges.set_policy(gtk.POLICY_AUTOMATIC,
709
#                                                    gtk.POLICY_AUTOMATIC)
710
#             self._treeview_files.set_sensitive(False)
711
#         
712
#         # Construct the dialog
713
#         self.action_area.pack_end(self._button_commit)
714
#         
715
#         self._scrolledwindow_files.add(self._treeview_files)
716
#         self._scrolledwindow_message.add(self._textview_message)
717
#         
718
#         self._expander_files.add(self._scrolledwindow_files)
719
#         
720
#         self._vbox_message.pack_start(self._label_message, False, False)
721
#         self._vbox_message.pack_start(self._scrolledwindow_message, True, True)
722
#         
723
#         if self._is_pending:        
724
#             self._expander_merges.add(self._scrolledwindow_merges)
725
#             self._scrolledwindow_merges.add(self._treeview_merges)
726
#             self._vpaned_list.add1(self._expander_files)
727
#             self._vpaned_list.add2(self._expander_merges)
728
#             self._vpaned_main.add1(self._vpaned_list)
729
#         else:
730
#             self._vpaned_main.add1(self._expander_files)
731
# 
732
#         self._vpaned_main.add2(self._vbox_message)
733
#         
734
#         self._hpane.pack1(self._vpaned_main)
735
#         self.vbox.pack_start(self._hpane, expand=True, fill=True)
736
#         if self._is_checkout: 
737
#             self._check_local = gtk.CheckButton(_("_Only commit locally"),
738
#                                                 use_underline=True)
739
#             self.vbox.pack_start(self._check_local, False, False)
740
#             if have_dbus:
741
#                 bus = dbus.SystemBus()
742
#                 proxy_obj = bus.get_object('org.freedesktop.NetworkManager', 
743
#                               '/org/freedesktop/NetworkManager')
744
#                 dbus_iface = dbus.Interface(
745
#                         proxy_obj, 'org.freedesktop.NetworkManager')
746
#                 try:
747
#                     # 3 is the enum value for STATE_CONNECTED
748
#                     self._check_local.set_active(dbus_iface.state() != 3)
749
#                 except dbus.DBusException, e:
750
#                     # Silently drop errors. While DBus may be 
751
#                     # available, NetworkManager doesn't necessarily have to be
752
#                     mutter("unable to get networkmanager state: %r" % e)
753
#                 
754
#         # Create the file list
755
#         self._create_file_view()
756
#         # Create the pending merges
757
#         self._create_pending_merges()
758
#         self._create_diff_view()
759
#         
760
#         # Expand the corresponding expander
761
#         if self._is_pending:
762
#             self._expander_merges.set_expanded(True)
763
#         else:
764
#             self._expander_files.set_expanded(True)
765
#         
766
#         # Display dialog
767
#         self.vbox.show_all()
768
#         
769
#         # Default to Commit button
770
#         self._button_commit.grab_default()
771
#     
772
#     def _show_diff_view(self, treeview):
773
#         # FIXME: the diff window freezes for some reason
774
#         treeselection = treeview.get_selection()
775
#         (model, iter) = treeselection.get_selected()
776
# 
777
#         if iter is not None:
778
#             selected = model.get_value(iter, 3) # Get the real_path attribute
779
#             self._diff_display.show_diff([selected])
780
# 
781
#     def _on_treeview_files_cursor_changed(self, treeview):
782
#         self._show_diff_view(treeview)
783
#         
784
#     def _on_treeview_files_row_activated(self, treeview, path, view_column):
785
#         self._show_diff_view(treeview)
786
#     
787
#     @show_bzr_error
788
#     def _on_commit_clicked(self, button):
789
#         """ Commit button clicked handler. """
790
#         textbuffer = self._textview_message.get_buffer()
791
#         start, end = textbuffer.get_bounds()
792
#         message = textbuffer.get_text(start, end).decode('utf-8')
793
#         
794
#         if not self.pending:
795
#             specific_files = self._get_specific_files()
796
#         else:
797
#             specific_files = None
798
# 
799
#         if message == '':
800
#             response = question_dialog(_('Commit with an empty message?'),
801
#                                        _('You can describe your commit intent in the message.'))
802
#             if response == gtk.RESPONSE_NO:
803
#                 # Kindly give focus to message area
804
#                 self._textview_message.grab_focus()
805
#                 return
806
# 
807
#         if self._is_checkout:
808
#             local = self._check_local.get_active()
809
#         else:
810
#             local = False
811
# 
812
#         if list(self.wt.unknowns()) != []:
813
#             response = question_dialog(_("Commit with unknowns?"),
814
#                _("Unknown files exist in the working tree. Commit anyway?"))
815
#             if response == gtk.RESPONSE_NO:
816
#                 return
817
#         
818
#         try:
819
#             self.wt.commit(message,
820
#                        allow_pointless=False,
821
#                        strict=False,
822
#                        local=local,
823
#                        specific_files=specific_files)
824
#         except errors.PointlessCommit:
825
#             response = question_dialog(_('Commit with no changes?'),
826
#                                        _('There are no changes in the working tree.'))
827
#             if response == gtk.RESPONSE_YES:
828
#                 self.wt.commit(message,
829
#                                allow_pointless=True,
830
#                                strict=False,
831
#                                local=local,
832
#                                specific_files=specific_files)
833
#         self.response(gtk.RESPONSE_OK)
834
# 
835
#     def _pending_merges(self, wt):
836
#         """ Return a list of pending merges or None if there are none of them. """
837
#         parents = wt.get_parent_ids()
838
#         if len(parents) < 2:
839
#             return None
840
#         
841
#         import re
842
#         from bzrlib.osutils import format_date
843
#         
844
#         pending = parents[1:]
845
#         branch = wt.branch
846
#         last_revision = parents[0]
847
#         
848
#         if last_revision is not None:
849
#             try:
850
#                 ignore = set(branch.repository.get_ancestry(last_revision))
851
#             except errors.NoSuchRevision:
852
#                 # the last revision is a ghost : assume everything is new 
853
#                 # except for it
854
#                 ignore = set([None, last_revision])
855
#         else:
856
#             ignore = set([None])
857
#         
858
#         pm = []
859
#         for merge in pending:
860
#             ignore.add(merge)
861
#             try:
862
#                 m_revision = branch.repository.get_revision(merge)
863
#                 
864
#                 rev = {}
865
#                 rev['committer'] = re.sub('<.*@.*>', '', m_revision.committer).strip(' ')
866
#                 rev['summary'] = m_revision.get_summary()
867
#                 rev['date'] = format_date(m_revision.timestamp,
868
#                                           m_revision.timezone or 0, 
869
#                                           'original', date_fmt="%Y-%m-%d",
870
#                                           show_offset=False)
871
#                 
872
#                 pm.append(rev)
873
#                 
874
#                 inner_merges = branch.repository.get_ancestry(merge)
875
#                 assert inner_merges[0] is None
876
#                 inner_merges.pop(0)
877
#                 inner_merges.reverse()
878
#                 for mmerge in inner_merges:
879
#                     if mmerge in ignore:
880
#                         continue
881
#                     mm_revision = branch.repository.get_revision(mmerge)
882
#                     
883
#                     rev = {}
884
#                     rev['committer'] = re.sub('<.*@.*>', '', mm_revision.committer).strip(' ')
885
#                     rev['summary'] = mm_revision.get_summary()
886
#                     rev['date'] = format_date(mm_revision.timestamp,
887
#                                               mm_revision.timezone or 0, 
888
#                                               'original', date_fmt="%Y-%m-%d",
889
#                                               show_offset=False)
890
#                 
891
#                     pm.append(rev)
892
#                     
893
#                     ignore.add(mmerge)
894
#             except errors.NoSuchRevision:
895
#                 print "DEBUG: NoSuchRevision:", merge
896
#         
897
#         return pm
898
# 
899
#     def _create_file_view(self):
900
#         self._file_store = gtk.ListStore(gobject.TYPE_BOOLEAN,   # [0] checkbox
901
#                                          gobject.TYPE_STRING,    # [1] path to display
902
#                                          gobject.TYPE_STRING,    # [2] changes type
903
#                                          gobject.TYPE_STRING)    # [3] real path
904
#         self._treeview_files.set_model(self._file_store)
905
#         crt = gtk.CellRendererToggle()
906
#         crt.set_property("activatable", True)
907
#         crt.connect("toggled", self._toggle_commit, self._file_store)
908
#         self._treeview_files.append_column(gtk.TreeViewColumn(_('Commit'),
909
#                                      crt, active=0))
910
#         self._treeview_files.append_column(gtk.TreeViewColumn(_('Path'),
911
#                                      gtk.CellRendererText(), text=1))
912
#         self._treeview_files.append_column(gtk.TreeViewColumn(_('Type'),
913
#                                      gtk.CellRendererText(), text=2))
914
# 
915
#         for path, id, kind in self.delta.added:
916
#             marker = osutils.kind_marker(kind)
917
#             if self.selected is not None:
918
#                 if path == os.path.join(self.wtpath, self.selected):
919
#                     self._file_store.append([ True, path+marker, _('added'), path ])
920
#                 else:
921
#                     self._file_store.append([ False, path+marker, _('added'), path ])
922
#             else:
923
#                 self._file_store.append([ True, path+marker, _('added'), path ])
924
# 
925
#         for path, id, kind in self.delta.removed:
926
#             marker = osutils.kind_marker(kind)
927
#             if self.selected is not None:
928
#                 if path == os.path.join(self.wtpath, self.selected):
929
#                     self._file_store.append([ True, path+marker, _('removed'), path ])
930
#                 else:
931
#                     self._file_store.append([ False, path+marker, _('removed'), path ])
932
#             else:
933
#                 self._file_store.append([ True, path+marker, _('removed'), path ])
934
# 
935
#         for oldpath, newpath, id, kind, text_modified, meta_modified in self.delta.renamed:
936
#             marker = osutils.kind_marker(kind)
937
#             if text_modified or meta_modified:
938
#                 changes = _('renamed and modified')
939
#             else:
940
#                 changes = _('renamed')
941
#             if self.selected is not None:
942
#                 if newpath == os.path.join(self.wtpath, self.selected):
943
#                     self._file_store.append([ True,
944
#                                               oldpath+marker + '  =>  ' + newpath+marker,
945
#                                               changes,
946
#                                               newpath
947
#                                             ])
948
#                 else:
949
#                     self._file_store.append([ False,
950
#                                               oldpath+marker + '  =>  ' + newpath+marker,
951
#                                               changes,
952
#                                               newpath
953
#                                             ])
954
#             else:
955
#                 self._file_store.append([ True,
956
#                                           oldpath+marker + '  =>  ' + newpath+marker,
957
#                                           changes,
958
#                                           newpath
959
#                                         ])
960
# 
961
#         for path, id, kind, text_modified, meta_modified in self.delta.modified:
962
#             marker = osutils.kind_marker(kind)
963
#             if self.selected is not None:
964
#                 if path == os.path.join(self.wtpath, self.selected):
965
#                     self._file_store.append([ True, path+marker, _('modified'), path ])
966
#                 else:
967
#                     self._file_store.append([ False, path+marker, _('modified'), path ])
968
#             else:
969
#                 self._file_store.append([ True, path+marker, _('modified'), path ])
970
#     
971
#     def _create_pending_merges(self):
972
#         if not self.pending:
973
#             return
974
#         
975
#         liststore = gtk.ListStore(gobject.TYPE_STRING,
976
#                                   gobject.TYPE_STRING,
977
#                                   gobject.TYPE_STRING)
978
#         self._treeview_merges.set_model(liststore)
979
#         
980
#         self._treeview_merges.append_column(gtk.TreeViewColumn(_('Date'),
981
#                                             gtk.CellRendererText(), text=0))
982
#         self._treeview_merges.append_column(gtk.TreeViewColumn(_('Committer'),
983
#                                             gtk.CellRendererText(), text=1))
984
#         self._treeview_merges.append_column(gtk.TreeViewColumn(_('Summary'),
985
#                                             gtk.CellRendererText(), text=2))
986
#         
987
#         for item in self.pending:
988
#             liststore.append([ item['date'],
989
#                                item['committer'],
990
#                                item['summary'] ])
991
#     
992
# 
993
#     def _create_diff_view(self):
278.1.12 by John Arbash Meinel
Delay computing the delta, and clean up some of the diff view names.
994
#         from diff import DiffView
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
995
# 
278.1.12 by John Arbash Meinel
Delay computing the delta, and clean up some of the diff view names.
996
#         self._diff_display = DiffView()
278.1.5 by John Arbash Meinel
Starting to flesh out the dialog with actual windows.
997
#         self._diff_display.set_trees(self.wt, self.wt.basis_tree())
998
#         self._diff_display.show_diff(None)
999
#         self._diff_display.show()
1000
#         self._hpane.pack2(self._diff_display)
1001
# 
1002
#     def _get_specific_files(self):
1003
#         ret = []
1004
#         it = self._file_store.get_iter_first()
1005
#         while it:
1006
#             if self._file_store.get_value(it, 0):
1007
#                 # get real path from hidden column 3
1008
#                 ret.append(self._file_store.get_value(it, 3))
1009
#             it = self._file_store.iter_next(it)
1010
# 
1011
#         return ret
1012
#     
1013
#     def _toggle_commit(self, cell, path, model):
1014
#         model[path][0] = not model[path][0]
1015
#         return