/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')
159 by Jelmer Vernooij
Use network manager for checking default of "Local Commit" setting rather than hiding the option completely.
156
                # 3 is the enum value for STATE_CONNECTED
157
                self._check_local.set_active(dbus_iface.state() != 3)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
158
        
159
        # Create the file list
160
        self._create_file_view()
161
        # Create the pending merges
162
        self._create_pending_merges()
163
        
164
        # Expand the corresponding expander
165
        if self._is_pending:
166
            self._expander_merges.set_expanded(True)
167
        else:
168
            self._expander_files.set_expanded(True)
169
        
170
        # Display dialog
171
        self.vbox.show_all()
126.1.29 by Szilveszter Farkas (Phanatic)
Default button set on Commit dialog (Fixed: #83030)
172
        
173
        # Default to Commit button
174
        self._button_commit.grab_default()
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
175
    
176
    def _on_treeview_files_row_activated(self, treeview, path, view_column):
177
        # FIXME: the diff window freezes for some reason
178
        treeselection = treeview.get_selection()
179
        (model, iter) = treeselection.get_selected()
180
        
181
        if iter is not None:
153 by Jelmer Vernooij
Fix references to dialog.
182
            from diff import DiffWindow
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
183
            
184
            _selected = model.get_value(iter, 1)
185
            
186
            diff = DiffWindow()
126.1.28 by Szilveszter Farkas (Phanatic)
The Diff window won't freeze when calling from the Commit dialog.
187
            diff.set_type_hint(gtk.gdk.WINDOW_TYPE_HINT_DIALOG)
188
            diff.set_modal(True)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
189
            parent_tree = self.wt.branch.repository.revision_tree(self.wt.branch.last_revision())
190
            diff.set_diff(self.wt.branch.nick, self.wt, parent_tree)
191
            try:
192
                diff.set_file(_selected)
193
            except errors.NoSuchFile:
194
                pass
195
            diff.show()
196
    
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.
197
    @show_bzr_error
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
198
    def _on_commit_clicked(self, button):
199
        """ Commit button clicked handler. """
200
        textbuffer = self._textview_message.get_buffer()
201
        start, end = textbuffer.get_bounds()
202
        message = textbuffer.get_text(start, end).decode('utf-8')
203
        
204
        if not self.pending:
205
            specific_files = self._get_specific_files()
206
        else:
207
            specific_files = None
208
209
        if message == '':
210
            response = question_dialog(_('Commit with an empty message?'),
211
                                       _('You can describe your commit intent in the message.'))
212
            if response == gtk.RESPONSE_NO:
213
                # Kindly give focus to message area
214
                self._textview_message.grab_focus()
215
                return
216
217
        if self._is_checkout:
159 by Jelmer Vernooij
Use network manager for checking default of "Local Commit" setting rather than hiding the option completely.
218
            local = self._check_local.get_active()
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
219
        else:
220
            local = False
176 by Jelmer Vernooij
Don't make the user worry about strict commit unless we actually find unknown files.
221
222
        if list(self.wt.unknowns()) != []:
223
            response = question_dialog(_("Commit with unknowns?"),
224
               _("Unknown files exist in the working tree. Commit anyway?"))
225
            if response == gtk.RESPONSE_NO:
226
                return
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
227
        
228
        try:
229
            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.
230
                       allow_pointless=False,
176 by Jelmer Vernooij
Don't make the user worry about strict commit unless we actually find unknown files.
231
                       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.
232
                       local=local,
233
                       specific_files=specific_files)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
234
        except errors.PointlessCommit:
235
            response = question_dialog(_('Commit with no changes?'),
236
                                       _('There are no changes in the working tree.'))
237
            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.
238
                self.wt.commit(message,
239
                               allow_pointless=True,
176 by Jelmer Vernooij
Don't make the user worry about strict commit unless we actually find unknown files.
240
                               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.
241
                               local=local,
242
                               specific_files=specific_files)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
243
        self.response(gtk.RESPONSE_OK)
244
245
    def _pending_merges(self, wt):
246
        """ Return a list of pending merges or None if there are none of them. """
247
        parents = wt.get_parent_ids()
248
        if len(parents) < 2:
249
            return None
250
        
251
        import re
252
        from bzrlib.osutils import format_date
253
        
254
        pending = parents[1:]
255
        branch = wt.branch
256
        last_revision = parents[0]
257
        
258
        if last_revision is not None:
259
            try:
260
                ignore = set(branch.repository.get_ancestry(last_revision))
261
            except errors.NoSuchRevision:
262
                # the last revision is a ghost : assume everything is new 
263
                # except for it
264
                ignore = set([None, last_revision])
265
        else:
266
            ignore = set([None])
267
        
268
        pm = []
269
        for merge in pending:
270
            ignore.add(merge)
271
            try:
272
                m_revision = branch.repository.get_revision(merge)
273
                
274
                rev = {}
275
                rev['committer'] = re.sub('<.*@.*>', '', m_revision.committer).strip(' ')
276
                rev['summary'] = m_revision.get_summary()
277
                rev['date'] = format_date(m_revision.timestamp,
278
                                          m_revision.timezone or 0, 
279
                                          'original', date_fmt="%Y-%m-%d",
280
                                          show_offset=False)
281
                
282
                pm.append(rev)
283
                
284
                inner_merges = branch.repository.get_ancestry(merge)
285
                assert inner_merges[0] is None
286
                inner_merges.pop(0)
287
                inner_merges.reverse()
288
                for mmerge in inner_merges:
289
                    if mmerge in ignore:
290
                        continue
291
                    mm_revision = branch.repository.get_revision(mmerge)
292
                    
293
                    rev = {}
294
                    rev['committer'] = re.sub('<.*@.*>', '', mm_revision.committer).strip(' ')
295
                    rev['summary'] = mm_revision.get_summary()
296
                    rev['date'] = format_date(mm_revision.timestamp,
297
                                              mm_revision.timezone or 0, 
298
                                              'original', date_fmt="%Y-%m-%d",
299
                                              show_offset=False)
300
                
301
                    pm.append(rev)
302
                    
303
                    ignore.add(mmerge)
304
            except errors.NoSuchRevision:
305
                print "DEBUG: NoSuchRevision:", merge
306
        
307
        return pm
308
309
    def _create_file_view(self):
310
        self._file_store = gtk.ListStore(gobject.TYPE_BOOLEAN,   # [0] checkbox
311
                                         gobject.TYPE_STRING,    # [1] path to display
312
                                         gobject.TYPE_STRING,    # [2] changes type
313
                                         gobject.TYPE_STRING)    # [3] real path
314
        self._treeview_files.set_model(self._file_store)
315
        crt = gtk.CellRendererToggle()
316
        crt.set_property("activatable", True)
317
        crt.connect("toggled", self._toggle_commit, self._file_store)
318
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Commit'),
319
                                     crt, active=0))
320
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Path'),
321
                                     gtk.CellRendererText(), text=1))
322
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Type'),
323
                                     gtk.CellRendererText(), text=2))
324
325
        for path, id, kind in self.delta.added:
326
            marker = osutils.kind_marker(kind)
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
327
            if self.selected is not None:
328
                if path == os.path.join(self.wtpath, self.selected):
329
                    self._file_store.append([ True, path+marker, _('added'), path ])
330
                else:
331
                    self._file_store.append([ False, path+marker, _('added'), path ])
332
            else:
333
                self._file_store.append([ True, path+marker, _('added'), path ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
334
335
        for path, id, kind in self.delta.removed:
336
            marker = osutils.kind_marker(kind)
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
337
            if self.selected is not None:
338
                if path == os.path.join(self.wtpath, self.selected):
339
                    self._file_store.append([ True, path+marker, _('removed'), path ])
340
                else:
341
                    self._file_store.append([ False, path+marker, _('removed'), path ])
342
            else:
343
                self._file_store.append([ True, path+marker, _('removed'), path ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
344
345
        for oldpath, newpath, id, kind, text_modified, meta_modified in self.delta.renamed:
346
            marker = osutils.kind_marker(kind)
347
            if text_modified or meta_modified:
348
                changes = _('renamed and modified')
349
            else:
350
                changes = _('renamed')
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
351
            if self.selected is not None:
352
                if newpath == os.path.join(self.wtpath, self.selected):
353
                    self._file_store.append([ True,
354
                                              oldpath+marker + '  =>  ' + newpath+marker,
355
                                              changes,
356
                                              newpath
357
                                            ])
358
                else:
359
                    self._file_store.append([ False,
360
                                              oldpath+marker + '  =>  ' + newpath+marker,
361
                                              changes,
362
                                              newpath
363
                                            ])
364
            else:
365
                self._file_store.append([ True,
366
                                          oldpath+marker + '  =>  ' + newpath+marker,
367
                                          changes,
368
                                          newpath
369
                                        ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
370
371
        for path, id, kind, text_modified, meta_modified in self.delta.modified:
372
            marker = osutils.kind_marker(kind)
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
373
            if self.selected is not None:
374
                if path == os.path.join(self.wtpath, self.selected):
375
                    self._file_store.append([ True, path+marker, _('modified'), path ])
376
                else:
377
                    self._file_store.append([ False, path+marker, _('modified'), path ])
378
            else:
379
                self._file_store.append([ True, path+marker, _('modified'), path ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
380
    
381
    def _create_pending_merges(self):
382
        if not self.pending:
383
            return
384
        
385
        liststore = gtk.ListStore(gobject.TYPE_STRING,
386
                                  gobject.TYPE_STRING,
387
                                  gobject.TYPE_STRING)
388
        self._treeview_merges.set_model(liststore)
389
        
390
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Date'),
391
                                            gtk.CellRendererText(), text=0))
392
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Committer'),
393
                                            gtk.CellRendererText(), text=1))
394
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Summary'),
395
                                            gtk.CellRendererText(), text=2))
396
        
397
        for item in self.pending:
398
            liststore.append([ item['date'],
399
                               item['committer'],
400
                               item['summary'] ])
401
    
402
    def _get_specific_files(self):
403
        ret = []
404
        it = self._file_store.get_iter_first()
405
        while it:
406
            if self._file_store.get_value(it, 0):
407
                # get real path from hidden column 3
408
                ret.append(self._file_store.get_value(it, 3))
409
            it = self._file_store.iter_next(it)
410
411
        return ret
412
    
413
    def _toggle_commit(self, cell, path, model):
414
        model[path][0] = not model[path][0]
415
        return