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

  • Committer: Szilveszter Farkas (Phanatic)
  • Date: 2006-08-20 13:02:35 UTC
  • mto: (0.14.1 main) (93.1.1 win32.bialix)
  • mto: This revision was merged to the branch mainline in revision 83.
  • Revision ID: Szilveszter.Farkas@gmail.com-20060820130235-62c9c5753f5d8774
Gettext support added.

2006-08-20  Szilveszter Farkas <Szilveszter.Farkas@gmail.com>

    * po/hu.po: added Hungarian traslation
    * Added gettext support to all files.
    * genpot.sh: added olive-gtk.pot generator script

Show diffs side-by-side

added added

removed removed

Lines of Context:
14
14
# along with this program; if not, write to the Free Software
15
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
16
 
 
17
import sys
 
18
 
17
19
try:
18
20
    import pygtk
19
21
    pygtk.require("2.0")
20
22
except:
21
23
    pass
22
 
 
23
 
import gtk
24
 
import gtk.glade
25
 
import gobject
26
 
import pango
 
24
try:
 
25
    import gtk
 
26
    import gtk.glade
 
27
    import gobject
 
28
    import pango
 
29
except:
 
30
    sys.exit(1)
 
31
 
 
32
from bzrlib import version_info
 
33
 
 
34
if version_info < (0, 9):
 
35
    # function deprecated after 0.9
 
36
    from bzrlib.delta import compare_trees
27
37
 
28
38
import bzrlib.errors as errors
29
 
from bzrlib import osutils
30
 
 
31
 
from dialog import error_dialog, question_dialog
32
 
from guifiles import GLADEFILENAME
33
 
 
34
 
 
35
 
class CommitDialog:
 
39
from bzrlib.workingtree import WorkingTree
 
40
 
 
41
class OliveCommit:
36
42
    """ Display Commit dialog and perform the needed actions. """
37
 
    def __init__(self, wt, wtpath, notbranch):
38
 
        """ Initialize the Commit dialog.
39
 
        :param  wt:         bzr working tree object
40
 
        :param  wtpath:     path to working tree root
41
 
        :param  notbranch:  flag that path is not a brach
42
 
        :type   notbranch:  bool
43
 
        """
44
 
        self.glade = gtk.glade.XML(GLADEFILENAME, 'window_commit', 'olive-gtk')
45
 
        
46
 
        self.wt = wt
47
 
        self.wtpath = wtpath
48
 
        self.notbranch = notbranch
49
 
 
 
43
    def __init__(self, gladefile, comm, dialog):
 
44
        """ Initialize the Commit dialog. """
 
45
        self.gladefile = gladefile
 
46
        self.glade = gtk.glade.XML(self.gladefile, 'window_commit', 'olive-gtk')
 
47
        
 
48
        # Communication object
 
49
        self.comm = comm
 
50
        # Dialog object
 
51
        self.dialog = dialog
 
52
        
50
53
        # Get some important widgets
51
54
        self.window = self.glade.get_widget('window_commit')
52
55
        self.checkbutton_local = self.glade.get_widget('checkbutton_commit_local')
53
56
        self.textview = self.glade.get_widget('textview_commit')
54
 
        self.file_expander = self.glade.get_widget('expander_commit_select')
55
57
        self.file_view = self.glade.get_widget('treeview_commit_select')
56
 
        self.pending_expander = self.glade.get_widget('expander_commit_pending')
57
 
        self.pending_label = self.glade.get_widget('label_commit_pending')
58
 
        self.pending_view = self.glade.get_widget('treeview_commit_pending')
59
 
 
60
 
        if wt is None or notbranch:
 
58
 
 
59
        # Check if current location is a branch
 
60
        try:
 
61
            (self.wt, path) = WorkingTree.open_containing(self.comm.get_path())
 
62
            branch = self.wt.branch
 
63
        except errors.NotBranchError:
 
64
            self.notbranch = True
 
65
            return
 
66
        except:
 
67
            raise
 
68
 
 
69
        file_id = self.wt.path2id(path)
 
70
 
 
71
        self.notbranch = False
 
72
        if file_id is None:
 
73
            self.notbranch = True
61
74
            return
62
75
        
63
76
        # Set the delta
64
77
        self.old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
65
 
        self.delta = self.wt.changes_from(self.old_tree)
66
 
        
67
 
        # Get pending merges
68
 
        self.pending = self._pending_merges(self.wt)
 
78
        if version_info < (0, 9):
 
79
            self.delta = compare_trees(self.old_tree, self.wt)
 
80
        else:
 
81
            self.delta = self.wt.changes_from(self.old_tree)
69
82
        
70
83
        # Dictionary for signal_autoconnect
71
84
        dic = { "on_button_commit_commit_clicked": self.commit,
72
85
                "on_button_commit_cancel_clicked": self.close }
73
 
 
 
86
        
74
87
        # Connect the signals to the handlers
75
88
        self.glade.signal_autoconnect(dic)
76
89
        
77
90
        # Create the file list
78
91
        self._create_file_view()
79
 
        # Create the pending merges
80
 
        self._create_pending_merges()
81
92
    
82
93
    def display(self):
83
 
        """ Display the Push dialog.
84
 
        @return:    True if dialog is shown.
85
 
        """
86
 
        if self.wt is None and not self.notbranch:
87
 
            error_dialog(_('Directory does not have a working tree'),
88
 
                         _('Operation aborted.'))
89
 
            self.close()
90
 
            return False
 
94
        """ Display the Push dialog. """
91
95
        if self.notbranch:
92
 
            error_dialog(_('Directory is not a branch'),
93
 
                         _('You can perform this action only in a branch.'))
 
96
            self.dialog.error_dialog(_('Directory is not a branch'),
 
97
                                     _('You can perform this action only in a branch.'))
94
98
            self.close()
95
 
            return False
96
99
        else:
97
 
            if self.wt.branch.get_bound_location() is not None:
 
100
            from olive.backend.info import is_checkout
 
101
            if is_checkout(self.comm.get_path()):
98
102
                # we have a checkout, so the local commit checkbox must appear
99
103
                self.checkbutton_local.show()
100
104
            
101
 
            if self.pending:
102
 
                # There are pending merges, file selection not supported
103
 
                self.file_expander.set_expanded(False)
104
 
                self.file_view.set_sensitive(False)
105
 
            else:
106
 
                # No pending merges
107
 
                self.pending_expander.hide()
108
 
            
109
105
            self.textview.modify_font(pango.FontDescription("Monospace"))
110
106
            self.window.show()
111
 
            return True
 
107
            
112
108
    
 
109
    # This code is from Jelmer Vernooij's bzr-gtk branch
113
110
    def _create_file_view(self):
114
 
        self.file_store = gtk.ListStore(gobject.TYPE_BOOLEAN,   # [0] checkbox
115
 
                                        gobject.TYPE_STRING,    # [1] path to display
116
 
                                        gobject.TYPE_STRING,    # [2] changes type
117
 
                                        gobject.TYPE_STRING)    # [3] real path
 
111
        self.file_store = gtk.ListStore(gobject.TYPE_BOOLEAN,
 
112
                                        gobject.TYPE_STRING,
 
113
                                        gobject.TYPE_STRING)
118
114
        self.file_view.set_model(self.file_store)
119
115
        crt = gtk.CellRendererToggle()
120
116
        crt.set_property("activatable", True)
127
123
                                     gtk.CellRendererText(), text=2))
128
124
 
129
125
        for path, id, kind in self.delta.added:
130
 
            marker = osutils.kind_marker(kind)
131
 
            self.file_store.append([ True, path+marker, _('added'), path ])
 
126
            self.file_store.append([ True, path, _('added') ])
132
127
 
133
128
        for path, id, kind in self.delta.removed:
134
 
            marker = osutils.kind_marker(kind)
135
 
            self.file_store.append([ True, path+marker, _('removed'), path ])
 
129
            self.file_store.append([ True, path, _('removed') ])
136
130
 
137
131
        for oldpath, newpath, id, kind, text_modified, meta_modified in self.delta.renamed:
138
 
            marker = osutils.kind_marker(kind)
139
 
            if text_modified or meta_modified:
140
 
                changes = _('renamed and modified')
141
 
            else:
142
 
                changes = _('renamed')
143
 
            self.file_store.append([ True,
144
 
                                     oldpath+marker + '  =>  ' + newpath+marker,
145
 
                                     changes,
146
 
                                     newpath
147
 
                                   ])
 
132
            self.file_store.append([ True, oldpath, _('renamed') ])
148
133
 
149
134
        for path, id, kind, text_modified, meta_modified in self.delta.modified:
150
 
            marker = osutils.kind_marker(kind)
151
 
            self.file_store.append([ True, path+marker, _('modified'), path ])
152
 
    
153
 
    def _create_pending_merges(self):
154
 
        if not self.pending:
155
 
            # hide unused pending merge part
156
 
            scrolled_window = self.glade.get_widget('scrolledwindow_commit_pending')
157
 
            parent = scrolled_window.get_parent()
158
 
            parent.remove(scrolled_window)
159
 
            parent = self.pending_label.get_parent()
160
 
            parent.remove(self.pending_label)
161
 
            return
162
 
        
163
 
        liststore = gtk.ListStore(gobject.TYPE_STRING,
164
 
                                  gobject.TYPE_STRING,
165
 
                                  gobject.TYPE_STRING)
166
 
        self.pending_view.set_model(liststore)
167
 
        
168
 
        self.pending_view.append_column(gtk.TreeViewColumn(_('Date'),
169
 
                                        gtk.CellRendererText(), text=0))
170
 
        self.pending_view.append_column(gtk.TreeViewColumn(_('Committer'),
171
 
                                        gtk.CellRendererText(), text=1))
172
 
        self.pending_view.append_column(gtk.TreeViewColumn(_('Summary'),
173
 
                                        gtk.CellRendererText(), text=2))
174
 
        
175
 
        for item in self.pending:
176
 
            liststore.append([ item['date'],
177
 
                               item['committer'],
178
 
                               item['summary'] ])
 
135
            self.file_store.append([ True, path, _('modified') ])
179
136
    
180
137
    def _get_specific_files(self):
181
138
        ret = []
182
139
        it = self.file_store.get_iter_first()
183
140
        while it:
184
141
            if self.file_store.get_value(it, 0):
185
 
                # get real path from hidden column 3
186
 
                ret.append(self.file_store.get_value(it, 3))
 
142
                ret.append(self.file_store.get_value(it, 1))
187
143
            it = self.file_store.iter_next(it)
188
144
 
189
145
        return ret
 
146
    # end of bzr-gtk code
190
147
    
191
148
    def _toggle_commit(self, cell, path, model):
192
149
        model[path][0] = not model[path][0]
193
150
        return
194
151
    
195
 
    def _pending_merges(self, wt):
196
 
        """ Return a list of pending merges or None if there are none of them. """
197
 
        parents = wt.get_parent_ids()
198
 
        if len(parents) < 2:
199
 
            return None
200
 
        
201
 
        import re
202
 
        from bzrlib.osutils import format_date
203
 
        
204
 
        pending = parents[1:]
205
 
        branch = wt.branch
206
 
        last_revision = parents[0]
207
 
        
208
 
        if last_revision is not None:
209
 
            try:
210
 
                ignore = set(branch.repository.get_ancestry(last_revision))
211
 
            except errors.NoSuchRevision:
212
 
                # the last revision is a ghost : assume everything is new 
213
 
                # except for it
214
 
                ignore = set([None, last_revision])
215
 
        else:
216
 
            ignore = set([None])
217
 
        
218
 
        pm = []
219
 
        for merge in pending:
220
 
            ignore.add(merge)
221
 
            try:
222
 
                m_revision = branch.repository.get_revision(merge)
223
 
                
224
 
                rev = {}
225
 
                rev['committer'] = re.sub('<.*@.*>', '', m_revision.committer).strip(' ')
226
 
                rev['summary'] = m_revision.get_summary()
227
 
                rev['date'] = format_date(m_revision.timestamp,
228
 
                                          m_revision.timezone or 0, 
229
 
                                          'original', date_fmt="%Y-%m-%d",
230
 
                                          show_offset=False)
231
 
                
232
 
                pm.append(rev)
233
 
                
234
 
                inner_merges = branch.repository.get_ancestry(merge)
235
 
                assert inner_merges[0] is None
236
 
                inner_merges.pop(0)
237
 
                inner_merges.reverse()
238
 
                for mmerge in inner_merges:
239
 
                    if mmerge in ignore:
240
 
                        continue
241
 
                    mm_revision = branch.repository.get_revision(mmerge)
242
 
                    
243
 
                    rev = {}
244
 
                    rev['committer'] = re.sub('<.*@.*>', '', mm_revision.committer).strip(' ')
245
 
                    rev['summary'] = mm_revision.get_summary()
246
 
                    rev['date'] = format_date(mm_revision.timestamp,
247
 
                                              mm_revision.timezone or 0, 
248
 
                                              'original', date_fmt="%Y-%m-%d",
249
 
                                              show_offset=False)
250
 
                
251
 
                    pm.append(rev)
252
 
                    
253
 
                    ignore.add(mmerge)
254
 
            except errors.NoSuchRevision:
255
 
                print "DEBUG: NoSuchRevision:", merge
256
 
        
257
 
        return pm
258
 
 
259
152
    def commit(self, widget):
260
153
        textbuffer = self.textview.get_buffer()
261
154
        start, end = textbuffer.get_bounds()
262
 
        message = textbuffer.get_text(start, end).decode('utf-8')
 
155
        message = textbuffer.get_text(start, end)
263
156
        
264
157
        checkbutton_strict = self.glade.get_widget('checkbutton_commit_strict')
265
158
        checkbutton_force = self.glade.get_widget('checkbutton_commit_force')
266
159
        
267
 
        if not self.pending:
268
 
            specific_files = self._get_specific_files()
269
 
        else:
270
 
            specific_files = None
271
 
 
272
 
        if message == '':
273
 
            response = question_dialog('Commit with an empty message ?',
274
 
                                       'You can describe your commit intent'
275
 
                                       +' in the message')
276
 
            if response == gtk.RESPONSE_NO:
277
 
                # Kindly give focus to message area
278
 
                self.textview.grab_focus()
279
 
                return
280
 
 
 
160
        specific_files = self._get_specific_files()
 
161
        
 
162
        self.comm.set_busy(self.window)
 
163
        # merged from Jelmer Vernooij's olive integration branch
281
164
        try:
282
 
            self.wt.commit(message,
 
165
            self.wt.commit(message, 
283
166
                           allow_pointless=checkbutton_force.get_active(),
284
167
                           strict=checkbutton_strict.get_active(),
285
168
                           local=self.checkbutton_local.get_active(),
286
169
                           specific_files=specific_files)
287
170
        except errors.NotBranchError:
288
 
            error_dialog(_('Directory is not a branch'),
289
 
                         _('You can perform this action only in a branch.'))
 
171
            self.dialog.error_dialog(_('Directory is not a branch'),
 
172
                                     _('You can perform this action only in a branch.'))
 
173
            self.comm.set_busy(self.window, False)
290
174
            return
291
175
        except errors.LocalRequiresBoundBranch:
292
 
            error_dialog(_('Directory is not a checkout'),
293
 
                         _('You can perform local commit only on checkouts.'))
 
176
            self.dialog.error_dialog(_('Directory is not a checkout'),
 
177
                                     _('You can perform local commit only on checkouts.'))
 
178
            self.comm.set_busy(self.window, False)
294
179
            return
295
180
        except errors.PointlessCommit:
296
 
            error_dialog(_('No changes to commit'),
297
 
                         _('Try force commit if you want to commit anyway.'))
 
181
            self.dialog.error_dialog(_('No changes to commit'),
 
182
                                     _('Try force commit if you want to commit anyway.'))
 
183
            self.comm.set_busy(self.window, False)
298
184
            return
299
185
        except errors.ConflictsInTree:
300
 
            error_dialog(_('Conflicts in tree'),
301
 
                         _('You need to resolve the conflicts before committing.'))
 
186
            self.dialog.error_dialog(_('Conflicts in tree'),
 
187
                                     _('You need to resolve the conflicts before committing.'))
 
188
            self.comm.set_busy(self.window, False)
302
189
            return
303
190
        except errors.StrictCommitFailed:
304
 
            error_dialog(_('Strict commit failed'),
305
 
                         _('There are unknown files in the working tree.\nPlease add or delete them.'))
 
191
            self.dialog.error_dialog(_('Strict commit failed'),
 
192
                                     _('There are unknown files in the working tree.\nPlease add or delete them.'))
 
193
            self.comm.set_busy(self.window, False)
306
194
            return
307
195
        except errors.BoundBranchOutOfDate, errmsg:
308
 
            error_dialog(_('Bound branch is out of date'),
309
 
                         _('%s') % errmsg)
310
 
            return
311
 
        except errors.BzrError, msg:
312
 
            error_dialog(_('Unknown bzr error'), str(msg))
313
 
            return
314
 
        except Exception, msg:
315
 
            error_dialog(_('Unknown error'), str(msg))
316
 
            return
317
 
 
 
196
            self.dialog.error_dialog(_('Bound branch is out of date'),
 
197
                                     _('%s') % errmsg)
 
198
            self.comm.set_busy(self.window, False)
 
199
            return
 
200
        except:
 
201
            raise
 
202
        
318
203
        self.close()
319
 
 
 
204
        self.comm.refresh_right()
 
205
        
320
206
    def close(self, widget=None):
321
207
        self.window.destroy()
322
 
 
323
 
class CommitDialogNew(gtk.Dialog):
324
 
    """ New implementation of the Commit dialog. """
325
 
    def __init__(self, wt, wtpath, notbranch, selected=None, parent=None):
326
 
        """ Initialize the Commit Dialog. """
327
 
        gtk.Dialog.__init__(self, title="Commit - Olive",
328
 
                                  parent=parent,
329
 
                                  flags=0,
330
 
                                  buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
331
 
        
332
 
        # Get arguments
333
 
        self.wt = wt
334
 
        self.wtpath = wtpath
335
 
        self.notbranch = notbranch
336
 
        self.selected = selected
337
 
        
338
 
        # Set the delta
339
 
        self.old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
340
 
        self.delta = self.wt.changes_from(self.old_tree)
341
 
        
342
 
        # Get pending merges
343
 
        self.pending = self._pending_merges(self.wt)
344
 
        
345
 
        # Do some preliminary checks
346
 
        self._is_checkout = False
347
 
        self._is_pending = False
348
 
        if self.wt is None and not self.notbranch:
349
 
            error_dialog(_('Directory does not have a working tree'),
350
 
                         _('Operation aborted.'))
351
 
            self.close()
352
 
            return
353
 
 
354
 
        if self.notbranch:
355
 
            error_dialog(_('Directory is not a branch'),
356
 
                         _('You can perform this action only in a branch.'))
357
 
            self.close()
358
 
            return
359
 
        else:
360
 
            if self.wt.branch.get_bound_location() is not None:
361
 
                # we have a checkout, so the local commit checkbox must appear
362
 
                self._is_checkout = True
363
 
            
364
 
            if self.pending:
365
 
                # There are pending merges, file selection not supported
366
 
                self._is_pending = True
367
 
        
368
 
        # Create the widgets
369
 
        self._button_commit = gtk.Button(_("Comm_it"), use_underline=True)
370
 
        if self._is_checkout:
371
 
            self._check_local = gtk.CheckButton(_("_Local only commit (works in checkouts)"),
372
 
                                                use_underline=True)
373
 
        self._check_strict = gtk.CheckButton(_("_Strict commit (fails if unknown files are present)"),
374
 
                                             use_underline=True)
375
 
        self._expander_files = gtk.Expander(_("Please select the file(s) to commit"))
376
 
        self._vpaned_main = gtk.VPaned()
377
 
        self._scrolledwindow_files = gtk.ScrolledWindow()
378
 
        self._scrolledwindow_message = gtk.ScrolledWindow()
379
 
        self._treeview_files = gtk.TreeView()
380
 
        self._vbox_message = gtk.VBox()
381
 
        self._label_message = gtk.Label(_("Please specify a commit message:"))
382
 
        self._textview_message = gtk.TextView()
383
 
        
384
 
        if self._is_pending:
385
 
            self._expander_merges = gtk.Expander(_("Pending merges"))
386
 
            self._vpaned_list = gtk.VPaned()
387
 
            self._scrolledwindow_merges = gtk.ScrolledWindow()
388
 
            self._treeview_merges = gtk.TreeView()
389
 
 
390
 
        # Set callbacks
391
 
        self._button_commit.connect('clicked', self._on_commit_clicked)
392
 
        self._treeview_files.connect('row_activated', self._on_treeview_files_row_activated)
393
 
        
394
 
        # Set properties
395
 
        self._scrolledwindow_files.set_policy(gtk.POLICY_AUTOMATIC,
396
 
                                              gtk.POLICY_AUTOMATIC)
397
 
        self._scrolledwindow_message.set_policy(gtk.POLICY_AUTOMATIC,
398
 
                                                gtk.POLICY_AUTOMATIC)
399
 
        self._textview_message.modify_font(pango.FontDescription("Monospace"))
400
 
        self.set_default_size(500, 500)
401
 
        self._vpaned_main.set_position(200)
402
 
 
403
 
        if self._is_pending:
404
 
            self._scrolledwindow_merges.set_policy(gtk.POLICY_AUTOMATIC,
405
 
                                                   gtk.POLICY_AUTOMATIC)
406
 
            self._treeview_files.set_sensitive(False)
407
 
        
408
 
        # Construct the dialog
409
 
        self.action_area.pack_end(self._button_commit)
410
 
        
411
 
        self._scrolledwindow_files.add(self._treeview_files)
412
 
        self._scrolledwindow_message.add(self._textview_message)
413
 
        
414
 
        self._expander_files.add(self._scrolledwindow_files)
415
 
        
416
 
        self._vbox_message.pack_start(self._label_message, False, False)
417
 
        self._vbox_message.pack_start(self._scrolledwindow_message, True, True)
418
 
        
419
 
        if self._is_pending:        
420
 
            self._expander_merges.add(self._scrolledwindow_merges)
421
 
            self._scrolledwindow_merges.add(self._treeview_merges)
422
 
            self._vpaned_list.add1(self._expander_files)
423
 
            self._vpaned_list.add2(self._expander_merges)
424
 
            self._vpaned_main.add1(self._vpaned_list)
425
 
        else:
426
 
            self._vpaned_main.add1(self._expander_files)
427
 
 
428
 
        self._vpaned_main.add2(self._vbox_message)
429
 
        
430
 
        self.vbox.pack_start(self._vpaned_main, True, True)
431
 
        if self._is_checkout:
432
 
            self.vbox.pack_start(self._check_local, False, False)
433
 
        self.vbox.pack_start(self._check_strict, False, False)
434
 
        
435
 
        # Create the file list
436
 
        self._create_file_view()
437
 
        # Create the pending merges
438
 
        self._create_pending_merges()
439
 
        
440
 
        # Expand the corresponding expander
441
 
        if self._is_pending:
442
 
            self._expander_merges.set_expanded(True)
443
 
        else:
444
 
            self._expander_files.set_expanded(True)
445
 
        
446
 
        # Display dialog
447
 
        self.vbox.show_all()
448
 
    
449
 
    def _on_treeview_files_row_activated(self, treeview, path, view_column):
450
 
        # FIXME: the diff window freezes for some reason
451
 
        treeselection = treeview.get_selection()
452
 
        (model, iter) = treeselection.get_selected()
453
 
        
454
 
        if iter is not None:
455
 
            from olive import DiffWindow
456
 
            
457
 
            _selected = model.get_value(iter, 1)
458
 
            
459
 
            diff = DiffWindow()
460
 
            parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
461
 
            diff.set_diff(self.wt.branch.nick, self.wt, parent_tree)
462
 
            try:
463
 
                diff.set_file(_selected)
464
 
            except errors.NoSuchFile:
465
 
                pass
466
 
            diff.show()
467
 
    
468
 
    def _on_commit_clicked(self, button):
469
 
        """ Commit button clicked handler. """
470
 
        textbuffer = self._textview_message.get_buffer()
471
 
        start, end = textbuffer.get_bounds()
472
 
        message = textbuffer.get_text(start, end).decode('utf-8')
473
 
        
474
 
        if not self.pending:
475
 
            specific_files = self._get_specific_files()
476
 
        else:
477
 
            specific_files = None
478
 
 
479
 
        if message == '':
480
 
            response = question_dialog(_('Commit with an empty message?'),
481
 
                                       _('You can describe your commit intent in the message.'))
482
 
            if response == gtk.RESPONSE_NO:
483
 
                # Kindly give focus to message area
484
 
                self._textview_message.grab_focus()
485
 
                return
486
 
 
487
 
        if self._is_checkout:
488
 
            local = self._check_local.get_active()
489
 
        else:
490
 
            local = False
491
 
        
492
 
        try:
493
 
            self.wt.commit(message,
494
 
                           allow_pointless=False,
495
 
                           strict=self._check_strict.get_active(),
496
 
                           local=local,
497
 
                           specific_files=specific_files)
498
 
        except errors.NotBranchError:
499
 
            error_dialog(_('Directory is not a branch'),
500
 
                         _('You can perform this action only in a branch.'))
501
 
            return
502
 
        except errors.LocalRequiresBoundBranch:
503
 
            error_dialog(_('Directory is not a checkout'),
504
 
                         _('You can perform local commit only on checkouts.'))
505
 
            return
506
 
        except errors.ConflictsInTree:
507
 
            error_dialog(_('Conflicts in tree'),
508
 
                         _('You need to resolve the conflicts before committing.'))
509
 
            return
510
 
        except errors.StrictCommitFailed:
511
 
            error_dialog(_('Strict commit failed'),
512
 
                         _('There are unknown files in the working tree.\nPlease add or delete them.'))
513
 
            return
514
 
        except errors.BoundBranchOutOfDate, errmsg:
515
 
            error_dialog(_('Bound branch is out of date'),
516
 
                         _('%s') % errmsg)
517
 
            return
518
 
        except errors.PointlessCommit:
519
 
            response = question_dialog(_('Commit with no changes?'),
520
 
                                       _('There are no changes in the working tree.'))
521
 
            if response == gtk.RESPONSE_YES:
522
 
                # Try to commit again
523
 
                try:
524
 
                    self.wt.commit(message,
525
 
                                   allow_pointless=True,
526
 
                                   strict=self._check_strict.get_active(),
527
 
                                   local=local,
528
 
                                   specific_files=specific_files)
529
 
                except errors.BzrError, msg:
530
 
                    error_dialog(_('Unknown bzr error'), str(msg))
531
 
                    return
532
 
                except Exception, msg:
533
 
                    error_dialog(_('Unknown error'), str(msg))
534
 
                    return
535
 
        except errors.BzrError, msg:
536
 
            error_dialog(_('Unknown bzr error'), str(msg))
537
 
            return
538
 
        except Exception, msg:
539
 
            error_dialog(_('Unknown error'), str(msg))
540
 
            return
541
 
        
542
 
        self.response(gtk.RESPONSE_OK)
543
 
 
544
 
    def _pending_merges(self, wt):
545
 
        """ Return a list of pending merges or None if there are none of them. """
546
 
        parents = wt.get_parent_ids()
547
 
        if len(parents) < 2:
548
 
            return None
549
 
        
550
 
        import re
551
 
        from bzrlib.osutils import format_date
552
 
        
553
 
        pending = parents[1:]
554
 
        branch = wt.branch
555
 
        last_revision = parents[0]
556
 
        
557
 
        if last_revision is not None:
558
 
            try:
559
 
                ignore = set(branch.repository.get_ancestry(last_revision))
560
 
            except errors.NoSuchRevision:
561
 
                # the last revision is a ghost : assume everything is new 
562
 
                # except for it
563
 
                ignore = set([None, last_revision])
564
 
        else:
565
 
            ignore = set([None])
566
 
        
567
 
        pm = []
568
 
        for merge in pending:
569
 
            ignore.add(merge)
570
 
            try:
571
 
                m_revision = branch.repository.get_revision(merge)
572
 
                
573
 
                rev = {}
574
 
                rev['committer'] = re.sub('<.*@.*>', '', m_revision.committer).strip(' ')
575
 
                rev['summary'] = m_revision.get_summary()
576
 
                rev['date'] = format_date(m_revision.timestamp,
577
 
                                          m_revision.timezone or 0, 
578
 
                                          'original', date_fmt="%Y-%m-%d",
579
 
                                          show_offset=False)
580
 
                
581
 
                pm.append(rev)
582
 
                
583
 
                inner_merges = branch.repository.get_ancestry(merge)
584
 
                assert inner_merges[0] is None
585
 
                inner_merges.pop(0)
586
 
                inner_merges.reverse()
587
 
                for mmerge in inner_merges:
588
 
                    if mmerge in ignore:
589
 
                        continue
590
 
                    mm_revision = branch.repository.get_revision(mmerge)
591
 
                    
592
 
                    rev = {}
593
 
                    rev['committer'] = re.sub('<.*@.*>', '', mm_revision.committer).strip(' ')
594
 
                    rev['summary'] = mm_revision.get_summary()
595
 
                    rev['date'] = format_date(mm_revision.timestamp,
596
 
                                              mm_revision.timezone or 0, 
597
 
                                              'original', date_fmt="%Y-%m-%d",
598
 
                                              show_offset=False)
599
 
                
600
 
                    pm.append(rev)
601
 
                    
602
 
                    ignore.add(mmerge)
603
 
            except errors.NoSuchRevision:
604
 
                print "DEBUG: NoSuchRevision:", merge
605
 
        
606
 
        return pm
607
 
 
608
 
    def _create_file_view(self):
609
 
        self._file_store = gtk.ListStore(gobject.TYPE_BOOLEAN,   # [0] checkbox
610
 
                                         gobject.TYPE_STRING,    # [1] path to display
611
 
                                         gobject.TYPE_STRING,    # [2] changes type
612
 
                                         gobject.TYPE_STRING)    # [3] real path
613
 
        self._treeview_files.set_model(self._file_store)
614
 
        crt = gtk.CellRendererToggle()
615
 
        crt.set_property("activatable", True)
616
 
        crt.connect("toggled", self._toggle_commit, self._file_store)
617
 
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Commit'),
618
 
                                     crt, active=0))
619
 
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Path'),
620
 
                                     gtk.CellRendererText(), text=1))
621
 
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Type'),
622
 
                                     gtk.CellRendererText(), text=2))
623
 
 
624
 
        for path, id, kind in self.delta.added:
625
 
            marker = osutils.kind_marker(kind)
626
 
            self._file_store.append([ True, path+marker, _('added'), path ])
627
 
 
628
 
        for path, id, kind in self.delta.removed:
629
 
            marker = osutils.kind_marker(kind)
630
 
            self._file_store.append([ True, path+marker, _('removed'), path ])
631
 
 
632
 
        for oldpath, newpath, id, kind, text_modified, meta_modified in self.delta.renamed:
633
 
            marker = osutils.kind_marker(kind)
634
 
            if text_modified or meta_modified:
635
 
                changes = _('renamed and modified')
636
 
            else:
637
 
                changes = _('renamed')
638
 
            self._file_store.append([ True,
639
 
                                      oldpath+marker + '  =>  ' + newpath+marker,
640
 
                                      changes,
641
 
                                      newpath
642
 
                                    ])
643
 
 
644
 
        for path, id, kind, text_modified, meta_modified in self.delta.modified:
645
 
            marker = osutils.kind_marker(kind)
646
 
            self._file_store.append([ True, path+marker, _('modified'), path ])
647
 
    
648
 
    def _create_pending_merges(self):
649
 
        if not self.pending:
650
 
            return
651
 
        
652
 
        liststore = gtk.ListStore(gobject.TYPE_STRING,
653
 
                                  gobject.TYPE_STRING,
654
 
                                  gobject.TYPE_STRING)
655
 
        self._treeview_merges.set_model(liststore)
656
 
        
657
 
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Date'),
658
 
                                            gtk.CellRendererText(), text=0))
659
 
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Committer'),
660
 
                                            gtk.CellRendererText(), text=1))
661
 
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Summary'),
662
 
                                            gtk.CellRendererText(), text=2))
663
 
        
664
 
        for item in self.pending:
665
 
            liststore.append([ item['date'],
666
 
                               item['committer'],
667
 
                               item['summary'] ])
668
 
    
669
 
    def _get_specific_files(self):
670
 
        ret = []
671
 
        it = self._file_store.get_iter_first()
672
 
        while it:
673
 
            if self._file_store.get_value(it, 0):
674
 
                # get real path from hidden column 3
675
 
                ret.append(self._file_store.get_value(it, 3))
676
 
            it = self._file_store.iter_next(it)
677
 
 
678
 
        return ret
679
 
    
680
 
    def _toggle_commit(self, cell, path, model):
681
 
        model[path][0] = not model[path][0]
682
 
        return