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