/b-gtk/fix-viz

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/b-gtk/fix-viz

« back to all changes in this revision

Viewing changes to commit.py

  • Committer: Scott James Remnant
  • Date: 2005-10-17 01:07:49 UTC
  • Revision ID: scott@netsplit.com-20051017010749-15fa95fc2cf09289
Commit the first version of bzrk.

Show diffs side-by-side

added added

removed removed

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