/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 olive/commit.py

List pull and merge in nautilus-bzr.

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 gtk.glade
 
25
import gobject
 
26
import pango
 
27
 
 
28
import bzrlib.errors as errors
 
29
 
 
30
from dialog import error_dialog
 
31
from olive import gladefile
 
32
 
 
33
class CommitDialog:
 
34
    """ Display Commit dialog and perform the needed actions. """
 
35
    def __init__(self, wt, wtpath):
 
36
        """ Initialize the Commit dialog. """
 
37
        self.glade = gtk.glade.XML(gladefile, 'window_commit', 'olive-gtk')
 
38
        
 
39
        self.wt = wt
 
40
        self.wtpath = wtpath
 
41
 
 
42
        # Get some important widgets
 
43
        self.window = self.glade.get_widget('window_commit')
 
44
        self.checkbutton_local = self.glade.get_widget('checkbutton_commit_local')
 
45
        self.textview = self.glade.get_widget('textview_commit')
 
46
        self.file_view = self.glade.get_widget('treeview_commit_select')
 
47
        self.pending_label = self.glade.get_widget('label_commit_pending')
 
48
        self.pending_view = self.glade.get_widget('treeview_commit_pending')
 
49
 
 
50
        file_id = self.wt.path2id(wtpath)
 
51
 
 
52
        self.notbranch = False
 
53
        if file_id is None:
 
54
            self.notbranch = True
 
55
            return
 
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
        # Dictionary for signal_autoconnect
 
65
        dic = { "on_button_commit_commit_clicked": self.commit,
 
66
                "on_button_commit_cancel_clicked": self.close }
 
67
        
 
68
        # Connect the signals to the handlers
 
69
        self.glade.signal_autoconnect(dic)
 
70
        
 
71
        # Create the file list
 
72
        self._create_file_view()
 
73
        # Create the pending merges
 
74
        self._create_pending_merges()
 
75
    
 
76
    def display(self):
 
77
        """ Display the Push dialog. """
 
78
        if self.notbranch:
 
79
            error_dialog(_('Directory is not a branch'),
 
80
                         _('You can perform this action only in a branch.'))
 
81
            self.close()
 
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.checkbutton_local.show()
 
86
            
 
87
            if self.pending:
 
88
                # There are pending merges, file selection not supported
 
89
                self.file_view.set_sensitive(False)
 
90
            else:
 
91
                # No pending merges
 
92
                self.pending_view.set_sensitive(False)
 
93
            
 
94
            self.textview.modify_font(pango.FontDescription("Monospace"))
 
95
            self.window.show()
 
96
            
 
97
    
 
98
    def _create_file_view(self):
 
99
        self.file_store = gtk.ListStore(gobject.TYPE_BOOLEAN,
 
100
                                        gobject.TYPE_STRING,
 
101
                                        gobject.TYPE_STRING)
 
102
        self.file_view.set_model(self.file_store)
 
103
        crt = gtk.CellRendererToggle()
 
104
        crt.set_property("activatable", True)
 
105
        crt.connect("toggled", self._toggle_commit, self.file_store)
 
106
        self.file_view.append_column(gtk.TreeViewColumn(_('Commit'),
 
107
                                     crt, active=0))
 
108
        self.file_view.append_column(gtk.TreeViewColumn(_('Path'),
 
109
                                     gtk.CellRendererText(), text=1))
 
110
        self.file_view.append_column(gtk.TreeViewColumn(_('Type'),
 
111
                                     gtk.CellRendererText(), text=2))
 
112
 
 
113
        for path, id, kind in self.delta.added:
 
114
            self.file_store.append([ True, path, _('added') ])
 
115
 
 
116
        for path, id, kind in self.delta.removed:
 
117
            self.file_store.append([ True, path, _('removed') ])
 
118
 
 
119
        for oldpath, newpath, id, kind, text_modified, meta_modified in self.delta.renamed:
 
120
            self.file_store.append([ True, oldpath, _('renamed') ])
 
121
 
 
122
        for path, id, kind, text_modified, meta_modified in self.delta.modified:
 
123
            self.file_store.append([ True, path, _('modified') ])
 
124
    
 
125
    def _create_pending_merges(self):
 
126
        liststore = gtk.ListStore(gobject.TYPE_STRING,
 
127
                                  gobject.TYPE_STRING,
 
128
                                  gobject.TYPE_STRING)
 
129
        self.pending_view.set_model(liststore)
 
130
        
 
131
        self.pending_view.append_column(gtk.TreeViewColumn(_('Date'),
 
132
                                        gtk.CellRendererText(), text=0))
 
133
        self.pending_view.append_column(gtk.TreeViewColumn(_('Committer'),
 
134
                                        gtk.CellRendererText(), text=1))
 
135
        self.pending_view.append_column(gtk.TreeViewColumn(_('Summary'),
 
136
                                        gtk.CellRendererText(), text=2))
 
137
        
 
138
        if not self.pending:
 
139
            return
 
140
        
 
141
        for item in self.pending:
 
142
            liststore.append([ item['date'],
 
143
                               item['committer'],
 
144
                               item['summary'] ])
 
145
    
 
146
    def _get_specific_files(self):
 
147
        ret = []
 
148
        it = self.file_store.get_iter_first()
 
149
        while it:
 
150
            if self.file_store.get_value(it, 0):
 
151
                ret.append(self.file_store.get_value(it, 1))
 
152
            it = self.file_store.iter_next(it)
 
153
 
 
154
        return ret
 
155
    
 
156
    def _toggle_commit(self, cell, path, model):
 
157
        model[path][0] = not model[path][0]
 
158
        return
 
159
    
 
160
    def _pending_merges(self, wt):
 
161
        """ Return a list of pending merges or None if there are none of them. """
 
162
        parents = wt.get_parent_ids()
 
163
        if len(parents) < 2:
 
164
            return None
 
165
        
 
166
        import re
 
167
        from bzrlib.osutils import format_date
 
168
        
 
169
        pending = parents[1:]
 
170
        branch = wt.branch
 
171
        last_revision = parents[0]
 
172
        
 
173
        if last_revision is not None:
 
174
            try:
 
175
                ignore = set(branch.repository.get_ancestry(last_revision))
 
176
            except errors.NoSuchRevision:
 
177
                # the last revision is a ghost : assume everything is new 
 
178
                # except for it
 
179
                ignore = set([None, last_revision])
 
180
        else:
 
181
            ignore = set([None])
 
182
        
 
183
        pm = []
 
184
        for merge in pending:
 
185
            ignore.add(merge)
 
186
            try:
 
187
                m_revision = branch.repository.get_revision(merge)
 
188
                
 
189
                rev = {}
 
190
                rev['committer'] = re.sub('<.*@.*>', '', m_revision.committer).strip(' ')
 
191
                rev['summary'] = m_revision.get_summary()
 
192
                rev['date'] = format_date(m_revision.timestamp,
 
193
                                          m_revision.timezone or 0, 
 
194
                                          'original', date_fmt="%Y-%m-%d",
 
195
                                          show_offset=False)
 
196
                
 
197
                pm.append(rev)
 
198
                
 
199
                inner_merges = branch.repository.get_ancestry(merge)
 
200
                assert inner_merges[0] is None
 
201
                inner_merges.pop(0)
 
202
                inner_merges.reverse()
 
203
                for mmerge in inner_merges:
 
204
                    if mmerge in ignore:
 
205
                        continue
 
206
                    mm_revision = branch.repository.get_revision(mmerge)
 
207
                    
 
208
                    rev = {}
 
209
                    rev['committer'] = re.sub('<.*@.*>', '', mm_revision.committer).strip(' ')
 
210
                    rev['summary'] = mm_revision.get_summary()
 
211
                    rev['date'] = format_date(mm_revision.timestamp,
 
212
                                              mm_revision.timezone or 0, 
 
213
                                              'original', date_fmt="%Y-%m-%d",
 
214
                                              show_offset=False)
 
215
                
 
216
                    pm.append(rev)
 
217
                    
 
218
                    ignore.add(mmerge)
 
219
            except errors.NoSuchRevision:
 
220
                print "DEBUG: NoSuchRevision:", merge
 
221
        
 
222
        return pm
 
223
 
 
224
    def commit(self, widget):
 
225
        textbuffer = self.textview.get_buffer()
 
226
        start, end = textbuffer.get_bounds()
 
227
        message = textbuffer.get_text(start, end)
 
228
        
 
229
        checkbutton_strict = self.glade.get_widget('checkbutton_commit_strict')
 
230
        checkbutton_force = self.glade.get_widget('checkbutton_commit_force')
 
231
        
 
232
        if not self.pending:
 
233
            specific_files = self._get_specific_files()
 
234
        else:
 
235
            specific_files = None
 
236
        
 
237
        try:
 
238
            self.wt.commit(message, 
 
239
                           allow_pointless=checkbutton_force.get_active(),
 
240
                           strict=checkbutton_strict.get_active(),
 
241
                           local=self.checkbutton_local.get_active(),
 
242
                           specific_files=specific_files)
 
243
        except errors.NotBranchError:
 
244
            error_dialog(_('Directory is not a branch'),
 
245
                         _('You can perform this action only in a branch.'))
 
246
            return
 
247
        except errors.LocalRequiresBoundBranch:
 
248
            error_dialog(_('Directory is not a checkout'),
 
249
                         _('You can perform local commit only on checkouts.'))
 
250
            return
 
251
        except errors.PointlessCommit:
 
252
            error_dialog(_('No changes to commit'),
 
253
                         _('Try force commit if you want to commit anyway.'))
 
254
            return
 
255
        except errors.ConflictsInTree:
 
256
            error_dialog(_('Conflicts in tree'),
 
257
                         _('You need to resolve the conflicts before committing.'))
 
258
            return
 
259
        except errors.StrictCommitFailed:
 
260
            error_dialog(_('Strict commit failed'),
 
261
                         _('There are unknown files in the working tree.\nPlease add or delete them.'))
 
262
            return
 
263
        except errors.BoundBranchOutOfDate, errmsg:
 
264
            error_dialog(_('Bound branch is out of date'),
 
265
                         _('%s') % errmsg)
 
266
            return
 
267
        except errors.BzrError, msg:
 
268
            error_dialog(_('Unknown bzr error'), str(msg))
 
269
            return
 
270
        except Exception, msg:
 
271
            error_dialog(_('Unknown error'), str(msg))
 
272
            return
 
273
        
 
274
        self.close()
 
275
        
 
276
    def close(self, widget=None):
 
277
        self.window.destroy()