/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
248 by Jelmer Vernooij
Merge fixes for #127392 and #127381)
29
from bzrlib import errors, osutils
235.1.5 by Mateusz Korniak
Missing mutter import added.
30
from bzrlib.trace import mutter
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()
319 by Gary van der Merwe
Make it possible to view the diff from the commit window when there are pending merges.
103
            self._scrolledwindow_merges.set_policy(gtk.POLICY_AUTOMATIC,
104
                                                   gtk.POLICY_AUTOMATIC)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
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
        # Construct the dialog
121
        self.action_area.pack_end(self._button_commit)
122
        
123
        self._scrolledwindow_files.add(self._treeview_files)
124
        self._scrolledwindow_message.add(self._textview_message)
125
        
126
        self._expander_files.add(self._scrolledwindow_files)
127
        
128
        self._vbox_message.pack_start(self._label_message, False, False)
129
        self._vbox_message.pack_start(self._scrolledwindow_message, True, True)
130
        
131
        if self._is_pending:        
132
            self._expander_merges.add(self._scrolledwindow_merges)
133
            self._scrolledwindow_merges.add(self._treeview_merges)
134
            self._vpaned_list.add1(self._expander_files)
135
            self._vpaned_list.add2(self._expander_merges)
136
            self._vpaned_main.add1(self._vpaned_list)
137
        else:
138
            self._vpaned_main.add1(self._expander_files)
139
140
        self._vpaned_main.add2(self._vbox_message)
141
        
142
        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.
143
        if self._is_checkout: 
158 by Jelmer Vernooij
If available, use NetworkManager to find out whether a commit should be local or not.
144
            self._check_local = gtk.CheckButton(_("_Only commit locally"),
145
                                                use_underline=True)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
146
            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.
147
            if have_dbus:
148
                bus = dbus.SystemBus()
149
                proxy_obj = bus.get_object('org.freedesktop.NetworkManager', 
150
                              '/org/freedesktop/NetworkManager')
151
                dbus_iface = dbus.Interface(
152
                        proxy_obj, 'org.freedesktop.NetworkManager')
235.1.1 by Mateusz Korniak
Fix for broken dbus detection if network is avaiable.
153
                try:
154
                    # 3 is the enum value for STATE_CONNECTED
240 by Jelmer Vernooij
Merge fix for local commits when network manager isn't available.
155
                    self._check_local.set_active(dbus_iface.state() != 3)
156
                except dbus.DBusException, e:
157
                    # Silently drop errors. While DBus may be 
158
                    # available, NetworkManager doesn't necessarily have to be
159
                    mutter("unable to get networkmanager state: %r" % e)
235.1.1 by Mateusz Korniak
Fix for broken dbus detection if network is avaiable.
160
                
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
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()
126.1.29 by Szilveszter Farkas (Phanatic)
Default button set on Commit dialog (Fixed: #83030)
174
        
175
        # Default to Commit button
176
        self._button_commit.grab_default()
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
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:
153 by Jelmer Vernooij
Fix references to dialog.
184
            from diff import DiffWindow
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
185
            
186
            _selected = model.get_value(iter, 1)
187
            
188
            diff = DiffWindow()
126.1.28 by Szilveszter Farkas (Phanatic)
The Diff window won't freeze when calling from the Commit dialog.
189
            diff.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
190
            diff.set_modal(True)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
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
    
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.
199
    @show_bzr_error
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
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:
159 by Jelmer Vernooij
Use network manager for checking default of "Local Commit" setting rather than hiding the option completely.
220
            local = self._check_local.get_active()
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
221
        else:
222
            local = False
176 by Jelmer Vernooij
Don't make the user worry about strict commit unless we actually find unknown files.
223
224
        if list(self.wt.unknowns()) != []:
225
            response = question_dialog(_("Commit with unknowns?"),
226
               _("Unknown files exist in the working tree. Commit anyway?"))
227
            if response == gtk.RESPONSE_NO:
228
                return
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
229
        
230
        try:
231
            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.
232
                       allow_pointless=False,
176 by Jelmer Vernooij
Don't make the user worry about strict commit unless we actually find unknown files.
233
                       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.
234
                       local=local,
235
                       specific_files=specific_files)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
236
        except errors.PointlessCommit:
237
            response = question_dialog(_('Commit with no changes?'),
238
                                       _('There are no changes in the working tree.'))
239
            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.
240
                self.wt.commit(message,
241
                               allow_pointless=True,
176 by Jelmer Vernooij
Don't make the user worry about strict commit unless we actually find unknown files.
242
                               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.
243
                               local=local,
244
                               specific_files=specific_files)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
245
        self.response(gtk.RESPONSE_OK)
246
247
    def _pending_merges(self, wt):
248
        """ Return a list of pending merges or None if there are none of them. """
249
        parents = wt.get_parent_ids()
250
        if len(parents) < 2:
251
            return None
252
        
253
        import re
254
        from bzrlib.osutils import format_date
255
        
256
        pending = parents[1:]
257
        branch = wt.branch
258
        last_revision = parents[0]
259
        
260
        if last_revision is not None:
261
            try:
262
                ignore = set(branch.repository.get_ancestry(last_revision))
263
            except errors.NoSuchRevision:
264
                # the last revision is a ghost : assume everything is new 
265
                # except for it
266
                ignore = set([None, last_revision])
267
        else:
268
            ignore = set([None])
269
        
270
        pm = []
271
        for merge in pending:
272
            ignore.add(merge)
273
            try:
274
                m_revision = branch.repository.get_revision(merge)
275
                
276
                rev = {}
277
                rev['committer'] = re.sub('<.*@.*>', '', m_revision.committer).strip(' ')
278
                rev['summary'] = m_revision.get_summary()
279
                rev['date'] = format_date(m_revision.timestamp,
280
                                          m_revision.timezone or 0, 
281
                                          'original', date_fmt="%Y-%m-%d",
282
                                          show_offset=False)
283
                
284
                pm.append(rev)
285
                
286
                inner_merges = branch.repository.get_ancestry(merge)
287
                assert inner_merges[0] is None
288
                inner_merges.pop(0)
289
                inner_merges.reverse()
290
                for mmerge in inner_merges:
291
                    if mmerge in ignore:
292
                        continue
293
                    mm_revision = branch.repository.get_revision(mmerge)
294
                    
295
                    rev = {}
296
                    rev['committer'] = re.sub('<.*@.*>', '', mm_revision.committer).strip(' ')
297
                    rev['summary'] = mm_revision.get_summary()
298
                    rev['date'] = format_date(mm_revision.timestamp,
299
                                              mm_revision.timezone or 0, 
300
                                              'original', date_fmt="%Y-%m-%d",
301
                                              show_offset=False)
302
                
303
                    pm.append(rev)
304
                    
305
                    ignore.add(mmerge)
306
            except errors.NoSuchRevision:
307
                print "DEBUG: NoSuchRevision:", merge
308
        
309
        return pm
310
311
    def _create_file_view(self):
312
        self._file_store = gtk.ListStore(gobject.TYPE_BOOLEAN,   # [0] checkbox
313
                                         gobject.TYPE_STRING,    # [1] path to display
314
                                         gobject.TYPE_STRING,    # [2] changes type
315
                                         gobject.TYPE_STRING)    # [3] real path
316
        self._treeview_files.set_model(self._file_store)
317
        crt = gtk.CellRendererToggle()
318
        crt.set_property("activatable", True)
319
        crt.connect("toggled", self._toggle_commit, self._file_store)
319 by Gary van der Merwe
Make it possible to view the diff from the commit window when there are pending merges.
320
        commit_column = gtk.TreeViewColumn(_('Commit'), crt, active=0)
321
        if self._is_pending:
322
            commit_column.set_visible(False)
323
        self._treeview_files.append_column(commit_column)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
324
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Path'),
325
                                     gtk.CellRendererText(), text=1))
326
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Type'),
327
                                     gtk.CellRendererText(), text=2))
328
329
        for path, id, kind in self.delta.added:
330
            marker = osutils.kind_marker(kind)
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
331
            if self.selected is not None:
332
                if path == os.path.join(self.wtpath, self.selected):
333
                    self._file_store.append([ True, path+marker, _('added'), path ])
334
                else:
335
                    self._file_store.append([ False, path+marker, _('added'), path ])
336
            else:
337
                self._file_store.append([ True, path+marker, _('added'), path ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
338
339
        for path, id, kind in self.delta.removed:
340
            marker = osutils.kind_marker(kind)
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
341
            if self.selected is not None:
342
                if path == os.path.join(self.wtpath, self.selected):
343
                    self._file_store.append([ True, path+marker, _('removed'), path ])
344
                else:
345
                    self._file_store.append([ False, path+marker, _('removed'), path ])
346
            else:
347
                self._file_store.append([ True, path+marker, _('removed'), path ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
348
349
        for oldpath, newpath, id, kind, text_modified, meta_modified in self.delta.renamed:
350
            marker = osutils.kind_marker(kind)
351
            if text_modified or meta_modified:
352
                changes = _('renamed and modified')
353
            else:
354
                changes = _('renamed')
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
355
            if self.selected is not None:
356
                if newpath == os.path.join(self.wtpath, self.selected):
357
                    self._file_store.append([ True,
358
                                              oldpath+marker + '  =>  ' + newpath+marker,
359
                                              changes,
360
                                              newpath
361
                                            ])
362
                else:
363
                    self._file_store.append([ False,
364
                                              oldpath+marker + '  =>  ' + newpath+marker,
365
                                              changes,
366
                                              newpath
367
                                            ])
368
            else:
369
                self._file_store.append([ True,
370
                                          oldpath+marker + '  =>  ' + newpath+marker,
371
                                          changes,
372
                                          newpath
373
                                        ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
374
375
        for path, id, kind, text_modified, meta_modified in self.delta.modified:
376
            marker = osutils.kind_marker(kind)
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
377
            if self.selected is not None:
378
                if path == os.path.join(self.wtpath, self.selected):
379
                    self._file_store.append([ True, path+marker, _('modified'), path ])
380
                else:
381
                    self._file_store.append([ False, path+marker, _('modified'), path ])
382
            else:
383
                self._file_store.append([ True, path+marker, _('modified'), path ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
384
    
385
    def _create_pending_merges(self):
386
        if not self.pending:
387
            return
388
        
389
        liststore = gtk.ListStore(gobject.TYPE_STRING,
390
                                  gobject.TYPE_STRING,
391
                                  gobject.TYPE_STRING)
392
        self._treeview_merges.set_model(liststore)
393
        
394
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Date'),
395
                                            gtk.CellRendererText(), text=0))
396
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Committer'),
397
                                            gtk.CellRendererText(), text=1))
398
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Summary'),
399
                                            gtk.CellRendererText(), text=2))
400
        
401
        for item in self.pending:
402
            liststore.append([ item['date'],
403
                               item['committer'],
404
                               item['summary'] ])
405
    
406
    def _get_specific_files(self):
407
        ret = []
408
        it = self._file_store.get_iter_first()
409
        while it:
410
            if self._file_store.get_value(it, 0):
411
                # get real path from hidden column 3
412
                ret.append(self._file_store.get_value(it, 3))
413
            it = self._file_store.iter_next(it)
414
415
        return ret
416
    
417
    def _toggle_commit(self, cell, path, model):
418
        model[path][0] = not model[path][0]
419
        return