/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 nautilus-bzr.py

  • Committer: Curtis Hovey
  • Date: 2012-02-05 05:14:11 UTC
  • mto: This revision was merged to the branch mainline in revision 775.
  • Revision ID: sinzui.is@verizon.net-20120205051411-y9ra08wae1wsfv52
Remove unneeded gtksourceview1 support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
2
2
#
3
3
# Copyright (C) 2006 Jeff Bailey
4
4
# Copyright (C) 2006 Wouter van Heyst
5
 
# Copyright (C) 2006 Jelmer Vernooij
6
 
#
7
 
# Published under the GNU GPL
8
 
 
9
 
import gtk
10
 
import nautilus
11
 
import bzrlib
12
 
from bzrlib.bzrdir import BzrDir
13
 
from bzrlib.errors import NotBranchError
14
 
from bzrlib.errors import NoWorkingTree
15
 
from bzrlib.errors import UnsupportedProtocol
16
 
from bzrlib.workingtree import WorkingTree
17
 
from bzrlib.branch import Branch
18
 
from bzrlib.tree import file_status
 
5
# Copyright (C) 2006-2011 Jelmer Vernooij <jelmer@samba.org>
 
6
#
 
7
# This program is free software; you can redistribute it and/or modify
 
8
# it under the terms of the GNU General Public License as published by
 
9
# the Free Software Foundation; either version 3 of the License, or
 
10
# (at your option) any later version.
 
11
 
 
12
# This program is distributed in the hope that it will be useful,
 
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
# GNU General Public License for more details.
 
16
 
 
17
# You should have received a copy of the GNU General Public License
 
18
# along with this program; if not, write to the Free Software
 
19
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
20
 
 
21
# Installation:
 
22
# setup.py can install nautilus-bzr to the right system folder, if pkg-config
 
23
# is present.
 
24
#
 
25
# You can also install nautilus-bzr manually by copying it (or linking it from)
 
26
# ~/.local/share/nautilus-python/extensions/nautilus-bzr.py
 
27
 
 
28
from gi.repository import Gtk, GObject, Nautilus
 
29
from bzrlib.controldir import ControlDir
 
30
from bzrlib.errors import (
 
31
    NotBranchError,
 
32
    NoWorkingTree,
 
33
    )
 
34
from bzrlib.ignores import tree_ignores_add_patterns
 
35
from bzrlib.tree import InterTree
19
36
 
20
37
from bzrlib.plugin import load_plugins
21
38
load_plugins()
22
39
 
23
 
from bzrlib.plugins.gtk import cmd_visualise, cmd_gannotate
24
 
 
25
 
class BzrExtension(nautilus.MenuProvider, nautilus.ColumnProvider, nautilus.InfoProvider):
 
40
from bzrlib.plugins.gtk.i18n import _i18n
 
41
 
 
42
 
 
43
class BazaarExtension(Nautilus.MenuProvider, Nautilus.ColumnProvider,
 
44
        Nautilus.InfoProvider, Nautilus.PropertyPageProvider,
 
45
        Nautilus.LocationWidgetProvider, GObject.GObject):
 
46
    """Nautilus extension providing Bazaar integration."""
 
47
 
26
48
    def __init__(self):
27
49
        pass
28
50
 
29
 
    def add_cb(self, menu, vfs_file):
30
 
        # We can only cope with local files
31
 
        if vfs_file.get_uri_scheme() != 'file':
32
 
            return
33
 
 
34
 
        file = vfs_file.get_uri()
35
 
        try:
36
 
            tree, path = WorkingTree.open_containing(file)
37
 
        except NotBranchError:
38
 
            return
39
 
 
 
51
    @classmethod
 
52
    def _open_bzrdir(cls, vfs_file):
 
53
        uri = vfs_file.get_uri()
 
54
        controldir, path = ControlDir.open_containing(uri)
 
55
        return controldir, path
 
56
 
 
57
    @classmethod
 
58
    def _open_tree(cls, vfs_file):
 
59
        controldir, path = cls._open_bzrdir(vfs_file)
 
60
        return controldir.open_workingtree(), path
 
61
 
 
62
    def add_cb(self, menu, tree, path):
40
63
        tree.add(path)
41
64
 
42
 
        return
43
 
 
44
 
    def ignore_cb(self, menu, vfs_file):
45
 
        # We can only cope with local files
46
 
        if vfs_file.get_uri_scheme() != 'file':
47
 
            return
48
 
 
49
 
        file = vfs_file.get_uri()
50
 
        try:
51
 
            tree, path = WorkingTree.open_containing(file)
52
 
        except NotBranchError:
53
 
            return
54
 
 
55
 
        #FIXME
56
 
 
57
 
        return
58
 
 
59
 
    def unignore_cb(self, menu, vfs_file):
60
 
        # We can only cope with local files
61
 
        if vfs_file.get_uri_scheme() != 'file':
62
 
            return
63
 
 
64
 
        file = vfs_file.get_uri()
65
 
        try:
66
 
            tree, path = WorkingTree.open_containing(file)
67
 
        except NotBranchError:
68
 
            return
69
 
 
70
 
        #FIXME
71
 
 
72
 
        return
73
 
 
74
 
    def diff_cb(self, menu, vfs_file):
75
 
        # We can only cope with local files
76
 
        if vfs_file.get_uri_scheme() != 'file':
77
 
            return
78
 
 
79
 
        file = vfs_file.get_uri()
80
 
        try:
81
 
            tree, path = WorkingTree.open_containing(file)
82
 
        except NotBranchError:
83
 
            return
84
 
 
 
65
    def ignore_cb(self, menu, tree, path):
 
66
        # We can only cope with local files
 
67
        tree_ignores_add_patterns(tree, [path])
 
68
        #FIXME: Add path to ignore file
 
69
 
 
70
    def unignore_cb(self, menu, tree, path):
 
71
        pass
 
72
        # We can only cope with local files
 
73
        #FIXME
 
74
 
 
75
    def diff_cb(self, menu, tree, path=None):
85
76
        from bzrlib.plugins.gtk.diff import DiffWindow
86
77
        window = DiffWindow()
87
 
        window.set_diff(tree.branch.nick, tree, tree.branch.basis_tree())
 
78
        window.set_diff(tree.branch._get_nick(local=True), tree, 
 
79
                        tree.branch.basis_tree())
88
80
        window.show()
89
81
 
90
 
        return
91
 
 
92
82
    def newtree_cb(self, menu, vfs_file):
93
 
        # We can only cope with local files
94
 
        if vfs_file.get_uri_scheme() != 'file':
95
 
            return
96
 
 
97
 
        file = vfs_file.get_uri()
98
 
 
99
 
        # We only want to continue here if we get a NotBranchError
100
 
        try:
101
 
            tree, path = WorkingTree.open_containing(file)
102
 
        except NotBranchError:
103
 
            BzrDir.create_standalone_workingtree(file)
104
 
 
105
 
    def remove_cb(self, menu, vfs_file):
106
 
        # We can only cope with local files
107
 
        if vfs_file.get_uri_scheme() != 'file':
108
 
            return
109
 
 
110
 
        file = vfs_file.get_uri()
111
 
        try:
112
 
            tree, path = WorkingTree.open_containing(file)
113
 
        except NotBranchError:
114
 
            return
115
 
 
 
83
        controldir, path = self._open_bzrdir(vfs_file)
 
84
        controldir.create_workingtree()
 
85
 
 
86
    def remove_cb(self, menu, tree, path):
116
87
        tree.remove(path)
117
88
 
118
 
    def annotate_cb(self, menu, vfs_file):
119
 
        # We can only cope with local files
120
 
        if vfs_file.get_uri_scheme() != 'file':
121
 
            return
122
 
 
123
 
        file = vfs_file.get_uri()
124
 
 
125
 
        vis = cmd_gannotate()
126
 
        vis.run(file)
 
89
    def annotate_cb(self, menu, tree, path, file_id):
 
90
        from bzrlib.plugins.gtk.annotate.gannotate import GAnnotateWindow
 
91
        win = GAnnotateWindow()
 
92
        win.show()
 
93
        win.annotate(tree, tree.branch, file_id)
 
94
        Gtk.main()
127
95
 
128
96
    def clone_cb(self, menu, vfs_file=None):
129
 
        # We can only cope with local files
130
 
        if vfs_file.get_uri_scheme() != 'file':
131
 
            return
132
 
 
133
97
        from bzrlib.plugins.gtk.branch import BranchDialog
134
 
        
 
98
        controldir, path = self._open_bzrdir(vfs_file)
 
99
 
135
100
        dialog = BranchDialog(vfs_file.get_name())
136
101
        response = dialog.run()
137
 
        if response != gtk.RESPONSE_NONE:
 
102
        if response != Gtk.ResponseType.NONE:
138
103
            dialog.hide()
139
104
            dialog.destroy()
140
 
 
141
 
    def commit_cb(self, menu, vfs_file=None):
142
 
        # We can only cope with local files
143
 
        if vfs_file.get_uri_scheme() != 'file':
144
 
            return
145
 
 
146
 
        file = vfs_file.get_uri()
147
 
        tree = None
148
 
        branch = None
149
 
        try:
150
 
            tree, path = WorkingTree.open_containing(file)
151
 
            branch = tree.branch
152
 
        except NotBranchError, e:
153
 
            path = e.path
154
 
            #return
155
 
        except NoWorkingTree, e:
156
 
            path = e.base
157
 
            try:
158
 
                (branch, path) = Branch.open_containing(path)
159
 
            except NotBranchError, e:
160
 
                path = e.path
161
 
 
 
105
 
 
106
    def commit_cb(self, menu, tree, path=None):
162
107
        from bzrlib.plugins.gtk.commit import CommitDialog
163
 
        dialog = CommitDialog(tree, path, not branch)
 
108
        dialog = CommitDialog(tree, path)
164
109
        response = dialog.run()
165
 
        if response != gtk.RESPONSE_NONE:
 
110
        if response != Gtk.ResponseType.NONE:
166
111
            dialog.hide()
167
112
            dialog.destroy()
168
113
 
169
 
    def log_cb(self, menu, vfs_file):
170
 
        # We can only cope with local files
171
 
        if vfs_file.get_uri_scheme() != 'file':
172
 
            return
173
 
 
174
 
        file = vfs_file.get_uri()
175
 
 
176
 
        # We only want to continue here if we get a NotBranchError
177
 
        try:
178
 
            tree, path = WorkingTree.open_containing(file)
179
 
        except NotBranchError:
180
 
            return
181
 
 
182
 
        vis = cmd_visualise()
183
 
        vis.run(file)
184
 
 
185
 
        return
186
 
 
187
 
    def pull_cb(self, menu, vfs_file):
188
 
        # We can only cope with local files
189
 
        if vfs_file.get_uri_scheme() != 'file':
190
 
            return
191
 
 
192
 
        file = vfs_file.get_uri()
193
 
 
194
 
        # We only want to continue here if we get a NotBranchError
195
 
        try:
196
 
            tree, path = WorkingTree.open_containing(file)
197
 
        except NotBranchError:
198
 
            return
199
 
 
 
114
    def log_cb(self, menu, controldir, path=None):
 
115
        from bzrlib.plugins.gtk.viz import BranchWindow
 
116
        branch = controldir.open_branch()
 
117
        pp = BranchWindow(branch, [branch.last_revision()], None)
 
118
        pp.show()
 
119
        Gtk.main()
 
120
 
 
121
    def pull_cb(self, menu, controldir, path=None):
200
122
        from bzrlib.plugins.gtk.pull import PullDialog
201
 
        dialog = PullDialog(tree, path)
 
123
        dialog = PullDialog(controldir.open_workingtree(), path)
202
124
        dialog.display()
203
 
        gtk.main()
204
 
 
205
 
    def merge_cb(self, menu, vfs_file):
206
 
        # We can only cope with local files
207
 
        if vfs_file.get_uri_scheme() != 'file':
208
 
            return
209
 
 
210
 
        file = vfs_file.get_uri()
211
 
 
212
 
        # We only want to continue here if we get a NotBranchError
213
 
        try:
214
 
            tree, path = WorkingTree.open_containing(file)
215
 
        except NotBranchError:
216
 
            return
217
 
 
 
125
        Gtk.main()
 
126
 
 
127
    def merge_cb(self, menu, tree, path=None):
218
128
        from bzrlib.plugins.gtk.merge import MergeDialog
219
129
        dialog = MergeDialog(tree, path)
220
 
        dialog.display()
221
 
        gtk.main()
 
130
        dialog.run()
 
131
        dialog.destroy()
 
132
 
 
133
    def create_tree_cb(self, menu, controldir):
 
134
        controldir.create_workingtree()
222
135
 
223
136
    def get_background_items(self, window, vfs_file):
224
 
        items = []
225
 
        file = vfs_file.get_uri()
226
137
        try:
227
 
            tree, path = WorkingTree.open_containing(file)
228
 
        except UnsupportedProtocol:
 
138
            controldir, path = self._open_bzrdir(vfs_file)
 
139
        except NotBranchError:
229
140
            return
 
141
        try:
 
142
            branch = controldir.open_branch()
230
143
        except NotBranchError:
231
 
            item = nautilus.MenuItem('BzrNautilus::newtree',
232
 
                                 'Make directory versioned',
233
 
                                 'Create new Bazaar tree in this folder')
 
144
            items = []
 
145
            item = Nautilus.MenuItem(name='BzrNautilus::newtree',
 
146
                                 label='Make directory versioned',
 
147
                                 tip='Create new Bazaar tree in this folder',
 
148
                                 icon='')
234
149
            item.connect('activate', self.newtree_cb, vfs_file)
235
150
            items.append(item)
236
151
 
237
 
            item = nautilus.MenuItem('BzrNautilus::clone',
238
 
                                 'Checkout Bazaar branch',
239
 
                                 'Checkout Existing Bazaar Branch')
 
152
            item = Nautilus.MenuItem(name='BzrNautilus::clone',
 
153
                                 label='Checkout Bazaar branch ...',
 
154
                                 tip='Checkout Existing Bazaar Branch',
 
155
                                 icon='')
240
156
            item.connect('activate', self.clone_cb, vfs_file)
241
157
            items.append(item)
242
 
 
243
158
            return items
244
159
 
245
 
        item = nautilus.MenuItem('BzrNautilus::log',
246
 
                             'Log',
247
 
                             'Show Bazaar history')
248
 
        item.connect('activate', self.log_cb, vfs_file)
249
 
        items.append(item)
250
 
 
251
 
        item = nautilus.MenuItem('BzrNautilus::pull',
252
 
                             'Pull',
253
 
                             'Pull from another branch')
254
 
        item.connect('activate', self.pull_cb, vfs_file)
255
 
        items.append(item)
256
 
 
257
 
        item = nautilus.MenuItem('BzrNautilus::merge',
258
 
                             'Merge',
259
 
                             'Merge from another branch')
260
 
        item.connect('activate', self.merge_cb, vfs_file)
261
 
        items.append(item)
262
 
 
263
 
        item = nautilus.MenuItem('BzrNautilus::commit',
264
 
                             'Commit',
265
 
                             'Commit Changes')
266
 
        item.connect('activate', self.commit_cb, vfs_file)
267
 
        items.append(item)
 
160
        items = []
 
161
 
 
162
        nautilus_integration = self.check_branch_enabled(branch)
 
163
        if not nautilus_integration:
 
164
            item = Nautilus.MenuItem(name='BzrNautilus::enable',
 
165
                                     label='Enable Bazaar Plugin for this Branch',
 
166
                                     tip='Enable Bazaar plugin for nautilus',
 
167
                                     icon='')
 
168
            item.connect('activate', self.toggle_integration, True, branch)
 
169
            return [item]
 
170
        else:
 
171
            item = Nautilus.MenuItem(name='BzrNautilus::disable',
 
172
                                     label='Disable Bazaar Plugin this Branch',
 
173
                                     tip='Disable Bazaar plugin for nautilus',
 
174
                                     icon='')
 
175
            item.connect('activate', self.toggle_integration, False, branch)
 
176
            items.append(item)
 
177
 
 
178
        item = Nautilus.MenuItem(name='BzrNautilus::log',
 
179
                             label='History ...',
 
180
                             tip='Show Bazaar history',
 
181
                             icon='')
 
182
        item.connect('activate', self.log_cb, controldir)
 
183
        items.append(item)
 
184
 
 
185
        item = Nautilus.MenuItem(name='BzrNautilus::pull',
 
186
                             label='Pull ...',
 
187
                             tip='Pull from another branch',
 
188
                             icon='')
 
189
        item.connect('activate', self.pull_cb, controldir)
 
190
        items.append(item)
 
191
 
 
192
        try:
 
193
            tree = controldir.open_workingtree()
 
194
        except NoWorkingTree:
 
195
            item = Nautilus.MenuItem(name='BzrNautilus::create_tree',
 
196
                                 label='Create working tree...',
 
197
                                 tip='Create a working tree for this branch',
 
198
                                 icon='')
 
199
            item.connect('activate', self.create_tree_cb, controldir)
 
200
            items.append(item)
 
201
        else:
 
202
            item = Nautilus.MenuItem(name='BzrNautilus::merge',
 
203
                                 label='Merge ...',
 
204
                                 tip='Merge from another branch',
 
205
                                 icon='')
 
206
            item.connect('activate', self.merge_cb, tree, path)
 
207
            items.append(item)
 
208
 
 
209
            item = Nautilus.MenuItem(name='BzrNautilus::commit',
 
210
                                 label='Commit ...',
 
211
                                 tip='Commit Changes',
 
212
                                 icon='')
 
213
            item.connect('activate', self.commit_cb, tree, path)
 
214
            items.append(item)
268
215
 
269
216
        return items
270
217
 
 
218
    def _get_file_menuitems(self, tree, intertree, path):
 
219
        file_id = tree.path2id(path)
 
220
        if file_id is None:
 
221
            item = Nautilus.MenuItem(name='BzrNautilus::add',
 
222
                                 label='Add',
 
223
                                 tip='Add as versioned file',
 
224
                                 icon='')
 
225
            item.connect('activate', self.add_cb, tree, path)
 
226
            yield item
 
227
 
 
228
            item = Nautilus.MenuItem(name='BzrNautilus::ignore',
 
229
                                 label='Ignore',
 
230
                                 tip='Ignore file for versioning',
 
231
                                 icon='')
 
232
            item.connect('activate', self.ignore_cb, tree, path)
 
233
            yield item
 
234
        elif tree.is_ignored(path):
 
235
            item = Nautilus.MenuItem(name='BzrNautilus::unignore',
 
236
                                 label='Unignore',
 
237
                                 tip='Unignore file for versioning',
 
238
                                 icon='')
 
239
            item.connect('activate', self.unignore_cb, tree, path)
 
240
            yield item
 
241
        else:
 
242
            item = Nautilus.MenuItem(name='BzrNautilus::log',
 
243
                             label='History ...',
 
244
                             tip='List changes',
 
245
                             icon='')
 
246
            item.connect('activate', self.log_cb, tree.bzrdir, path)
 
247
            yield item
 
248
 
 
249
            if not intertree.file_content_matches(file_id, file_id):
 
250
                item = Nautilus.MenuItem(name='BzrNautilus::diff',
 
251
                                 label='View Changes ...',
 
252
                                 tip='Show differences',
 
253
                                 icon='')
 
254
                item.connect('activate', self.diff_cb, tree, path)
 
255
                yield item
 
256
 
 
257
                item = Nautilus.MenuItem(name='BzrNautilus::commit',
 
258
                             label='Commit ...',
 
259
                             tip='Commit Changes',
 
260
                             icon='')
 
261
                item.connect('activate', self.commit_cb, tree, path)
 
262
                yield item
 
263
 
 
264
            item = Nautilus.MenuItem(name='BzrNautilus::remove',
 
265
                                 label='Remove',
 
266
                                 tip='Remove this file from versioning',
 
267
                                 icon='')
 
268
            item.connect('activate', self.remove_cb, tree, path)
 
269
            yield item
 
270
 
 
271
            item = Nautilus.MenuItem(name='BzrNautilus::annotate',
 
272
                         label='Annotate ...',
 
273
                         tip='Annotate File Data',
 
274
                         icon='')
 
275
            item.connect('activate', self.annotate_cb, tree, path, file_id)
 
276
            yield item
271
277
 
272
278
    def get_file_items(self, window, files):
273
279
        items = []
274
 
 
275
 
        wtfiles = {}
276
 
        for vfs_file in files:
277
 
            # We can only cope with local files
278
 
            if vfs_file.get_uri_scheme() != 'file':
279
 
                return
280
 
 
281
 
            file = vfs_file.get_uri()
282
 
            try:
283
 
                tree, path = WorkingTree.open_containing(file)
284
 
            except NotBranchError:
285
 
                if not vfs_file.is_directory():
286
 
                    return
287
 
                item = nautilus.MenuItem('BzrNautilus::newtree',
288
 
                                     'Make directory versioned',
289
 
                                     'Create new Bazaar tree in %s' % vfs_file.get_name())
290
 
                item.connect('activate', self.newtree_cb, vfs_file)
291
 
                return item,
292
 
            # Refresh the list of filestatuses in the working tree
293
 
            if path not in wtfiles.keys():
294
 
                tree.lock_read()
295
 
                for rpath, file_class, kind, id, entry in tree.list_files():
296
 
                    wtfiles[rpath] = file_class
 
280
        trees = {}
 
281
 
 
282
        try:
 
283
            for vfs_file in files:
 
284
                controldir, path = self._open_bzrdir(vfs_file)
 
285
 
 
286
                try:
 
287
                    tree = trees[controldir.user_url]
 
288
                except KeyError:
 
289
                    try:
 
290
                        tree = controldir.open_workingtree()
 
291
                    except NoWorkingTree:
 
292
                        continue
 
293
                    trees[controldir.user_url] = tree
 
294
                    tree.lock_read()
 
295
 
 
296
                nautilus_integration = self.check_branch_enabled(tree.branch)
 
297
                if not nautilus_integration:
 
298
                    continue
 
299
 
 
300
                intertree = InterTree.get(tree.basis_tree(), tree)
 
301
                items.extend(list(self._get_file_menuitems(tree, intertree, path)))
 
302
        finally:
 
303
            for tree in trees.itervalues():
297
304
                tree.unlock()
298
 
                wtfiles[u''] = 'V'
299
 
 
300
 
            if wtfiles[path] == '?':
301
 
                item = nautilus.MenuItem('BzrNautilus::add',
302
 
                                     'Add',
303
 
                                     'Add as versioned file')
304
 
                item.connect('activate', self.add_cb, vfs_file)
305
 
                items.append(item)
306
 
 
307
 
                item = nautilus.MenuItem('BzrNautilus::ignore',
308
 
                                     'Ignore',
309
 
                                     'Ignore file for versioning')
310
 
                item.connect('activate', self.ignore_cb, vfs_file)
311
 
                items.append(item)
312
 
            elif wtfiles[path] == 'I':
313
 
                item = nautilus.MenuItem('BzrNautilus::unignore',
314
 
                                     'Unignore',
315
 
                                     'Unignore file for versioning')
316
 
                item.connect('activate', self.unignore_cb, vfs_file)
317
 
                items.append(item)
318
 
            elif wtfiles[path] == 'V':
319
 
                item = nautilus.MenuItem('BzrNautilus::log',
320
 
                                 'Log',
321
 
                                 'List changes')
322
 
                item.connect('activate', self.log_cb, vfs_file)
323
 
                items.append(item)
324
 
 
325
 
                item = nautilus.MenuItem('BzrNautilus::diff',
326
 
                                 'Diff',
327
 
                                 'Show differences')
328
 
                item.connect('activate', self.diff_cb, vfs_file)
329
 
                items.append(item)
330
 
 
331
 
                item = nautilus.MenuItem('BzrNautilus::remove',
332
 
                                     'Remove',
333
 
                                     'Remove this file from versioning')
334
 
                item.connect('activate', self.remove_cb, vfs_file)
335
 
                items.append(item)
336
 
 
337
 
                item = nautilus.MenuItem('BzrNautilus::annotate',
338
 
                             'Annotate',
339
 
                             'Annotate File Data')
340
 
                item.connect('activate', self.annotate_cb, vfs_file)
341
 
                items.append(item)
342
 
 
343
 
                item = nautilus.MenuItem('BzrNautilus::commit',
344
 
                             'Commit',
345
 
                             'Commit Changes')
346
 
                item.connect('activate', self.commit_cb, vfs_file)
347
 
                items.append(item)
348
305
 
349
306
        return items
350
307
 
351
308
    def get_columns(self):
352
 
        return nautilus.Column("BzrNautilus::bzr_status",
353
 
                               "bzr_status",
354
 
                               "Bzr Status",
355
 
                               "Version control status"),
356
 
 
357
 
    def update_file_info(self, file):
358
 
        if file.get_uri_scheme() != 'file':
359
 
            return
360
 
        
361
 
        try:
362
 
            tree, path = WorkingTree.open_containing(file.get_uri())
363
 
        except NotBranchError:
364
 
            return
365
 
 
 
309
        return [
 
310
            Nautilus.Column(name="BzrNautilus::bzr_status",
 
311
                            attribute="bzr_status",
 
312
                            label="Status",
 
313
                            description="Version control status"),
 
314
            Nautilus.Column(name="BzrNautilus::bzr_revision",
 
315
                            attribute="bzr_revision",
 
316
                            label="Revision",
 
317
                            description="Last change revision"),
 
318
            ]
 
319
 
 
320
    def _file_summary(self, tree, basis_tree, intertree, path):
 
321
        file_revision = ""
366
322
        emblem = None
367
 
        status = None
368
 
 
369
 
        if tree.has_filename(path):
370
 
            emblem = 'cvs-controlled'
371
 
            status = 'unchanged'
372
 
            id = tree.path2id(path)
373
 
 
374
 
            delta = tree.changes_from(tree.branch.basis_tree())
375
 
            if delta.touches_file_id(id):
376
 
                emblem = 'cvs-modified'
377
 
                status = 'modified'
378
 
            for f, _, _ in delta.added:
379
 
                if f == path:
380
 
                    emblem = 'cvs-added'
 
323
 
 
324
        file_id = tree.path2id(path)
 
325
        if file_id is None:
 
326
            if tree.is_ignored(path):
 
327
                status = 'ignored'
 
328
                emblem = 'bzr-ignored'
 
329
            else:
 
330
                status = 'unversioned'
 
331
            file_revision = "N/A"
 
332
        elif tree.has_filename(path): # Still present
 
333
            if not intertree.file_content_matches(file_id, file_id):
 
334
                if not basis_tree.has_id(file_id):
 
335
                    emblem = 'bzr-added'
381
336
                    status = 'added'
382
 
 
383
 
            for of, f, _, _, _, _ in delta.renamed:
384
 
                if f == path:
385
 
                    status = 'renamed from %s' % f
386
 
 
387
 
        elif tree.branch.basis_tree().has_filename(path):
388
 
            emblem = 'cvs-removed'
 
337
                    file_revision = "new file"
 
338
                elif basis_tree.path2id(file_id) != path:
 
339
                    status = 'bzr-renamed'
 
340
                    status = 'renamed from %s' % basis_tree.path2id(file_id)
 
341
                else:
 
342
                    emblem = 'bzr-modified'
 
343
                    status = 'modified'
 
344
            else:
 
345
                emblem = 'bzr-controlled'
 
346
                status = 'unchanged'
 
347
        elif basis_tree.has_filename(path):
 
348
            emblem = 'bzr-removed'
389
349
            status = 'removed'
390
350
        else:
391
351
            # FIXME: Check for ignored files
392
352
            status = 'unversioned'
393
 
        
394
 
        if emblem is not None:
395
 
            file.add_emblem(emblem)
396
 
        file.add_string_attribute('bzr_status', status)
 
353
        return (status, emblem, file_revision)
 
354
 
 
355
    def update_file_info(self, vfs_file):
 
356
        try:
 
357
            controldir, path = self._open_bzrdir(vfs_file)
 
358
        except NotBranchError:
 
359
            return
 
360
 
 
361
        try:
 
362
            tree = controldir.open_workingtree()
 
363
        except NoWorkingTree:
 
364
            return
 
365
 
 
366
        tree.lock_read()
 
367
        try:
 
368
            nautilus_integration = self.check_branch_enabled(tree.branch)
 
369
            if not nautilus_integration:
 
370
                return
 
371
 
 
372
            basis_tree = tree.basis_tree()
 
373
            intertree = InterTree.get(basis_tree, tree)
 
374
 
 
375
            basis_tree.lock_read()
 
376
            try:
 
377
                (status, emblem, file_revision) = self._file_summary(tree, basis_tree, intertree, path)
 
378
            finally:
 
379
                basis_tree.unlock()
 
380
            if emblem is not None:
 
381
                vfs_file.add_emblem(emblem)
 
382
            vfs_file.add_string_attribute('bzr_status', status)
 
383
            vfs_file.add_string_attribute('bzr_revision', file_revision)
 
384
        finally:
 
385
            tree.unlock()
 
386
 
 
387
    def check_branch_enabled(self, branch):
 
388
        # Supports global disable, but there is currently no UI to do this
 
389
        config = branch.get_config_stack()
 
390
        return config.get("nautilus_integration")
 
391
 
 
392
    def toggle_integration(self, menu, action, branch):
 
393
        config = branch.get_config_stack()
 
394
        config.set("nautilus_integration", action)
 
395
 
 
396
    def get_property_pages(self, files):
 
397
        pages = []
 
398
        for vfs_file in files:
 
399
            try:
 
400
                controldir, path = self._open_bzrdir(vfs_file)
 
401
            except NotBranchError:
 
402
                continue
 
403
 
 
404
            try:
 
405
                tree = controldir.open_workingtree()
 
406
            except NoWorkingTree:
 
407
                continue
 
408
 
 
409
            tree.lock_read()
 
410
            try:
 
411
                file_id = tree.path2id(path)
 
412
                pages.append(PropertyPageFile(tree, file_id, path))
 
413
                pages.append(PropertyPageBranch(tree.branch))
 
414
            finally:
 
415
                tree.unlock()
 
416
        return pages
 
417
 
 
418
    def get_widget(self, uri, window):
 
419
        controldir, path = ControlDir.open_containing(uri)
 
420
        try:
 
421
            tree = controldir.open_workingtree()
 
422
        except NoWorkingTree:
 
423
            return
 
424
        ret = Gtk.HBox(False, 4)
 
425
        text = 'This is a Bazaar working tree. '
 
426
        get_shelf_manager = getattr(tree, 'get_shelf_manager', None)
 
427
        if get_shelf_manager is not None:
 
428
            manager = get_shelf_manager()
 
429
            shelves = manager.active_shelves()
 
430
            if len(shelves) == 0:
 
431
                pass
 
432
            elif len(shelves) == 1:
 
433
                text += '1 shelf exists. '
 
434
            else:
 
435
                text += '%d shelf exists. ' % len(shelves)
 
436
        label = Gtk.Label(text)
 
437
        label.show()
 
438
        ret.pack_start(label, True, True, 0)
 
439
        ret.show_all()
 
440
        return ret
 
441
 
 
442
 
 
443
class PropertyPageFile(Nautilus.PropertyPage):
 
444
 
 
445
    def __init__(self, tree, file_id, path):
 
446
        self.tree = tree
 
447
        self.file_id = file_id
 
448
        self.path = path
 
449
        label = Gtk.Label('File Version')
 
450
        label.show()
 
451
 
 
452
        table = self._create_table()
 
453
 
 
454
        super(PropertyPageFile, self).__init__(label=label,
 
455
            name="BzrNautilus::file_page", page=table)
 
456
 
 
457
    def _create_table(self):
 
458
        table = Gtk.Table(homogeneous=False, columns=2, rows=3)
 
459
 
 
460
        table.attach(Gtk.Label(_i18n('File id:')), 0, 1, 0, 1)
 
461
        table.attach(Gtk.Label(self.file_id), 1, 2, 0, 1)
 
462
 
 
463
        table.attach(Gtk.Label(_i18n('SHA1Sum:')), 0, 1, 1, 2)
 
464
        table.attach(Gtk.Label(self.tree.get_file_sha1(self.file_id, self.path)), 1, 1, 1, 2)
 
465
 
 
466
        basis_tree = self.tree.revision_tree(self.tree.last_revision())
 
467
        last_revision = basis_tree.get_file_revision(self.file_id)
 
468
 
 
469
        table.attach(Gtk.Label(_i18n('Last Change Revision:')), 0, 1, 2, 3)
 
470
        revno = ".".join([str(x) for x in
 
471
            self.tree.branch.revision_id_to_dotted_revno(last_revision)])
 
472
        table.attach(Gtk.Label(revno), 1, 1, 2, 3)
 
473
 
 
474
        table.attach(Gtk.Label(_i18n('Last Change Author:')), 0, 1, 3, 4)
 
475
        rev = self.tree.branch.repository.get_revision(last_revision)
 
476
        table.attach(Gtk.Label("\n".join(rev.get_apparent_authors())), 1, 1, 3, 4)
 
477
 
 
478
        table.show_all()
 
479
        return table
 
480
 
 
481
 
 
482
class PropertyPageBranch(Nautilus.PropertyPage):
 
483
 
 
484
    def __init__(self, branch):
 
485
        self.branch = branch
 
486
        label = Gtk.Label('Branch')
 
487
        label.show()
 
488
 
 
489
        table = self._create_table()
 
490
 
 
491
        super(PropertyPageBranch, self).__init__(label=label,
 
492
            name="BzrNautilus::branch_page", page=table)
 
493
 
 
494
    def _create_location_entry(self, get_location, set_location):
 
495
        location = get_location()
 
496
        ret = Gtk.Entry()
 
497
        if location is not None:
 
498
            ret.set_text(location)
 
499
        return ret
 
500
 
 
501
    def _create_table(self):
 
502
        table = Gtk.Table(homogeneous=False, columns=2, rows=6)
 
503
 
 
504
        self._push_location_entry = self._create_location_entry(
 
505
            self.branch.get_push_location, self.branch.set_push_location)
 
506
        self._parent_location_entry = self._create_location_entry(
 
507
            self.branch.get_parent, self.branch.set_parent)
 
508
        self._bound_location_entry = self._create_location_entry(
 
509
            self.branch.get_bound_location, self.branch.set_bound_location)
 
510
        self._public_location_entry = self._create_location_entry(
 
511
            self.branch.get_public_branch, self.branch.set_public_branch)
 
512
        self._submit_location_entry = self._create_location_entry(
 
513
            self.branch.get_submit_branch, self.branch.set_submit_branch)
 
514
 
 
515
        table.attach(Gtk.Label(_i18n('Push location:')), 0, 1, 0, 1)
 
516
        table.attach(self._push_location_entry, 1, 2, 0, 1)
 
517
 
 
518
        table.attach(Gtk.Label(_i18n('Parent location:')), 0, 1, 1, 2)
 
519
        table.attach(self._parent_location_entry, 1, 1, 1, 2)
 
520
 
 
521
        table.attach(Gtk.Label(_i18n('Bound location:')), 0, 1, 2, 3)
 
522
        table.attach(self._bound_location_entry, 1, 1, 2, 3)
 
523
 
 
524
        table.attach(Gtk.Label(_i18n('Public location:')), 0, 1, 3, 4)
 
525
        table.attach(self._public_location_entry, 1, 1, 3, 4)
 
526
 
 
527
        table.attach(Gtk.Label(_i18n('Submit location:')), 0, 1, 4, 5)
 
528
        table.attach(self._submit_location_entry, 1, 1, 4, 5)
 
529
 
 
530
        self._append_revisions_only = Gtk.CheckButton(_i18n('Append revisions only'))
 
531
        value = self.branch.get_append_revisions_only()
 
532
        if value is None:
 
533
            value = False
 
534
        self._append_revisions_only.set_active(value)
 
535
        table.attach(self._append_revisions_only, 0, 2, 5, 6)
 
536
 
 
537
        table.show_all()
 
538
        return table