/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: Jelmer Vernooij
  • Date: 2012-03-29 13:15:14 UTC
  • mfrom: (786.1.1 register-lazy)
  • Revision ID: jelmer@samba.org-20120329131514-knrl1w2wzntx89rv
Use lazy registration.

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