/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz
0.8.19 by Szilveszter Farkas (Phanatic)
2006-07-21 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
1
# Copyright (C) 2006 by Szilveszter Farkas (Phanatic) <szilveszter.farkas@gmail.com>
0.8.46 by Szilveszter Farkas (Phanatic)
Modified OliveDialog class interface; huge cleanups.
2
#
0.8.19 by Szilveszter Farkas (Phanatic)
2006-07-21 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
3
# This program is free software; you can redistribute it and/or modify
4
# it under the terms of the GNU General Public License as published by
5
# the Free Software Foundation; either version 2 of the License, or
6
# (at your option) any later version.
0.8.46 by Szilveszter Farkas (Phanatic)
Modified OliveDialog class interface; huge cleanups.
7
#
0.8.19 by Szilveszter Farkas (Phanatic)
2006-07-21 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
8
# This program is distributed in the hope that it will be useful,
9
# but WITHOUT ANY WARRANTY; without even the implied warranty of
10
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
# GNU General Public License for more details.
0.8.46 by Szilveszter Farkas (Phanatic)
Modified OliveDialog class interface; huge cleanups.
12
#
0.8.19 by Szilveszter Farkas (Phanatic)
2006-07-21 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
13
# You should have received a copy of the GNU General Public License
14
# along with this program; if not, write to the Free Software
15
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
try:
18
    import pygtk
19
    pygtk.require("2.0")
20
except:
21
    pass
0.8.98 by Szilveszter Farkas (Phanatic)
Loads of fixes. Pyflakes cleanup.
22
0.13.11 by Jelmer Vernooij
Bunch of small fixes, cleanups and simplifications.
23
import gtk
24
import gobject
25
import pango
0.8.19 by Szilveszter Farkas (Phanatic)
2006-07-21 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
26
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
27
import os.path
28
0.8.20 by Szilveszter Farkas (Phanatic)
2006-07-24 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
29
import bzrlib.errors as errors
235.1.5 by Mateusz Korniak
Missing mutter import added.
30
93.1.10 by Alexander Belchenko
- Show file kind marker with path (i.e. directory path ends with '/')
31
from bzrlib import osutils
235.1.5 by Mateusz Korniak
Missing mutter import added.
32
from bzrlib.trace import mutter
0.8.20 by Szilveszter Farkas (Phanatic)
2006-07-24 Szilveszter Farkas <Szilveszter.Farkas@gmail.com>
33
153 by Jelmer Vernooij
Fix references to dialog.
34
from dialog import error_dialog, question_dialog
132 by Jelmer Vernooij
Use decorator for catching and showing bzr-gtk errors graphically. Eventually, this should go away and should be handled by the ui factory.
35
from errors import show_bzr_error
93.1.6 by Alexander Belchenko
detecting name of glade file doing in separate module (olive.gladefile)
36
158 by Jelmer Vernooij
If available, use NetworkManager to find out whether a commit should be local or not.
37
try:
38
    import dbus
39
    import dbus.glib
180 by Jelmer Vernooij
Don't obtain handle to network manager until it's actually needed.
40
    have_dbus = True
158 by Jelmer Vernooij
If available, use NetworkManager to find out whether a commit should be local or not.
41
except ImportError:
180 by Jelmer Vernooij
Don't obtain handle to network manager until it's actually needed.
42
    have_dbus = False
158 by Jelmer Vernooij
If available, use NetworkManager to find out whether a commit should be local or not.
43
135 by Jelmer Vernooij
Throw out the old CommitDialog code and use the new code instead, also for 'gcommit'.
44
class CommitDialog(gtk.Dialog):
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
45
    """ New implementation of the Commit dialog. """
46
    def __init__(self, wt, wtpath, notbranch, selected=None, parent=None):
47
        """ Initialize the Commit Dialog. """
48
        gtk.Dialog.__init__(self, title="Commit - Olive",
49
                                  parent=parent,
50
                                  flags=0,
51
                                  buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
52
        
53
        # Get arguments
54
        self.wt = wt
55
        self.wtpath = wtpath
56
        self.notbranch = notbranch
57
        self.selected = selected
58
        
59
        # Set the delta
60
        self.old_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
61
        self.delta = self.wt.changes_from(self.old_tree)
62
        
63
        # Get pending merges
64
        self.pending = self._pending_merges(self.wt)
65
        
66
        # Do some preliminary checks
67
        self._is_checkout = False
68
        self._is_pending = False
69
        if self.wt is None and not self.notbranch:
70
            error_dialog(_('Directory does not have a working tree'),
71
                         _('Operation aborted.'))
72
            self.close()
73
            return
74
75
        if self.notbranch:
76
            error_dialog(_('Directory is not a branch'),
77
                         _('You can perform this action only in a branch.'))
78
            self.close()
79
            return
80
        else:
81
            if self.wt.branch.get_bound_location() is not None:
82
                # we have a checkout, so the local commit checkbox must appear
83
                self._is_checkout = True
84
            
85
            if self.pending:
86
                # There are pending merges, file selection not supported
87
                self._is_pending = True
88
        
89
        # Create the widgets
90
        self._button_commit = gtk.Button(_("Comm_it"), use_underline=True)
145 by Jelmer Vernooij
Fix some strings, import.
91
        self._expander_files = gtk.Expander(_("File(s) to commit"))
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
92
        self._vpaned_main = gtk.VPaned()
93
        self._scrolledwindow_files = gtk.ScrolledWindow()
94
        self._scrolledwindow_message = gtk.ScrolledWindow()
95
        self._treeview_files = gtk.TreeView()
96
        self._vbox_message = gtk.VBox()
145 by Jelmer Vernooij
Fix some strings, import.
97
        self._label_message = gtk.Label(_("Commit message:"))
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
98
        self._textview_message = gtk.TextView()
99
        
100
        if self._is_pending:
101
            self._expander_merges = gtk.Expander(_("Pending merges"))
102
            self._vpaned_list = gtk.VPaned()
103
            self._scrolledwindow_merges = gtk.ScrolledWindow()
104
            self._treeview_merges = gtk.TreeView()
105
106
        # Set callbacks
107
        self._button_commit.connect('clicked', self._on_commit_clicked)
108
        self._treeview_files.connect('row_activated', self._on_treeview_files_row_activated)
109
        
110
        # Set properties
111
        self._scrolledwindow_files.set_policy(gtk.POLICY_AUTOMATIC,
112
                                              gtk.POLICY_AUTOMATIC)
113
        self._scrolledwindow_message.set_policy(gtk.POLICY_AUTOMATIC,
114
                                                gtk.POLICY_AUTOMATIC)
115
        self._textview_message.modify_font(pango.FontDescription("Monospace"))
116
        self.set_default_size(500, 500)
117
        self._vpaned_main.set_position(200)
126.1.29 by Szilveszter Farkas (Phanatic)
Default button set on Commit dialog (Fixed: #83030)
118
        self._button_commit.set_flags(gtk.CAN_DEFAULT)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
119
120
        if self._is_pending:
121
            self._scrolledwindow_merges.set_policy(gtk.POLICY_AUTOMATIC,
122
                                                   gtk.POLICY_AUTOMATIC)
123
            self._treeview_files.set_sensitive(False)
124
        
125
        # Construct the dialog
126
        self.action_area.pack_end(self._button_commit)
127
        
128
        self._scrolledwindow_files.add(self._treeview_files)
129
        self._scrolledwindow_message.add(self._textview_message)
130
        
131
        self._expander_files.add(self._scrolledwindow_files)
132
        
133
        self._vbox_message.pack_start(self._label_message, False, False)
134
        self._vbox_message.pack_start(self._scrolledwindow_message, True, True)
135
        
136
        if self._is_pending:        
137
            self._expander_merges.add(self._scrolledwindow_merges)
138
            self._scrolledwindow_merges.add(self._treeview_merges)
139
            self._vpaned_list.add1(self._expander_files)
140
            self._vpaned_list.add2(self._expander_merges)
141
            self._vpaned_main.add1(self._vpaned_list)
142
        else:
143
            self._vpaned_main.add1(self._expander_files)
144
145
        self._vpaned_main.add2(self._vbox_message)
146
        
147
        self.vbox.pack_start(self._vpaned_main, True, True)
159 by Jelmer Vernooij
Use network manager for checking default of "Local Commit" setting rather than hiding the option completely.
148
        if self._is_checkout: 
158 by Jelmer Vernooij
If available, use NetworkManager to find out whether a commit should be local or not.
149
            self._check_local = gtk.CheckButton(_("_Only commit locally"),
150
                                                use_underline=True)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
151
            self.vbox.pack_start(self._check_local, False, False)
180 by Jelmer Vernooij
Don't obtain handle to network manager until it's actually needed.
152
            if have_dbus:
153
                bus = dbus.SystemBus()
154
                proxy_obj = bus.get_object('org.freedesktop.NetworkManager', 
155
                              '/org/freedesktop/NetworkManager')
156
                dbus_iface = dbus.Interface(
157
                        proxy_obj, 'org.freedesktop.NetworkManager')
235.1.1 by Mateusz Korniak
Fix for broken dbus detection if network is avaiable.
158
                try:
159
                    # 3 is the enum value for STATE_CONNECTED
240 by Jelmer Vernooij
Merge fix for local commits when network manager isn't available.
160
                    self._check_local.set_active(dbus_iface.state() != 3)
161
                except dbus.DBusException, e:
162
                    # Silently drop errors. While DBus may be 
163
                    # available, NetworkManager doesn't necessarily have to be
164
                    mutter("unable to get networkmanager state: %r" % e)
235.1.1 by Mateusz Korniak
Fix for broken dbus detection if network is avaiable.
165
                
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
166
        # Create the file list
167
        self._create_file_view()
168
        # Create the pending merges
169
        self._create_pending_merges()
170
        
171
        # Expand the corresponding expander
172
        if self._is_pending:
173
            self._expander_merges.set_expanded(True)
174
        else:
175
            self._expander_files.set_expanded(True)
176
        
177
        # Display dialog
178
        self.vbox.show_all()
126.1.29 by Szilveszter Farkas (Phanatic)
Default button set on Commit dialog (Fixed: #83030)
179
        
180
        # Default to Commit button
181
        self._button_commit.grab_default()
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
182
    
183
    def _on_treeview_files_row_activated(self, treeview, path, view_column):
184
        # FIXME: the diff window freezes for some reason
185
        treeselection = treeview.get_selection()
186
        (model, iter) = treeselection.get_selected()
187
        
188
        if iter is not None:
153 by Jelmer Vernooij
Fix references to dialog.
189
            from diff import DiffWindow
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
190
            
191
            _selected = model.get_value(iter, 1)
192
            
193
            diff = DiffWindow()
126.1.28 by Szilveszter Farkas (Phanatic)
The Diff window won't freeze when calling from the Commit dialog.
194
            diff.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
195
            diff.set_modal(True)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
196
            parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
197
            diff.set_diff(self.wt.branch.nick, self.wt, parent_tree)
198
            try:
199
                diff.set_file(_selected)
200
            except errors.NoSuchFile:
201
                pass
202
            diff.show()
203
    
132 by Jelmer Vernooij
Use decorator for catching and showing bzr-gtk errors graphically. Eventually, this should go away and should be handled by the ui factory.
204
    @show_bzr_error
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
205
    def _on_commit_clicked(self, button):
206
        """ Commit button clicked handler. """
207
        textbuffer = self._textview_message.get_buffer()
208
        start, end = textbuffer.get_bounds()
209
        message = textbuffer.get_text(start, end).decode('utf-8')
210
        
211
        if not self.pending:
212
            specific_files = self._get_specific_files()
213
        else:
214
            specific_files = None
215
216
        if message == '':
217
            response = question_dialog(_('Commit with an empty message?'),
218
                                       _('You can describe your commit intent in the message.'))
219
            if response == gtk.RESPONSE_NO:
220
                # Kindly give focus to message area
221
                self._textview_message.grab_focus()
222
                return
223
224
        if self._is_checkout:
159 by Jelmer Vernooij
Use network manager for checking default of "Local Commit" setting rather than hiding the option completely.
225
            local = self._check_local.get_active()
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
226
        else:
227
            local = False
176 by Jelmer Vernooij
Don't make the user worry about strict commit unless we actually find unknown files.
228
229
        if list(self.wt.unknowns()) != []:
230
            response = question_dialog(_("Commit with unknowns?"),
231
               _("Unknown files exist in the working tree. Commit anyway?"))
232
            if response == gtk.RESPONSE_NO:
233
                return
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
234
        
235
        try:
236
            self.wt.commit(message,
132 by Jelmer Vernooij
Use decorator for catching and showing bzr-gtk errors graphically. Eventually, this should go away and should be handled by the ui factory.
237
                       allow_pointless=False,
176 by Jelmer Vernooij
Don't make the user worry about strict commit unless we actually find unknown files.
238
                       strict=False,
132 by Jelmer Vernooij
Use decorator for catching and showing bzr-gtk errors graphically. Eventually, this should go away and should be handled by the ui factory.
239
                       local=local,
240
                       specific_files=specific_files)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
241
        except errors.PointlessCommit:
242
            response = question_dialog(_('Commit with no changes?'),
243
                                       _('There are no changes in the working tree.'))
244
            if response == gtk.RESPONSE_YES:
132 by Jelmer Vernooij
Use decorator for catching and showing bzr-gtk errors graphically. Eventually, this should go away and should be handled by the ui factory.
245
                self.wt.commit(message,
246
                               allow_pointless=True,
176 by Jelmer Vernooij
Don't make the user worry about strict commit unless we actually find unknown files.
247
                               strict=False,
132 by Jelmer Vernooij
Use decorator for catching and showing bzr-gtk errors graphically. Eventually, this should go away and should be handled by the ui factory.
248
                               local=local,
249
                               specific_files=specific_files)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
250
        self.response(gtk.RESPONSE_OK)
251
252
    def _pending_merges(self, wt):
253
        """ Return a list of pending merges or None if there are none of them. """
254
        parents = wt.get_parent_ids()
255
        if len(parents) < 2:
256
            return None
257
        
258
        import re
259
        from bzrlib.osutils import format_date
260
        
261
        pending = parents[1:]
262
        branch = wt.branch
263
        last_revision = parents[0]
264
        
265
        if last_revision is not None:
266
            try:
267
                ignore = set(branch.repository.get_ancestry(last_revision))
268
            except errors.NoSuchRevision:
269
                # the last revision is a ghost : assume everything is new 
270
                # except for it
271
                ignore = set([None, last_revision])
272
        else:
273
            ignore = set([None])
274
        
275
        pm = []
276
        for merge in pending:
277
            ignore.add(merge)
278
            try:
279
                m_revision = branch.repository.get_revision(merge)
280
                
281
                rev = {}
282
                rev['committer'] = re.sub('<.*@.*>', '', m_revision.committer).strip(' ')
283
                rev['summary'] = m_revision.get_summary()
284
                rev['date'] = format_date(m_revision.timestamp,
285
                                          m_revision.timezone or 0, 
286
                                          'original', date_fmt="%Y-%m-%d",
287
                                          show_offset=False)
288
                
289
                pm.append(rev)
290
                
291
                inner_merges = branch.repository.get_ancestry(merge)
292
                assert inner_merges[0] is None
293
                inner_merges.pop(0)
294
                inner_merges.reverse()
295
                for mmerge in inner_merges:
296
                    if mmerge in ignore:
297
                        continue
298
                    mm_revision = branch.repository.get_revision(mmerge)
299
                    
300
                    rev = {}
301
                    rev['committer'] = re.sub('<.*@.*>', '', mm_revision.committer).strip(' ')
302
                    rev['summary'] = mm_revision.get_summary()
303
                    rev['date'] = format_date(mm_revision.timestamp,
304
                                              mm_revision.timezone or 0, 
305
                                              'original', date_fmt="%Y-%m-%d",
306
                                              show_offset=False)
307
                
308
                    pm.append(rev)
309
                    
310
                    ignore.add(mmerge)
311
            except errors.NoSuchRevision:
312
                print "DEBUG: NoSuchRevision:", merge
313
        
314
        return pm
315
316
    def _create_file_view(self):
317
        self._file_store = gtk.ListStore(gobject.TYPE_BOOLEAN,   # [0] checkbox
318
                                         gobject.TYPE_STRING,    # [1] path to display
319
                                         gobject.TYPE_STRING,    # [2] changes type
320
                                         gobject.TYPE_STRING)    # [3] real path
321
        self._treeview_files.set_model(self._file_store)
322
        crt = gtk.CellRendererToggle()
323
        crt.set_property("activatable", True)
324
        crt.connect("toggled", self._toggle_commit, self._file_store)
325
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Commit'),
326
                                     crt, active=0))
327
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Path'),
328
                                     gtk.CellRendererText(), text=1))
329
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Type'),
330
                                     gtk.CellRendererText(), text=2))
331
332
        for path, id, kind in self.delta.added:
333
            marker = osutils.kind_marker(kind)
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
334
            if self.selected is not None:
335
                if path == os.path.join(self.wtpath, self.selected):
336
                    self._file_store.append([ True, path+marker, _('added'), path ])
337
                else:
338
                    self._file_store.append([ False, path+marker, _('added'), path ])
339
            else:
340
                self._file_store.append([ True, path+marker, _('added'), path ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
341
342
        for path, id, kind in self.delta.removed:
343
            marker = osutils.kind_marker(kind)
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
344
            if self.selected is not None:
345
                if path == os.path.join(self.wtpath, self.selected):
346
                    self._file_store.append([ True, path+marker, _('removed'), path ])
347
                else:
348
                    self._file_store.append([ False, path+marker, _('removed'), path ])
349
            else:
350
                self._file_store.append([ True, path+marker, _('removed'), path ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
351
352
        for oldpath, newpath, id, kind, text_modified, meta_modified in self.delta.renamed:
353
            marker = osutils.kind_marker(kind)
354
            if text_modified or meta_modified:
355
                changes = _('renamed and modified')
356
            else:
357
                changes = _('renamed')
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
358
            if self.selected is not None:
359
                if newpath == os.path.join(self.wtpath, self.selected):
360
                    self._file_store.append([ True,
361
                                              oldpath+marker + '  =>  ' + newpath+marker,
362
                                              changes,
363
                                              newpath
364
                                            ])
365
                else:
366
                    self._file_store.append([ False,
367
                                              oldpath+marker + '  =>  ' + newpath+marker,
368
                                              changes,
369
                                              newpath
370
                                            ])
371
            else:
372
                self._file_store.append([ True,
373
                                          oldpath+marker + '  =>  ' + newpath+marker,
374
                                          changes,
375
                                          newpath
376
                                        ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
377
378
        for path, id, kind, text_modified, meta_modified in self.delta.modified:
379
            marker = osutils.kind_marker(kind)
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
380
            if self.selected is not None:
381
                if path == os.path.join(self.wtpath, self.selected):
382
                    self._file_store.append([ True, path+marker, _('modified'), path ])
383
                else:
384
                    self._file_store.append([ False, path+marker, _('modified'), path ])
385
            else:
386
                self._file_store.append([ True, path+marker, _('modified'), path ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
387
    
388
    def _create_pending_merges(self):
389
        if not self.pending:
390
            return
391
        
392
        liststore = gtk.ListStore(gobject.TYPE_STRING,
393
                                  gobject.TYPE_STRING,
394
                                  gobject.TYPE_STRING)
395
        self._treeview_merges.set_model(liststore)
396
        
397
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Date'),
398
                                            gtk.CellRendererText(), text=0))
399
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Committer'),
400
                                            gtk.CellRendererText(), text=1))
401
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Summary'),
402
                                            gtk.CellRendererText(), text=2))
403
        
404
        for item in self.pending:
405
            liststore.append([ item['date'],
406
                               item['committer'],
407
                               item['summary'] ])
408
    
409
    def _get_specific_files(self):
410
        ret = []
411
        it = self._file_store.get_iter_first()
412
        while it:
413
            if self._file_store.get_value(it, 0):
414
                # get real path from hidden column 3
415
                ret.append(self._file_store.get_value(it, 3))
416
            it = self._file_store.iter_next(it)
417
418
        return ret
419
    
420
    def _toggle_commit(self, cell, path, model):
421
        model[path][0] = not model[path][0]
422
        return