/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: Szilveszter Farkas (Phanatic)
  • Date: 2007-03-15 12:43:48 UTC
  • mto: (126.1.38 bzr-gtk)
  • mto: This revision was merged to the branch mainline in revision 172.
  • Revision ID: szilveszter.farkas@gmail.com-20070315124348-0nx0zb7fv4pa8xk6
Fix the indentation error in the TortoiseBZR test.

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
 
 
27
import os.path
 
28
 
28
29
import bzrlib.errors as errors
29
30
from bzrlib import osutils
30
31
 
31
32
from dialog import error_dialog, question_dialog
32
 
from guifiles import GLADEFILENAME
33
 
 
34
 
 
35
 
class CommitDialog:
36
 
    """ 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')
 
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))
45
54
        
 
55
        # Get arguments
46
56
        self.wt = wt
47
57
        self.wtpath = wtpath
48
58
        self.notbranch = notbranch
49
 
 
50
 
        # Get some important widgets
51
 
        self.window = self.glade.get_widget('window_commit')
52
 
        self.checkbutton_local = self.glade.get_widget('checkbutton_commit_local')
53
 
        self.textview = self.glade.get_widget('textview_commit')
54
 
        self.file_expander = self.glade.get_widget('expander_commit_select')
55
 
        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:
61
 
            return
 
59
        self.selected = selected
62
60
        
63
61
        # Set the delta
64
62
        self.old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
67
65
        # Get pending merges
68
66
        self.pending = self._pending_merges(self.wt)
69
67
        
70
 
        # Dictionary for signal_autoconnect
71
 
        dic = { "on_button_commit_commit_clicked": self.commit,
72
 
                "on_button_commit_cancel_clicked": self.close }
73
 
 
74
 
        # Connect the signals to the handlers
75
 
        self.glade.signal_autoconnect(dic)
76
 
        
77
 
        # Create the file list
78
 
        self._create_file_view()
79
 
        # Create the pending merges
80
 
        self._create_pending_merges()
81
 
    
82
 
    def display(self):
83
 
        """ Display the Push dialog.
84
 
        @return:    True if dialog is shown.
85
 
        """
 
68
        # Do some preliminary checks
 
69
        self._is_checkout = False
 
70
        self._is_pending = False
86
71
        if self.wt is None and not self.notbranch:
87
72
            error_dialog(_('Directory does not have a working tree'),
88
73
                         _('Operation aborted.'))
89
74
            self.close()
90
 
            return False
 
75
            return
 
76
 
91
77
        if self.notbranch:
92
78
            error_dialog(_('Directory is not a branch'),
93
79
                         _('You can perform this action only in a branch.'))
94
80
            self.close()
95
 
            return False
 
81
            return
96
82
        else:
97
83
            if self.wt.branch.get_bound_location() is not None:
98
84
                # we have a checkout, so the local commit checkbox must appear
99
 
                self.checkbutton_local.show()
 
85
                self._is_checkout = True
100
86
            
101
87
            if self.pending:
102
88
                # 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
 
            self.textview.modify_font(pango.FontDescription("Monospace"))
110
 
            self.window.show()
111
 
            return True
112
 
    
113
 
    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
118
 
        self.file_view.set_model(self.file_store)
119
 
        crt = gtk.CellRendererToggle()
120
 
        crt.set_property("activatable", True)
121
 
        crt.connect("toggled", self._toggle_commit, self.file_store)
122
 
        self.file_view.append_column(gtk.TreeViewColumn(_('Commit'),
123
 
                                     crt, active=0))
124
 
        self.file_view.append_column(gtk.TreeViewColumn(_('Path'),
125
 
                                     gtk.CellRendererText(), text=1))
126
 
        self.file_view.append_column(gtk.TreeViewColumn(_('Type'),
127
 
                                     gtk.CellRendererText(), text=2))
128
 
 
129
 
        for path, id, kind in self.delta.added:
130
 
            marker = osutils.kind_marker(kind)
131
 
            self.file_store.append([ True, path+marker, _('added'), path ])
132
 
 
133
 
        for path, id, kind in self.delta.removed:
134
 
            marker = osutils.kind_marker(kind)
135
 
            self.file_store.append([ True, path+marker, _('removed'), path ])
136
 
 
137
 
        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
 
                                   ])
148
 
 
149
 
        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):
 
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)
 
160
        
 
161
        # Create the file list
 
162
        self._create_file_view()
 
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
        
154
206
        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'] ])
179
 
    
180
 
    def _get_specific_files(self):
181
 
        ret = []
182
 
        it = self.file_store.get_iter_first()
183
 
        while it:
184
 
            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))
187
 
            it = self.file_store.iter_next(it)
188
 
 
189
 
        return ret
190
 
    
191
 
    def _toggle_commit(self, cell, path, model):
192
 
        model[path][0] = not model[path][0]
193
 
        return
194
 
    
 
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
 
195
241
    def _pending_merges(self, wt):
196
242
        """ Return a list of pending merges or None if there are none of them. """
197
243
        parents = wt.get_parent_ids()
256
302
        
257
303
        return pm
258
304
 
259
 
    def commit(self, widget):
260
 
        textbuffer = self.textview.get_buffer()
261
 
        start, end = textbuffer.get_bounds()
262
 
        message = textbuffer.get_text(start, end).decode('utf-8')
263
 
        
264
 
        checkbutton_strict = self.glade.get_widget('checkbutton_commit_strict')
265
 
        checkbutton_force = self.glade.get_widget('checkbutton_commit_force')
266
 
        
 
305
    def _create_file_view(self):
 
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)
 
311
        crt = gtk.CellRendererToggle()
 
312
        crt.set_property("activatable", True)
 
313
        crt.connect("toggled", self._toggle_commit, self._file_store)
 
314
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Commit'),
 
315
                                     crt, active=0))
 
316
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Path'),
 
317
                                     gtk.CellRendererText(), text=1))
 
318
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Type'),
 
319
                                     gtk.CellRendererText(), text=2))
 
320
 
 
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):
267
378
        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
 
 
281
 
        try:
282
 
            self.wt.commit(message,
283
 
                           allow_pointless=checkbutton_force.get_active(),
284
 
                           strict=checkbutton_strict.get_active(),
285
 
                           local=self.checkbutton_local.get_active(),
286
 
                           specific_files=specific_files)
287
 
        except errors.NotBranchError:
288
 
            error_dialog(_('Directory is not a branch'),
289
 
                         _('You can perform this action only in a branch.'))
290
 
            return
291
 
        except errors.LocalRequiresBoundBranch:
292
 
            error_dialog(_('Directory is not a checkout'),
293
 
                         _('You can perform local commit only on checkouts.'))
294
 
            return
295
 
        except errors.PointlessCommit:
296
 
            error_dialog(_('No changes to commit'),
297
 
                         _('Try force commit if you want to commit anyway.'))
298
 
            return
299
 
        except errors.ConflictsInTree:
300
 
            error_dialog(_('Conflicts in tree'),
301
 
                         _('You need to resolve the conflicts before committing.'))
302
 
            return
303
 
        except errors.StrictCommitFailed:
304
 
            error_dialog(_('Strict commit failed'),
305
 
                         _('There are unknown files in the working tree.\nPlease add or delete them.'))
306
 
            return
307
 
        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
 
 
318
 
        self.close()
319
 
 
320
 
    def close(self, widget=None):
321
 
        self.window.destroy()
 
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'] ])
 
397
    
 
398
    def _get_specific_files(self):
 
399
        ret = []
 
400
        it = self._file_store.get_iter_first()
 
401
        while 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)
 
406
 
 
407
        return ret
 
408
    
 
409
    def _toggle_commit(self, cell, path, model):
 
410
        model[path][0] = not model[path][0]
 
411
        return