/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz

« back to all changes in this revision

Viewing changes to commit.py

  • Committer: John Arbash Meinel
  • Date: 2007-10-02 23:08:12 UTC
  • mto: (322.1.1 trunk) (330.3.3 trunk)
  • mto: This revision was merged to the branch mainline in revision 368.
  • Revision ID: john@arbash-meinel.com-20071002230812-h8i6pq8fwvodute4
Start testing with Unicode data.
It seems there is some brokenness with serializing Unicode messages.
But otherwise everything seems to be working.

Show diffs side-by-side

added added

removed removed

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