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