/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: Jelmer Vernooij
  • Date: 2007-03-09 17:47:28 UTC
  • Revision ID: jelmer@samba.org-20070309174728-gljlmt9b7fu0rrn9
Add simple test for tortoise_bzr

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
# Copyright (C) 2006 by Szilveszter Farkas (Phanatic) <szilveszter.farkas@gmail.com>
2
 
 
 
2
#
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
5
5
# the Free Software Foundation; either version 2 of the License, or
6
6
# (at your option) any later version.
7
 
 
 
7
#
8
8
# This program is distributed in the hope that it will be useful,
9
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
# GNU General Public License for more details.
12
 
 
 
12
#
13
13
# You should have received a copy of the GNU General Public License
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
 
 
19
17
try:
20
18
    import pygtk
21
19
    pygtk.require("2.0")
22
20
except:
23
21
    pass
24
 
try:
25
 
    import gtk
26
 
    import gtk.glade
27
 
    import gobject
28
 
except:
29
 
    sys.exit(1)
30
 
 
31
 
from bzrlib.delta import compare_trees
 
22
 
 
23
import gtk
 
24
import gobject
 
25
import pango
 
26
 
 
27
import os.path
 
28
 
32
29
import bzrlib.errors as errors
33
 
from bzrlib.workingtree import WorkingTree
34
 
 
35
 
from dialog import OliveDialog
36
 
 
37
 
class OliveCommit:
38
 
    """ Display Commit dialog and perform the needed actions. """
39
 
    def __init__(self, gladefile, comm):
40
 
        """ Initialize the Commit dialog. """
41
 
        import bzrlib
42
 
        
43
 
        self.gladefile = gladefile
44
 
        self.glade = gtk.glade.XML(self.gladefile, 'window_commit')
45
 
        
46
 
        self.comm = comm
47
 
        
48
 
        self.dialog = OliveDialog(self.gladefile)
49
 
        
50
 
        # Check if current location is a branch
51
 
        try:
52
 
            (self.wt, path) = WorkingTree.open_containing(self.comm.get_path())
53
 
            branch = self.wt.branch
54
 
        except errors.NotBranchError:
55
 
            self.notbranch = True
56
 
            return
57
 
        except:
58
 
            raise
59
 
 
60
 
        file_id = self.wt.path2id(path)
61
 
 
62
 
        self.notbranch = False
63
 
        if file_id is None:
64
 
            self.notbranch = True
65
 
            return
 
30
from bzrlib import osutils
 
31
 
 
32
from dialog import error_dialog, question_dialog
 
33
from errors import show_bzr_error
 
34
 
 
35
try:
 
36
    import dbus
 
37
    import dbus.glib
 
38
    bus = dbus.SystemBus()
 
39
    proxy_obj = bus.get_object('org.freedesktop.NetworkManager', 
 
40
                              '/org/freedesktop/NetworkManager')
 
41
    dbus_iface = dbus.Interface(proxy_obj, 'org.freedesktop.NetworkManager')
 
42
    have_nm = True
 
43
except ImportError:
 
44
    have_nm = False
 
45
 
 
46
class CommitDialog(gtk.Dialog):
 
47
    """ New implementation of the Commit dialog. """
 
48
    def __init__(self, wt, wtpath, notbranch, selected=None, parent=None):
 
49
        """ Initialize the Commit Dialog. """
 
50
        gtk.Dialog.__init__(self, title="Commit - Olive",
 
51
                                  parent=parent,
 
52
                                  flags=0,
 
53
                                  buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
 
54
        
 
55
        # Get arguments
 
56
        self.wt = wt
 
57
        self.wtpath = wtpath
 
58
        self.notbranch = notbranch
 
59
        self.selected = selected
66
60
        
67
61
        # Set the delta
68
62
        self.old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
69
 
        if bzrlib.version_info[1] < 9:
70
 
            self.delta = compare_trees(self.old_tree, self.wt)
71
 
        else:
72
 
            self.delta = self.wt.changes_from(self.old_tree)
73
 
        
74
 
        # Get the Commit dialog widget
75
 
        self.window = self.glade.get_widget('window_commit')
76
 
        
77
 
        # Dictionary for signal_autoconnect
78
 
        dic = { "on_button_commit_commit_clicked": self.commit,
79
 
                "on_button_commit_cancel_clicked": self.close }
80
 
        
81
 
        # Connect the signals to the handlers
82
 
        self.glade.signal_autoconnect(dic)
 
63
        self.delta = self.wt.changes_from(self.old_tree)
 
64
        
 
65
        # Get pending merges
 
66
        self.pending = self._pending_merges(self.wt)
 
67
        
 
68
        # Do some preliminary checks
 
69
        self._is_checkout = False
 
70
        self._is_pending = False
 
71
        if self.wt is None and not self.notbranch:
 
72
            error_dialog(_('Directory does not have a working tree'),
 
73
                         _('Operation aborted.'))
 
74
            self.close()
 
75
            return
 
76
 
 
77
        if self.notbranch:
 
78
            error_dialog(_('Directory is not a branch'),
 
79
                         _('You can perform this action only in a branch.'))
 
80
            self.close()
 
81
            return
 
82
        else:
 
83
            if self.wt.branch.get_bound_location() is not None:
 
84
                # we have a checkout, so the local commit checkbox must appear
 
85
                self._is_checkout = True
 
86
            
 
87
            if self.pending:
 
88
                # There are pending merges, file selection not supported
 
89
                self._is_pending = True
 
90
        
 
91
        # Create the widgets
 
92
        self._button_commit = gtk.Button(_("Comm_it"), use_underline=True)
 
93
        self._check_strict = gtk.CheckButton(_("_Allow unknown files"),
 
94
                                             use_underline=True)
 
95
        self._expander_files = gtk.Expander(_("File(s) to commit"))
 
96
        self._vpaned_main = gtk.VPaned()
 
97
        self._scrolledwindow_files = gtk.ScrolledWindow()
 
98
        self._scrolledwindow_message = gtk.ScrolledWindow()
 
99
        self._treeview_files = gtk.TreeView()
 
100
        self._vbox_message = gtk.VBox()
 
101
        self._label_message = gtk.Label(_("Commit message:"))
 
102
        self._textview_message = gtk.TextView()
 
103
        
 
104
        if self._is_pending:
 
105
            self._expander_merges = gtk.Expander(_("Pending merges"))
 
106
            self._vpaned_list = gtk.VPaned()
 
107
            self._scrolledwindow_merges = gtk.ScrolledWindow()
 
108
            self._treeview_merges = gtk.TreeView()
 
109
 
 
110
        # Set callbacks
 
111
        self._button_commit.connect('clicked', self._on_commit_clicked)
 
112
        self._treeview_files.connect('row_activated', self._on_treeview_files_row_activated)
 
113
        
 
114
        # Set properties
 
115
        self._scrolledwindow_files.set_policy(gtk.POLICY_AUTOMATIC,
 
116
                                              gtk.POLICY_AUTOMATIC)
 
117
        self._scrolledwindow_message.set_policy(gtk.POLICY_AUTOMATIC,
 
118
                                                gtk.POLICY_AUTOMATIC)
 
119
        self._textview_message.modify_font(pango.FontDescription("Monospace"))
 
120
        self.set_default_size(500, 500)
 
121
        self._vpaned_main.set_position(200)
 
122
        self._button_commit.set_flags(gtk.CAN_DEFAULT)
 
123
 
 
124
        if self._is_pending:
 
125
            self._scrolledwindow_merges.set_policy(gtk.POLICY_AUTOMATIC,
 
126
                                                   gtk.POLICY_AUTOMATIC)
 
127
            self._treeview_files.set_sensitive(False)
 
128
        
 
129
        # Construct the dialog
 
130
        self.action_area.pack_end(self._button_commit)
 
131
        
 
132
        self._scrolledwindow_files.add(self._treeview_files)
 
133
        self._scrolledwindow_message.add(self._textview_message)
 
134
        
 
135
        self._expander_files.add(self._scrolledwindow_files)
 
136
        
 
137
        self._vbox_message.pack_start(self._label_message, False, False)
 
138
        self._vbox_message.pack_start(self._scrolledwindow_message, True, True)
 
139
        
 
140
        if self._is_pending:        
 
141
            self._expander_merges.add(self._scrolledwindow_merges)
 
142
            self._scrolledwindow_merges.add(self._treeview_merges)
 
143
            self._vpaned_list.add1(self._expander_files)
 
144
            self._vpaned_list.add2(self._expander_merges)
 
145
            self._vpaned_main.add1(self._vpaned_list)
 
146
        else:
 
147
            self._vpaned_main.add1(self._expander_files)
 
148
 
 
149
        self._vpaned_main.add2(self._vbox_message)
 
150
        
 
151
        self.vbox.pack_start(self._vpaned_main, True, True)
 
152
        if self._is_checkout: 
 
153
            self._check_local = gtk.CheckButton(_("_Only commit locally"),
 
154
                                                use_underline=True)
 
155
            self.vbox.pack_start(self._check_local, False, False)
 
156
            if have_nm:
 
157
                # 3 is the enum value for STATE_CONNECTED
 
158
                self._check_local.set_active(dbus_iface.state() != 3)
 
159
        self.vbox.pack_start(self._check_strict, False, False)
83
160
        
84
161
        # Create the file list
85
162
        self._create_file_view()
86
 
        
87
 
        # Some additional widgets
88
 
        self.checkbutton_local = self.glade.get_widget('checkbutton_commit_local')
89
 
    
90
 
    def display(self):
91
 
        """ Display the Push dialog. """
92
 
        if self.notbranch:
93
 
            self.dialog.error_dialog('Directory is not a branch.')
94
 
        else:
95
 
            from olive.backend.info import is_checkout
96
 
            if is_checkout(self.comm.get_path()):
97
 
                # we have a checkout, so the local commit checkbox must appear
98
 
                self.checkbutton_local.show()
99
 
            
100
 
            self.window.show()
101
 
            
102
 
    
103
 
    # This code is from Jelmer Vernooij's bzr-gtk branch
 
163
        # Create the pending merges
 
164
        self._create_pending_merges()
 
165
        
 
166
        # Expand the corresponding expander
 
167
        if self._is_pending:
 
168
            self._expander_merges.set_expanded(True)
 
169
        else:
 
170
            self._expander_files.set_expanded(True)
 
171
        
 
172
        # Display dialog
 
173
        self.vbox.show_all()
 
174
        
 
175
        # Default to Commit button
 
176
        self._button_commit.grab_default()
 
177
    
 
178
    def _on_treeview_files_row_activated(self, treeview, path, view_column):
 
179
        # FIXME: the diff window freezes for some reason
 
180
        treeselection = treeview.get_selection()
 
181
        (model, iter) = treeselection.get_selected()
 
182
        
 
183
        if iter is not None:
 
184
            from diff import DiffWindow
 
185
            
 
186
            _selected = model.get_value(iter, 1)
 
187
            
 
188
            diff = DiffWindow()
 
189
            diff.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
 
190
            diff.set_modal(True)
 
191
            parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
 
192
            diff.set_diff(self.wt.branch.nick, self.wt, parent_tree)
 
193
            try:
 
194
                diff.set_file(_selected)
 
195
            except errors.NoSuchFile:
 
196
                pass
 
197
            diff.show()
 
198
    
 
199
    @show_bzr_error
 
200
    def _on_commit_clicked(self, button):
 
201
        """ Commit button clicked handler. """
 
202
        textbuffer = self._textview_message.get_buffer()
 
203
        start, end = textbuffer.get_bounds()
 
204
        message = textbuffer.get_text(start, end).decode('utf-8')
 
205
        
 
206
        if not self.pending:
 
207
            specific_files = self._get_specific_files()
 
208
        else:
 
209
            specific_files = None
 
210
 
 
211
        if message == '':
 
212
            response = question_dialog(_('Commit with an empty message?'),
 
213
                                       _('You can describe your commit intent in the message.'))
 
214
            if response == gtk.RESPONSE_NO:
 
215
                # Kindly give focus to message area
 
216
                self._textview_message.grab_focus()
 
217
                return
 
218
 
 
219
        if self._is_checkout:
 
220
            local = self._check_local.get_active()
 
221
        else:
 
222
            local = False
 
223
        
 
224
        try:
 
225
            self.wt.commit(message,
 
226
                       allow_pointless=False,
 
227
                       strict=self._check_strict.get_active(),
 
228
                       local=local,
 
229
                       specific_files=specific_files)
 
230
        except errors.PointlessCommit:
 
231
            response = question_dialog(_('Commit with no changes?'),
 
232
                                       _('There are no changes in the working tree.'))
 
233
            if response == gtk.RESPONSE_YES:
 
234
                self.wt.commit(message,
 
235
                               allow_pointless=True,
 
236
                               strict=self._check_strict.get_active(),
 
237
                               local=local,
 
238
                               specific_files=specific_files)
 
239
        self.response(gtk.RESPONSE_OK)
 
240
 
 
241
    def _pending_merges(self, wt):
 
242
        """ Return a list of pending merges or None if there are none of them. """
 
243
        parents = wt.get_parent_ids()
 
244
        if len(parents) < 2:
 
245
            return None
 
246
        
 
247
        import re
 
248
        from bzrlib.osutils import format_date
 
249
        
 
250
        pending = parents[1:]
 
251
        branch = wt.branch
 
252
        last_revision = parents[0]
 
253
        
 
254
        if last_revision is not None:
 
255
            try:
 
256
                ignore = set(branch.repository.get_ancestry(last_revision))
 
257
            except errors.NoSuchRevision:
 
258
                # the last revision is a ghost : assume everything is new 
 
259
                # except for it
 
260
                ignore = set([None, last_revision])
 
261
        else:
 
262
            ignore = set([None])
 
263
        
 
264
        pm = []
 
265
        for merge in pending:
 
266
            ignore.add(merge)
 
267
            try:
 
268
                m_revision = branch.repository.get_revision(merge)
 
269
                
 
270
                rev = {}
 
271
                rev['committer'] = re.sub('<.*@.*>', '', m_revision.committer).strip(' ')
 
272
                rev['summary'] = m_revision.get_summary()
 
273
                rev['date'] = format_date(m_revision.timestamp,
 
274
                                          m_revision.timezone or 0, 
 
275
                                          'original', date_fmt="%Y-%m-%d",
 
276
                                          show_offset=False)
 
277
                
 
278
                pm.append(rev)
 
279
                
 
280
                inner_merges = branch.repository.get_ancestry(merge)
 
281
                assert inner_merges[0] is None
 
282
                inner_merges.pop(0)
 
283
                inner_merges.reverse()
 
284
                for mmerge in inner_merges:
 
285
                    if mmerge in ignore:
 
286
                        continue
 
287
                    mm_revision = branch.repository.get_revision(mmerge)
 
288
                    
 
289
                    rev = {}
 
290
                    rev['committer'] = re.sub('<.*@.*>', '', mm_revision.committer).strip(' ')
 
291
                    rev['summary'] = mm_revision.get_summary()
 
292
                    rev['date'] = format_date(mm_revision.timestamp,
 
293
                                              mm_revision.timezone or 0, 
 
294
                                              'original', date_fmt="%Y-%m-%d",
 
295
                                              show_offset=False)
 
296
                
 
297
                    pm.append(rev)
 
298
                    
 
299
                    ignore.add(mmerge)
 
300
            except errors.NoSuchRevision:
 
301
                print "DEBUG: NoSuchRevision:", merge
 
302
        
 
303
        return pm
 
304
 
104
305
    def _create_file_view(self):
105
 
        self.file_store = gtk.ListStore(gobject.TYPE_BOOLEAN,
106
 
                                        gobject.TYPE_STRING,
107
 
                                        gobject.TYPE_STRING)
108
 
        self.file_view = self.glade.get_widget('treeview_commit_select')
109
 
        self.file_view.set_model(self.file_store)
 
306
        self._file_store = gtk.ListStore(gobject.TYPE_BOOLEAN,   # [0] checkbox
 
307
                                         gobject.TYPE_STRING,    # [1] path to display
 
308
                                         gobject.TYPE_STRING,    # [2] changes type
 
309
                                         gobject.TYPE_STRING)    # [3] real path
 
310
        self._treeview_files.set_model(self._file_store)
110
311
        crt = gtk.CellRendererToggle()
111
312
        crt.set_property("activatable", True)
112
 
        crt.connect("toggled", self._toggle_commit, self.file_store)
113
 
        self.file_view.append_column(gtk.TreeViewColumn("Commit",
 
313
        crt.connect("toggled", self._toggle_commit, self._file_store)
 
314
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Commit'),
114
315
                                     crt, active=0))
115
 
        self.file_view.append_column(gtk.TreeViewColumn("Path",
 
316
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Path'),
116
317
                                     gtk.CellRendererText(), text=1))
117
 
        self.file_view.append_column(gtk.TreeViewColumn("Type",
 
318
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Type'),
118
319
                                     gtk.CellRendererText(), text=2))
119
320
 
120
 
        for path, _, _ in self.delta.added:
121
 
            self.file_store.append([ True, path, "added" ])
122
 
 
123
 
        for path, _, _ in self.delta.removed:
124
 
            self.file_store.append([ True, path, "removed" ])
125
 
 
126
 
        for oldpath, _, _, _, _, _ in self.delta.renamed:
127
 
            self.file_store.append([ True, oldpath, "renamed"])
128
 
 
129
 
        for path, _, _, _, _ in self.delta.modified:
130
 
            self.file_store.append([ True, path, "modified"])
 
321
        for path, id, kind in self.delta.added:
 
322
            marker = osutils.kind_marker(kind)
 
323
            if self.selected is not None:
 
324
                if path == os.path.join(self.wtpath, self.selected):
 
325
                    self._file_store.append([ True, path+marker, _('added'), path ])
 
326
                else:
 
327
                    self._file_store.append([ False, path+marker, _('added'), path ])
 
328
            else:
 
329
                self._file_store.append([ True, path+marker, _('added'), path ])
 
330
 
 
331
        for path, id, kind in self.delta.removed:
 
332
            marker = osutils.kind_marker(kind)
 
333
            if self.selected is not None:
 
334
                if path == os.path.join(self.wtpath, self.selected):
 
335
                    self._file_store.append([ True, path+marker, _('removed'), path ])
 
336
                else:
 
337
                    self._file_store.append([ False, path+marker, _('removed'), path ])
 
338
            else:
 
339
                self._file_store.append([ True, path+marker, _('removed'), path ])
 
340
 
 
341
        for oldpath, newpath, id, kind, text_modified, meta_modified in self.delta.renamed:
 
342
            marker = osutils.kind_marker(kind)
 
343
            if text_modified or meta_modified:
 
344
                changes = _('renamed and modified')
 
345
            else:
 
346
                changes = _('renamed')
 
347
            if self.selected is not None:
 
348
                if newpath == os.path.join(self.wtpath, self.selected):
 
349
                    self._file_store.append([ True,
 
350
                                              oldpath+marker + '  =>  ' + newpath+marker,
 
351
                                              changes,
 
352
                                              newpath
 
353
                                            ])
 
354
                else:
 
355
                    self._file_store.append([ False,
 
356
                                              oldpath+marker + '  =>  ' + newpath+marker,
 
357
                                              changes,
 
358
                                              newpath
 
359
                                            ])
 
360
            else:
 
361
                self._file_store.append([ True,
 
362
                                          oldpath+marker + '  =>  ' + newpath+marker,
 
363
                                          changes,
 
364
                                          newpath
 
365
                                        ])
 
366
 
 
367
        for path, id, kind, text_modified, meta_modified in self.delta.modified:
 
368
            marker = osutils.kind_marker(kind)
 
369
            if self.selected is not None:
 
370
                if path == os.path.join(self.wtpath, self.selected):
 
371
                    self._file_store.append([ True, path+marker, _('modified'), path ])
 
372
                else:
 
373
                    self._file_store.append([ False, path+marker, _('modified'), path ])
 
374
            else:
 
375
                self._file_store.append([ True, path+marker, _('modified'), path ])
 
376
    
 
377
    def _create_pending_merges(self):
 
378
        if not self.pending:
 
379
            return
 
380
        
 
381
        liststore = gtk.ListStore(gobject.TYPE_STRING,
 
382
                                  gobject.TYPE_STRING,
 
383
                                  gobject.TYPE_STRING)
 
384
        self._treeview_merges.set_model(liststore)
 
385
        
 
386
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Date'),
 
387
                                            gtk.CellRendererText(), text=0))
 
388
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Committer'),
 
389
                                            gtk.CellRendererText(), text=1))
 
390
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Summary'),
 
391
                                            gtk.CellRendererText(), text=2))
 
392
        
 
393
        for item in self.pending:
 
394
            liststore.append([ item['date'],
 
395
                               item['committer'],
 
396
                               item['summary'] ])
131
397
    
132
398
    def _get_specific_files(self):
133
399
        ret = []
134
 
        it = self.file_store.get_iter_first()
 
400
        it = self._file_store.get_iter_first()
135
401
        while it:
136
 
            if self.file_store.get_value(it, 0):
137
 
                ret.append(self.file_store.get_value(it, 1))
138
 
            it = self.file_store.iter_next(it)
 
402
            if self._file_store.get_value(it, 0):
 
403
                # get real path from hidden column 3
 
404
                ret.append(self._file_store.get_value(it, 3))
 
405
            it = self._file_store.iter_next(it)
139
406
 
140
407
        return ret
141
 
    # end of bzr-gtk code
142
408
    
143
409
    def _toggle_commit(self, cell, path, model):
144
410
        model[path][0] = not model[path][0]
145
411
        return
146
 
    
147
 
    def commit(self, widget):
148
 
        textview = self.glade.get_widget('textview_commit')
149
 
        textbuffer = textview.get_buffer()
150
 
        start, end = textbuffer.get_bounds()
151
 
        message = textbuffer.get_text(start, end)
152
 
        
153
 
        checkbutton_strict = self.glade.get_widget('checkbutton_commit_strict')
154
 
        checkbutton_force = self.glade.get_widget('checkbutton_commit_force')
155
 
        
156
 
        specific_files = self._get_specific_files()
157
 
        
158
 
        self.comm.set_busy(self.window)
159
 
        # merged from Jelmer Vernooij's olive integration branch
160
 
        try:
161
 
            self.wt.commit(message, 
162
 
                           allow_pointless=checkbutton_force.get_active(),
163
 
                           strict=checkbutton_strict.get_active(),
164
 
                           local=self.checkbutton_local.get_active(),
165
 
                           specific_files=specific_files)
166
 
        except errors.NotBranchError:
167
 
            self.dialog.error_dialog('Directory is not a branch.')
168
 
            self.comm.set_busy(self.window, False)
169
 
            return
170
 
        except errors.LocalRequiresBoundBranch:
171
 
            self.dialog.error_dialog('Local commit requires a bound branch.')
172
 
            self.comm.set_busy(self.window, False)
173
 
            return
174
 
        except errors.PointlessCommit:
175
 
            self.dialog.error_dialog('No changes to commit. Try force commit.')
176
 
            self.comm.set_busy(self.window, False)
177
 
            return
178
 
        except errors.ConflictsInTree:
179
 
            self.dialog.error_dialog('Conflicts in tree. Please resolve them first.')
180
 
            self.comm.set_busy(self.window, False)
181
 
            return
182
 
        except errors.StrictCommitFailed:
183
 
            self.dialog.error_dialog('Strict commit failed. There are unknown files.')
184
 
            self.comm.set_busy(self.window, False)
185
 
            return
186
 
        except errors.BoundBranchOutOfDate, errmsg:
187
 
            self.dialog.error_dialog('Bound branch is out of date: %s' % errmsg)
188
 
            self.comm.set_busy(self.window, False)
189
 
            return
190
 
        except:
191
 
            raise
192
 
        
193
 
        self.close()
194
 
        self.comm.refresh_right()
195
 
        
196
 
    def close(self, widget=None):
197
 
        self.window.destroy()