/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._check_strict = gtk.CheckButton(_("_Allow unknown files"),
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
94
                                             use_underline=True)
145 by Jelmer Vernooij
Fix some strings, import.
95
        self._expander_files = gtk.Expander(_("File(s) to commit"))
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
96
        self._vpaned_main = gtk.VPaned()
97
        self._scrolledwindow_files = gtk.ScrolledWindow()
98
        self._scrolledwindow_message = gtk.ScrolledWindow()
99
        self._treeview_files = gtk.TreeView()
100
        self._vbox_message = gtk.VBox()
145 by Jelmer Vernooij
Fix some strings, import.
101
        self._label_message = gtk.Label(_("Commit message:"))
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
102
        self._textview_message = gtk.TextView()
103
        
104
        if self._is_pending:
105
            self._expander_merges = gtk.Expander(_("Pending merges"))
106
            self._vpaned_list = gtk.VPaned()
107
            self._scrolledwindow_merges = gtk.ScrolledWindow()
108
            self._treeview_merges = gtk.TreeView()
109
110
        # Set callbacks
111
        self._button_commit.connect('clicked', self._on_commit_clicked)
112
        self._treeview_files.connect('row_activated', self._on_treeview_files_row_activated)
113
        
114
        # Set properties
115
        self._scrolledwindow_files.set_policy(gtk.POLICY_AUTOMATIC,
116
                                              gtk.POLICY_AUTOMATIC)
117
        self._scrolledwindow_message.set_policy(gtk.POLICY_AUTOMATIC,
118
                                                gtk.POLICY_AUTOMATIC)
119
        self._textview_message.modify_font(pango.FontDescription("Monospace"))
120
        self.set_default_size(500, 500)
121
        self._vpaned_main.set_position(200)
126.1.29 by Szilveszter Farkas (Phanatic)
Default button set on Commit dialog (Fixed: #83030)
122
        self._button_commit.set_flags(gtk.CAN_DEFAULT)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
123
124
        if self._is_pending:
125
            self._scrolledwindow_merges.set_policy(gtk.POLICY_AUTOMATIC,
126
                                                   gtk.POLICY_AUTOMATIC)
127
            self._treeview_files.set_sensitive(False)
128
        
129
        # Construct the dialog
130
        self.action_area.pack_end(self._button_commit)
131
        
132
        self._scrolledwindow_files.add(self._treeview_files)
133
        self._scrolledwindow_message.add(self._textview_message)
134
        
135
        self._expander_files.add(self._scrolledwindow_files)
136
        
137
        self._vbox_message.pack_start(self._label_message, False, False)
138
        self._vbox_message.pack_start(self._scrolledwindow_message, True, True)
139
        
140
        if self._is_pending:        
141
            self._expander_merges.add(self._scrolledwindow_merges)
142
            self._scrolledwindow_merges.add(self._treeview_merges)
143
            self._vpaned_list.add1(self._expander_files)
144
            self._vpaned_list.add2(self._expander_merges)
145
            self._vpaned_main.add1(self._vpaned_list)
146
        else:
147
            self._vpaned_main.add1(self._expander_files)
148
149
        self._vpaned_main.add2(self._vbox_message)
150
        
151
        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.
152
        if self._is_checkout: 
158 by Jelmer Vernooij
If available, use NetworkManager to find out whether a commit should be local or not.
153
            self._check_local = gtk.CheckButton(_("_Only commit locally"),
154
                                                use_underline=True)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
155
            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.
156
            if have_nm:
157
                # 3 is the enum value for STATE_CONNECTED
158
                self._check_local.set_active(dbus_iface.state() != 3)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
159
        self.vbox.pack_start(self._check_strict, False, False)
160
        
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
223
        
224
        try:
225
            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.
226
                       allow_pointless=False,
227
                       strict=self._check_strict.get_active(),
228
                       local=local,
229
                       specific_files=specific_files)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
230
        except errors.PointlessCommit:
231
            response = question_dialog(_('Commit with no changes?'),
232
                                       _('There are no changes in the working tree.'))
233
            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.
234
                self.wt.commit(message,
235
                               allow_pointless=True,
236
                               strict=self._check_strict.get_active(),
237
                               local=local,
238
                               specific_files=specific_files)
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
239
        self.response(gtk.RESPONSE_OK)
240
241
    def _pending_merges(self, wt):
242
        """ Return a list of pending merges or None if there are none of them. """
243
        parents = wt.get_parent_ids()
244
        if len(parents) < 2:
245
            return None
246
        
247
        import re
248
        from bzrlib.osutils import format_date
249
        
250
        pending = parents[1:]
251
        branch = wt.branch
252
        last_revision = parents[0]
253
        
254
        if last_revision is not None:
255
            try:
256
                ignore = set(branch.repository.get_ancestry(last_revision))
257
            except errors.NoSuchRevision:
258
                # the last revision is a ghost : assume everything is new 
259
                # except for it
260
                ignore = set([None, last_revision])
261
        else:
262
            ignore = set([None])
263
        
264
        pm = []
265
        for merge in pending:
266
            ignore.add(merge)
267
            try:
268
                m_revision = branch.repository.get_revision(merge)
269
                
270
                rev = {}
271
                rev['committer'] = re.sub('<.*@.*>', '', m_revision.committer).strip(' ')
272
                rev['summary'] = m_revision.get_summary()
273
                rev['date'] = format_date(m_revision.timestamp,
274
                                          m_revision.timezone or 0, 
275
                                          'original', date_fmt="%Y-%m-%d",
276
                                          show_offset=False)
277
                
278
                pm.append(rev)
279
                
280
                inner_merges = branch.repository.get_ancestry(merge)
281
                assert inner_merges[0] is None
282
                inner_merges.pop(0)
283
                inner_merges.reverse()
284
                for mmerge in inner_merges:
285
                    if mmerge in ignore:
286
                        continue
287
                    mm_revision = branch.repository.get_revision(mmerge)
288
                    
289
                    rev = {}
290
                    rev['committer'] = re.sub('<.*@.*>', '', mm_revision.committer).strip(' ')
291
                    rev['summary'] = mm_revision.get_summary()
292
                    rev['date'] = format_date(mm_revision.timestamp,
293
                                              mm_revision.timezone or 0, 
294
                                              'original', date_fmt="%Y-%m-%d",
295
                                              show_offset=False)
296
                
297
                    pm.append(rev)
298
                    
299
                    ignore.add(mmerge)
300
            except errors.NoSuchRevision:
301
                print "DEBUG: NoSuchRevision:", merge
302
        
303
        return pm
304
305
    def _create_file_view(self):
306
        self._file_store = gtk.ListStore(gobject.TYPE_BOOLEAN,   # [0] checkbox
307
                                         gobject.TYPE_STRING,    # [1] path to display
308
                                         gobject.TYPE_STRING,    # [2] changes type
309
                                         gobject.TYPE_STRING)    # [3] real path
310
        self._treeview_files.set_model(self._file_store)
311
        crt = gtk.CellRendererToggle()
312
        crt.set_property("activatable", True)
313
        crt.connect("toggled", self._toggle_commit, self._file_store)
314
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Commit'),
315
                                     crt, active=0))
316
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Path'),
317
                                     gtk.CellRendererText(), text=1))
318
        self._treeview_files.append_column(gtk.TreeViewColumn(_('Type'),
319
                                     gtk.CellRendererText(), text=2))
320
321
        for path, id, kind in self.delta.added:
322
            marker = osutils.kind_marker(kind)
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
323
            if self.selected is not None:
324
                if path == os.path.join(self.wtpath, self.selected):
325
                    self._file_store.append([ True, path+marker, _('added'), path ])
326
                else:
327
                    self._file_store.append([ False, path+marker, _('added'), path ])
328
            else:
329
                self._file_store.append([ True, path+marker, _('added'), path ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
330
331
        for path, id, kind in self.delta.removed:
332
            marker = osutils.kind_marker(kind)
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
333
            if self.selected is not None:
334
                if path == os.path.join(self.wtpath, self.selected):
335
                    self._file_store.append([ True, path+marker, _('removed'), path ])
336
                else:
337
                    self._file_store.append([ False, path+marker, _('removed'), path ])
338
            else:
339
                self._file_store.append([ True, path+marker, _('removed'), path ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
340
341
        for oldpath, newpath, id, kind, text_modified, meta_modified in self.delta.renamed:
342
            marker = osutils.kind_marker(kind)
343
            if text_modified or meta_modified:
344
                changes = _('renamed and modified')
345
            else:
346
                changes = _('renamed')
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
347
            if self.selected is not None:
348
                if newpath == os.path.join(self.wtpath, self.selected):
349
                    self._file_store.append([ True,
350
                                              oldpath+marker + '  =>  ' + newpath+marker,
351
                                              changes,
352
                                              newpath
353
                                            ])
354
                else:
355
                    self._file_store.append([ False,
356
                                              oldpath+marker + '  =>  ' + newpath+marker,
357
                                              changes,
358
                                              newpath
359
                                            ])
360
            else:
361
                self._file_store.append([ True,
362
                                          oldpath+marker + '  =>  ' + newpath+marker,
363
                                          changes,
364
                                          newpath
365
                                        ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
366
367
        for path, id, kind, text_modified, meta_modified in self.delta.modified:
368
            marker = osutils.kind_marker(kind)
126.1.10 by Szilveszter Farkas (Phanatic)
Allow to commit single files from the context menu (Fixed: #54983)
369
            if self.selected is not None:
370
                if path == os.path.join(self.wtpath, self.selected):
371
                    self._file_store.append([ True, path+marker, _('modified'), path ])
372
                else:
373
                    self._file_store.append([ False, path+marker, _('modified'), path ])
374
            else:
375
                self._file_store.append([ True, path+marker, _('modified'), path ])
126.1.1 by Szilveszter Farkas (Phanatic)
New Commit dialog implementation (no more Glade).
376
    
377
    def _create_pending_merges(self):
378
        if not self.pending:
379
            return
380
        
381
        liststore = gtk.ListStore(gobject.TYPE_STRING,
382
                                  gobject.TYPE_STRING,
383
                                  gobject.TYPE_STRING)
384
        self._treeview_merges.set_model(liststore)
385
        
386
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Date'),
387
                                            gtk.CellRendererText(), text=0))
388
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Committer'),
389
                                            gtk.CellRendererText(), text=1))
390
        self._treeview_merges.append_column(gtk.TreeViewColumn(_('Summary'),
391
                                            gtk.CellRendererText(), text=2))
392
        
393
        for item in self.pending:
394
            liststore.append([ item['date'],
395
                               item['committer'],
396
                               item['summary'] ])
397
    
398
    def _get_specific_files(self):
399
        ret = []
400
        it = self._file_store.get_iter_first()
401
        while it:
402
            if self._file_store.get_value(it, 0):
403
                # get real path from hidden column 3
404
                ret.append(self._file_store.get_value(it, 3))
405
            it = self._file_store.iter_next(it)
406
407
        return ret
408
    
409
    def _toggle_commit(self, cell, path, model):
410
        model[path][0] = not model[path][0]
411
        return